上篇文章浅尝辄止,想了一个场景来讲述对称密钥以及非对称密钥解决了什么问题,以及各自有什么优缺点,本文用实际的案例来分析签名能解决什么问题,以及该如何正确的签名。
阅读了支付宝、微信支付、腾讯云、阿里云的开放文档,发现他们签名方式几乎一致,在不同的场景分别使用MD5和数字证书签名,甚至在不同的时间节点进行相同类型的升级,下面是我各大平台的开放文档中找到的作为案例分析。
下面是我从支付宝平台找到的一个文档,我们先看MD5签名方式,通过阅读文档知道使用MD5哈希步骤如下:
1)筛选:获取所有请求参数,不包括字节类型参数,如文件、字节流,剔除sign与sign_type参数。
2)排序:将筛选的参数按照第一个字符的键值ASCII码递增排序(字母升序排序),如果遇到相同字符则按照第二个字符的键值ASCII码递增排序,以此类推。
3)拼接:将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为待签名字符串。MD5签名的商户需要将key的值拼接在字符串后面,调用MD5算法生成sign。
那么按照以上过程,我们可以拼出如下签名原传,其中signkey是商户和支付宝约定的签名key, 对该串求md5,形成签名:
out_trade_no=2012113000001&total_fee=0.01&signkey=XXX
由于MD5不可逆的特点,攻击者并不知道signkey,因此也就无法计算签名,同时如果攻击者修改了参数,后台服务在校验签名时就会提示签名错误,不予处理,达到了请求方身份校验和保证参数不被更改的目的。
但是细心的话应该可以发现,腾讯云、阿里云等各大平台的开发文档中,几乎所有使用这种签名方式的接口都会要求传入另外两个参数,nostr和timestamp,nostr是一个随机字符串、timestamp是unix时间戳,这又是为什么呢?
先说结论:为了防止重放攻击,https可以解决传输层面的安全问题,但不能解决应用层面的安全问题。
比如某一个接口是文件下载接口,攻击者尽管不知道你的signkey,可是他可以把你的签名串以及参数记下来,然后疯狂请求服务器,这样服务器校验签名依然通过,需要耗费巨大的资源来处理攻击者海量的恶意请求,从而影响服务。
现在我们再来看这两个参数,很多地方说nostr是用来增加签名的不可预测性,但是我认为这是不正确的,在signkey没有泄漏的情况下,由于MD5的特性,任何人都无法仿冒签名或者预测签名。
为了规避重放攻击,我们很容易就想到在每个请求中增加一个随机字符串,这样当服务器每处理完一个请求就会把这个字符串记下来,下次再有相同请求相同nostr就不予处理,从而防止重放攻击,然而随着请求越来越多,需要缓存的nostr也越来越多,显然服务器不可能永久的缓存nostr,然而一旦删掉请求过的nostr就意味着攻击者又可以使用这部分nostr进行攻击了,于是又加了timestamp。我们给签名设置了一个有效期,在每次请求处理前先校验签名,签名通过后校验timestamp确认签名是否过期,这样服务器既不需要缓存nostr,又解决了重放攻击问题。
这里再额外说一下为什么需要nostr和timestamp两个参数来解决重放攻击问题:
1)假如只有nostr服务器就需要永久的缓存使用过的nostr,这个存储成本以及检索效率都是问题;
2)假如只有timestamp,在并发情况如果很有可能同一时间有两个相同参数的请求都是有效的,但服务会错误的认为是重放攻击从而仅处理第一个。
MD5签名方式可以应用在大多数场景,完全可以满足鉴权和参数校验的需求,然而支付场景有更高的安全要求,我们再来分析MD5有什么安全问题:
1)无法防御跨接口攻击,在restful标准下同一资源的不同操作url、参数很可能相同,仅请求方法不同;
2)使用对称密钥签名,无法防抵赖,因为是双方持有签名key,一旦发生安全问题,无法确定是哪一方的责任。
3)没有对参数转移,可能导致不同请求做出的签名相同,比如某一个参数的值是“tom&key=1”
在涉及到支付,比如扣款、退款等接口,支付宝和微信支付的开放文档都是使用了更为严格的签名方式,签名的内容也不再仅对参数进行校验,下面是微信支付升级后的签名内容(支付宝也类似,有微小区别):
签名串一共有五行,每一行为一个参数。行尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。如果参数本身以\n结束,也需要附加一个\n。
1:HTTP请求方法\n
2:URL\n
3:请求时间戳\n
4:请求随机串\n
5:请求报文主体\n
其签名方式也不再是使用MD5,而是使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。
与MD5签名方式相比较:
1)请求方法和url参与签名可以解决跨接口攻击;
2)请求时间戳和请求随机串参与签名可以解决重放攻击;
3)请求报文主体不再是拼接字符串,而是json格式,可以解决不同请求签名相同的问题;
4)使用证书签名,证书持有者仅商户自己,可以防抵赖。
在阅读支付宝和微信支付的文档时,发现两家都对证书进行过一次升级,由原来使用的自签名升级为第三方可信机构颁发的证书,原因有两个:
1)国家相关标准规定 “电子签名需要第三方认证的,由依法设立的电子认证服务提供者提供认证服务。”(还记得12306的那个安全提示吗,就是因为之前12306使用的也是自签名),因此申请了第三方可信机构的证书,然后使用这个证书为每个商户签发证书;
2)自签名有安全隐患;只要理解了签名的原理,任何人都可以按照教程生成证书,做证书并不难,难的是发挥它该有的作用。但是还记得上篇中讲到数字证书出现的原因吗,是为了解决中间人攻击问题,它能够解决中间人攻击的原因正是因为证书颁发机构是可信的,但是如果使用了自签名,签名机构是没有经过认证的,也就是不可信的,一切又回到了原点。
支付场景对安全性有着更高的要求,自从做了支付小心翼翼、如履薄冰。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有