如何保证对外接口的安全?

文章目录

  • 前言
  • 一、生成及校验Token
    • 1.1 生成Token
    • 1.2 校验Token
    • 1.3 SignUtil 签名工具类

前言

1.什么是安全接口?
通常来说要将暴露在外网的 API 接口视为安全接口,需要实现防篡改和防重放的功能。

1.1 什么是篡改问题?
由于 HTTP 是一种无状态协议,服务端无法确定客户端发送的请求是否合法,也不了解请求中的参数是否正确。以一个充值接口为例:

http://127.0.0.1:8080/api/user/recharge?user_id=1001&amount=10

如果非法用户通过抓包获取接口参数并修改 user_id 或 amount 的值,就能为任意账户添加余额。

1.2 如何解决篡改问题?
虽然使用 HTTPS 协议能对传输的明文进行加密,但黑客仍可截获数据包进行重放攻击。两种通用解决方案是:

  1. 使用 HTTPS 加密接口数据传输,即使被黑客破解,也需要耗费大量时间和精力。
  2. 在接口后台对请求参数进行签名验证,以防止黑客篡改。

签名的实现过程如下图所示:
在这里插入图片描述
步骤1:客户端使用约定好的规则对传输的参数进行加密,得到签名值sign1,并且将签名值也放入请求的参数中,随请求发送至服务端。
步骤2:服务端接收到请求后,使用约定好的规则对请求的参数再次进行签名,得到签名值 sign2。
步骤3:服务端比对 sign1 和 sign2 的值,若不一致,则认定为被篡改,判定为非法请求。

1.3 什么是重放问题?
防重放也叫防复用。简单来说就是我获取到这个请求的信息之后什么也不改,,直接拿着接口的参数去重复请求这个充值的接口。此时我的请求是合法的, 因为所有参数都是跟合法请求一模一样的。重放攻击会造成两种后果:

  1. 针对插入数据库接口:重放攻击,会出现大量重复数据,甚至垃圾数据会把数据库撑爆。
  2. 针对查询的接口:黑客一般是重点攻击慢查询接口,例如一个慢查询接口1s,只要黑客发起重放攻击,就必然造成系统被拖垮,数据库查询被阻塞死。

1.4 如何解决重放问题?
防重放,业界通常基于 nonce + timestamp 方案实现。每次请求接口时生成 timestamp 和 nonce 两个额外参数,其中 timestamp 代表当前请求时间,nonce 代表仅一次有效的随机字符串。生成这两个字段后,与其他参数一起进行签名,并发送至服务端。服务端接收请求后,先比较 timestamp 是否超过规定时间(如60秒),再查看 Redis 中是否存在 nonce,最后校验签名是否一致,是否有篡改。

在这里插入图片描述

一、生成及校验Token

1.1 生成Token

public static final String equipmentSecret = "Equipment_Secret";@PostMapping("/getToken/app")
@ApiOperation("获取鉴权token")
public Message.DataRespone<AppTokenVo> getToken(@RequestBody AppTokenRequest appTokenRequest) {//兼容正负3分钟Date endTime = DateTimeUtils.getDateAfterNow(3, "m");Date startTime = DateTimeUtils.getDateAfterNow(-3, "m");Date targetTime = new Date(appTokenRequest.getTime());if (startTime.after(targetTime) || targetTime.after(endTime)) {return Message.Time_Not_In_Use.create();}PProduct product = productService.getProductByProductKey(appTokenRequest.getProductKey());Map<String, String> claims = new HashMap<>();claims.put("productKey", appTokenRequest.getProductKey());claims.put("time", String.valueOf(appTokenRequest.getTime()));String targetSign = SignUtil.sign(claims, product.getProductSecret());if (!targetSign.equals(appTokenRequest.getSign())) {return Message.Sign_Error.create();}String token = Jwts.builder().setClaims(claims).setExpiration(DateTimeUtils.getDateAfterNow(2, "H"))//采用什么算法是可以自己选择的,不一定非要采用HS512.signWith(SignatureAlgorithm.HS512, equipmentSecret).compact();AppTokenVo appTokenVo1 = new AppTokenVo();appTokenVo1.setToken(token);appTokenVo1.setExpiration(DateTimeUtils.getDateAfterNow(2, "H").getTime());return Message.Success.createWithData(appTokenVo1);
}

1.2 校验Token

@GetMapping("/checkToken")
@ApiOperation("校验token")
public Message.DataRespone<CheckTokenResultVo> getToken(@RequestParam(required = true, defaultValue = "") String token) {CheckTokenResultVo checkTokenResultVo = new CheckTokenResultVo();Claims claims = null;try {claims = Jwts.parser().setSigningKey(equipmentSecret).parseClaimsJws(token).getBody();} catch (Exception e) {claims = null;}if (claims == null) {return Message.Token_CHECK_ERROR.create();}String productKey = String.valueOf(claims.get("productKey"));checkTokenResultVo.setProductKey(productKey);checkTokenResultVo.setExpiration(claims.getExpiration().getTime());return Message.Success.createWithData(checkTokenResultVo);
}

1.3 SignUtil 签名工具类

