接口安全性问题01——接口签名
接口安全性问题
我们写过很多接口,有没有想想接口的安全性呢?jwt,openid 侧重 于 认证(就是用户是谁),OAuth2 侧重于授权(就是说这个东西是否有权限访问),接口签名呢 侧重于安全
1.请求来源(身份)是否合法?
2.请求参数被篡改?
3.请求的唯一性(不可复制)
今天来介绍dotnet环境下接口签名处理
签名介绍:
AccessKey&SecretKey 使用md5签名处理放篡改
请求身份
为开发者分配AccessKey(开发者标识,确保唯一)和SecretKey(用于接口加密,确保不易被穷举,生成算法不易被猜测),也可以自己生成!
防止篡改
参数签名
- 按照请求参数名的字母升序排列非空请求参数(包含AccessKey),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA;
- 在stringA最后拼接上Secretkey得到字符串stringSignTemp;
- 对stringSignTemp进行MD5运算,并将得到的字符串所有字符转换为大写,得到sign值。
请求携带参数AccessKey和Sign,只有拥有合法的身份AccessKey和正确的签名Sign才能放行。这样就解决了身份验证和参数篡改问题,即使请求参数被劫持,由于获取不到SecretKey(仅作本地加密使用,不参与网络传输),无法伪造合法的请求。
重放攻击
虽然解决了请求参数被篡改的隐患,但是还存在着重复使用请求参数伪造二次请求的隐患。
timestamp+nonce+加密字符串 方案
nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用)。
然而,对服务器来说永久存储所有接收到的nonce的代价是非常大的。可以使用timestamp来优化nonce的存储。
假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)。
实现
构造secret:
前端:
1.生成当前时间戳timestamp=now和唯一随机字符串nonce=random
2.封装加密字典 GetSecretParams 包含有加密串1,加密串2
3.计算参数签名 GetSignature 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起, 使用MD5对待签名串求签 生成一个MD5加密后的token
4.拼接 secretstr =
$"timestamp={timestamp}&nonce={nonce}&apptype={"Web"}&signature={token}";
5.urlbase64转码处理secretstr得到 secret1 ;
最终请求在请求的header中加上键值对 secret:secret1
验证secret:
服务端:
说明:
1.secret1和secret2可以切换成非堆成加密的AccessKey 和 SecretKey,可以多添加一个验证
2.本次验证利用的是md5的不可逆性,验证两次生成的签名是否相同,不相同则说明签名被篡改了。
3.timestamp 参数时间各有不同,具体看项目要求!
项目代码demo地址: https://github.com/Hedgehogcat/2023