【java】API接口防重放机制研究

devtools/2025/1/23 19:40:15/

1、接口重放的定义

接口重放是一种常见的安全需求,特别是api接口在网络通信中,攻击者捕捉并重放发送有效的请求,进行探测,分析 从而获取可利用的信息,进一步进行攻击, 达到非法目的。如何防止重复提交请求、减少接口攻击风险,在实际的开发中需确保每个请求的唯一性和时效性。以下是通过研究常见的几种防止接口重放攻击策略

2、解决措施

通过引入时间戳 timestamp 、和唯一随机数 nonce one-time-number 可以确保每个请求在服务器端具有唯一性

2.1时间戳

通过引入时间戳 timestamp记录web端当前触发接口的开始时间,服务器端可以验证特定时间范围内的运行的请求

2.2唯一随机数

每个请求都包含一个唯一的,不可预测的值,服务器保存已经处理过的nonce 确保每个请求的唯一性

2.3签名验签

通过签名机制,服务器校验来自客户端的请求是否被篡改,从而判断其合法性

3、验证实验

3.1环境

本套测试使用 java+springboot+jsp的整合研究(应用程序搭建自行部署)

3.2思考

3.2.1生成时间戳timestamp和nonce

当客户端发送请求时,请求接口自带当前的时间戳和唯一的随机生成的nonce

3.2.2如何生成

后端生成通过 model视图返回前端表单、接口发送请求携带此参数即可

3.3具体实现

3.3.1前端jsp代码加上 timestamp和nonce

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录</title>
</head>
<body>
<h2>登录</h2>
<form action="/nonce" method="POST"><label for="username">用户名:</label><input type="text" id="username" name="username" required/><br/><label for="password">密码:</label><input type="password" id="password" name="password" required/><br/><!-- 加入时间戳和Nonce --><input type="hidden" name="timestamp" value="${timestamp}"/><input type="hidden" name="nonce" value="${nonce}"/><button type="submit">登录</button>
</form>
<p style="color:red">时间戳${timestamp}</p >
<p style="color:red">一次性校验码${nonce}</p >
<p style="color:red">${error}</p >
<p style="color:darkmagenta">${success}</p >
</body>
</html>

控制层用户接收来自客户端的请求

通过 model.addAttribute("timestamp", timestamp); 和 model.addAttribute("nonce", nonce); 将生成的时间戳和随机 nonce 传递到 JSP 页面,以便在客户端使用