@Deprecated
public class SignUtil {/*** @param @param  sPara* @param @param  appecret* @param @return 参数描述* @return String    返回类型描述* @throws* @Title: buildRequestMysign* @Description: 签名方法*/public static String sign(Map<String, String> sPara, String appecret) {String prestr = SignUtil.createLinkString(paraFilter(sPara)); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串String mysign = "";mysign = MD5.sign(prestr, appecret, "utf-8");return mysign;}/*** 除去数组中的空值和签名参数** @param sArray 签名参数组* @return 去掉空值与签名参数后的新签名参数组*/private static Map<String, String> paraFilter(Map<String, String> sArray) {Map<String, String> result = new HashMap<String, String>();if (sArray == null || sArray.size() <= 0) {return result;}for (String key : sArray.keySet()) {String value = sArray.get(key);if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {continue;}result.put(key, value);}return result;}/*** 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串** @param params 需要排序并参与字符拼接的参数组* @return 拼接后字符串*/private static String createLinkString(Map<String, String> params) {List<String> keys = new ArrayList<String>(params.keySet());Collections.sort(keys);String prestr = "";for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);String value = params.get(key);if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符prestr = prestr + key + "=" + value;} else {prestr = prestr + key + "=" + value + "&";}}return prestr;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/527475.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32CubeIDE基础学习-STM32CubeIDE软件程序下载方法

STM32CubeIDE基础学习-STM32CubeIDE软件代码下载方法 文章目录 STM32CubeIDE基础学习-STM32CubeIDE软件代码下载方法前言第1章 代码下载第2章 下载器固件更新总结 前言 编写完代码&#xff0c;一般都会选择在线下载程序的方式进行验证该程序是否正确&#xff0c;如果发现结果和…

2024年【化工自动化控制仪表】考试总结及化工自动化控制仪表作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【化工自动化控制仪表】考试总结及化工自动化控制仪表作业考试题库&#xff0c;包含化工自动化控制仪表考试总结答案和解析及化工自动化控制仪表作业考试题库练习。安全生产模拟考试一点通结合国家化工自动化控…

CorelDRAW2024新功能有哪些 ?CorelDRAW2024最新版本更新怎么样

coreldraw 2024是一款非常好用的设计软件&#xff0c;功能非常强大&#xff0c;它可应用于商标设计、标志制作、模型绘制、插图描画、排版及分色输出等领域&#xff0c;因此受到了不少设计师的青睐&#xff0c; CorelDRAW2024新功能有哪些&#xff1f;CorelDRAW2024最新版本更新…

uniapp iOS 真机调试

一、下载爱思助手 二、打开爱思助手&#xff0c;把你的 苹果手机 用原装数据线连接至电脑&#xff1a; 找到 工具箱 > 搜索IPA > 打开IAP签名 三、添加 IPA 文件 mac&#xff1a;finder 》应用程序 》右键 HbuilderX 》显示包内容 》HbuilderX / plugins/ lau…

论文阅读:Diffusion Model-Based Image Editing: A Survey

Diffusion Model-Based Image Editing: A Survey 论文链接 GitHub仓库 摘要 这篇文章是一篇基于扩散模型&#xff08;Diffusion Model&#xff09;的图片编辑&#xff08;image editing&#xff09;方法综述。作者从多个方面对当前的方法进行分类和分析&#xff0c;包括学习…

【工具相关】zentao用例管理平台部署实践

文章目录 一、备份还原1、数据备份1.1、前言1.2、版本备份1.3、数据备份 2、数据恢复2.1、版本恢复2.2、数据恢复 二、问题处理1、ERROR: SQLSTATE[HY000] [2002] Connection refused 一、备份还原 1、数据备份 1.1、前言 禅道系统从10.6版本以后&#xff0c;新增数据备份设…

LeetCode 173.二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在…

stega11

下载附件是一张照片 010查看图片发现一串base MZWGCZ33GZTDCNZZG5SDIMBYGBRDEOLCGY2GIYJVHA4TONZYGA2DMM3FGMYH2 base32解码得到&#xff1a; flag{6f1797d4080b29b64da5897780463e30}

MySQL通过SQL语句进行递归查询

这里主要是针对于MySQL8.0以下版本&#xff0c;因为MySQL8.0版本出来了一个WITH RECURSIVE函数专门用来进行递归查询的 先看下表格数据&#xff0c;就是很普通的树结构数据&#xff0c;通过parentId关联上下级关系 下面我们先根据上级节点id递归获取所有的下级节点数据&#x…

回归测试重复测试

重复测试和回归测试在测试的过程中都会遇到过&#xff0c;出现的概率都是高频的&#xff0c;两者如何区分如下图&#xff1a; 回归测试 回归测试是什么&#xff1f; 回归测试&#xff08;Regression Testing&#xff09;是指在软件修改之后&#xff0c;对已有功能点重新执行测…

高级IO【select、poll、epoll】

高山仰止&#xff0c;景行行止 文章目录 五种IO模型阻塞I/O非阻塞I/OI/O复用信号驱动I/O异步I/O 同步通信与异步通信同步通信异步通信 非阻塞IO基于fcntl实现setNonblock函数注意事项 IO多路转接—select文件描述符集合timeval结构调用过程返回值缺点和局限性 IO多路转接—poll…

【HarmonyOS】ArkUI - 自定义卡片样式

ArkUI - 自定义卡片样式 HarmonyOS API 9 没有提供原生的卡片样式&#xff0c;我定义了一个卡片样式&#xff0c;可以方便大家在日常开发中使用。 效果图&#xff1a; 卡片样式代码如下&#xff1a; Styles function card() {.width(95%).padding(20).backgroundColor(Col…