API接口安全性设计,项目中该如何保证API接口安全?
mhr18 2025-05-02 19:48 22 浏览 0 评论
很多时候在开发对外接口的时候,为了保证接口的安全以及服务的稳定,要对接口的访问添加一定的限制规则。
那么就有几个问题需要注意一下:
- 请求参数是否被篡改;
- 请求来源是否合法;
- 请求是否具有唯一性;
- 参数签名方式。
我们也是围绕这几个点进行展开说明。
为什么需要接口签名?
前后端分离架构早已成为目前行业主流,现在越来越多的项目以API 的形式对外提供服务,这些 API 接口大多暴露在公网上,所以安全性就变的很重要了。最直接的风险如下:
- 非法使用 API 服务。(收费接口非法调用)
- 恶意攻击和破坏。(数据篡改、DOS)
因此需要设计一些接口安全保护的方式来增强接口安全,目前主流的一种方式是API签名。
可能有人会有疑问,现在项目中使用了https后,还需要对数据进行签名来确保数据没有被篡改吗?
答案是有必要。
这里就需要明确https的工作机制了。
HTTPS是保证通过中间人攻击抓到的报文是密文,无法或者说很难破解。但仍然可以将报文重发,形成DOS攻击。同时,如果不签名,只用 HTTP 简单认证,通过抓包,直接可以获取到 Authorization,就可以随意发起请求了。
因此最安全的方法就是结合 HTTPS 和 API 签名。
所以,综上所述:
- API 签名保证的是应用的数据安全和防篡改,并且可以作为业务的参数校验和处理重放攻击。
- HTTPS 保证的是运输层的加密传输,但是无法防御重放攻击。
接口签名
一个服务调用另外一个服务,肯定是有参数需要传递的,我们可以将参数按照以下步骤进行签名。
对所有非空参数值的的参数进行拼接:
key1value1key2value2...
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
- 传送的sign参数不参与签名;
- 1.在stringA最后拼接上secret密钥得到stringSignTemp字符串
- 2.对stringSignTemp进行MD5加密得到signValue
接口在网络传输过程中,参数值可以被修改,但是因为不了解sign计算方式,一般没法修改sign的值。当服务器调用接口前会按照sign的规则重新计算出sign的值然后和接口传递的sign参数的值做比较,如果相等表示参数值没有被篡改,如果不等,表示参数被非法篡改了。
public class AntiReplayAttackV1Example {
//如果是对称加密,则是调用方和被调用方都知道的私钥;如果是
//非对称加密,调用方这里是被调用方生成的公钥
private static final String SECRET_KEY = "your_secret_key";
// 模拟支付请求类
static class PaymentRequest {
private String transactionId;
private double amount;
private String nonce;
public PaymentRequest(String transactionId, double amount, String nonce) {
this.transactionId = transactionId;
this.amount = amount;
this.nonce = nonce;
}
public String getTransactionId() {
return transactionId;
}
public double getAmount() {
return amount;
}
public String getNonce() {
return nonce;
}
}
public static String generateSign(Map<String, String> params, String secret) throws NoSuchAlgorithmException {
// 将参数按ASCII码从小到大排序
Map<String, String> sortedParams = new TreeMap<>(params);
StringBuilder stringA = new StringBuilder();
// 拼接成字符串stringA
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
if (entry.getValue() != null && !entry.getValue().isEmpty()) {
stringA.append(entry.getKey()).append(entry.getValue());
}
}
// 在stringA最后拼接上secret密钥得到stringSignTemp字符串
String stringSignTemp = stringA.toString() + secret;
// 对stringSignTemp进行MD5加密得到signValue
return md5(stringSignTemp);
}
private static String md5(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : messageDigest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static void main(String[] args) {
try {
// 模拟一个支付请求
PaymentRequest request = new PaymentRequest("txn-001", 100.0, "nonce-123");
// 模拟请求参数集合
Map<String, String> params = new TreeMap<>();
params.put("transactionId", request.getTransactionId());
params.put("amount", String.valueOf(request.getAmount()));
params.put("nonce", request.getNonce());
// 生成签名
String sign = generateSign(params, SECRET_KEY);
System.out.println("Generated Sign: " + sign);
// 模拟服务器端验证签名
boolean isValid = verifySign(params, sign, SECRET_KEY);
System.out.println("Is Sign Valid: " + isValid);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static boolean verifySign(Map<String, String> params, String providedSign, String secret) throws NoSuchAlgorithmException {
// 生成签名
String generatedSign = generateSign(params, secret);
// 比较生成的签名和提供的签名
return generatedSign.equals(providedSign);
}
}
//输出:
Generated Sign: 1f7cc39bcb0eb7e293c29d49906d69d6
Is Sign Valid: true
示例代码中严格来说是一个demo,大家还需根据实际情况进行对应关键属性的传递设计。
通过代码可以发现,签名的方式是只能验证数据有没有被修改,但是,防不了重放攻击。
我们继续往下进行。
重放攻击
什么是重放攻击
API重放攻击(Replay Attacks)又称为重播攻击。就是把你的请求原封不动地再发送一次,两次...n次,一般正常的请求都会通过验证进入到正常逻辑中,如果这个正常逻辑是插入数据库操作,那么一旦插入数据库的语句写的不好,就有可能出现多条重复的数据。一旦是比较慢的查询操作,就可能导致数据库堵住等情况,如果是付款接口,或者购买接口就会造成损失。因此需要采用防重放的机制来做请求验证,下面介绍如何对接口做防重放攻击。
带时间戳的签名算法
请求端:timestamp由请求方生成,代表请求被发送的时间(需双方共用一套时间计数系统)随请求参数一并发出,并将 timestamp作为一个参数加入 sign 加密计算。
服务端:平台服务器接到请求后对比当前时间戳,设定不超过30s 即认为该请求正常,否则认为超时拒绝服务
但是这样还是有缺陷的,若攻击者如果在30s之内进行重放攻击那就没办法了,因为30s之内的请求都认为是合法请求,那将这30s设置的小一些,那多小算小了?太小的话,如果网络拥挤,会将正常请求也拒绝掉的 !因此将时间改小这不是一个解决问题的根本办法。所以更进一步地,可以为sign 加上一个随机码(称之为盐值)这里我们定义为 nonce。
带nonce的签名算法
请求方:nonce 是由请求方生成的随机数(在规定的时间内保证有充足的随机数产生,即在60s 内产生的随机数重复的概率为0)也作为参数之一加入 sign 签名。
服务端:服务器接受到请求先判定 nonce 是否被请求过(一般会放到redis中),如果发现 nonce 参数在规定时间是全新的则正常返回结果,反之,则判定是重放攻击拒绝服务。
这里注意对于处理过的请求,将其nonce存放到redis的时候设置过期时间,一定要配置过期时间。否则占用Redis空间会越来越大。
接口签名总结
上面所有内容可以概括为接口签名,接口签名是目前主流的方案。核心处理流程为:
接口签名总结起来就是通过一些签名规则对参数进行签名,然后把签名的信息放入请求头部,服务端收到客户端请求之后,同样的只需要按照已定的规则生产对应的签名串与客户端的签名信息进行对比,如果一致,就进入业务处理流程;如果不通过,就提示签名验证失败。
在接口签名方案中,主要有四个核心参数:
1、appid表示应用ID(可以视情况添加),接口请求数据记性签名加密,不同的对接项目分配不同的appid,保证数据安全。
2、timestamp 表示时间戳,当请求的时间戳与服务器中的时间戳,差值在5分钟之内,属于有效请求,不在此范围内,属于无效请求
3、nonce 表示随机数,用于防止重复提交验证
4、signature 表示签名字段,用于判断接口请求是否有效。
我再补充一个大家会首先想到但存在较大问题的方案,就是token方案。
token方案
从上图,我们可以很清晰的看到,token 方案的实现主要有以下几个步骤:
- 1、用户登录成功之后,服务端会给用户生成一个唯一有效的凭证,这个有效值被称为token
- 2、当用户每次请求其他的业务接口时,需要在请求头部带上token
- 3、服务端接受到客户端业务接口请求时,会验证token的合法性,如果不合法会提示给客户端;如果合法,才会进入业务处理流程。
在实际使用过程中,当用户登录成功之后,生成的token存放在redis中时是有时效的,一般设置为2个小时,过了2个小时之后会自动失效,这个时候我们就需要重新登录,然后再次获取有效token。
token方案,是目前业务类型的项目当中使用最广的方案,而且实用性非常高,可以很有效的防止黑客们进行抓包、爬取数据。
但是 token 方案也有一些缺点!最明显的就是与第三方公司进行接口对接的时候,当你的接口请求量非常大,这个时候 token 突然失效了,会有大量的接口请求失败。
正常流程是当token失效时,会调用刷新token接口,刷新完成之后,在token失效与重新刷新token这个时间间隔期间,就会出现大量的请求失败的日志,因此在实际API对接过程中,我不推荐大家采用 token方案。
以上为全部内容。
相关推荐
- Dubai's AI Boom Lures Global Tech as Emirate Reinvents Itself as Middle East's Silicon Gateway
-
AI-generatedimageAsianFin--Dubaiisrapidlytransformingitselffromadesertoilhubintoaglob...
- OpenAI Releases o3-pro, Cuts o3 Prices by 80% as Deal with Google Cloud Reported to Make for Compute Needs
-
TMTPOST--OpenAIisescalatingthepricewarinlargelanguagemodel(LLM)whileseekingpartnershi...
- 黄仁勋说AI Agent才是未来!但究竟有些啥影响?
-
,抓住风口(iOS用户请用电脑端打开小程序)本期要点:详解2025年大热点你好,我是王煜全,这里是王煜全要闻评论。最近,有个词被各个科技大佬反复提及——AIAgent,智能体。黄仁勋在CES展的发布...
- 商城微服务项目组件搭建(五)——Kafka、Tomcat等安装部署
-
1、本文属于mini商城系列文档的第0章,由于篇幅原因,这篇文章拆成了6部分,本文属于第5部分2、mini商城项目详细文档及代码见CSDN:https://blog.csdn.net/Eclipse_...
- Python+Appium环境搭建与自动化教程
-
以下是保姆级教程,手把手教你搭建Python+Appium环境并实现简单的APP自动化测试:一、环境搭建(Windows系统)1.安装Python访问Python官网下载最新版(建议...
- 零配置入门:用VSCode写Java代码的正确姿
-
一、环境准备:安装JDK,让电脑“听懂”Java目标:安装Java开发工具包(JDK),配置环境变量下载JDKJava程序需要JDK(JavaDevelopmentKit)才能运行和编译。以下是两...
- Mycat的搭建以及配置与启动(mycat2)
-
1、首先开启服务器相关端口firewall-cmd--permanent--add-port=9066/tcpfirewall-cmd--permanent--add-port=80...
- kubernetes 部署mysql应用(k8s mysql部署)
-
这边仅用于测试环境,一般生产环境mysql不建议使用容器部署。这里假设安装mysql版本为mysql8.0.33一、创建MySQL配置(ConfigMap)#mysql-config.yaml...
- Spring Data Jpa 介绍和详细入门案例搭建
-
1.SpringDataJPA的概念在介绍SpringDataJPA的时候,我们首先认识下Hibernate。Hibernate是数据访问解决技术的绝对霸主,使用O/R映射(Object-Re...
- 量子点格棋上线!“天衍”邀您执子入局
-
你是否能在策略上战胜量子智能?这不仅是一场博弈更是一次量子智力的较量——量子点格棋正式上线!试试你能否赢下这场量子智局!游戏玩法详解一笔一画间的策略博弈游戏目标:封闭格子、争夺领地点格棋的基本目标是利...
- 美国将与阿联酋合作建立海外最大的人工智能数据中心
-
当地时间5月15日,美国白宫宣布与阿联酋合作建立人工智能数据中心园区,据称这是美国以外最大的人工智能园区。阿布扎比政府支持的阿联酋公司G42及多家美国公司将在阿布扎比合作建造容量为5GW的数据中心,占...
- 盘后股价大涨近8%!甲骨文的业绩及指引超预期?
-
近期,美股的AI概念股迎来了一波上升行情,微软(MSFT.US)频创新高,英伟达(NVDA.US)、台积电(TSM.US)、博通(AVGO.US)、甲骨文(ORCL.US)等多股亦出现显著上涨。而从基...
- 甲骨文预计新财年云基础设施营收将涨超70%,盘后一度涨8% | 财报见闻
-
甲骨文(Oracle)周三盘后公布财报显示,该公司第四财季业绩超预期,虽然云基建略微逊于预期,但管理层预计2026财年云基础设施营收预计将增长超过70%,同时资本支出继上年猛增三倍后,新财年将继续增至...
- Springboot数据访问(整合MongoDB)
-
SpringBoot整合MongoDB基本概念MongoDB与我们之前熟知的关系型数据库(MySQL、Oracle)不同,MongoDB是一个文档数据库,它具有所需的可伸缩性和灵活性,以及所需的查询和...
- Linux环境下,Jmeter压力测试的搭建及报错解决方法
-
概述 Jmeter最早是为了测试Tomcat的前身JServ的执行效率而诞生的。到目前为止,它的最新版本是5.3,其测试能力也不再仅仅只局限于对于Web服务器的测试,而是涵盖了数据库、JM...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Dubai's AI Boom Lures Global Tech as Emirate Reinvents Itself as Middle East's Silicon Gateway
- OpenAI Releases o3-pro, Cuts o3 Prices by 80% as Deal with Google Cloud Reported to Make for Compute Needs
- 黄仁勋说AI Agent才是未来!但究竟有些啥影响?
- 商城微服务项目组件搭建(五)——Kafka、Tomcat等安装部署
- Python+Appium环境搭建与自动化教程
- 零配置入门:用VSCode写Java代码的正确姿
- Mycat的搭建以及配置与启动(mycat2)
- kubernetes 部署mysql应用(k8s mysql部署)
- Spring Data Jpa 介绍和详细入门案例搭建
- 量子点格棋上线!“天衍”邀您执子入局
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)