shadowsocks / shadowsocks-org

www.shadowsocks.org
MIT License
877 stars 539 forks source link

设计一个随机密钥滚动下发机制,实现前向安全、防长期重放、防潜在攻击等 #177

Open RPRX opened 3 years ago

RPRX commented 3 years ago

Shadowsocks 现有的设计存在一个非常明显的问题:无前向安全。而对于 TLS,非 FS 套件早已被视为不够安全了。 “前向安全”指的是攻击者拿到现有的密钥时无法解密过往的通讯内容,实现前向安全需要依赖动态密钥及可信源。

由于现在的国产安卓系统都有云备份功能,手机上的 SS 密码没有安全保证,它可以被用来解密一切通讯内容。

此外,由于 SS 的加密不依赖于时间戳,防重放只能靠缓存,但缓存并不是无限的,这就导致实质上的 无法防重放。 虽然 VMess 也没有前向安全,但它的头部加密依赖于时间戳,至少做到了防重放(不过,时间戳并不是唯一解)

顺便提一下:Shadowsocks 没有 UoT 结构,各个实现都是 TCP、UDP 同端口,这并不常见,是非常明显的特征。


为了解决现在的一些问题,SS 需要设计一个随机密钥滚动下发机制,以下是我的构想:

  1. 首先,这只是内层明文结构的改变,复用现有的加密方式,比如 AEAD 系列
  2. 初次配置时,初始密钥 数等于客户端数量,需通过可信通道传递(显然这不是问题,SSH 或 HTTPS 均可)
  3. 对某个客户端而言,初次连接服务端时用的是初始密钥,并发连接也是如此
  4. 对于服务端,当某个密钥被使用了一定次数(按连接计),后续的连接返回数据时需要带同一个新的 随机密钥 一起返回
  5. 客户端一旦收到了新的密钥,就要存起来,新的连接必须使用它,同时逐步忘记旧的密钥(直到旧的连接全关闭)
  6. 服务端对于同一个客户端,只存最近的几个密钥,而且每个密钥都有 使用次数限制
  7. 注意客户端只持久化收到的最新的密钥。若新增了一个客户端,需要服务端下发新的初始密钥(可以 API 接口)

通过上述机制可以实现:

  1. 前向安全。即使攻击者拿到了现有的密钥,也无法解密绝大多数过往的通信内容。
  2. 后向安全。即使攻击者拿到了现有的密钥,他还必须能拿到后续的所有连接,不然跟不上密钥的更新节奏。
  3. 防长期重放。很简单,因为服务端只存最近的几个密钥。
  4. 防潜在攻击。很简单,因为限制了每个密钥的使用次数。至于是什么攻击,过几天才可以说。
  5. 限制设备数。

可以看到,相对于现有的机制,上述机制并没有明显增加配置复杂度,却大大增强了各方面的安全性。欢迎补充建议。