grpc使用自制CA證書校驗公網(wǎng)上的連接請求

方法在最后一小節(jié)佛南,前面都是用到的知識的總結(jié)梗掰,了解的可以跳過。


1. 對稱加密和非對稱加密

對稱加密:加密和解密都用同一個密碼
非對稱加密:公鑰對所有人公開嗅回,發(fā)送者加密用公鑰及穗,接收者唯一掌握私鑰,對公鑰加密內(nèi)容的解密用且只能用私鑰
非對稱加密缺點:加密速度比對稱慢
非對稱加密優(yōu)點:公鑰本身就是公開給別人的妈拌,所以不用擔(dān)心被竊取拥坛,私鑰永遠在自己手里,只有自己能解密消息

2. https和http

??https在http的基礎(chǔ)上尘分,對傳輸內(nèi)容進行了加密猜惋。
??我們都知道http建立連接的三次握手和四次揮手過程。如果使用的是https培愁,在三次握手過后著摔,需要進行SSL握手,然后客戶端和服務(wù)端通信過程中使用SSL(新版本叫TLS了)的互相加解密定续。通信完之后谍咆,在四次揮手之前禾锤,先關(guān)閉SSL連接。
??從這里能看出摹察,https比http要慢(多了SSL握手恩掷、揮手,就多了好幾次TCP通信供嚎,建立連接之后每次通信還要加解密黄娘,http/1.1開始支持長連接,以及http/2支持多路復(fù)用克滴,都可以減少建立連接的次數(shù)逼争,也就減少了多次http請求下每次http請求的平均耗時)。
??https相比http還可以防篡改劝赔。接收到消息之后計算出數(shù)字簽名誓焦,對比收到的數(shù)字簽名,就知道消息體是否被篡改了着帽。(想了解數(shù)字簽名可以參考阿里云視頻監(jiān)控產(chǎn)品OpenAPI的簽名機制

3. https單向認證和雙向認證

圖來自這里

https單向認證

https雙向認證

??從上面對比可以看到杂伟,https使用的非對稱加密是用在客戶端和服務(wù)端交互SSL信息的過程中,SSL握手完成后启摄,客戶端和服務(wù)端通信使用的還是對稱加密稿壁,對稱加密的密鑰在本次連接隨機生成幽钢,其他的連接以及本次連接關(guān)閉后都不能使用歉备。
??雙向認證和單向認證的區(qū)別就在于,客戶端需要向服務(wù)端發(fā)送自己的證書匪燕,服務(wù)端需要校驗客戶端的證書蕾羊,以及服務(wù)端選擇加密方案通知客戶端時也是加密的。

4. CA證書和自制證書

??CA(Certificate Authority)是負責(zé)管理和簽發(fā)證書的第三方權(quán)威機構(gòu)帽驯,常見的有Symantec龟再、GeoTrust、Comodo等等尼变,他們是所有行業(yè)和公眾都信任的利凑、認可的,并負責(zé)審核向他們申請證書的網(wǎng)站的安全性嫌术。
??CA證書哀澈,就是CA頒發(fā)的證書,可用于驗證網(wǎng)站是否可信(針對HTTPS)度气、驗證某文件是否可信(是否被篡改)等割按,也可以用一個證書來證明另一個證書是真實可信,最頂級的證書稱為根證書磷籍。除了根證書(自己證明自己是可靠)适荣,其它證書都要依靠上一級的證書现柠,來證明自己。
??我們用的操作系統(tǒng)都預(yù)置了很多可信任的根證書弛矛,SSL握手時服務(wù)器會把它的服務(wù)器證書發(fā)給瀏覽器够吩。例如CSDN的服務(wù)器證書是GeoTrust頒發(fā)的,本地的GeoTrust根證書可以證明CSDN的服務(wù)器證書是真的丈氓,值得信任废恋,于是我們訪問CSDN時瀏覽器就建立了和CSDN服務(wù)器的https連接。
??我們也可以自己做CA根證書扒寄,我們自己的機器或者訪問我們服務(wù)的客戶的機器鱼鼓,都安裝上該CA根證書。12306以前就是這樣干的(SRCA就是12306的根證書该编,現(xiàn)在已經(jīng)換成DigiCert的證書了)迄本。
??關(guān)于CA證書更多的解釋,以及各種證書文件的區(qū)別课竣,參考這里嘉赎。
??自制CA證書可以用OpenSSL命令行工具,linux基本都自帶于樟,也可以使用GUI工具公条,參考這里

5. 利用chrome和nginx實踐一下單向認證和雙向認證

??先假定我們已經(jīng)做好了證書文件迂曲,包括根證書ca.pem靶橱、服務(wù)端證書server.pem、服務(wù)端私鑰server.key路捧、客戶端證書client.pem关霸、客戶端私鑰client.key,可以來這里下載我做好的杰扫,可以用于你自己測試队寇,提取碼:yd11。
??nginx加上配置文件:

server {
    listen       443 ssl; # ssl代表該端口監(jiān)聽啟用https
    server_name  localhost;
    ssl_certificate      /data/sslKey/server.pem;  # 證書
    ssl_certificate_key  /data/sslKey/server.key;  # 私鑰
    ssl_client_certificate /data/sslKey/ca.pem;    # 根證書章姓,用于驗證各個下級證書
    ssl_verify_client on; # 校驗客戶端證書開啟
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

其中:

ssl_certificate      /data/sslKey/server.pem;  # server證書公鑰
ssl_certificate_key  /data/sslKey/server.key;  # server私鑰

很常見佳遣。
??通常我們需要讓自己的網(wǎng)站變成https訪問時都是這么做。使用nginx對外暴露https請求接口凡伊,nginx到后端的內(nèi)網(wǎng)服務(wù)仍然是http零渐,改動小,效率高窗声。
??只有這兩項配置就是單向認證相恃,即客戶端需要校驗服務(wù)端的證書來確信服務(wù)端是安全網(wǎng)站。這時候訪問https://localhost:443會提示不安全的網(wǎng)站(以下所有截圖都是chrome瀏覽器的交互,其他瀏覽器可能不是這樣拦耐,自行處理)耕腾,因為服務(wù)端提供的證書是我們自制的,操作系統(tǒng)預(yù)存的證書無法識別該證書杀糯。

不安全的網(wǎng)站

??點擊繼續(xù)訪問代表我們手動告訴瀏覽器信任這個網(wǎng)站扫俺,就可以繼續(xù)訪問了。
繼續(xù)訪問

再加上:

ssl_client_certificate /data/sslKey/ca.pem;    # 根證書固翰,用于驗證各個下級證書
ssl_verify_client on; # 校驗客戶端證書開啟

這兩項配置就是雙向認證狼纬。
??服務(wù)端需要驗證客戶端的證書,我們直接訪問就會得到報錯400 No Required SSL certificate was sent骂际,需要在chrome中導(dǎo)入自制的client.pem證書疗琉,導(dǎo)入方法參考這里
??需要注意的是windows導(dǎo)入證書的格式不是pem和crt歉铝,需要轉(zhuǎn)換一下才能導(dǎo)入盈简,OpenSSL命令行工具可以轉(zhuǎn)換,上面的GUI工具也可以在導(dǎo)出時選擇指定格式太示。
??再次訪問chrome會彈窗提示柠贤,

選擇證書

??選擇剛才導(dǎo)入的證書就能正常訪問了。
nginx訪問結(jié)果

6. 利用自制CA證書雙向認證實現(xiàn)安全訪問

??以go代碼示例类缤,仍然使用上面的證書文件臼勉,加載證書文件的代碼:

import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "log"
    "google.golang.org/grpc/credentials"
)

// GetServerCredentials 服務(wù)端證書
func GetServerCredentials() credentials.TransportCredentials {
    cert, err := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key")
    if err != nil {
        log.Fatalf("加載服務(wù)端證書失敗, err: %v\n", err)
    }
    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("cert/ca.pem")
    if err != nil {
        log.Fatalf("讀取公鑰文件失敗: %v\n", err)
    }
    certPool.AppendCertsFromPEM(ca)
    creds := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{cert},
        ClientAuth:   tls.RequireAndVerifyClientCert,
        ClientCAs:    certPool,
    })
    return creds
}

