透過 Rust 探索系統的本原:安全篇

安全是我的老本行,隔一段時間不拉出來談一談就不舒服。我個人覺得:做應用不談安全都是在耍流氓。

按照 CISSP[1] 的定義,安全有八大領域:

本文只關注 Communication and Network Security 中 TCP/IP 範疇下的 Session Layer Security,也就是 TCP/UDP 層之上的安全方案:

目前業界首選的方案是 TLS[2]。在所有流行的應用層解決方案中,都離不開 TLS。

在 p2p 領域,TLS 並不那麼受待見,大家似乎更喜歡和 TLS 提供了同等安全水平,但更加去中心化(不需要 CA[3])的 noise protocol[4]。我去年寫過一篇關於 Noise protocol 的文章:Noise 框架:構建安全協議的藍圖

本文圍繞 TLS 和 Noise protocol,以及它們在 Rust 下的使用場景,談談我們如何做安全的系統和應用。

安全的本質

很多人談到安全,首先想到的是加密解密。加解密只解決了安全範疇的機密性(confidentialilty)的問題,但它沒有觸及另外兩個重要的範疇:完整性(integrity)和可用性(availability)。我們簡單講一下這三個概念:

爲了保證可用性,我們會提供服務的高可用性(防止 DoS 以及服務故障),做數據冗餘和災備處理(防止數據丟失),監控,故障轉移等等。

爲了保證完整性,我們會使用哈希算法,數字簽名來保證數據的一致性。

爲了保證機密性,我們會使用對稱和非對稱加密來保證在傳輸途中,以及在數據載體上的機密性。機密性往往需要完整性作爲先決條件;而完整性不一定需要機密性作爲先決條件。

下圖闡述了安全領域涉及機密性和完整性的主要算法:

注意,這裏的一些算法是泛稱,而非具體某種算法。比如:sha3 算法族下面除了 keccak 以外,還有 blake2,blake3 等其他算法;而 ECC 算法下面,屬於簽名算法的有 Ed25519,Ed448 等,屬於非對稱加密的有 x25519,x448 等。

如果你看了我前幾周的文章,大概對我介紹的《胖客戶端,廋服務器》有些印象。文章中我提到了服務端把用戶端的事件寫入到事件日誌中,客戶端可以 clone / pull 這些事件日誌,在本地生成相應的狀態。那麼問題來了,客戶端怎麼知道 clone 下來的事件日誌是未經第三方篡改的事件日誌呢?很簡單,我們只需對日誌文件做個 hash,然後用服務器的私鑰對這個 hash 做一個簽名,把簽名附帶在文件頭上。這樣客戶端收到文件後,用服務器的公鑰驗證這個簽名即可。這樣,只要服務器的私鑰不泄露,這個簽名就可以驗證文件的完整性。在比特幣的世界裏,每個區塊的完整性都由打包該區塊的礦工的簽名來保證,而整個鏈的完整性則由哈希鏈和中本聰共識(最長鏈)保證。

進一步的,如果我們用戶的私有 repo 下的所有事件日誌都只有用戶自己才能訪問,其他人(包括服務端應用)都無法訪問,那麼我們可以用用戶的公鑰來加密 repo 的所有事件日誌。

DH 算法:互聯網安全的基石

當我們需要保證存儲在媒介上的信息的安全性時,一切都簡單而直觀;但當我們需要保證在網絡傳輸中的實時信息的安全性時,我們就面臨着巨大的挑戰。

這其中第一個挑戰就是:每個連接使用什麼密鑰來加密數據?

我們知道,在網絡傳輸中,非對稱加密的效率不高,不適合大量數據的加密,而對稱加密則需要雙方共享密鑰,才能正常通訊。因此,我們需要一種手段,在不安全的網絡信道中,只傳輸部分信息,通過這部分信息 + 本地的私有信息,協商出來雙方一致的共享密鑰。第三方即便獲得明文傳輸的信息,也無法推導出密鑰。如果這樣的手段行得通,那麼,我們就可以在網絡通訊的握手過程,生成每個 session 獨立的共享密鑰(session key),後續的通訊都通過這個(這對)密鑰來加密完成。這個協商的過程就是 DH 算法(Diffie-Hellman Key Exchange Algorithm)[5](對算法細節感興趣的可以去看 wikipedia):

