API接口签名(app接口签名)
前言
基于安全考虑(防止伪造、防止重放),网关提供可配置的针对关键接口进行签名的功能。
一.接口签名设计
由于新规范,我们统一使用POST请求和request json body进行参数传递,所以,不考虑GET请求和query参数的场景。
1.签名规则
签名公式
sign = subString(md5(body + & + secureKey + & + nonce + & + timestamp),8, 24) + | + nonce + | + timestamp
- 以UTF-8作为编码。
- body 仅支持 application/json、
application/x-www-form-urlencoded、text/plain这几种content-type类型的body。默认为“”(空字符串)。 - secureKey 为内置于 App 的安全 key,值类型为 UUID 字符串。由后网关服务分配 ,不同的App版本的secureKey可能不同。
例如:app-version - nonce 为随机值,保证每次计算的md5盐均不相同。值为1000-9999的四位随机数。
- timestamp 校验客户端请求发送时间与服务端时间偏移量是否在和合法范围最终完整的实现,防?伪造请求,防?重放攻击。时间搓统一取零时区的当前时间戳 不能为空。
- 以上参数间(body、secureKey、nonce、timestamp)以&拼接。
2.签名传输
签名最终以上形式,组织成字符串,放到请求头的sign中。
二.header参数签名设计
1.签名规则
headers签名
header-sign = subString(md5(headers + & + secureKey + & + nonce + & + timestamp),8, 24) + | + nonce + | + timestamp
- 以UTF-8作为编码。
- headers : 参与签名的请求头参数字符串
- secureKey: 为内置于App 的安全 key,值类型为 UUID 字符串 ,由后网关服务分配 ,与接口签名共用同一个key。不同的App版本的secureKey可能不同(目前统一用一个key 避免key管理混乱)。
- nonce: 为随机值,保证每次计算的md5盐均不相同。值为1000-9999的四位随机数(与接口签名保持一致)。
- timestamp: 校验客户端请求发送时间与服务端时间偏移量是否在和合法范围最终完整的实现,防?伪造请求,防?重放攻击。时间戳统一取零时区的当前时间戳 不能为空。
- 以上参数间(headers、secureKey、nonce、timestamp)以&拼接。
- 请求头参数签名参数名称 header-sign
2.请求头参数签名顺序
- 参与签名请求头参数排序 签名请求头参数按ASCII码自然顺序作排序。
- 签名格式 :请求头参数名称+":"+参数的值 参数用‘|’字符串拼接。
- 例子: keyName1:keyValue1|keyName1:keyValue1 , app-version:3.2|country-id:2|device-id:oikjslfksj 。
- 如果指定参与签名的header在请求头里根本不存在,使用 key: 来参与签名, 例子: app-version:3.2|country-id:|device-id:
3.签名传输
- 签名最终以上形式,组织成字符串,放到请求头的header-sign请求参数中。
- 协商好的android和ios版本 必须要请求头 header-sign
4.增减参与签名的请求头参数配置
- 网关支持根据版本号动态配置增减签名参数 根据app版本号分组配置在apollo
- 签名参数规则android和ios最多维护两个版本
- 配置签名样例:参考网关配置说明 配置映射的java对象类 ApiAuthConfig
- 修改类注解 动态更新配置 @ApolloExternalConfig(appId = "al-gateway-capi",namespace ="ApiAuthConfig" ,prefix = "api.auth")
- 参与签名的请求头参数:app-version country-id device-id deviceUUID device-type
三.签名检验
在后端,提供可针对特定api的配置方式,按以上签名方式组织校验。
1.网关配置说明
网关签名配置说明
备注:
- 凡是启动签名的android和ios版本必须带请求头参数sign和hender-sign参数
- 过滤器是capi全局过滤器 代码逻辑需兼容区分非终端路由请求的 不需要参与对应的签名校验
- 是否开启签名开关
enableApiAuth 设置为true开启签名,
signWhiteListUrl 设置灰度签名url
android-api-secure-key 设置android 签名条件
ios-api-secure-key 设置ios签名条件 - 线上环境可以根据以上参数动态调整灰度签名功能
2.功用及各参数作用说明
假设有如下接口:
那么我们可以通过证书篡改或直接穷举,截取到这个接口及其格式(所需请求头和请求参数)。当知道接口格式而没加签名,会存在什么潜在安全问题呢?比如,
1、穷举接口参数偷取数据。
2、截取支付接口信息,修改用户id或金额去支付,或者重放请求信息,重复支付。
因为用户设备所处的环境复杂多样,接口签名可以保证在用户设备https证书被篡改情况下,一些重要接口仍然得到保护。
参数说明
假设单单使用 body + secureKey 的加密方式,可以防止一般情况下的接口参数伪造。
nonce 在前面基础上能够防止攻击者记录下接口参数和签名值的重放攻击。
timestamp 能够一定程度防止攻击者单单是截取了用户的请求,直接进行重放。
关于nonce和timestamp的意义说明,请点击查看:API接口防止参数篡改和重放攻击说明
辅助debug功能约定:
事项 | 测试环境 | 正式环境 | ||
客户端 | 网关 | 客户端 | 网关 | |
判断是否签名 | 请求头塞入isSign=1 | 根据isSign=1来判断 | 无isSign请求头 | 根据客户端类型和版本号判断 |
是否塞入签名中间过程信息 | 通通都有 sign-before-md5: sign-md5: 如果签名过程发生异常,则增加: sign-e: 错误信息 | 仅签名校验失败时,在errorMsg里返回. | 测试包,切到正式环境,有 sign-before-md5: sign-md5: 等信息. 正式包没有这些信息. | 只返回常规信息. |
Reference
[1] 阿里云 | MTOP、API网关
[2] 微信支付 | 微信支付接口签名