专栏名称: 程序人生
十年漫漫程序人生,打过各种杂,也做过让我骄傲的软件;管理过数十人的团队,还带领一班兄弟姐妹创过业,目前在硅谷一家创业公司担任 VP。关注程序人生,了解程序猿,学做程序猿,做好程序猿,让我们的程序人生精彩满满。
目录
相关文章推荐
51好读  ›  专栏  ›  程序人生

透过 Rust 探索系统的本原:安全篇

程序人生  · 公众号  · 程序员  · 2021-03-22 08:05

正文

请到「今天看啥」查看全文


  1. 生成一个临时公钥对

  1. 用私钥和用户的公钥算 DH key

  1. 用 DH key 作为 AES[8] 或者 ChachaPoly[9] 的密钥,加密文件

  1. 在文件头添加临时生成的公钥

这样,在解密端,用户可以用自己的私钥和文件中携带的公钥算出 DH key,然后解密之。

如果大家对这个思路感兴趣,可以参考我用 Noise protocol 做的类似的解决方案:tyrchen/conceal[10]。

除了 x25519-dalek 外,ristretto255-dh[11] 也值得一试,它是 zcash 实现的 Ristretto255[12] DH 算法。

TLS:不仅仅是 HTTP 的安全防线

作为 HTTPS 的安全协议的唯一选择,相信大家对 TLS(以及它的前身 SSL)有一定的了解 — 起码知道:

  • 服务端需要安装经过合法 CA 签署的证书(certificate)。如果你配过 nginx,你还会知道,证书和证书的私钥一般都是 PEM [13] 格式存储在文件系统的。一般来说,除了配置自己的证书外,还需要配置整个服务器证书链以便客户端验证。

  • 客户端在连接服务器时,会获取服务器证书,然后通过操作系统受信的根证书来验证服务器的证书以及签署该证书的 CA,以及签署该 CA 的上一级 CA 等形成的整个证书链可以由某个根证书验证。

  • 客户端验证了服务器的证书后,会跟服务器交互建立一个安全信道,保证之后的传输的安全。这个过程是 TLS 握手。

  • 之后整个 HTTP 协议交互的过程,都被这个安全信道保护起来(说人话就是加密了),第三方无法嗅探到内部的交互,也无法破坏其完整性。

如果你经常调试(或者逆向工程)HTTPS,你大概还知道:

  • 通过 Charles Proxy 这样的工具,可以做 Man-In-The-Middle[14],来截获加密的数据。使用 Charles Proxy 时,需要在操作系统级「信任」其根证书,这是证书验证的流程所决定的。一旦某个根证书被系统信任,那么它可以签署任何域名的证书,这样第三方就可以伪装成目标服务器,terminate 客户端到服务器的任何 TLS 流量,然后再伪装成客户端,向实际服务器发送数据。所以,不要轻易信任来路不明的根证书。

  • 如果要避免 Charles Proxy 等工具做 Man-In-The-Middle,你可以使用 certificate pinning。

你大概率不知道:

  • TLS 支持 client certificate - 也就是说不光客户端可以验证服务器是否是我要连的服务器;服务器也可以验证客户端是否是我(的 CA)签署的客户端。

  • 客户端验证服务器时,除了可以通过系统的根证书验证,也可以预置一个 CA 证书来验证服务器的证书是否由该 CA 签署。

证书是个什么鬼?

我们这里所说的证书,是 PKI 体系下的 X.509 证书[16]。X.509 证书用于证明一个公钥的身份。我说我是 domain.com 的合法服务器,何以见得?我生成一对私钥和公钥,通过其签署一个 CSR(Certificate Signing Request [17]),里面通过 CN(Common Name)声索我对 *.domain.com 的占有。一般一个 CSR 包含这些信息:

随后我把 CSR 提交给一个由某个根证书签署的 CA,由其签名并发回给我。这样,任何应用通过 HTTPS 连接 domain.com 时就可以正常通讯。

在 letsencrypt[18] 成为主流之前,证书是个几乎相当于特许经营的好生意。像 godaddy 这样的家伙,一个证书可以卖上百美金一年,简直如同抢钱。证书作为一门生意, 极大地 破坏了互联网的安全性,很多小的玩家不想支付每年的证书费用,干脆就避免使用 HTTPS。letsencrypt 的出现,几乎摧毁了各大吃相难看的 CA 的生意。Letsencrypt 自动化了证书的申请流程,只要你能把某个域名指向你的服务器,让 letsencrypt 验证到你请求的域名就是你拥有的域名,可以立即签署一个有效期是 3 个月的免费证书。至于证书的有效期为啥不能更长,这个,根本不是技术原因,我猜是来自做垂死挣扎的既得利益者们的压力。

能不能自己做 CA?

CA 机构是 internet 的不可或缺,却相对脆弱的一环。Letsencrypt 只是解决了证书收费的问题,不过没有解决 CA 机构本身的脆弱性 — 任何一个中心化的,可以签署证书,被数亿设备信任的机构都是有安全风险的,因为黑客随时盯着这些机构的漏洞。一旦一个CA 被攻陷,黑客们可以伪造出成千上万的域名的服务器证书。

有没有可能一个应用的客户端和服务器使用自己的 CA,绕过任何 CA 机构?

当然可以。你可以生成自己的 CA cert(自签名),然后用 CA key 签名 Server cert。你的客户端在启动 TLS 连接时,信任你自己的 CA cert 即可。你甚至还可以通过你的 CA 给每个客户端签名,让服务器也同时验证客户端是你信任的客户端。如下图所示:

一个新的客户端在注册新用户/登录时,服务器会从 CA 获取证书,连同用户登录获得的 token 一同返回给客户端。之后,客户端访问任何服务端的 API(除 auth 之外),都需要提供 client cert 供服务器验证,这样,额外增加安全性,并且,可以杜绝 Charles Proxy 这样的中间人。

当然这样的手段只适合客户端代码由你自己控制(比如 iOS/android/OSX/Linux/Windows app)。你无法让你的服务器证书通过浏览器的安全验证(因为证书不在系统根证书的信任列表中),因而,任何使用浏览器访问你的服务器的用户将无法使用你的服务。

如果你对这样的方案感兴趣,可以看看我的 crate: tyrchen/cellar[19]。它借鉴比特币分层钱包[20]的设计,可以从一个 passphrase 衍生出确定的分层密码/密钥/证书。生成的证书可以被应用在 TLS 应用中,比如:tyrchen/mobc-tonic[21](我做的一个 grpc client connection pool)。

下面是我通过 celllar 生成的 CA 证书(注意 CA: TRUE ):







请到「今天看啥」查看全文


推荐文章
全球局势战略纵横  ·  跟美国过招,中国或可汲取俄罗斯过往经验!
8 年前
正午故事  ·  穿铅衣的心内科医生 | 正午
8 年前
医学界影像诊断与介入频道  ·  致癌食物排行榜,看完你还敢吃吗?
8 年前