赞
踩
大家好,我是程序员大猩猩。
在我们日常开发中,通常不会考虑到Api的安全性,但是在运维部署时,如果是小公司,大可能的配置ssl文件是免费的,安全性并不是很高,市场上有很多的工具可以简单的进行破解,这大大的增加了我们Api接口的风险值。
如果不管不问,我们的Api接口就像在互联网上裸奔一样,专业破解方就像看我们的API没穿裤衩子一样,随意的更改我们的请求与回放。
当领导找到我们时,是不是内心遭受了百万暴击一样,满腹在骂娘!~~
我TM我的接口没有一点毛病,有攻击就加强服务器的安全组件,干什么说我技术不行,CAO~~~~
心里骂了半天,但是又有什么办法,领导又不懂代码,我们不是还得撸起袖子搞点安全系数高的代码来增强我们的Api。
那么如何更改呢?
1. 前端Json块使用约定俗成的加密盐进行对称加密。
2. 后端进行解密操作。
3. 后端对请求的返回Json块进行加密
4. 前端进行解密操作。
注:双方一定要约定一套有加密盐的对称加密方式最佳哦!~~
接下来,我们来完成后端部分的全局解密方法。
一、RequestBodyAdvice
RequestBodyAdvice是Spring框架中用于处理HTTP请求体的一个接口,它允许我们在控制器处理请求之前对请求体进行一些自定义操作。
这个接口通常用于对请求体进行校验、转换或者日志记录等操作。
RequestBodyAdvice接口提供了下面几个方法:
a. supports: 这个方法用于判断当前的RequestBodyAdvice是否适用于给定的控制器方法参数。
b. beforeBodyRead: 这个方法在请求体被读取并反序列化为对象之前调用,可以在这里对请求体进行预处理。
c. afterBodyRead: 这个方法在请求体被读取并反序列化为对象之后调用,可以在这里对反序列化后的对象进行后处理。
d.handleEmptyBody: 这个方法在请求没有请求体时调用,可以在这里提供默认值或者进行其他处理。
我们来重写上面的方法吧,只要是重写beforeBodyRead来实现。
二、beforeBodyRead
- /**
- * Invoked second before the request body is read and converted.
- *
- * @param inputMessage the request
- * @param parameter the target method parameter
- * @param targetType the target type, not necessarily the same as the method
- * parameter type, e.g. for {@code HttpEntity<String>}.
- * @param converterType the converter used to deserialize the body
- * @return the input request or a new instance, never {@code null}
- */
- @Override
- public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
- try {
- return new RequestHttpInputMessage(inputMessage, parameter);
- } catch (Exception e) {
- return inputMessage;
- }
- }
RequestHttpInputMessage是一个继承HttpInputMessage的自定义类。
三、HttpInputMessage获取API接口头和请求体
HttpInputMessage 它代表了一个 HTTP 输入消息,通常用于读取 HTTP 请求的正文,这个接口提供了对 HTTP 请求头和请求体的访问。
HttpInputMessage 接口定义了以下两个方法:
getHeaders(): 返回一个不可变的 MultiValueMap<String, String>,包含了 HTTP 消息头的键值对。这些消息头可以包含如内容类型、内容长度、缓存控制等信息。
getBody(): 返回一个 InputStream,通过这个流可以读取 HTTP 消息的正文。这通常用于读取客户端发送的数据,如 JSON 或 XML 格式的数据。
注意:getBody是一次性的方法,当你使用了一次获取了InputStream之后,再使用此方法,是无法再次获取到的。为了规避此问题,我们应该使用如下代码块进行获取。
- final ByteArrayInputStream bais = new ByteArrayInputStream(readBytes(body));
-
- privatebyte[] readBytes(InputStream in) throws IOException {
- int buffSize = 1024;
- try (BufferedInputStream bis = new BufferedInputStream(in); ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize)) {
- byte[] temp = new byte[buffSize];
- int size;
- while ((size = bis.read(temp)) != -1) {
- out.write(temp, 0, size);
- }
- return out.toByteArray();
- }
- }
四、实现RequestHttpInputMessage
我们来实现一下这个RequestHttpInputMessage,主要在构造函数内进行解密即可。
- public RequestHttpInputMessage(HttpInputMessage inputMessage, MethodParameter parameter) throws Exception {
- this.headers = inputMessage.getHeaders();
- String encryptStr = easeString(IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8));
- // 解密
- String decrypt = AesEncryptUtils.decrypt(encryptStr);
- String replace = decrypt;
- log.info("RequestHttpInputMessage:{}", replace);
- // 特殊处理
- if (decrypt.contains("certImages")) {
- replace = decrypt.replace("\\", "");
- }
- // 解密后的请求块
- this.body = IOUtils.toInputStream(replace, StandardCharsets.UTF_8);
- }
AesEncryptUtils.decrypt属于请求块的解密方法。假如有特殊的请求,我们可以进行方法变通。最后更改请求块,然后将解密后的请求块发送给Controller了。
另外需要我自己的加密类,可以留言联系我获取,谢谢~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。