SpringBoot实现防篡改防重放的操作步骤

 更新时间:2025年07月08日 09:37:38   作者:墨瑾轩  
你的SpringBoot接口还在“裸奔”吗?或者想让接口像“钢铁侠战衣”一样防篡改、防重放?今天,我们将用5个“超能力”技巧,手把手教你实现接口安全加固,彻底告别“抓包改参数”和“重放攻击”,需要的朋友可以参考下

第一步:环境搭建——给你的接口项目打个底

首先,我们需要准备好开发环境,并安装必要的依赖!

1.1 创建SpringBoot项目

# 使用Spring Initializr快速创建项目
mvn archetype:generate -DgroupId=com.example -DartifactId=SecureAPI -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
cd SecureAPI

1.2 添加依赖

<dependencies>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- Hmac加密 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.16.0</version>
    </dependency>
    <!-- Lombok(简化代码) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

1.3 配置Redis

spring:
  redis:
    host: localhost
    port: 6379

第二步:传统方法——“裸奔接口”的惨痛教训

先来看看“零防护接口”的漏洞案例,对比之后你会更珍惜安全机制!

2.1 错误方法一:纯明文传输(失败案例)

// 未加密的接口示例
@RestController
public class UserController {
    @GetMapping("/user")
    public String getUser(@RequestParam String username) {
        return "Hello, " + username; // 黑客可轻易修改username参数!
    }
}

2.2 错误方法二:无时间戳验证

// 未防重放的接口示例
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount) {
    // 黑客可重复发送请求,多次转账!
    return "Transfer " + amount + "成功!";
}

疑问来了:为什么这两种方法不行?

  • 明文传输:参数易被篡改,攻击者可直接修改。
  • 无时间戳验证:攻击者可重放请求,导致重复操作。

第三步:推荐方法一——参数加密与签名:让接口“穿上防弹衣”!

用HMAC-SHA256实现参数签名,确保数据未被篡改!

3.1 客户端签名生成(JavaScript示例)

// 前端生成签名
function generateSign(params, secretKey) {
    // 1. 参数按字典序排序
    const sortedParams = Object.keys(params)
        .sort()
        .map(key => `${key}=${params[key]}`)
        .join('&');
    // 2. 使用HMAC-SHA256生成签名
    const hmac = CryptoJS.HmacSHA256(sortedParams, secretKey);
    return hmac.toString(CryptoJS.enc.Hex);
}

// 示例调用
const params = { username: 'alice', timestamp: Date.now() };
const sign = generateSign(params, 'your-secret-key');

3.2 服务端签名验证(Java代码)

@Component
public class SignatureValidator {
    private final String secretKey = "your-secret-key";

    public boolean validateSignature(HttpServletRequest request) {
        // 1. 获取请求参数和签名
        Map<String, String> params = getParams(request);
        String sign = request.getHeader("Sign");
        // 2. 重新生成签名
        String sortedParams = params.entrySet().stream()
            .sorted(Comparator.comparing(Map.Entry::getKey))
            .map(entry -> entry.getKey() + "=" + entry.getValue())
            .collect(Collectors.joining("&"));
        String generatedSign = HmacUtils.hmacSha256Hex(secretKey, sortedParams);
        // 3. 对比签名
        return sign.equals(generatedSign);
    }

    private Map<String, String> getParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            params.put(paramName, request.getParameter(paramName));
        }
        return params;
    }
}

3.3 过滤器集成

@Component
public class SignatureFilter implements Filter {
    @Autowired
    private SignatureValidator validator;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest req = (HttpServletRequest) request;
        if (!validator.validateSignature(req)) {
            throw new RuntimeException("签名验证失败!参数被篡改");
        }
        chain.doFilter(request, response);
    }
}

第四步:推荐方法二——时间戳与Redis防重放:让接口“时间刺客”无处遁形!

用时间戳+Redis记录nonce,防止重复请求!

4.1 时间戳验证逻辑

public boolean validateTimestamp(HttpServletRequest request) {
    long currentTime = System.currentTimeMillis();
    long requestTime = Long.parseLong(request.getHeader("Timestamp"));
    // 允许时间差60秒
    return (currentTime - requestTime) <= 60_000;
}

4.2 Redis记录nonce(唯一标识)

public boolean validateNonce(HttpServletRequest request) {
    String nonce = request.getHeader("Nonce");
    // 使用Redis记录已使用的nonce,有效期60秒
    String key = "nonce:" + nonce;
    if (redisTemplate.hasKey(key)) {
        return false; // 已存在,说明是重放请求
    }
    redisTemplate.opsForValue().set(key, "used", 60, TimeUnit.SECONDS);
    return true;
}

4.3 完整过滤器实现

@Component
public class SecurityFilter implements Filter {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        HttpServletRequest req = (HttpServletRequest) request;
        // 1. 验证签名
        if (!validateSignature(req)) {
            throw new RuntimeException("签名验证失败!");
        }
        // 2. 验证时间戳
        if (!validateTimestamp(req)) {
            throw new RuntimeException("时间戳超时!");
        }
        // 3. 验证nonce
        if (!validateNonce(req)) {
            throw new RuntimeException("重复请求!防重放失败");
        }
        chain.doFilter(request, response);
    }
}

第五步:推荐方法三——HTTPS加密传输:给接口“穿金戴银”!

