接口加密总结

本文分享了在公司接口遭受攻击后,采用接口加密作为防御措施的全过程。通过对比多种加密方案,如基于filter、RequestBodyAdvice和HandlerMethodArgumentResolver的实现,最终选定spring提供的HandlerInterceptorAdapter结合HttpServletRequestWrapper实现接口加密。文章深入探讨了不同方案的优缺点及实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要做接口加密

头几天公司注册接口被人用ip池攻击了,攻击者不断用不同的手机号码攻击我们的接口来确认这个手机号是否在我们平台注册,这个人使用的是ip池,大约几千个的感觉,手机号也不是有规律的,所以也没有触发公司运维的防御系统(这说明运维的防御系统有很大问题啊!)为什么发现也是很偶然,leader突发奇想去线上看一下nginx的日志,发现这个接口访问异常的高,观察了一阵之后确认的。

解决

有了问题肯定要解决啊,内部怎么处理这种攻击的就不方便说了。

需求

leader提出了要对接口进行加密工作。这个工作就落到我身上了。
我们的期望是:

  1. 将这个新的依赖做成一个jar,引入之后,不需要配置,或者很少的配置就可以进行使用,最好是在需要加密的接口上加个注解就可以实现。
  2. 这个jar必须能够兼容老接口,对老接口不能进行修改,但是可以拓展(设计模式中的对修改关闭和对拓展开放)
  3. 公司有两种controller层的框架,一种是springmvc,另一种是基于小米的rose框架进行二次开发的自研框架,这个jar必须能够兼容这两种框架。
  4. get请求和post请求都支持
  5. 实现最好优雅,杂乱的代码没有人愿意看

确定加密方案

加密方案我们选择了https的加密模型——对称加密加密数据,非对称加密加密对称加密密钥。

开发方案

基于filter的解决方案

首先想做一种两种框架都支持的解决方案,要兼容两种不同的控制层框架,肯定得将解密的过程在一个请求的实际处理过程中提的非常前才行,理所应该的想到了filter来实现。

问题

  1. 想要在filter中从request中把请求的密文拦截,然后解密,然后再讲解密出来的参数塞回request中,但是有一个问题是,request的inputstream只能读一次,再次读的话就会没有了。这不行呀,我还希望不会对后来的请求造成影响呢,这样的话controller获取的参数都是null了。
  2. 还有一个问题是,我对于老接口怎么拦截呢?filter是基于路径的呀,我一个controller类中可能有好几个方法的呀,我不能基于controller的类进行拦截啊!如果对每一个方法层面进行路径的修改的话,那改动就打了呀!

解决

  1. 针对第一个问题,想到了使用HttpServletRequestWrapper包装一下我的请求,这个方案解决了第一个问题
  2. 针对第二个问题,我想到了在request的header中带一个特征过来,如果有这个特征我就认为是需要解密的请求,否则放行。可是又引入了另一个问题:***如果攻击者不将这个特征带过来,参数还是按照未加密的方式传过来,那我的加密就和没有做一样的呀!***为了解决这个问题,我就想到了使用一个controller层的intercepter来进行拦截一下请求加上注解的方法的request的header中有没有对应的特征,但是这种方案不是很优雅。搁置。。。

springmvc基于RequestBodyAdvice的实现

RequestBodyAdvice是springmvc提供的一个接口(公司二次开发的框架我下文就不说了),他在一个请求的生命周期的作用位置在参数解析器之前,如果我能在RequestBodyAdvice中将请求中的参数解密,就可以被controller正常的拿到。

问题

理想很丰满,现实很骨感,RequestBodyAdvice只针对@RequestBody注解生效的,这就意味着如果是get方法或者是使用了post但是不是@RequestBody接参数的方法就没有办法支持了,强行使用不满足我们不改造老接口的初衷,这个方案废弃了。(但是如果你的项目是新开发的,同时需要接口加密的话,那这个是一个很好的解决方案哦,而且代码实现起来很优雅!)