@Controller
public class NonceContrller {private static final Set<String> usedNonces = new HashSet<>();@GetMapping("/nonce")public String showNonce(Model model) {// 生成一个时间戳和一个随机的 noncelong timestamp = System.currentTimeMillis();String nonce = UUID.randomUUID().toString();// 将时间戳和nonce传递到JSP页面model.addAttribute("timestamp", timestamp);model.addAttribute("nonce", nonce);System.out.println(nonce);return "nonce"; // 返回login.jsp视图}

3.3.2时间戳回显

启动spingboot 项目访问 http://192.168.3.118:8080/nonce 则出现一下内容 界面的时间戳和一次性校验码则返回前端

接口值携带时间戳和一次性校验码

后端代码校验

通过启动springboot服务器, 向服务器发送请求登录

提交form表单,信息内容提交至服务器端 服务器端获取来自前端的参数进行判断

其中

final long MAX_TIMESTAMP_DIFF1 = 15 * 1000; // 15秒 时间戳15s后过期
usedNonces.contains(nonce)判断来自客户端的nonce值是否被使用

二者均满足则服务器合法处理

@PostMapping("/nonce")public String handleLogin(@RequestParam String username, @RequestParam String password,@RequestParam long timestamp, @RequestParam String nonce,Model model) {final long MAX_TIMESTAMP_DIFF1 = 15 * 1000; // 15秒long currentTimestamp = System.currentTimeMillis();long times = currentTimestamp - timestamp;System.out.println("时间差: " + times);// 1. 时间超时校验if (times > MAX_TIMESTAMP_DIFF1) {model.addAttribute("error", "时间超时,请重新登录");return "nonce"; // 返回登录页面}// 2. 验证 nonce 是否已使用过if (usedNonces.contains(nonce)) {model.addAttribute("error", "请求重复,请重新登录");return "nonce"; // 返回登录页面}// 3. 进行用户身份验证String sql = "SELECT * FROM users WHERE username = ? AND password = ?";try (Connection connection = getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql)) {preparedStatement.setString(1, username);preparedStatement.setString(2, password); // 注意:应使用加密后的密码ResultSet resultSet = preparedStatement.executeQuery();if (resultSet.next()) {// 4. 用户存在且密码匹配,nonce 记录到 usedNonces,防止重放usedNonces.add(nonce);model.addAttribute("success", "登录成功");return "home"; // 跳转到首页} else {// 5. 登录失败但 nonce 不能存入model.addAttribute("error", "用户名或密码错误,请重新登录");// model.addAttribute("refresh", true);return "redirect:/nonce";}} catch (SQLException e) {e.printStackTrace();model.addAttribute("error", "系统错误,请稍后重试");return "nonce";}}

超期校验,刷新接口 待生成时间戳 15s后向服务器发送请求则提示超时

重放校验,拦截请求重放发送 nonce使用则提示请求重复


http://www.ppmy.cn/devtools/152954.html

相关文章

迅为RK3568开发板篇OpenHarmony实操HDF驱动控制LED-添加内核编译

编译内核时将该 HDF 驱动编译到镜像中&#xff0c;接下来编写驱动编译脚本 Makefile&#xff0c;代码如下所示&#xff1a; 加入编译体系&#xff0c;填加模块目录到 drivers/hdf_core/adapter/khdf/linux/Makefile 文件 更多内容可以关注&#xff1a;迅为RK3568开发板篇OpenHa…

Java并发10 - ForkJoin并发框架

ForkJoin并发框架 ForkJoin只适用于大型任务且能将任务切分的场景&#xff0c;因此使用场景不多 了解一下即可&#xff0c;太过庞大复杂 文章目录 ForkJoin并发框架一&#xff1a;ForkJoin框架概述二&#xff1a;ForkJoin框架原理1&#xff1a;ForkJoin框架原理2&#xff1a;成…

java 中多线程、 队列使用实例,处理大数据业务

场景&#xff1a; 从redis 订阅数据 调用线程来异步处理数据 直接上代码 定义线程管理类 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org…

ElasticSearch 学习课程入门(一)

引子 前文已经介绍了windows下如何安装ES&#xff0c;接下来的文章我会边学习边记录。OK&#xff0c;那就让我们开始吧。 一、ES基础操作 1、预备知识 &#xff08;1&#xff09;RESTful REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 …

Android系统开发(二十):字体活起来,安卓自定义字体改造指南

为什么要写这篇文章&#xff1f; 你是否厌倦了千篇一律的安卓默认字体&#xff1f;想让你的设备从“乏味的配角”变成“炫酷的主角”&#xff1f;好消息&#xff01;从Android 12到Android 15&#xff0c;自定义字体变得更简单、更强大。尤其是表情字体的更新&#xff0c;不仅…

蓝桥杯算法|基础笔记(1)

**时间复杂度** 一、概念理解 时间复杂度是用来衡量算法运行时间随输入规模增长而增长的量级。它主要关注的是当输入规模趋向于无穷大时&#xff0c;算法执行基本操作的次数的增长趋势&#xff0c;而不是精确的运行时间。 二、分析代码中的基本操作 确定关键操作 在一段代码…

如何安装linux版本的node.js

在 Linux 系统上安装 Node.js 可以通过多种方式。以下是一些常见的安装方法&#xff1a; 方法 1: 使用包管理器 Ubuntu / Debian 更新包信息&#xff1a; sudo apt update安装 Node.js 和 npm&#xff1a; sudo apt install nodejs npm验证安装&#xff1a; node -v npm -vCe…

小米Vela操作系统开源:AIoT时代的全新引擎

小米近日正式开源了其物联网嵌入式软件平台——Vela操作系统&#xff0c;并将其命名为OpenVela。这一举动在AIoT&#xff08;人工智能物联网&#xff09;领域掀起了不小的波澜&#xff0c;也为开发者们提供了一个强大的AI代码生成器和开发平台。OpenVela项目源代码已托管至GitH…