SpringBoot接口设计防篡改和防重放攻击

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 本文介绍了API接口的安全问题及解决方案,包括防止接口参数被篡改和重放攻击的方法。主要措施有:使用HTTPS传输、参数加密、时间戳签名验证等。并通过创建过滤器对请求参数进行签名验证,确保接口的安全性。
  • API 接口暴露问题
  • 防止接口参数篡改
  • 核心思路代码设计

API 接口防篡改、防重放攻击常见方案。

API 接口暴露问题

由于提供给第三方服务调用的 API 接口需要暴露在外网中,并且接口上提供了具体的请求地址和请求参数,那么,接口就有可能被人抓包拦截并对请求参数进行修改后再次发起请求 ,这样一来可能会被盗取信息,二来服务器可能会受到攻击。

b2d966e49b018f57708feab1410348d.png

为了防止这种情况发生,需要采取安全机制措施进行防范,方法有多种,比如:

  • 接口采用 https 的传输方式,https 传输的数据是经过了加密的,可以保证不被篡改;
  • 项目后台采用安全的验证机制,比如采用参数加密请求时间限制 来防止参数篡改和二次投放(*我们以这种方式为案例进行讲解 *)。

防止接口参数篡改

为了防止参数被抓包篡改参数,我们可以对参数进行加密。具体方式如下:

  • 前端使用约定好的秘钥 对传输参数进行加密,得到签名值 sign1,并且将签名值存入headers,然后发送请求给服务端;
  • 服务端接收客户端的请求后,在过滤器 中使用约定好的秘钥对请求的参数再次进行签名,得到签名值 sign2
  • 最后对比 sign1 和 sign2 的值,如果相同,则认定为合法请求,如果不同,则说明参数被篡改,认定为非法请求。

防止接口重投放

重投放 或者叫二次投放 ,指的是接口被人拦截篡改参数后重新发送请求。防止重投放的方案是:基于 timestamp 对参数进行签名 ,具体的实现是:

  • 每次 http 请求,headers 都加上 timestamp 时间戳,并且 timestamp 和请求的参数一起进行数字签名;
  • 服务器收到请求之后,先判断时间戳参数与当前时间是否超过了60s(这个可以自定义配置,一般黑客从抓包到重放的耗时远远超过了60s),如果超过了则提示签名过期;
  • 如果黑客修改了 timestamp 参数,则 sign 参数对应的数字签名就会失效,因为黑客不知道签名秘钥,没有办法生成新的数字签名(前端一定要保护好秘钥和加密算法 )。

当然也有一些其他方案,比如:数据库唯一主键 + 乐观锁;防重 Token 令牌,跳转前端表单页面时,设置一个 UUID 作为 token,并设置在表单隐藏域。

同时,前端页面表提交钮置灰不可点击 + js 节流防抖。

核心思路代码设计

代码思路主要是通过创建过滤器,对参数进行签名验证,核心过滤器代码如下:

@Component
@Slf4j
public class SignAuthFilter implements Filter {
    @Autowired
    private SignAuthProperties signAuthProperties;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("初始化 SignAuthFilter...");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        // 过滤不需要签名验证的地址
        String requestUri = httpRequest.getRequestURI();
        for (String ignoreUri : signAuthProperties.getIgnoreUri()) {
            if (requestUri.contains(ignoreUri)) {
                log.info("当前URI地址:" + requestUri + ",不需要签名校验!");
                chain.doFilter(request, response);
                return;
            }
        }
        // 获取签名和时间戳
        String sign = httpRequest.getHeader("Sign");
        String timestampStr = httpRequest.getHeader("Timestamp");
        if (StringUtils.isEmpty(sign)) {
            responseFail("签名不能为空", response);
            return;
        }
        if (StringUtils.isEmpty(timestampStr)) {
            responseFail("时间戳不能为空", response);
            return;
        }
        // 重放时间限制
        long timestamp = Long.parseLong(timestampStr);
        if (System.currentTimeMillis() - timestamp >= signAuthProperties.getTimeout()*1000) {
            responseFail("签名已过期", response);
            return;
        }
        // 校验签名
        Map<String, String[]> parameterMap = httpRequest.getParameterMap();
        if (SignUtils.verifySign(parameterMap, sign, timestamp)) {
            chain.doFilter(httpRequest, response);
        } else {
            responseFail("签名校验失败", response);
        }
    }
    /**
     * 响应错误信息
     */
    private void responseFail(String msg, ServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(msg);
        out.flush();
        out.close();
    }
    @Override
    public void destroy() {
        log.info("销毁 SignAuthFilter...");
    }
}