// GetClientCredentials 客戶端證書
func GetClientCredentials() credentials.TransportCredentials {
    cert, err := tls.LoadX509KeyPair("cert/client.pem", "cert/client.key")
    if err != nil {
        log.Fatalf("加載客戶端證書失敗, err: %v\n", err)
    }
    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("cert/ca.pem")
    if err != nil {
        log.Fatalf("讀取公鑰文件失敗: %v\n", err)
    }
    certPool.AppendCertsFromPEM(ca)
    creds := credentials.NewTLS(&tls.Config{
        Certificates: []tls.Certificate{cert},
        ServerName:   "localhost",
        RootCAs:      certPool,
    })
    return creds
}

??服務(wù)端加上:

opts := []grpc.ServerOption{
    grpc.Creds(utils.GetServerCredentials()),
}

??客戶端加上:

grpc.Dial(
  "localhost:8080",
    grpc.WithTransportCredentials(cert.GetClientCredentials()),

??如果服務(wù)端使用了證書,客戶端沒有使用證書餐弱,在grpc.Dial()時連接可以建立成功宴霸,但是訪問時會報錯:

rpc error: code = Unavailable desc = connection closed

并且可以一直訪問一直報錯。
??這里涉及到gRPC連接機制的問題岸裙。調(diào)用Dial或者DialContext函數(shù)創(chuàng)建連接時猖败,默認只是返回ClientConn結(jié)構(gòu)體指針,同時會啟動一個Goroutine異步的去建立連接降允,連接失敗會一直重試,這個機制可以避免服務(wù)器因為連接空閑時間過長關(guān)閉連接艺糜、服務(wù)器重啟等造成的客戶端連接失效問題剧董,可以完美的解決連接的超時與保活問題破停。
??如果想要等連接建立完再返回(起到創(chuàng)建連接時就檢測連接是否可用的目的)翅楼,可以指定grpc.WithBlock()。連接不上就會報錯:

context deadline exceeded

??如果服務(wù)端沒有使用證書真慢,客戶端使用了毅臊,也是可以成功建立連接,但是訪問時報錯:

connection error: desc = "transport: authentication handshake failed: tls: first record does not look like a TLS handshake"

??因為客戶端收不到服務(wù)端的TLS握手信息(服務(wù)端不使用證書黑界,根本就不知道要TLS握手)管嬉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末皂林,一起剝皮案震驚了整個濱河市六荒,隨后出現(xiàn)的幾起案子由缆,更是在濱河造成了極大的恐慌面褐,老刑警劉巖糖荒,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件添祸,死亡現(xiàn)場離奇詭異掘而,居然都是意外死亡三娩,警方通過查閱死者的電腦和手機段审,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門犹菇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來德迹,“玉大人,你說我怎么就攤上這事揭芍∑直妫” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵沼沈,是天一觀的道長流酬。 經(jīng)常有香客問我,道長列另,這世上最難降的妖魔是什么芽腾? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮页衙,結(jié)果婚禮上摊滔,老公的妹妹穿的比我還像新娘。我一直安慰自己店乐,他們只是感情好艰躺,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著眨八,像睡著了一般腺兴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廉侧,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天页响,我揣著相機與錄音,去河邊找鬼段誊。 笑死闰蚕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的连舍。 我是一名探鬼主播没陡,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盼玄?” 一聲冷哼從身側(cè)響起贴彼,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎强岸,沒想到半個月后锻弓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡蝌箍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年青灼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妓盲。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡杂拨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悯衬,到底是詐尸還是另有隱情弹沽,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布筋粗,位于F島的核電站策橘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娜亿。R本人自食惡果不足惜丽已,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望买决。 院中可真熱鬧沛婴,春花似錦、人聲如沸督赤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躲舌。三九已至丑婿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間孽糖,已是汗流浹背枯冈。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留办悟,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓滩褥,卻偏偏與公主長得像病蛉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356