注意场景:
综合以上三点。为什么在 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 ) 的附加请求参数
101
sekfung 2021-04-13 19:45:30 +08:00
SSL Pinning 安全性问题,见#88 楼
我赞同#100 楼说的,就是不同层次的做法。 逆向与反逆向就是道高一尺,魔高一丈,安全领域没有绝对性的安全,只有提高破解的成本。 |
102
3dwelcome 2021-04-13 19:46:13 +08:00
@dzdh "所以是,仅仅 HTTPS 已经足够安全,所谓签名只是锦上添花?"
光"锦上添花"就很重要,支付 API 设计能强过竞争对手,才能抢到足够的市场份额。 你开发一个 HTTPS 网站,去做网站安全评级,每一个服务器设置的细节,都是打分点。 你开启一个云服务器站点,服务器平均无故障就是一大卖点,数 99.99 小数点之后有几个 9,就能比同行抢到更多的用户。 支付签名设计也是一样,能给 API 安全打分后面加个 9,何乐而不为。 |
103
dzdh OP @catchexception 100
对的。『签名机制』的目的是为了防止在『传输时』被篡改(被截获倒不可怕)。 且我认为就只有这一项作用了,而 HTTPS 的存在就足以保障『无限接近 100%』的传输安全,因此有此一问,为何当下大厂在『有 HTTPS 的前提下还要有签名机制辅助』 |
104
akira 2021-04-13 20:01:32 +08:00
@LeeReamond 这是反话呢。。
|
105
dzdh OP @sekfung 101
对于#88 楼的回复见 #96 楼 SSLPinning 被攻破,仅仅是单个客户端的安全(而且绝大多数情况下是自己搞得)。 而『签名』的密钥通过 HOOK 方法一样也能轻松拿到,而且拿到签名密钥是不是意味着所有的客户端都不安全? |
107
3dwelcome 2021-04-13 20:08:16 +08:00
@dzdh "所以,『纯技术』上,在有 HTTPS 保护的前提下,签名没有『必要性』"
那是自然,只要 PC 机器能 [物理隔绝] ,使用时只有机主一个人能进入密室访问电脑,那 windows 登录密码也没有存在的 [必要性] 。 |
109
3dwelcome 2021-04-13 21:13:18 +08:00
@dzdh "如果一个密码公开发放,那的确没有必要性。"
密码怎么可能公开?举个例子,微信支付的 url 签名 hash 算法是 HMAC, 也就是需要 key 才能使用的 HASH 算法。这个 key 是严格保密的,外人肯定不会随便知道。 |
110
hxndg 2021-04-13 21:15:08 +08:00
@catchexception
@ashuai 你俩的对话可以完美对接, 实际上我看到 ashuai 的回复的时候也是想的这个,不过后来想想算了,国内的很多程序员就是喜欢层与层之间要通信,而不是只提供依赖。 我这几年写 TLS 自动机的最大感受就是国内很多程序员就是不分层,一部分问题确实不分层比方说四层的零信任,但是很多业务层的事情非得扔给 TLS 做导致极其不灵活。 @dzdh 为什么要和一群根本不知道 TLS 做了什么的人讨论具体细节呢?一个合格的程序员(架构)必然会拆分不同的层做不同的工作,你自己都明明知道咋回事何必争论呢? |
112
dzdh OP |
115
3dwelcome 2021-04-13 21:33:06 +08:00
@dzdh
"同样的『客户端证书』也是严格保密的,外人肯定不会知道" 不不,客户端证书和微信商户 KEY 安全性没法相提并论。 客户端证书获取流程是写进 SSL 规范里的东西,你比如访问 api.mch.weixin.qq.com 之类的网站,只要服务器发一个 CERTIFICATE_REQUEST 请求,客户端就会乖乖主动发证书发给对方,也不知道对方是真是假。 但是微信商户 KEY 不一样啊,默认就是私密存放,不发给别人的。除了去登录微信的开发账号查看,没别的办法获取到了。 |
116
dzdh OP @3dwelcome #115
1. 抛弃『客户端证书』,`curl -u $ukey ..` 的 $ukey 也是『严格保密』的 2. SSLPinning 3. SSLPinning 被攻破代表着已经控制了物理设备,控制了物理设备可以直接读取所谓的『 KEY 』 |
118
3dwelcome 2021-04-13 21:40:38 +08:00
@dzdh “2. SSLPinning”
你这就是先有鸡还是先有蛋的问题,SSL Pinning 的前提,就是双方验证对方的证书。然而你证书不发送出去,又何来验证一说?但是你一旦发送,你的客户端证书就有可能被泄露。 学一下微信 KEY 多好,只签名不发送,稳妥多了。 |
119
dzdh OP |
120
swulling 2021-04-13 21:42:47 +08:00 via iPhone 1
最早是用在 http 情况下防止重放攻击的。
后来换 https 后设计就没用了,但是要么同时提供 http https,要么就是保持历史代码兼容,所以也就不改了。 |
121
dzdh OP |
123
jim9606 2021-04-13 21:48:04 +08:00 2
API 接口搞一套自订签名的目的是适应不能使用 TLS 双向认证的情况,例如:
1. client 环境存在强制部署的 MITM 代理 2. CDN/API 网关服务 /高防服务不支持客户端 TLS 认证透传,或者位于网关后的 API 应用服务器不能获得充足的客户端身份信息,例如网关做了统一 TLS 解密 3. 任一端无法保证系统时间准确 4. API 服务器所使用的网络框架难以适应 TLS 客户端认证的需要,例如异步 request handler 没有方法获取来源的 TLS 连接状态,或者需要重复解析客户端证书信息导致性能瓶颈 5.客户端采用精简的 TLS 实现,不支持双向认证 第二点在很多企业中是个麻烦事,如果你确定这套 API 只用于支持端对端的 TLS 双向认证的环境,而且有能力维护签发 /吊销客户端证书的附属系统,那确实可以只依赖 TLS 双向认证。 如果希望服务器认证也完全在自身掌控之中,服务器也可以使用私有 CA 签发的证书,客户端配置只信任私有 CA 即可。 PKP 是用来防止第三方 CA 滥发证书的,且有很多实践上的问题,已经被弃用。 |
124
dzdh OP @jim9606 #123
1. 强制出网 HTTPS 请求走代理?什么场景?需要做审计么? 2. Stripe 和 Paypal 的全球 CDN 的解决方案是什么?高防服务可以数据包转发。抛弃『客户端证书不谈』,就单纯的仅『 HTTPS 』形式如标题的『 curl -u $ukey https://....』貌似并不存在这问题?全链路保证 https ( cdn https 回源) 3. 签名需要的 TIMESTAMP 参数也无法保证 4. 性能问题? 5. 服务端强制要求的密码套件设置呢? |
125
3dwelcome 2021-04-13 21:56:54 +08:00
@dzdh "比如我微信支付商户的证书公钥你要吗?我发给你。"
微信没有公钥,在 url 签名算法里,只有商户平台设置的密钥 key,这个绝对不能发给别人,绝对不能在网络上流传,必须严格保密。 公钥和商户 KEY 的区别,就好比一台联网的 PC 和一台物理断网的 PC 差别,你说哪一个更安全? |
126
dzdh OP |
127
dzdh OP @3dwelcome #125
curl -u $ukey https://... $ukey 只有商户平台设置的$ukey,这个绝对不能发给别人。 > "这个绝对不能发给别人,绝对不能在网络上流传,必须严格保密。" 你的意思是破解了 HTTPS ??????破解了 ECC ??从而拿到了我的数据包? |
128
kejialiu 2021-04-13 22:07:28 +08:00 via Android 1
@dzdh - https 服务端的密钥是怎么管理的,都有谁经手了,不小心泄露了呢?
回:签名模式的密钥怎么管理的?都谁经手了,不小心泄露了呢? 不是这个意思。我作为参与通信的其中一方,无法保证对方的安全管理足够好,我最多只能控制自己这一边。对于使用了 https+签名的情况,从服务端的角度看,某个客户的签名密钥泄露只会影响这个特定的客户;从客户端的角度看,服务端的 https 密钥泄露等同于通信变明文,但别人还是伪造不了我的签名。两种情况都比最好情况好很多。 - 签发 https 证书的 CA 是不是足够可信任呢? 回:本地指定 CA 文件验证 这个指的是 CA 本身被攻击,导致客户密钥泄露,甚至主动参与犯罪 /配合有关部门。当然这种可能性很小,但小不等于没有。 以上讨论的出发点都是 “https 防中间人是有条件的”,与题主的问题没有直接关系。 再多嘴一句,其实 https 网站很多很多时候都不是全链路加密,tls termination 发生在负载均衡,甚至更前面的某个第三方(比如 CDN 或云厂商)的反向代理或者所谓应用防火墙上上,后面都是明文,就算是在内网,走明文也是非常不安全的。 |
129
nikan999 2021-04-13 22:10:21 +08:00
猜测可能是为了保证端到端的数据不会发生错误。保证应用层的数据完整性。
|
130
BinaryLeeward 2021-04-13 22:14:18 +08:00 1
个人觉得纯粹的服务端对服务端的场景有了 https 和密钥就够了,再加签名机制是没啥用,但是作为服务提供方是无法强制调用方一定得在服务器调用,如果调用方直接在客户端调用了接口,如果不用签名的机制那随便抓个包就拿到密钥了跟裸奔差不多,用了签名机制至少加了一层安全性必须破解客户端才能拿到密钥。
|
131
dzdh OP @kejialiu #128
1+2. Server 端到 Server 端可以自签名证书。 泄露就也就是指的服务器攻击或者或主动或被动的泄露。 - 被攻击泄露,如果服务器被攻击且能读取到 ssl 证书的文件内容本体,我认为数据库也已经不安全了,所有商户的签名 key 也都不安全。 - 或主动或被动的泄露证书私钥,攻击成本他需要控制全国骨干网管理节点或攻破我 DNS 系统,最次也要控制某单个客户的服务器( server 端)或某单个用户的家庭网络,受影响的也仍然只是某单个用户吧? 链路问题可以设置成全链路 tls 吧?如 cloudflare ?阿里云、腾讯云等众多 CDN 厂商的 cdn 也是支持 https 回源的 |
132
3dwelcome 2021-04-13 22:15:57 +08:00
@dzdh “curl -u $ukey”
商户 key 不是这样用的,商户 key 是 hmac 算法的关键。SSL 里同样也有 hmac 算法,key 叫 master key,如果你有幸拿到了,那恭喜你,就真正意义上攻破了 HTTPS,喜大普奔。 |
133
kejialiu 2021-04-13 22:16:06 +08:00 via Android
@dzdh 看了一下你的其它回复,在*有客户端证书*的情况下确实没必要对请求额外签名,这两个原理上是等效的,或者说签名只是客户端证书的屌丝版。
|
134
dzdh OP @3dwelcome #132
不是那个问题。 而是,我设计的就是这样的,$ukey 就是我的商户 key 。 和你所谓的微信商户 key 同等权限(在应用设计上),微信商户 key 用来计算生成 hash 或 hmac,不参与网络传输,ok,没问题。 我的$ukey 在公网传输,但是有 https 保证不被泄露啊?有什么问题吗? |
135
dzdh OP |
136
kejialiu 2021-04-13 22:20:47 +08:00 via Android
@dzdh 链路问题可以设置成全链路 tls 吧?如 cloudflare ?阿里云、腾讯云等众多 CDN 厂商的 cdn 也是支持 https 回源的
其实这里还有一个问题是你要把 https 私钥分享给 CDN 厂商,这些大厂就这么可信吗?反正我胆子很小。。 |
138
kejialiu 2021-04-13 22:28:11 +08:00 via Android
|
139
BinaryLeeward 2021-04-13 22:37:33 +08:00
@dzdh 你说的没错 SSLPinning 某种程度上是可以防抓包,但是我想表达的场景是,调用方可能并不会按常规的方式来操作,假如我是服务提供方,我根本没法强制客户按照我的想法设计 app, 假如客户就是直接在 app 端不做任何安全措施就调用了接口,那对于服务提供方来说接口的安全性肯定是差了很多,这种情况下,加个签名机制简单又有效。
|
140
dzdh OP |
142
no1xsyzy 2021-04-13 23:19:24 +08:00
@dzdh SSL/TLS 对面可以手动关闭验证的,你不能保证对面不会犯蠢把验证关了,尤其关闭的选项还不复杂,置个 false 就成。
当然,都 ssl pinning 了,你对 Client 端似乎是有控制能力的?不过我都建议过“为了避免将来的自己犯蠢,不要在用户提交的格式化文本中使用 html (即使你能正确地使用白名单摆平一切)”…… 参考墨菲定律 存在一些实现或者 binding 中没包含客户端证书实现 遗留问题就是旧系统已经有签名了,习惯就是旧系统上搞了签名,新系统思维定势,就像明明有 prepare 了还搞一堆字符限制,明明 UTF-8 支持非常普遍且应当是默认,仍然有用 GBK 的人 上面一直在说重放,其实在恰当的使用下 SSL/TLS 已经可以避免中间人重放(两边都是每次需要产生新随机数,握手信息重放直接导致密钥不相等,但不过保持 TCP 链接重放就不清楚了,应当会被 CBR 防下来) 对了,有时会遇到没有根证书的情况,得自己想办法搞一个…… 我写 ponylang 的时候就发现 ponylang 的 SSL 库没法尝试从操作系统中获得证书信息,只能自己带了个 cacert.pem (但是将来也不太可能进行更新,是个隐患) https://github.com/no1xsyzy/project-v2c/tree/master/v2c-pony |
144
3dwelcome 2021-04-13 23:22:44 +08:00
@dzdh "我的$ukey 在公网传输,但是有 https 保证不被泄露啊?有什么问题吗?"
今天 V2 有个帖子,说的就是 chrome 现在版本的本地执行代码漏洞,光 JS 代码,就能成功调出用户电脑里的计算器程序。理论上 chrome 用户人数最多,版本更新最快,应该更安全,可事实却不是。 正所谓道高一尺,魔高一丈。 你说 https 保证$ukey 在未来不被泄露,这真不太好说。现在全民普及 SSL,大厂为了性能,会专门买那种 RSA 加速卡,设置一个专门网关来加速大批量 SSL 处理过程。一旦 SSL 经过了中间转手,一切都无法 100%保证了。 这种转手对于 SSL Pinning 是无感知的,因为和你交换证书的网关,背后有无数机器,不是一台单独 PC 。 |
145
dzdh OP @3dwelcome #144
??? 加速只是『计算』 TLS 通道仍然是『绝对安全』的。到终端业务机器保证全链路 TLS 就依然安全。 不要说如何保证链路,就像不能保证用户不会泄露 KEY 一样。这不是技术方案问题了。 |
146
ZeroClover 2021-04-13 23:29:33 +08:00 1
@kejialiu https://support.cloudflare.com/hc/zh-cn/articles/360022014111-%E4%BA%86%E8%A7%A3-Keyless-SSL
各种什么私钥泄露问题只要一个 HSM 就可以解决问题,私钥只进不出,所有调用只在 HSM 能完成签名,然后将签名结果给服务器。除非你买的是带后门的 HSM,或者刚好撞上有设计缺陷的 HSM 。 如果本身运行环境就是不可信的,那需要的是整个系统做零信任设计,客户端放个签名无非就是浪费恶意攻击者几分钟而已。 |
147
chizuo 2021-04-13 23:29:54 +08:00 3
我觉得你说的有一个错误:
``` sign = sign(signString) #按照指定算法如 md5/shaX 等计算 hash 得到最终的『签名』 ``` 签名是拿自己私钥去签名啊,怎么会使用 hash ?用 hash 是做消息验证 |
148
dzdh OP @3dwelcome #144
你对 HTTPS 所有可能或不可能碰到的问题,在『签名模式』下都有对应的风险。TLS 私钥泄露?那签名 KEY 也能泄露。算法破解?那 KEY 也能被破解。管理不善?那 KEY 也能管理不善。 chrome 漏洞? 签名模式的客户端就没漏洞? tls 算法漏洞?签名模式的 hash 算法没漏洞? 服务器环境不安全?签名模式服务器环境就安全? 难道就不做开发了吗? |
149
dzdh OP @chizuo #147
你说的签名是额外使用非对称加密算法生成的『签名』 我指的签名,就是我给出的代码的『所谓的签名』,早期的支付宝、微信 v2 版本支付接口、SNS 社交平台等等等的早期签名都是这种。 然而,即便是你说的非对称加密算法的签名,在 HTTPS 模式下为什么有存在的必要? |
150
3dwelcome 2021-04-13 23:44:01 +08:00
@dzdh "??? 加速只是『计算』 TLS 通道仍然是『绝对安全』的。"
RSA 加速卡就是 TLS 解密用的,你只能保证服务器到服务器这段距离是安全的,不会被运营商插入什么奇怪东西。但没办法保证客户集团网关解密后的数据流,是绝对安全的。 这和你 API 设计机关算尽,却防不了内鬼同事是一个道理。 |
151
dzdh OP |
152
3dwelcome 2021-04-13 23:50:18 +08:00 1
|
155
nikan999 2021-04-14 00:02:14 +08:00
补充一下# 129 的内容,
端到端不仅仅是 公网到公网,还有内网到内网, 所以 https 只保证了公网不会出现问题, 数字签名保证了整个传输链路不会出现问题 |
156
3dwelcome 2021-04-14 00:04:12 +08:00
@dzdh “请从『纯技术角度』来『『证明』』 HTTPS 不安全”
上面提到过,SSL 的安全核心依赖的是 hmac 的 key,俗称 master secret 。如果你电脑里这个硬件内存地址被泄露了,那所有的包都是能成功解密的。 你可以确保自己的服务器万无一失,可客户服务器凭什么去保证不会被挂什么木马? 安全从来就是相对而言的打分制,支付 API 加上 url 签名,哪怕只能提升一点点安全系数,那也是值得的。 |
157
chinvo 2021-04-14 00:06:33 +08:00 1
你可以用 oauth client credentials grant 给客户端发 token, 然后用这个 token 取代直接发送 apikey 的方式.
这样可以减少被中间人导致 apikey 泄露的风险. 与固定且不易更换的 apikey 比起来, 可以随时吊销的短期有效的 token 更安全. 用签名而不是直接发送 apikey 也有这方面的考虑 (避免 apikey 在传输过程中意外泄漏). |
158
dzdh OP |
160
chinvo 2021-04-14 00:13:24 +08:00 1
另外有一些系统不方便进行 mutual tls authentication, 因为 mutual tls authentication 是站级的, 不能对不同路径单独设置. (确实有相关实现可以区分路径设置 mutual tls, 但是这种行为是不标准的, 对不同的 客户端 /服务器 /代理 实现可能有不同表现)
RFC8446 section-4.6.2 定义了类似行为, 但是目前未被任何 HTTP 协议草案包含在内 (甚至被 HTTP/2 草案禁止: RFC8740 section-3). |
161
no1xsyzy 2021-04-14 00:17:19 +08:00 1
@dzdh 主要是“关闭验证”太简单了。
curl -k wget --no-check-certificate requests.get(..., verify=False) NODE_TLS_REJECT_UNAUTHORIZED=0 (任意一个被引入的 js 文件中的并不显而易见的环境变量就可以破坏整个体系,太恐怖了 签名密钥泄漏可以被发现继而解除密钥权限;但关闭验证…… 不看对面代码一百年不会被发现,看了代码也不一定能发现,各种语言各种工具采用了各种各样不同的名称,又很少添加任何“危险警示标志”( Sigh 考虑犯蠢准确地说不是技术问题,是风险管控问题。 至于遗留 / 习惯,是人脑的系统性偏差,这你得问造物主怎么想的( https://www.solidot.org/story?sid=67470 |
162
chinvo 2021-04-14 00:17:28 +08:00 1
总之, api 安全 的 设计思路 就是
降低风险 失效可靠 比如站里曾经讨论过把 Google 的 oauth 密钥放在 app 端 还是 自己实现个 oauth 然后把相应密钥放在 app. 其实结论就是, 必须要暴露安全相关的敏感信息的话, 应当选择暴露泄露或失效后损失小的. (相比换 Google 的密钥, 换自己的更容易, 同时也能避免第三方系统被恶意用户直接操作) |
163
jim9606 2021-04-14 00:18:14 +08:00 1
@dzdh #124
1. 有些企业网络的网管系统可能会干这种反人类的事,不过现在越来越少了,因为手机操作系统通常明确无法兼容这种环境。 2. 通常 CDN 会解密 TLS 流量,再通过预先设置的专用客户端证书 /无客户端证书的 TLS 连接回源至源站,这个过程会导致源站获取不到客户端连接状态,但不排除有 CDN 服务商支持将客户端证书信息嵌入 HTTP 头的方法,肯定不是所有服务商都支持这个。Stripe 和 Paypal 用啥我也不知道。 3.没有 RTC 时钟又没有正确执行时间同步的设备可能会出这个问题。 4. 这个得根据具体分析。 5. 如果你的客户端有廉价设备(例如单片机驱动的收付款 POS ),出于节省硬件资源会选择不实现复杂的 TLS,或者支持的套件和扩展大幅缩减的 TLS,然后服务器还得小心选择合适的套件集以避免部分设备连不上的问题。 Server 到 Server 通常不用考虑问题 1 、3 、5,我也没说 TLS 双向认证一定不能用,自行评估这些缺陷能不能接受即可。 |
164
dzdh OP |
165
3dwelcome 2021-04-14 00:19:24 +08:00
@dzdh "客户端环境都木马了,你的签名 KEY 还有何安全可谈?"
木马一般都是定向功能,比如能盗取 HTTPS 数据流并解密,又不一定能成功偷到商户 KEY 。 前几天有个类似安全贴子,讨论数据库被脱裤,数据加密还有什么意义? 回帖都表示,黑客只靠一个漏洞,要同时盗取数据和对应的解密 KEY 是有一定难度的。能黑进数据库,往往不代表能同时获取 KEY 。 用于 URL 签名的商户 KEY 也是同理。 |
167
dzdh OP @3dwelcome #165
> 木马一般都是定向功能,比如能盗取 HTTPS 数据流并解密,又不一定能成功偷到商户 KEY 。 木马一般都是定向功能,比如能成功偷到商户 KEY,又不一定能盗取 HTTPS 数据流并解密 > 前几天有个类似安全贴子,讨论数据库被....... 对啊?别说加密了,还搞开发干啥。管你什么 KEY 你数据库里总有吧? |
168
palfortime 2021-04-14 00:24:09 +08:00 via Android 1
我站楼主,双向证书的 https 就可以解决楼上很多人说的认证问题。现在很多第三方支付的接口用 rsa 的就是要先登管理平台上传商户证书的。
今天才和安全怼过这个问题,搞到最终的方案就是在 https 上套多一层业务自己实现的“tls”。安全还称 app 上加盐 hash 能够防串改,称 app 上的加盐 hash 是签名。公开的盐都不知道是谁的名。 |
169
dzdh OP |
170
chinvo 2021-04-14 00:27:58 +08:00 1
@dzdh
确实, 要求 mutual tls 的场景不多 但是你说的第二条, "不必在 webserver 层处理" 并不能实现, 用 nginx 也好, 用语言自带的 http server 也罢, 要想要求客户端发送自己的证书信息, 必须在站级启用 client tls authentication, 这样就会直接影响同站下的所有路径. 当然我是支持"不用或少用 mutual tls authentication"的, 同时我也认为"签名"在现在的环境下不是保护接口安全"不二法门". 签名其实和一个短期有效的 token 没有本质上的区别, 只是可以在客户端自行生成. 当然, 签名的方式, 相对于 oauth2 之类的解决方案, 进一步降低了密钥泄露的可能性, 毕竟 oauth2 在获取 token 之前需要通过网络发送 client secret 给授权服务器. api 安全, 需要必要的"冗余设计"来实现"失效可靠". |
171
3dwelcome 2021-04-14 00:31:26 +08:00
@dzdh "对啊?别说加密了,还搞开发干啥。管你什么 KEY 你数据库里总有吧?"
保存 key 可以靠操作系统的权限来隔离,windows/mac 搞了那么多年的 keychain,总比存数据库要安全一点了。 linux 系统 root 提权很难很难; windows 系统上,你 chrome 保存的网站密码文件泄露后,换台 PC 没有对应解密 key,神仙也解不出来。 |
172
chinvo 2021-04-14 00:33:10 +08:00 1
因前述"mutual tls 是站级设置, 不够灵活", 我会避免使用 tls client cert 认证.
通常情况下我选择使用 HTTPS + OAuth2. 如果有对外的资金等高安全需求的 API, 我选择增加额外的验证逻辑, 比如 Signing HTTP Messages (RFC Draft HttpBIS message signatures https://tools.ietf.org/html/draft-ietf-httpbis-message-signatures-00). |
173
dzdh OP @chinvo #170
是的。我纠正一下我的说法:服务层只需要拿到解析后的验证参数,如 nginx 的话: http_s|c_xx 等 Header 头。至于客户端证书的验证交由 Nginx 来处理至于路径我毫不关心,我只要知道我必须得要。 补充:像这种场景个人人为通常都是独立 API 域名吧?或者是 OpenAPI 网关,由网关(即是 WS 又是鉴权应用)来决定这个路径给不给验证信息。内网,到此步骤已经『完成并结束了对『安全』』的『需求』,再往后已经是各种服务协作,已经『没必要』再顾及 HTTPS 自身安全了。 |
174
dzdh OP @3dwelcome #171
> linux 系统 root 提权很难很难; windows 系统上,你 chrome 保存的... 像你说的,木马对吧?你总要把 Key 读出来吧?我读内存行吗?进程 HOOK 可以吗? |
175
nikan999 2021-04-14 00:37:10 +08:00
@palfortime
我举个防篡改的例子 如果用户发了消息 "转账给张三",当局域网有设备获取到这条明文消息,进行修改变成“转账给李四”,如果没有 hash 的话, 用户并不知道自己的消息被篡改,服务也不知道这条消息是被篡改的。如果有了 hash,那么进行计算可以知道这条消息被篡改了。 |
177
3dwelcome 2021-04-14 00:39:52 +08:00
@chinvo "我选择增加额外的验证逻辑, 比如 Signing HTTP Messages"
我去看了一眼,RFC 里完全解释了 TLS 不可全信。(for example, if the application is hosted behind a TLS-terminating gateway or if the client is behind a TLS Inspection appliance) 楼主就是死不承认有 TLS 解密网关的存在。都 2020 年了,http 签名还是浮上了水面,强烈支持啊! |
178
0o0O0o0O0o 2021-04-14 00:41:30 +08:00 via iPhone 1
提供一个视角:在我这种**过不少客户端的看来,原则就是客户端不可信任,对于客户端来说,ssl pinning 和 sign 都是客户端范畴,都是用来提高**成本,而前者通常很简单,后者可以配合保护和奇技淫巧变得相当相当难。
所以如果可以信任运行环境、没有什么反爬对抗的压力,那楼主提到的这类 api 的签名“无意义”我觉得没问题,防重放之类的逻辑当然是要放到服务端。 |
179
dzdh OP |
180
chinvo 2021-04-14 00:42:06 +08:00 1
@dzdh 既然是网关的话, 完全可以解密后重新加密, 和 https cdn 是一样的逻辑.
虽然可以通过要求 Digest 头来验证 body 的 hash, 但是 Header 毕竟也可以一起改. 当然这属于极端情况了. 服务器的网关如果都不能被信任, 那么这个环境就太恶劣了. |
181
dzdh OP |
184
3dwelcome 2021-04-14 00:50:08 +08:00 1
@dzdh "HTTP 的签名机制完全没有存在的必要"
有必要,老外说的很清楚,签名机制纯粹是为了 end-to-end integrity,为了 meaningful for the application 。不管中间乱七八糟的 TLS 网关,一切的签名,只为和我对接的终端所负责。 |
185
chinvo 2021-04-14 00:51:13 +08:00 1
@dzdh 我说的是客户端, 或者说, 发起请求的一端. 这一端不存在"HTTP Gateway 负责认证"的情况, 如果你提供的 API 是 HTTPS 的, 那么客户端的代码请求必然是 HTTPS 的. 这种情况下, 客户端的"网关设备"(路由 /防火墙 /审计设备 /代理服务器等)存在作恶的可能性("那么这个环境就太恶劣了").
|
186
dzdh OP |
187
no1xsyzy 2021-04-14 00:56:40 +08:00
@dzdh 安全又不是忠诚,“XX 不绝对就是绝对不 XX”并不适用
(真要说的话,衣服有过敏的风险,食物有中毒的风险,住宅有失火的风险,出门有撞车的风险……) 任何一分一毫增加安全性的措施均是有效的。在成本限制下通过有效的安全措施把风险降低到可接受的程度 —— 这是另一个专业范畴,准确地说也是一种“技术”,只不过不是“计算机技术”。我司安全方面出重大事故直接就是直辖市级政治命题;所以我被各种教育培训、各种要求填表搞得略通一二…… |
188
chinvo 2021-04-14 00:58:46 +08:00 1
@dzdh #171 这个并不是单纯"客户端"的问题, 是客户端到服务端的链路问题. 这条链路上存在的风险, 按理说 API 提供方是要考虑的. 所以我前面说, 涉及资金的对外接口, 我会选择 RFC Draft 的 Http Message Signatures. 至于客户端这边被黑客入侵或者其他什么人登录导致密钥泄露, 才是和 API 提供方无关的东西.
登录凭据是"客户"有义务安全保管的, 但是服务本身的安全(包括从客户端到服务端的链路上的安全)是服务提供者的义务. (法律上一般也是这样认为的) |
189
3dwelcome 2021-04-14 00:58:56 +08:00
@chinvo 上海电视台有个节目叫案件聚焦,有一期就是黑客修改银行的 HTTPS 抵押贷款数据,把原本抵押资金从 50W 改成了 50 元。然后赚了几千万,无数辆跑车,因为太贪心被银行报警抓了。
我不知道他是如何做到篡改加密数据包,怪只能怪银行开发码农和楼主一样,对 SSL Pinning 和 HTTPS 来的数据,太过自信了。 |
190
nikan999 2021-04-14 01:00:18 +08:00
@chinvo 最近在学密码学 消息认证的内容 ,一开始也不理解数字签名的意义,今天看了各位大大的发言,受益很多。理论上安全并不是保证 99%的安全就够了,而是越高越好。感谢各位大大!
|
191
chinvo 2021-04-14 01:02:01 +08:00 2
当然, 我避免使用反人类和小众的方式(包括对自己和对客户的开发者), 会避免使用自造轮子的方式去实作这些"精妙"的安全逻辑. 包括 mutual tls (前述, 这个对我服务器端 /API 网关端的实现存在不便)和类似支付宝的签名逻辑(这个对客户的开发者造成不便).
|
193
0o0O0o0O0o 2021-04-14 01:22:11 +08:00 via iPhone
@palfortime #168 我觉得你说的和楼主提的场景不太一样,不能一概而论,参见 #178,你是有不可信任的客户端的
|
194
dzdh OP 抱歉,单次回复次数太多,被限制 1800 秒回复
@3dwelcome #184 #189 所谓的『签名』是 HTTPS 自有特性,已经完全可以满足安全需要。因此,在 HTTPS 本身的数据签名之外的人工二次『签名』是完全没必要的。所谓『网关问题』请参看 173 楼。 新闻就不评论了,不能绝对排除银行犯二 F12 就给改了的可能 @chinvo #188 持反对意见 > 但是服务本身的安全(包括从客户端到服务端的链路上的安全)是服务提供者的义务. (法律上一般也是这样认为的) 假设从客户端到服务端经过了 C -> C1 中继城市核心交换机 -> S1 中继城市核心交换机 -> S 。在 C/C1/S1 任何一端由于网络提供商(和服务提供商没有任何关系)维护问题导致网络终端继而导致某个 C 或者某些某部分 C 无法访问我的服务,需要服务提供商负责吗?是应该责怪我没有备用线路?那极端情况所有备用线路都坏了(网络提供商问题)导致客户产生了巨额损失是需要我来赔偿吗? |
197
kejialiu 2021-04-14 09:44:53 +08:00
@dzdh Paypal 、Stripe 没有客户端证书。因何安全?
PayPal 等不使用客户端证书(或者准确的说,mutual TLS),也不使用签名(这里明确以下,我说的签名都是指请求端使用非对称密钥里面的私钥做的签名,服务端可以使用对应的公钥验证,只是把请求参数 hash 一下那个不叫数字签名),直接在 https 请求中传递原始密钥,可能有几种原因: 1. 设计 API 的人心比较大 2. 当初设计的时候没想清楚,已经有不少客户在用了,也很难改了 3. 为了降低使用门槛,做出了牺牲 Google 的 Cloud API 提供了多种验证机制,其中的 API key 就是直接通过请求参数传递,但是现在内部已经在绝大多数场景禁止使用了,替代方案是使用服务帐号的私钥进行类似 mutual TLS 的认证。对于外部用户,仍然允许使用 API key (也只是建议在访问公共数据的时候使用),主要也是出于上述 2 和 3 的考虑。 还是那句话,安全是相对的, 绝对安全 > https with mutual TLS >= https without mutual TLS + 请求端私钥签名 > https + 明文密钥 > 绝对不安全 看你自己的应用场景选择合适的。 |
198
3dwelcome 2021-04-14 09:54:07 +08:00
@dzdh "所谓的『签名』是 HTTPS 自有特性,已经完全可以满足安全需要。"
所谓 HTTPS 的签名,只是针对证书验证环节,又不是对具体发送内容进行签名验证。 就像你说的 F12 被修改问题一样,HTTPS 内容还是要解密落地后才能让代码处理的,为什么要让中间商赚差价?如果发送内容都 end-2-end,终端对终端签名。我就不信普通黑客,能轻松修改银行的数据包。 |
199
kejialiu 2021-04-14 10:00:09 +08:00
@ZeroClover 各种什么私钥泄露问题只要一个 HSM 就可以解决问题,私钥只进不出,所有调用只在 HSM 能完成签名,然后将签名结果给服务器。除非你买的是带后门的 HSM,或者刚好撞上有设计缺陷的 HSM 。
是的,HSM 确实是为了防止私钥泄露而设计的,这是很重要的安全设备。但也不是厂商声称使用 HSM 就万事大吉了。就楼主说的 https 请求里直接传密钥这种情况: 正常 CDN 厂商: https 密文 -> HSM -> http 明文 -> 应用各种 CDN 规则 -> HSM -> https 密文 -> 真正的 https 服务器 二逼 CDN 厂商: https 密文 -> HSM -> http 明文 -> 应用各种 CDN 规则,同时记一条日志 -> HSM -> https 密文 -> 真正的 https 服务器 恶意 CDN 厂商: https 密文 -> HSM -> http 明文 -> 应用各种 CDN 规则,全流量备份下来以后留着用 -> HSM -> https 密文 -> 真正的 https 服务器 先不说厂商是否真有恶意,就是记个日志都有可能不小心把请求里的密钥存下来,然后这个日志谁能看到咱就更不知道了。 |
200
wy315700 2021-04-14 10:07:35 +08:00
关于 162 楼的忍不住说一句
失效可靠 一直是一个安全系统设计的重要因素。比如指纹和虹膜认证,在安全界一直是被人看不上的,就是因为一旦信息泄漏,你无法更换自己的指纹,我们当时实验室打卡的机器就是用一个指纹膜就可以随便替人打卡了。一直到“快速认证”协议出来以后才变得可靠,我拿到你的指纹以后还必须用你的手机才能使用。用了一个可更换的私人设备+一个不可更换的个人信息,才保证了安全性和可靠性。 打个比方,PINNED Pub Key 了,万一你的私钥泄漏。。 为保障安全,还得设计一套证书吊销机制。。然后证书吊销机制的 URL 的证书怎么保证,如果也要用 PINNED Pub Key,,,层层套娃永无止境了。 另外提一下 SSL 实施过程中的一些小问题,但是都是可能造成不安全因素的问题。 以下两种方案在 SSL 实施过程中都是不安全的,当然可能造成的不安全风险很小: 1 众多机器使用同一个私钥和证书。 2 一台机器生成两个私钥。 |