这里我们可以在 yml 配置文件中进行配置重放超时时间和不过滤的 URI 地址:

sign:
  # 签名超时时间
  timeout: 60
  # 允许未签名访问的 url 地址
  ignoreUri:
    - /swagger-ui.html
    - /v2/api-docs

然后编写配置类:

@Data
@ConfigurationProperties(prefix = "sign")
public class SignAuthProperties {
    /**
     * 签名超时时间
     */
    private Integer timeout;
    /**
     * 允许未签名访问的 url 地址
     */
    private List<String> ignoreUri;
}

在签名的校验代码中,省略了具体的校验方法,因为不同的加密方式对应不用的校验方法,所以这里只提供一个代码思路,只要前后端约定好如何进行加密即可

本文我解释了多种方法,只实现了其中的一种。大家根据个人爱好和业务场景,选择不同的方案。

相关文章
|
安全 前端开发 Java
SpringBoot接口如何设计防篡改、防重放攻击
Spring Boot 防篡改、防重放攻击本示例主要内容请求参数防止篡改攻击基于timestamp方案,防止重放攻击使用swagger接口文档自动生成API接口设计API接口由于需要供第三方服务调用,所以必须暴露到外网,并提供了具体请求地址和请求参数,为了防止被别有用心之人获取到真实请求参数后再次发起请求获取信息,需要采取很多安全机制。
4423 0
|
6月前
|
SQL 安全 Java
Spring Boot中的跨站点脚本攻击(XSS)与SQL注入防护
【6月更文挑战第15天】在现代Web应用程序开发中,安全性是一个至关重要的课题。跨站点脚本攻击(XSS)和SQL注入是最常见的两种攻击类型,它们可以严重威胁到应用程序的安全。
613 0
|
7月前
|
设计模式 Java 应用服务中间件
Springboot抵御即跨站脚本(XSS)攻击2
Springboot抵御即跨站脚本(XSS)攻击2
|
7月前
|
安全 JavaScript 前端开发
Springboot抵御即跨站脚本(XSS)攻击
Springboot抵御即跨站脚本(XSS)攻击
|
Java
Springboot框架添加防止XSS攻击功能
觉得很不多的文章,推荐给大家! https://www.cnblogs.com/mrBeany/p/10649853.html
147 0
|
SQL JSON 安全
Spring Boot 如何防护 XSS + SQL 注入攻击 ?终于懂了!
Spring Boot 如何防护 XSS + SQL 注入攻击 ?终于懂了!
|
SQL 存储 JSON
Spring Boot 如果防护 XSS + SQL 注入攻击 ?一文带你搞定!
Spring Boot 如果防护 XSS + SQL 注入攻击 ?一文带你搞定!
620 0
|
Java Spring
无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范(二)
无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范(二)
无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范(二)
|
安全 JavaScript Java
无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范(一)
无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范(一)
|
JSON 移动开发 前端开发
Spring Boot XSS 攻击过滤插件使用
XSS(Cross Site Scripting)攻击全称跨站脚本攻击,为了不与 CSS(Cascading Style Sheets)名词混淆,故将跨站脚本攻击简称为 XSS,XSS 是一种常见 web 安全漏洞,它允许恶意代码植入到提供给其它用户使用的页面中。
4448 0

热门文章

最新文章