用HTTPS加密传输,确保数据不被窃取!

5.1 配置HTTPS

server:
  port: 8443
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: your-password
    key-store-type: PKCS12

5.2 生成密钥库(Java命令)

keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365

第六步:实战案例——从零到有实现一个“银行转账接口”

整合所有技术,实现一个安全的转账接口!

6.1 接口定义

@RestController
public class TransferController {
    @PostMapping("/transfer")
    public String transfer(@RequestParam String amount, @RequestParam String nonce) {
        // 实际转账逻辑(此处省略)
        return "转账" + amount + "元成功!";
    }
}

6.2 客户端调用示例(JavaScript)

const params = {
    amount: "1000",
    timestamp: Date.now(),
    nonce: Math.random().toString(36).substr(2)
};
const sign = generateSign(params, 'your-secret-key');

fetch('/transfer', {
    method: 'POST',
    headers: {
        'Sign': sign,
        'Timestamp': params.timestamp,
        'Nonce': params.nonce
    },
    body: new URLSearchParams(params)
});

第七步:隐藏技巧——分布式环境下时间同步与nonce全局管理

用NTP同步时间和Redis集群保证分布式部署!

7.1 NTP时间同步(Linux命令)

sudo ntpdate pool.ntp.org

7.2 Redis集群配置

spring:
  redis:
    cluster:
      nodes:
        - 192.168.1.100:6379
        - 192.168.1.101:6379

第八步:压力测试——让接口“吃鸡”!

最后,用压力测试验证你的安全机制是否扛得住百万级请求!

8.1 JMeter测试计划

<TestPlan>
    <ThreadGroup num_threads="1000">
        <HTTPSamplerProxy>
            <HeaderManager>
                <Header>Sign=your-sign</Header>
                <Header>Timestamp=1623456789</Header>
                <Header>Nonce=random-123</Header>
            </HeaderManager>
            <Path>/transfer</Path>
        </HTTPSamplerProxy>
    </ThreadGroup>
</TestPlan>

从“裸奔接口”到“黑客退退退”,让安全机制“秒变”神器

经过这8个步骤的学习,我们不仅掌握了参数签名、时间戳防重放和HTTPS加密,还了解了如何在分布式环境下实现全局安全控制。无论是电商支付接口还是物联网控制接口,这些技巧都能让你的SpringBoot项目像“钢铁侠”一样坚不可摧!

以上就是SpringBoot防篡改防重放的操作步骤的详细内容,更多关于SpringBoot防篡改防重放的资料请关注脚本之家其它相关文章!

相关文章

  • Java中验证 Mybatis 数据分片可以减轻GC压力的操作方法

    Java中验证 Mybatis 数据分片可以减轻GC压力的操作方法

    这篇文章主要介绍了Java中验证 Mybatis 数据分片可以减轻GC压力的操作方法,本文使用 Spock(可集成Spring Boot项目) 编写测试用例,基于 Groovy (JVM语言),感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • 10道springboot常见面试题

    10道springboot常见面试题

    这篇文章主要为大家详细介绍了10道springboot常见面试题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • spring mvc @PathVariable绑定URI模板变量值方式

    spring mvc @PathVariable绑定URI模板变量值方式

    这篇文章主要介绍了spring mvc @PathVariable绑定URI模板变量值方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java基础篇之serialVersionUID用法及注意事项详解

    Java基础篇之serialVersionUID用法及注意事项详解

    这篇文章主要给大家介绍了关于Java基础篇之serialVersionUID用法及注意事项的相关资料,SerialVersionUID属性是用于序列化/反序列化可序列化类的对象的标识符,我们可以用它来记住可序列化类的版本,以验证加载的类和序列化对象是否兼容,需要的朋友可以参考下
    2024-02-02
  • Java Mybatis架构设计深入了解

    Java Mybatis架构设计深入了解

    在本篇文章里小编给大家整理的是一篇关于Java Mybatis架构设计详解内容,对此有兴趣的朋友们可以参考下,希望能够给你带来帮助
    2021-11-11
  • SpringBoot集成RocketMQ发送事务消息的原理解析

    SpringBoot集成RocketMQ发送事务消息的原理解析

    RocketMQ 的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致,这篇文章主要介绍了SpringBoot集成RocketMQ发送事务消息,需要的朋友可以参考下
    2022-06-06
  • Java zxing生成条形码和二维吗代码实例

    Java zxing生成条形码和二维吗代码实例

    这篇文章主要介绍了java zxing生成条形码和二维吗代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • java处理图片背景颜色的方法

    java处理图片背景颜色的方法

    这篇文章主要为大家详细介绍了java处理图片背景颜色的方法,蓝底寸照批量转换为白底,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • Mybatis和其他主流框架的整合使用过程详解

    Mybatis和其他主流框架的整合使用过程详解

    MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code,这篇文章主要介绍了Mybatis和其他主流框架的整合使用,需要的朋友可以参考下
    2023-11-11
  • 如果淘宝的七天自动确认收货让你设计你用Java怎么实现

    如果淘宝的七天自动确认收货让你设计你用Java怎么实现

    在面试的时候如果面试官问淘宝的七天自动确认收货让你设计,你会怎么具体实现呢?跟着小编看一下下边的实现过程,对大家的学习或工作具有一定的参考借鉴价值
    2021-09-09

最新评论