项目点滴:前后端交互的数据加密

数据安全问题就不过多讲了,接下来直接讲讲我们咋做的。

前端:请求数据加密、响应数据解密

后端:响应数据加密,请求数据解密

思路:

①静态密钥:前后端提前约定好密钥和算法,请求和响应均进行对称加密。

②动态密钥:约定好加解密算法,前端在页面初始化时请求客户端标识(比如UUID)和动态密钥(可以是对称加密的动态密钥,也可以是非对称加密的动态公钥),后续请求头中均携带客户端标识,后端通过UUID识别客户端,进行请求数据解密和响应数据加密。

很显然,动态密钥要复杂些,但是更安全。

然鹅,我们选择了第一种。因为要快速开发功能应标的缘故。

额是后端人员,只有后端实现。用 RequestBodyAdviceAdapter 和 ResponseBodyAdvice来搞

===================== 后端代码实现 =========================

响应加密:

@Slf4j
@RestControllerAdvice(basePackages = {"com.secure"})
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object>, PriorityOrdered {

    @Resource
    private SecurityProperties securityProperties;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (returnType.getMethod() == null) {
            return false;
        }
        return securityProperties.getEncryptEnable();
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        try {
            HttpServletResponse httpServletResponse = ((ServletServerHttpResponse) response).getServletResponse();
            // 设置加密请求头
            httpServletResponse.setHeader("X-CRYPT-FOR", "1");
            // 加密
            String secret = SecureUtil.md5().digestHex16("i am handsome boy!");
            SM4 sm4 = SmUtil.sm4(secret.getBytes(StandardCharsets.UTF_8));
            return sm4.encryptBase64(JsonUtils.toJsonString(body));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return body;
    }

    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    }
}

请求解密:

@Slf4j
@RestControllerAdvice
public class DecryptRequestBodyAdvice extends RequestBodyAdviceAdapter {

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        HttpHeaders headers = inputMessage.getHeaders();
        String flag = headers.getFirst("X-CRYPT-FOR");
        if (!Objects.equals(flag, "1")) {
            return inputMessage;
        }
        byte[] body = IoUtil.readBytes(inputMessage.getBody(), false);
        String bodyStr = StrUtil.utf8Str(body);
        try {
            String secret = SecureUtil.md5().digestHex16("I am handsome boy!");
            SM4 sm4 = SmUtil.sm4(secret.getBytes(StandardCharsets.UTF_8));
            byte[] decrypt = sm4.decrypt(bodyStr);
            final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt);
            return new HttpInputMessage() {
                @Override
                public InputStream getBody() throws IOException {
                    return bais;
                }

                @Override
                public HttpHeaders getHeaders() {
                    return inputMessage.getHeaders();
                }
            };
        } catch (Exception e) {
            log.error(e.getLocalizedMessage(), e);
        }
        return super.beforeBodyRead(inputMessage, parameter, targetType, converterType);
    }
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值