我其实是在代码写完了之后才发现这个问题的,造成这个问题的原因还是初期没有调研完全(后来我决定避免这种问题,但是还是没有避免成,哭晕在厕所),没有想完整就去写了代码,浪费了半天的时间。当时看见这个方案的时候确实可以完美解决部分情况,但是却忘记考虑了其他的情况,大家引以为戒!

springmvc基于HandlerMethodArgumentResolver的实现

参数解析器使我们想到的另一个方案,觉得这个方案是一个完美的方案,在自定义的HandlerMethodArgumentResolver执行完后,执行内置的参数解析器(其实这里就埋下了失败的伏笔)。为了防止上一个调研不完全的问题再次发生,我去看了一下RequestMappingHandlerAdapter的源码,在spring加载完这个bean的之后,会触发afterPropertiesSe方法,在这个方法中,会获取所有的buildin的参数解析器,然后获取自定义参数解析器(这一步我就应该有警觉),将这些放在一个list中,我这时候就以为springmvc的参数解析器是链式调用的,调用完自定义的会调用buildin的,于是开始动工了,写完之后发现,为什么我解密之后咋json没有被controller拿到呢?难道是我的参数解析器在内置的解析器之后调用了?我应该怎么提前呢?这个接口没有给我设置他解析顺序的参数或者方法让我去override呀(这时候我还没有发现),去看源码吧,傻眼了,他的参数解析器根本不是链式的,而是调用他们的support方法,谁返回true就break跳出循环了。这个方案宣告失败!

还是事先调研的不够多,不应该去看加载,应该去看他是怎么取参数解析器的,方向搞错了,下次注意

最终方案

spring提供的HandlerInterceptorAdapter内部用HttpServletRequestWrapper包装request,然后forward到原来的接口实现。

写在最后

有人可能觉得我写的不是很详细,前端是怎么加密的,后台又是怎么搞的都没有说,只是说了几个使用的接口。一是因为这个东西本来就是为了防御别人的,我如果将我们的加密方案都公布出来,我做的加密有什么意义呢?;另一个方面,这个加密的思想都差不多,都是对称加密和非对称加密,核心的代码都差不多,就在于后台使用什么壳来做解密的工作,我这篇文章主要就是介绍了我选择壳的过程。

在Spring Boot中,可以使用RequestBodyAdvice和ResponseBodyAdvice来实现接口加密和解密逻辑。这两个接口可以在方法中使用@RequestBody和@ResponseBody注解时生效。具体的实现步骤如下: 1. 创建一个自动配置类,比如AppConfig,用于配置加密和解密的相关参数。在该类中,可以使用@Bean注解创建一个AES对象,用于进行加密和解密操作。可以参考\[3\]中的示例代码。 2. 在自动配置类中,可以使用@Configuration注解标记该类为配置类,并使用@Resource注解注入CryptConfig对象,该对象用于获取加密和解密的相关配置参数。 3. 在加密和解密的逻辑中,可以使用AES对象进行加密和解密操作。可以根据具体的需求选择合适的加密模式、填充方式、密钥和向量等参数。 4. 在接口方法中,使用@RequestBody注解标记需要加密的请求数据,在方法中进行解密操作。然后处理相应的业务逻辑,并使用@ResponseBody注解标记需要加密的返回数据,在返回之前进行加密操作。 通过以上步骤,可以将加密和解密的逻辑提取出来,使接口方法只关注业务逻辑的处理。具体的实现可以参考\[2\]中的项目结构示例代码。 总结起来,使用Spring Boot的RequestBodyAdvice和ResponseBodyAdvice可以很方便地实现接口加密和解密逻辑,提高代码的可维护性和安全性。 #### 引用[.reference_title] - *1* [springboot中如何优雅的对接口数据进行加密解密](https://blog.youkuaiyun.com/xinghui_liu/article/details/121208804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [SpringBoot 接口加密解密,新姿势!](https://blog.youkuaiyun.com/qq_42914528/article/details/128168527)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值