注意场景:
综合以上三点。为什么在 Https 的保护下,还要额外做签名验证?
主要疑问,如 stripe 的退款接口
curl https://api.stripe.com/v1/refunds -u "$密钥:" -d charge=$charge_id
就可以发起一笔订单的退款或者扣款。按照某些论述的话,没有签名的 Stripe 岂不是非常危险?
签名指的是
data = { "a":"1", "b":2}
data = sort(data) # 按照一定规则对data进行排序
signString = getSignString(data) # 按照一定规则将数据拼成一个字符串
sign = sign(signString) #按照指定算法如md5/shaX等计算hash得到最终的『签名』
data.sign = sign # 最终请求数据
初步总结:
在使用HTTPS的前提下,已经保证了足够的安全性。完全没有必要再额外做一套『签名机制』。
防重放攻击,依靠的是API接口本身的逻辑设计,如下场景,订单相关:
// 根据KEY找到user
$user = Db::table('key_user')->where('key', $request->get('key'))->find();
// 验证key、user是否合法、有权限、balabalabala
// 验证key、user的请求频率
// 如上两步都可以作为中间件全局统一处理
// 查: 无所谓、随便查,无所谓是否重放攻击
return new Response(balabalabala)
// 改: 下单、关闭、结算等balabala
// 下单:订单是否已经存在,存在报错已存在不存在入库
// 关闭:验证订单状态,能关闭就关闭,不能关闭报错
如上PHP代码逻辑完全可以有效防止『重放』带来的『损失』,而且还可以加入一个timestamp
参数,可以有效防止TCP数据包重放
第三次总结:
公开API的接口设计,在有HTTPS的前提下,签名负数『非必要』可以不使用签名。
要注意的是:
20210414-0320总结:
收集罗列了一些国内外的一些大型API服务使用单纯的HTTPS而没有『签名』参与的厂商和认证模式。
国外已知服务
总结: 国内还是偏向一定要有『签名』的多,不知为何。
最终总结
https+签名 ¹ 会『更』安全。
但是,https自身的安全程度足够,没有再额外增加签名 ¹ 机制的必要性。
安全问题主要出在客户端自身网络环境安全。
结贴
1: 签名指的是类似 md5( sortedString + key ) 的附加请求参数
201
chizuo 2021-04-14 10:09:32 +08:00 1
@dzdh 这样不叫签名,任何人都可以用 hash 来生成同样的数据,怎么保证这个数据是 bob 生成的呢?只有用 bob 唯一的东西(比如 bob 的私钥)去生成数据,才能保证这是 bob 的,这才是签名。你说的那叫消息验证,建议区分一下
|
202
q197 2021-04-14 10:20:22 +08:00
举例的网站也有不少人用 api 开发 app 的,那么 key 什么的都保存在本地。我作为用户想自己也写个类似 app 可以直接抓包 app 的通信直接“借用”key 。如果加入签名,就提高了直接“借用”key 的难度,所以还是防客户端。
|
203
3dwelcome 2021-04-14 10:31:52 +08:00 1
"第 5 条附言 20210414-0320 总结:国内还是偏向一定要有『签名』的多,不知为何。"
楼主说了那么多不签名的理由,我就问一句,你的客户在电子支付过程中出了金钱问题,你作为设计支付 API 方,赔不赔钱? 什么?你没钱?那还不赶紧加上签名。(国内签名现状) |
204
mmdsun 2021-04-14 12:33:02 +08:00 via Android
内部的 server 到 server 无需签名。
我们签名都是网关统一做的,内部调用不需要签名。 不过你是 server 是“客户”就需要了 |
205
palfortime 2021-04-14 12:55:06 +08:00 via Android
@nikan999 hash 用于完整性校验没有问题。我回复中提到涉及的 hash 的问题是,拿一个公开的盐来 hash,然后把这样的算法定义为签名,这样的认知上的一个问题。
|
206
palfortime 2021-04-14 13:04:25 +08:00 via Android
@0o0O0o0O0o #193 感觉你误会了我的意思,我回复的前半段是支持楼主的观点,tls+双向证书可以替代签名。后半段只是拿个类似的安全问题吐槽。并不是要在 app 上实现双向证书 tls,我只是吐槽安全把问题弄得复杂到业务实现 tls 双向证书。
|
207
EminemW 2021-04-14 13:06:40 +08:00 via iPhone
不是为了防止接口被别人恶意调用么
|
208
nikan999 2021-04-14 13:41:46 +08:00
@palfortime 确实, 楼主题中给出的签名例子 属于 data signature 而不是做 authentication 的那个 signature, 这是两种东西
|
210
dzdh OP @kejialiu #197
针对可能原因,Paypal 从 2004 年开始提供对外接口开始到现在,经历过 N 次的整体架构升级迭代都没有出一套新的(出新的并不意味废除旧的)接口规范?事实是出了,而且依然是 Http Authentication+OAuth 形式。如果硬要说 Paypal 的设计有问题,那后起新秀 Stripe 呢? facebook 、twitter 、instagram 等等等等呢?显然这种说法站不住脚。 我并不是要竭力的证明『 HTTPS 就绝对的安全了』而是『在 HTTPS 模式下,没有必要在额外做 hash 摘要签名』的逻辑。 真要说安全大可以硬件加密狗+DNA 验证+虹膜+人脸+物理快递安全设备+面对面认证+指纹授权。一次 HTTP 请求等 10 年,但是这不是『根本没必要』吗? |
212
dzdh OP |
213
dzdh OP @3dwelcome #198
依然没有在点子上。不是『要不要』的问题。而是: 回归本质,在 HTTPS 下是不是必须一定绝对只能真的一定要『 mdX/shaX(sortedString+key )』不可?不这么干的话这个设计方案就一无是处、垃圾、没用、渣渣、愚蠢至极? |
214
dzdh OP |
215
3dwelcome 2021-04-14 14:30:46 +08:00
@dzdh "不同意,你的意思是说:用了签名,客户损失了我就不用赔钱对么?"
你的意思是说:不管你支付 API 怎么设计,客户损失后,你们都不赔钱喽? 那还是支付宝好,人家愿意赔钱的。如果技术原因被盗刷,赔全款。 你可以去搜一下,人家核心就五个字:安全系数高。可这点你又不认,多尴尬。 |
216
3dwelcome 2021-04-14 14:35:09 +08:00
@dzdh “回归本质,在 HTTPS 下是不是必须一定绝对只能真的一定要『 mdX/shaX(sortedString+key )』不可?不这么干的话这个设计方案就一无是处、垃圾、没用、渣渣、愚蠢至极?"
安全系数是个无线趋近于 99.999%的函数,谁都不敢保证 100%没问题,当然要越做越细。 方案又不是非黑即白,有很多中间灰色地带的,一切都是筹码。 |
217
dzdh OP @3dwelcome #215
参看 215 楼 你的论点是:#203: 你的客户在电子支付过程中出了金钱问题,你作为设计支付 API 方,赔不赔钱?什么?你没钱?那还不赶紧加上签名。 并不是我的论点,我只是用你的问题在求证是否能得出相反的论点。 其次,你说支付宝的『你敢付,我敢赔』没问题,是的,真的非常的好,真的。 竞争对手微信呢?他可没这么承诺吧?而且盗刷新闻也不少吧?最终微信不承担责任的也不少对吧?但是并不能得出『微信支付是垃圾』或者『微信支付不安全』的结论,对吧? 再者,并是因为支付宝『使用了 mdX/shaX(sortedString+Key)』才定的『你敢付,我敢赔』吧?而是其复杂鉴权的风控体系和商业保险吧?个人认为这和主题并无关系。 参看#213 楼 最后:我从来没有任何言论表述过『不承认 https+data hash 』或『不承认 http+data hash 』的安全性吧?仍然请参看#213 楼 请不要漏调任何一个观点 |
218
dzdh OP @3dwelcome #216
或者我再换个说法。https+不使用 data hash signature 是个极简且安全(你说的不绝对 100%嘛)实施难度最小、接入速度最快、最便捷的方案。可以不? |
219
3dwelcome 2021-04-14 14:50:15 +08:00
@dzdh "https+不使用 data hash signature 是个极简且安全(你说的不绝对 100%嘛)实施难度最小、接入速度最快、最便捷的方案。"
这说法我能接受。 一些老式楼宇,有些人家大门前,还要额外再加装一道铁门,看起来好像很繁琐。( url 签名接入同样也很繁琐)。但是对比小偷来家里光顾一次,洗劫一空。这点繁琐的开门代价,实在是微乎其微。 写代码别的客户端都可以马虎,就是和金钱相关的代码伤不起,损失的都是真金白银。 |
220
dzdh OP |
221
3dwelcome 2021-04-14 15:19:12 +08:00
@dzdh 今天回复了别的帖子,右边 V2 摸鱼条已经变黄了,应该不能回复很多条了。
我的观点那么多来来回回,已经的比较清晰了。我就是觉得有必要把客户的钱当成自己的钱,你就会不自觉的把细节扣到极致。 试想一下由于忘关窗户的疏忽,晚上回家发现家里来过小偷,把你电脑和硬盘上所有的小姐姐资料全部偷走。是不是会后悔自己没有把安全防范做到极致?安全就是能把现在设想到的一切,都尽力做好,好让灾难真正发生的时候,没那么自责内疚和懊悔。 |
222
murmur 2021-04-14 15:21:00 +08:00
签名主要是防重放攻击,里面有一次性的随机码,用了就作废
|
223
dzdh OP @3dwelcome #221
『安全』应有『度』,要比极致请参考 210 楼 > 真要说安全大可以硬件加密狗+DNA 验证+虹膜+人脸+物理快递安全设备+面对面认证+指纹授权。一次 HTTP 请求等 10 年,但是这不是『根本没必要』吗? 即便用了上述所有手段就『真的『绝对』安全了吗』?但是也不能因为『无法保障绝对安全』就不做任何措施 在世界公认的 RSA&ECC 保护下已经有了这个『度』适应的安全保障。已经『够了』。 下班回家,离门 10 米自动开门,进屋自动开灯全凭身上一部手机和人脸。都『足够的安全』了。但是如果要说的话,这安全吗?装门干啥?有啥门是一锤子解决不了的?要密码干啥?银行就不能被抢了?我一定会懊悔为什么没装两个门,为什么没给家里装防弹玻璃,为什么没把密码设置成 100 位锁在银行保险柜里。 这不都是因为已经『足够安全了』吗? 就像有人在反复强调客户端的问题,我的观点是:针对于客户端,你任何的安全措施都没用,就像上面所有安全措施加一起,我就愣把密钥给出去,开源放到 github 上你凭什么保护?对客户端来说,也是需要他自己具备『安全自保能力的』。 核心论点是:足够的方案措施 |
224
Rheinmetal 2021-04-14 16:11:43 +08:00
有些业务原理上就没法防止重放 参考 AWS 接口签名的说法
Why requests are signed The signing process helps secure requests in the following ways: Verify the identity of the requester Signing makes sure that the request has been sent by someone with a valid access key. For more information, see Understanding and getting your AWS credentials. Protect data in transit To prevent tampering with a request while it's in transit, some of the request elements are used to calculate a hash (digest) of the request, and the resulting hash value is included as part of the request. When an AWS service receives the request, it uses the same information to calculate a hash and matches it against the hash value in your request. If the values don't match, AWS denies the request. Protect against potential replay attacks In most cases, a request must reach AWS within five minutes of the time stamp in the request. Otherwise, AWS denies the request. |
225
3dwelcome 2021-04-14 16:15:35 +08:00
@dzdh "这不都是因为已经『足够安全了』吗?"
够不够,因人而异。我个人觉得只靠 HTTPS 是不够的。 http 签名 RFC 协议是 2020 年发布的,假设 HTTPS 真的够用,那又何必在 HTTPS 发明的那么多年后,又发布这种额外协议,多此一举。 只有真正的 HTTPS End-To-End,在我眼里才算勉强够,可事实情况并不是,中间环节总会经过各种奇怪 TLS 解密终端。 |
226
timedivision 2021-04-14 16:25:39 +08:00
@dzdh 所以你还是没明白没有所谓的“足够安全”、“绝对安全”,万事无绝对
|
227
dzdh OP @Rheinmetal #224
我能想到的只有『没有业务唯一标记的业务』无法防止。否则其他场景像支付下单,你要传调用方本地订单号可防重放,关闭订单传订单号可防重放,但是像浏览器端的 event 日志,那的确没法防,因为请求进来就直接入日志库的。 @3dwelcome #225 这就不对了,那 HTTPS 出来以后还有 http2 呢,TLS 还有 1.0/1.1/1.2/1.3 呢。方案是不停进步的,出了 TLS1.3 也没必要全球废止 TLS1.0 对吧? 如果要『扯中间环节』那就一定要说密钥保全,这又是『客户端环境安全』的问题,我就故意泄露密钥、私钥。绕回来还是『无绝对』。但是这依然不能证明帖子标题是『不足够安全』的,我还是明白不能。 @timedivision #226 所以到底应该怎么定义『足够安全』合『绝对安全』。首先『绝对安全』是不存在的,也没必要也不可能做到『绝对安全』。所以为何标题就『不够安全』,我认为就标题的安全防护策略、手段在所隐含的『安全缺陷』在『签名(mdX/shaX(sortedString+key)』都能找到对应的。这并不能成为帖子标题的方案就是『不够安全』的理由吧? |
228
3dwelcome 2021-04-14 16:46:59 +08:00
@dzdh "如果要『扯中间环节』那就一定要说密钥保全,这又是『客户端环境安全』的问题,我就故意泄露密钥、私钥。"
不啊,你 HTTPS 证书密钥丢了,短期内并没有什么有效补救措施。 你微信商户 KEY 泄漏,马上进入商户后台吊销 KEY,重新生成一个就可以了,瞬间生效,方便快捷又安全。 |
231
timedivision 2021-04-14 16:56:27 +08:00 1
@dzdh 你觉得 https 足够安全,你不签名,张三也觉得 https 足够安全,但是他想做到更安全,所以他加个签名,李四觉得 http+签名足够安全,所以他用 http+签名
说来说去万事无绝对的情况下,只有客观的足够安全和更安全,所以你爱签不签,只要老板或者 cto 说行就行 |
232
3dwelcome 2021-04-14 16:57:12 +08:00
@dzdh "怎么定义『短期』。1 天? 1 小时? DV 证书重新签发 1-3 分钟。"
吊销又不是签发,不可能 3 分钟生效的。 吊销的流程是通知 CA 你证书密钥掉了,然后 CA 定期发布一个 CRL 吊销列表,把你的无效证书信息写进去。然后浏览器会定期同步一次。 和商户 KEY 对比一下速度,那真是乌龟和兔子赛跑 - 龟速反应。 |
233
dzdh OP |
235
1iuh 2021-04-14 17:13:11 +08:00
https 是网络层的东西,应用层不一定能拿到网络层的信息,可能在 cdn 那里丢失网络层的信息, 也可能系统内部的负载均衡这里丢失网络层的信息, 信息都拿不到,可不就得应用层自己搞吗?
单纯从技术上来说,TLS 确实足够安全了。自己实现一套无非也就是非对称加密,或者哈希摘要签名,要比 TLS 更安全是不可能的,这有什么讨论的意义的。 |
237
3dwelcome 2021-04-14 17:18:07 +08:00
@dzdh "只有合适的方案,合适的方案就是对的方案。"
用户才不管你方案是不是最合适的,资金被盗后,他只在乎你赔不赔钱。同样,你也不敢拍胸脯保证支付系统 API 设计 100%安全。也不敢和支付宝那样,宣传有用户任何金额损失,我站出来全额赔付。 如果连自己都说服不了自己,又怎么有底气去说服别人,这方案『足够的安全』? |
238
timedivision 2021-04-14 17:34:17 +08:00 1
@dzdh 是这个道理,好比冬天为了更保暖,多穿件毛衣有没有必要全看个人
|
239
dzdh OP |
242
3dwelcome 2021-04-14 17:51:54 +08:00
@dzdh "就说 RSA 算法这个本身,数学上,是不是足够安全?"
算法本身是安全的,这点不用怀疑。可是你这个系统里,又不是用 RSA 来加密内容的。 HTTPS 是用 RSA 做签名验证,仅仅只加密了握手阶段的密钥,而内容本身的加密部分,是 AES 这种对称式加密处理。为什么?因为 RSA 性能有问题,一次只能加密一小部分内容,全部加密 CPU 抗不住。 如果 RSA 加密和 AES 加密对比,无疑 RSA 安全性要胜出一截,关键 HTTPS 并不是全程 RSA 加密啊。 再者,你能确保自己的服务器上 HTTPS 通道万无一失,却没办法保证客户 HTTPS 通道没有任何问题。我上面回复过了,HTTPS End-To-End 是安全的,但也仅限为『 End-To-End 』,这个大前提,你不能无视。 |
243
3dwelcome 2021-04-14 18:09:00 +08:00
可能有人不了解 RSA 具体算法,我多罗嗦几句。
RSA 官方有 RFC 3447 使用规范,规定了 RSA 签名算法和 RSA 加密算法,是两套不同的 schemes 。 两者最大区别是,用 RSA 签名算法处理的数据,每次密文都是一样的。而用 RSA 加密算法处理的数据,每次都是不一样的(为了确保破解者的难度,每次加密后的密文都会变) 不幸的是,地球最强加密算法,RSA 加密算法并没有在 HTTPS 里使用,也没有任何能开启的方法。原因不明,反正就是没用 RFC 规定的那一套加密流程。仅仅用了一下公钥私钥的验证流程。 如果你们谁在 HTTP 处理流程里,加入了 RFC 提到的 RSA 加密算法,对内容重加密,那恭喜你,先不讨论 JS 的安全性,光加密后数据的安全性,已经超过了 HTTPS 。 |
244
dzdh OP @3dwelcome #242
--- 所以引申出来的是,不能考虑『外在因素』,就是上面说的,客户端环境你能保证安全吗?显然并不能。客户玩了命的作死没有什么方案可以达到『足够安全』的标准。 因此引申出来的是『客户要有保障包括但不限于自身环境安全、运维、运营、审计』的『基本安全』的能力 --- https 本身就是依靠协商出来的密钥进行 aes|des/3des(已不推荐)等算法进行加密通信,只要一次性密码不被泄露就是安全的 在起码保证客户端(调用方)的基本环境安全( pin,cacert.pem) ,出网的数据包(aes encrypted)可以认为已经安全了。并没有什么外在因素能攻破已经和服务器建立的通信。对不? --- 补充个题外回答,注意是题外。 微信证书是微信自己做的自签名 CA 颁发的,不存在『吊销』的说法,所谓『吊销』从库里删掉你的序列号就行了。 Certificate: Data: Version: 3 (0x2) Serial Number: 36:xxx:05 Signature Algorithm: sha256WithRSAEncryption Issuer: commonName = Tenpay.com Root CA organizationalUnitName = Tenpay.com CA Center organizationName = Tenpay.com countryName = CN Validity Not Before: **** GMT Not After : **** GMT Subject: localityName = Shanghai countryName = CN organizationalUnitName = \U4E0A |
245
3dwelcome 2021-04-14 18:22:28 +08:00
@dzdh "客户玩了命的作死没有什么方案可以达到『足够安全』的标准。"
客户明明是上帝,你怎么能说客户作死呢。互联网就是适者生存的竞争环境,是你去主动适应客户,而不是让客户来反向适应你。 换成我设计支付 API,如果客户的网络不可信,那就直接接管客户那头所有的收发代码。在发布的 SDK JS 里套一层额外虚拟机,用自己的流程和加密算法来处理所有敏感数据,这样哪怕客户的 TLS 解密网关保存了明文数据包,照样没办法轻易解读。 就算未来资金支付出错被盗,那也不能怪客户。一般都是码农站出来背锅,就从来没听说过让客户背锅的。 |
246
dzdh OP @3dwelcome #245..
跑题了啊喂。 我再再再换个说法,好吧?『在不考虑或者基本确认客户端(调用方)调用环境相对安全( pin,cacertpem)的前提下,仅 https 并没有 md4/5sha1/256/512(sortedString+key)签名的必要』还有争议么? |
247
est 2021-04-14 18:43:51 +08:00
如果有客户端证书,的确是不需要签名的
|
248
3dwelcome 2021-04-14 18:54:11 +08:00 via Android
换种说法,同样是银行,瑞士中央银行和普通小银行的安全系数也是不一样的。
“系统够不够安全”,完全取决于要保护东西的价值有多大。 有些东西可以丢,有些东西丢不起。 |