DH 算法是 TLS 以及 Noise protocol 的基石。如果沒有它,我們就不會有目前這樣一個繁榮且安全的互聯網世界。

在 Rust 下,如果你需要直接使用 DH 算法,可以使用 dalek 出品的 x25519-dalek[6]。它是使用 curve25519 [7] 的 ECDH(Elliptic Curve Diffie-Hellman) 的實現。代碼如下:

use rand_core::OsRng;
use x25519_dalek::{EphemeralSecret, PublicKey};
let alice_secret = EphemeralSecret::new(OsRng);
let alice_public = PublicKey::from(&alice_secret);
let bob_secret = EphemeralSecret::new(OsRng);
let bob_public = PublicKey::from(&bob_secret);
let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());

你也許會問:我又不去實現 TLS 或者類似的加密協議,而我自己的網絡傳輸都靠 TLS 保護着呢,DH 對我來說有什麼用呢?

我能想到的一個場景是文件加密。在本文開頭,我說:

進一步的,如果我們用戶的私有 repo 下的所有事件日誌都只有用戶自己才能訪問,其他人(包括服務端應用)都無法訪問,那麼我們可以用用戶的公鑰來加密 repo 的所有事件日誌。

這個方案的缺點是效率太低 — 如果需要加密的文件有幾個 G,非對稱加密顯然不好。但我們又沒法用對稱加密:畢竟我們不能跟每個人都預先共享一組密鑰(共享密鑰本身又存在安全風險)。這時,我們可以用 DH 算法生成一個只對這個文件有效的密鑰,加密文件,然後在文件頭提供必要的信息即可:

  1. 生成一個臨時公鑰對

  2. 用私鑰和用戶的公鑰算 DH key

  3. 用 DH key 作爲 AES[8] 或者 ChachaPoly[9] 的密鑰,加密文件

  4. 在文件頭添加臨時生成的公鑰

這樣,在解密端,用戶可以用自己的私鑰和文件中攜帶的公鑰算出 DH key,然後解密之。

如果大家對這個思路感興趣,可以參考我用 Noise protocol 做的類似的解決方案:tyrchen/conceal[10]。

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

TLS:不僅僅是 HTTP 的安全防線

作爲 HTTPS 的安全協議的唯一選擇,相信大家對 TLS(以及它的前身 SSL)有一定的瞭解 — 起碼知道:

如果你經常調試(或者逆向工程)HTTPS,你大概還知道:

你大概率不知道:

證書是個什麼鬼?

我們這裏所說的證書,是 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):

以及該 CA 簽署的服務器證書(注意 CA: FALSETLS Web Server Authentication):

以及該 CA 簽署的客戶端證書(注意 CA: FALSE 以及 TLS Web Client Authentication):

將 TLS 應用在 HTTP 之外

TLS 可以保護我們的 HTTP 應用,其中包括 REST/GraphQL/Websocket API,以及 gRPC API。雖然目前 HTTP 是幾乎絕大多數互聯網應用使用的協議,但還有大量的其它基於 TCP 層的協議。如果你要保證這些協議的安全性,使用 TLS 是一個簡單直接的選擇。

然而,理解和使用好 OpenSSL 庫不是一件容易的事情。十多年前,我曾經用 C 語言和老舊的 OpenSSL (0.9.x)打過交道,那體驗相當不好。Python / Erlang 有不錯的 OpenSSL 的封裝,在應用中使用 TLS 比較舒服自然。如果你熟悉的語言沒有很好的庫去包裝 OpenSSL,那麼,在應用中使用 TLS 就不那麼容易。

在 Rust 裏,除了 OpenSSL 的封裝,我們還有 Rustls[22]。它是一個經過了 security auditing[23] 的 TLS 安全褲,性能比 OpenSSL 更好,且理論上更加安全(沒有遺留的歷史問題,沒有 TLS1.1 及以下的不安全代碼,沒有遺留的不安全的加密算法,比如 RC4,3DES)。

Rustls 雖然比 OpenSSL 容易使用,但成功建立起 TLS 連接,還需要更多對 TLS 細節的理解。爲此,我做了一個 crate:tokio-tls-helper[24],可以讓你通過簡單的配置,創建 TLS connector (client) 和 acceptor (server)。

比如客戶端使用自定義的 CA cert 以及通過自定義 CA 簽署的 client cert:

domain = "localhost"
[cert]
pem = """-----BEGIN CERTIFICATE-----
MIIBeTCCASugAwIBAgIBKjAFBgMrZXAwNzELMAkGA1UEBgwCVVMxFDASBgNVBAoM
C0RvbWFpbiBJbmMuMRIwEAYDVQQDDAlEb21haW4gQ0EwHhcNMjEwMzE0MTg0NTU2
WhcNMzEwMzEyMTg0NTU2WjA3MQswCQYDVQQGDAJVUzEUMBIGA1UECgwLRG9tYWlu
IEluYy4xEjAQBgNVBAMMCURvbWFpbiBDQTAqMAUGAytlcAMhAAzhorM9IPsXjBTx
ZxykGl5xZrsj3X2XqKjaAVutnf7po1wwWjAUBgNVHREEDTALgglsb2NhbGhvc3Qw
HQYDVR0OBBYEFD+NqChBZDOs5FMgefHJSIWiRTHXMBIGA1UdEwEB/wQIMAYBAf8C
ARAwDwYDVR0PAQH/BAUDAwcGADAFBgMrZXADQQA9sligQcYGaBqTxR1+JadSelMK
Wp35+yhVVuu4PTL18kWdU819w3cVlRe/GHt+jjlbk1i22TvfO5AaNmdxySkO
-----END CERTIFICATE-----"""
[identity]
key = """-----BEGIN PRIVATE KEY-----
MFMCAQEwBQYDK2VwBCIEIArjJtHm3xb4aX3fsGHpuB8dD3yzcLxWcPCqy7AGtTG5
oSMDIQD/38MZBnYuyitIGU3ltOGwwDwtB6KYag4rL1zsSGTzYg==
-----END PRIVATE KEY-----"""
[identity.cert]
pem = """-----BEGIN CERTIFICATE-----
MIIBZDCCARagAwIBAgIBKjAFBgMrZXAwNzELMAkGA1UEBgwCVVMxFDASBgNVBAoM
C0RvbWFpbiBJbmMuMRIwEAYDVQQDDAlEb21haW4gQ0EwHhcNMjEwMzE0MTg0NTU2
WhcNMjEwOTEwMTg0NTU2WjAyMQswCQYDVQQGDAJVUzEQMA4GA1UECgwHYW5kcm9p
ZDERMA8GA1UEAwwIYWJjZDEyMzQwKjAFBgMrZXADIQD/38MZBnYuyitIGU3ltOGw
wDwtB6KYag4rL1zsSGTzYqNMMEowFAYDVR0RBA0wC4IJbG9jYWxob3N0MBMGA1Ud
JQQMMAoGCCsGAQUFBwMCMAwGA1UdEwQFMAMBAQAwDwYDVR0PAQH/BAUDAwfgADAF
BgMrZXADQQCKhph1Z3g6E+EULUi5yIROSXmMxWjzi+L1OmqNh9ANJlrQwlcfwq0G
8JbfGVwq1sotEI83mv42mWkSSX98uysO
-----END CERTIFICATE-----"""

有了這個配置,客戶端可以生成 ClientTlsConfig,然後生成 connector,在建立好 TCP stream 後,直接調用 connector.connect(stream) 就可以將 TCP 連接升級爲 TLS 連接,之後可以在其之上進行應用層的協議:

let msg = b"Hello world\n";
let mut buf = [0; 12];
let config: ClientTlsConfig = toml::from_str(config_file).unwrap();
let connector = config.tls_connector(Uri::from_static("localhost")).unwrap();
let stream = TcpStream::connect(addr).await.unwrap();
let mut stream = connector.connect(stream).await.unwrap();
info!("client: TLS conn established");
stream.write_all(msg).await.unwrap();
info!("client: send data");
let (mut reader, _writer) = split(stream);
reader.read_exact(buf).await.unwrap();
info!("client: read echoed data");

服務端的使用也很簡單:配置相同的 CA cert,以及服務器的 server/key:

[identity]
key = """-----BEGIN PRIVATE KEY-----
MFMCAQEwBQYDK2VwBCIEII0kozd0PJsbNfNUS/oqI/Q/enDiLwmdw+JUnTLpR9xs
oSMDIQAtkhJiFdF9SYBIMcLikWPRIgca/Rz9ngIgd6HuG6HI3g==
-----END PRIVATE KEY-----"""
[identity.cert]
pem = """-----BEGIN CERTIFICATE-----
MIIBazCCAR2gAwIBAgIBKjAFBgMrZXAwNzELMAkGA1UEBgwCVVMxFDASBgNVBAoM
C0RvbWFpbiBJbmMuMRIwEAYDVQQDDAlEb21haW4gQ0EwHhcNMjEwMzE0MTg0NTU2
WhcNMjIwMzE0MTg0NTU2WjA5MQswCQYDVQQGDAJVUzEUMBIGA1UECgwLRG9tYWlu
IEluYy4xFDASBgNVBAMMC0dSUEMgU2VydmVyMCowBQYDK2VwAyEALZISYhXRfUmA
SDHC4pFj0SIHGv0c/Z4CIHeh7huhyN6jTDBKMBQGA1UdEQQNMAuCCWxvY2FsaG9z
dDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMEBTADAQEAMA8GA1UdDwEB/wQF
AwMH4AAwBQYDK2VwA0EAy7EOIZp73XtcqaSopqDGWU7Umi4DVvIgjmY6qbJZP0sj
ExGdaVq/7MOlZl1I+vY7G0NSZWZIUilX0CoOkrn0DA==
-----END CERTIFICATE-----"""
[client_ca_root]
pem = """-----BEGIN CERTIFICATE-----
MIIBeTCCASugAwIBAgIBKjAFBgMrZXAwNzELMAkGA1UEBgwCVVMxFDASBgNVBAoM
C0RvbWFpbiBJbmMuMRIwEAYDVQQDDAlEb21haW4gQ0EwHhcNMjEwMzE0MTg0NTU2
WhcNMzEwMzEyMTg0NTU2WjA3MQswCQYDVQQGDAJVUzEUMBIGA1UECgwLRG9tYWlu
IEluYy4xEjAQBgNVBAMMCURvbWFpbiBDQTAqMAUGAytlcAMhAAzhorM9IPsXjBTx
ZxykGl5xZrsj3X2XqKjaAVutnf7po1wwWjAUBgNVHREEDTALgglsb2NhbGhvc3Qw
HQYDVR0OBBYEFD+NqChBZDOs5FMgefHJSIWiRTHXMBIGA1UdEwEB/wQIMAYBAf8C
ARAwDwYDVR0PAQH/BAUDAwcGADAFBgMrZXADQQA9sligQcYGaBqTxR1+JadSelMK
Wp35+yhVVuu4PTL18kWdU819w3cVlRe/GHt+jjlbk1i22TvfO5AaNmdxySkO
-----END CERTIFICATE-----"""

服務端同樣可以通過配置生成 ServerTlsConfig,然後生成 acceptor,之後正常使用 TCP listener accept 一個 TCP stream 後,就可以通過 acceptor.accept(stream) 把 TCP 連接升級爲 TLS。這個過程配合客戶端的 connector.connect(stream),共同完成前面所說的 DH 過程,協商出來 session key,然後開始加密 / 解密應用層的數據:

let config: ServerTlsConfig = toml::from_str(config_file).unwrap();
let acceptor = config.tls_acceptor().unwrap();
let listener = TcpListener::bind(addr).await.unwrap();
tokio::spawn(async move {
    loop {
        let (stream, peer_addr) = listener.accept().await.unwrap();
        let stream = acceptor.accept(stream).await.unwrap();
        info!("server: Accepted client conn with TLS");
        let fut = async move {
            let (mut reader, mut writer) = split(stream);
            let n = copy(&mut reader, &mut writer).await?;
            writer.flush().await?;
            debug!("Echo: {} - {}", peer_addr, n);
        }
        tokio::spawn(async move {
            if let Err(err) = fut.await {
                error!("{:?}", err);
            }
        });
    }
});

Noise Protocol:狂野西部的守護者

如果你沒看過我之前的文章,大概率 Noise Protocol 對你來說是個陌生的名字。如果你搭過各種各樣的梯子,你也許使用過 Wireguard[25],那麼恭喜你,你已經在不知不覺中使用 Noise Protocol 了 — 因爲 Wireguard 在安全層使用了 Noise Protocol。我曾經寫過一篇文章:Wireguard:簡約之美,介紹了 Wireguard 這個非常牛逼的 VPN 工具。

因爲之前的關於 Wireguard 和 Noise protocol 的文章對 Noise Protocol 本身已經有足夠豐富的介紹,這裏我就不再贅述 Noise Protocol 的細節。

如果說 TLS 是出身高貴的正規軍,那麼 Noise Protocol 就是出身草根的土八路。但二者其實互相借鑑,互相學習。TLS 1.3 和 Noise Protocol 的主要區別有兩個:

  1. 在身份驗證方面二者走上了不同的道路(TLS 1.3 使用證書,而 Noise Protocol 完全不使用)

  2. 通訊過程中使用的算法一個走協商(TLS)一個走預配置(Noise)

走協商還是走配置這跟協議的使用場景有關。TLS 關注的是大量不同版本的標準客戶端(比如 Firefox)和服務器之間的交互,兩端支持的算法族可能有不小的出入,協商出雙方都能接受的算法是最優的選擇,這樣可以支持儘可能廣的應用場景;而 Noise Protocol 關注的是定製的客戶端和服務器之間的交互,因而兩端可以通過預配置來確定使用的算法。比如 WireGuard 使用 Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s,那麼客戶端和服務端都需要:

因爲避免使用證書這樣天然具有中心化的東西,Noise Protocol 在 p2p 領域走出了新的天地。從最簡單的 NN(雙方都沒有固定公鑰)KK(雙方都知道對方的固定公鑰),到最複雜的 XX(雙方都有固定公鑰,通過網絡加密傳輸給對方),Noise Protocol 定義了 12 種協商模式,再輔以不同的哈希和加密算法,可以組合出上百種安全方案,總有一種適合你:

在 Rust 下,snow[26] 是 Noise Protocol 的非常成熟的實現,而 libp2p 則使用了 snow 來實現 libp2p 協議的安全層。

下面是使用 snow 在 TCP 協議之上建立加密信道的實例。我們可以看到,僅需額外的幾行代碼就可以將你的網絡應用打造得非常安全:

服務器:

let params: NoiseParams = "Noise_XX_25519_ChaChaPoly_BLAKE2s".parse().unwrap();
let builder: Builder<'_> = Builder::new(params.clone());
let static_key = builder.generate_keypair().unwrap().private;
let mut noise = builder
    .local_private_key(&static_key)
    .build_responder()
    .unwrap();
// wait on client's arrival
println!("Listening on 0.0.0.0:9999");
let (mut stream, _) = TcpListener::bind("0.0.0.0:9999").unwrap().accept().unwrap();
// <- e
noise
    .read_message(&recv(&mut stream).unwrap(), &mut buf)
    .unwrap();
// -> e, ee, s, es
let len = noise.write_message(&[0u8; 0], &mut buf).unwrap();
send(&mut stream, &buf[..len]);
// <- s, se
noise
    .read_message(&recv(&mut stream).unwrap(), &mut buf)
    .unwrap();
// transition the state machine to transport mode sinc handshake is complete.
let mut noise = noise.into_transport_mode().unwrap();
while let Ok(msg) = recv(&mut stream) {
    let len = noise.read_message(&msg, &mut buf).unwrap();
    println!("client said: {}", String::from_utf8_lossy(&buf[..len]));
}
println!("connection closed");

客戶端:

let params: NoiseParams = "Noise_XX_25519_ChaChaPoly_BLAKE2s".parse().unwrap();
let builder: Builder<'_> = Builder::new(params.clone());
let static_key = builder.generate_keypair().unwrap().private;
let mut noise = builder
    .local_private_key(&static_key)
    .build_initiator()
    .unwrap();
// connect to server
let mut stream = TcpStream::connect("127.0.0.1:9999").unwrap();
println!("connected!");
// -> e
let len = noise.write_message(&[], &mut buf).unwrap();
send(&mut stream, &buf[..len]);
// <- e, ee, s, es
noise
    .read_message(&recv(&mut stream).unwrap(), &mut buf)
    .unwrap();
// -> s, se
let len = noise.write_message(&[], &mut buf).unwrap();
send(&mut stream, &buf[..len]);
let mut noise = noise.into_transport_mode().unwrap();
println!("Session established...");
// send secure data
for _ in 0..10 {
    let len = noise.write_message(b"HACK THE PLANET", &mut buf).unwrap();
    send(&mut stream, &buf[..len]);
}

因爲 snow 的所有操作都直接操作內存的 buffer,所有的 IO 都是由你創建的 TCP stream 完成,所以 snow 可以很好地在同步或者異步模式下工作。

賢者時刻

連接千萬條,安全第一條。網絡不加密,親人兩行淚。- 魯迅:不是我說的

參考文獻

[1] CISSP: https://www.isc2.org/Certifications/CISSP

[2] TLS: https://en.wikipedia.org/wiki/Transport_Layer_Security

[3] CA: https://en.wikipedia.org/wiki/Certificate_authority

[4] Noise Protocol: https://noiseprotocol.org/

[5] DH 算法:https://en.wikipedia.org/wiki/Diffie–Hellman_key_exchange

[6] x25519-dalek: https://github.com/dalek-cryptography/x25519-dalek

[7] curve25519: https://en.wikipedia.org/wiki/Curve25519

[8] AES: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard

[9] ChachaPoly: https://tools.ietf.org/html/rfc7539

[10] tyrchen/conceal: https://github.com/tyrchen/conceal

[11] ristretto255-dh: https://github.com/ZcashFoundation/ristretto255-dh

[12] Ristretto: https://ristretto.group/

[13] PEM: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail

[14] Charles proxy: https://www.charlesproxy.com/

[15] Man in the middle: https://en.wikipedia.org/wiki/Man-in-the-middle_attack

[16] X.509 certificate: https://en.wikipedia.org/wiki/X.509

[17] Certificate Signing Request: https://en.wikipedia.org/wiki/Certificate_signing_request

[18] Let's encrypt: https://letsencrypt.org/

[19] Cellar: https://github.com/tyrchen/cellar

[20] BIP 32: HD wallet: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki

[21] mobc-tonic:https://github.com/tyrchen/mobc-tonic

[22] Rustls: https://github.com/ctz/rustls

[23] Rustls audit report: https://github.com/ctz/rustls/blob/master/audit/TLS-01-report.pdf

[24] Tokio TLS helper: https://github.com/tyrchen/tokio-tls-helper

[25] WireGuard: https://www.wireguard.com/

[26]snow: https://github.com/mcginty/snow

[27] libp2p: https://github.com/libp2p/rust-libp2p

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HCHYr5sWnEG_qOGE3hfNnQ