https單向驗證應用廣泛想必大家都很熟悉,我已經在一篇博文中分享過,這次來看看Nginx如何實作雙向驗證。
單向驗證與雙向驗證的差別:
單向驗證: 指用戶端驗證伺服器端證書,伺服器并不需要驗證用戶端證書。
雙向驗證:指用戶端驗證伺服器端證書,而伺服器也需要通過CA的公鑰證書來驗證用戶端證書。
詳細的握手過程:
單向驗證
浏覽器發送一個連接配接請求給安全伺服器。
1、伺服器将自己的證書,以及同證書相關的資訊發送給客戶浏覽器。
2、客戶浏覽器檢查伺服器送過來的證書是否是由自己信賴的CA中心所簽發的。如果是,就繼續執行協定;如果不是,客戶浏覽器就給客戶一個警告消息:警告客戶這個證書不是可以信賴的詢問客戶是否需要繼續。
3、接着客戶浏覽器比較證書裡的消息,例如域名和公鑰,與伺服器剛剛發送的相關消息是否一緻,如果是一緻的,客戶浏覽器認可這個伺服器的合法身份。
4、浏覽器随機産生一個用于後面通訊的“通話密鑰”,然後用伺服器的公鑰對其加密,然後将加密後的“預主密碼”傳給伺服器。
5、伺服器從客戶發送過來的密碼方案中,選擇一種加密程度最高的密碼方案,用伺服器的私鑰加密後通知浏覽器。
6、浏覽器針對這個密碼方案,接着用伺服器的公鑰加過密後發送給伺服器。
7、伺服器接收到浏覽器送過來的消息,用自己的私鑰解密,獲得。
8、伺服器、浏覽器接下來的通訊都是用對稱密碼方案,使用相同的對稱密鑰。
雙向驗證
1、浏覽器發送一個連接配接請求給安全伺服器。
2、伺服器将自己的證書,以及同證書相關的資訊發送給客戶浏覽器。
3、客戶浏覽器檢查伺服器送過來的證書是否是由自己信賴的CA中心所簽發的。如果是,就繼續執行協定;如果不是,客戶浏覽器就給客戶一個警告消息:警告客戶這個證書不是可以信賴的詢問客戶是否需要繼續。
4、接着客戶浏覽器比較證書裡的消息,例如域名和公鑰,與伺服器剛剛發送的相關消息是否一緻,如果是一緻的,客戶浏覽器認可這個伺服器的合法身份。
5、伺服器要求客戶的身份認證,使用者可以建立一個随機數然後對其進行數字簽名,将這個含有簽名的随機數和客戶自己的證書以及加密過的“預主密碼”一起傳給伺服器。
6、伺服器必須檢驗客戶證書和簽名随機數的合法性,具體的合法性驗證過程包括:客戶的證書使用日期是否有效,為客戶提供證書的CA 是否可靠,發行CA 的公鑰能否正确解開客戶證書的發行CA的數字簽名,檢查客戶的證書是否在證書廢止清單(CRL)中。檢驗如果沒有通過,通訊立刻中斷;如果驗證通過,伺服器将用自己的私鑰解開加密的“預主密碼”,然後執行一系列步驟來産生主通訊密碼(用戶端也将通過同樣的方法産生相同的主通訊密碼)。
7、客戶浏覽器告訴伺服器自己所能夠支援的通訊對稱密碼方案。
8、伺服器從客戶發送過來的密碼方案中,選擇一種加密程度最高的密碼方案,用客戶的公鑰加過密後通知浏覽器。
9、浏覽器針對這個密碼方案,選擇一個通話密鑰,接着用伺服器的公鑰加過密後發送給伺服器。
10、伺服器接收到浏覽器送過來的消息,用自己的私鑰解密,獲得通話密鑰。
11、伺服器、浏覽器接下來的通訊都是用對稱密碼方案,使用相同的對稱密鑰。
一、自建CA,簽署證書
1
2
3
4
5
6
7
8
9
10
11
<code># openssl 配置檔案路徑</code>
<code>vim </code><code>/etc/pki/tls/openssl</code><code>.cnf</code>
<code># 下面隻列出配置檔案中和自建CA有關的幾個關鍵指令</code>
<code>dir</code> <code>= </code><code>/etc/pki/CA</code> <code># CA的工作目錄</code>
<code>database = $</code><code>dir</code><code>/index</code><code>.txt </code><code># 簽署證書的資料記錄檔案</code>
<code>new_certs_dir = $</code><code>dir</code><code>/newcerts</code> <code># 存放新簽署證書的目錄</code>
<code>serial = $</code><code>dir</code><code>/serial</code> <code># 新證書簽署号記錄檔案</code>
<code>certificate = $</code><code>dir</code><code>/ca</code><code>.crt </code><code># CA的證書路徑</code>
<code>private_key = $</code><code>dir</code><code>/private/cakey</code><code>.pem </code><code># CA的私鑰路徑</code>
使用openssl制作CA的自簽名證書
12
13
14
15
<code># 切換到CA的工作目錄</code>
<code>cd</code> <code>/etc/pki/CA</code>
<code># 制作CA私鑰</code>
<code>(</code><code>umask</code> <code>077; openssl genrsa -out private</code><code>/cakey</code><code>.pem 2048)</code>
<code># 制作自簽名證書</code>
<code>openssl req -new -x509 -key private</code><code>/cakey</code><code>.pem -out ca.crt </code>
<code># 生成資料記錄檔案,生成簽署号記錄檔案,給檔案一個初始号。</code>
<code>touch</code> <code>index.txt</code>
<code>touch</code> <code>serial</code>
<code>echo</code> <code>'01'</code><code>> serial</code>
<code># 自建CA完成</code>
準備伺服器端證書
<code># 制作伺服器端私鑰</code>
<code>(</code><code>umask</code> <code>077; openssl genrsa -out server.key 1024)</code>
<code># 制作伺服器端證書申請指定使用sha512算法簽名 (預設使用sha1算法)</code>
<code>openssl req -new -key server.key -sha512 -out server.csr</code>
<code># 簽署證書</code>
<code>openssl ca -</code><code>in</code> <code>server.csr -out server.crt -days 3650</code>
準備用戶端證書
<code># 制作用戶端私鑰</code>
<code>(</code><code>umask</code> <code>077; openssl genrsa -out kehuduan.key 1024)</code>
<code># 制作用戶端證書申請</code>
<code>openssl req -new -key kehuduan.key -out kehuduan.csr</code>
<code>openssl ca -</code><code>in</code> <code>kehuduan.csr -out kehuduan.crt -days 3650</code>
注意事項:
1、制作證書時會提示輸入密碼,設定密碼可選,伺服器證書和用戶端證書密碼可以不相同。
2、伺服器證書和用戶端證書制作時提示輸入省份、城市、域名資訊等,需保持一緻。
3、以下資訊根證書需要和用戶端證書比對,否則可能出現簽署問題。
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = match
如何指定簽署證書的簽名算法
<code> </code><code>openssl req xx</code>
<code> </code>
<code> </code><code>-[digest] Digest to sign with (see openssl dgst -h </code><code>for</code> <code>list)</code>
檢視使用的簽名算法:
<a href="http://s1.51cto.com/wyfs02/M01/80/EA/wKiom1dEXMygjao6AABWovfkDhQ536.png" target="_blank"></a>
<code># 使用-sha256指定算法</code>
<code>openssl req -new -key server.key -sha256 -out server.csr</code>
二、提供Nginx配置檔案
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<code>server {</code>
<code> </code><code>listen 443;</code>
<code> </code><code>server_name pro.server.com;</code>
<code> </code><code>ssi on;</code>
<code> </code><code>ssi_silent_errors on;</code>
<code> </code><code>ssi_types text</code><code>/shtml</code><code>;</code>
<code> </code><code>ssl on;</code>
<code> </code><code>ssl_certificate </code><code>/data/server/nginx/ssl/self/server</code><code>.crt;</code>
<code> </code><code>ssl_certificate_key </code><code>/data/server/nginx/ssl/self/server</code><code>.key;</code>
<code> </code><code>ssl_client_certificate </code><code>/data/server/nginx/ssl/self/ca/ca</code><code>.crt;</code>
<code> </code><code>ssl_verify_client on;</code>
<code> </code><code>ssl_protocols TLSv1 TLSv1.1 TLSv1.2;</code>
<code> </code><code>ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:!ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:!RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;</code>
<code> </code><code>ssl_prefer_server_ciphers On;</code>
<code> </code><code>index index.html index.htm index.php;</code>
<code> </code><code>root </code><code>/data/www</code><code>;</code>
<code> </code><code>location ~ .*\.(php|php5)?$</code>
<code> </code><code>{</code>
<code> </code><code>#fastcgi_pass unix:/tmp/php-cgi.sock;</code>
<code> </code><code>fastcgi_pass 127.0.0.1:9000;</code>
<code> </code><code>fastcgi_index index.php;</code>
<code> </code><code>include fastcgi.conf;</code>
<code> </code><code>}</code>
<code> </code><code>location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$</code>
<code> </code><code>expires 30d;</code>
<code> </code><code>location ~ .*\.(js|css)?$</code>
<code> </code><code>expires 1h;</code>
<code>###this is to use open website lianjie like on apache##</code>
<code> </code><code>location / {</code>
<code> </code><code>if</code> <code>(!-e $request_filename) {</code>
<code> </code><code>rewrite ^(.*)$ </code><code>/index</code><code>.php?s=$1 last;</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>keepalive_timeout 0;</code>
<code> </code><code>location ~ /.svn/ {</code>
<code> </code><code>deny all;</code>
<code>###end##</code>
<code> </code><code>include </code><code>/data/server/nginx/conf/rewrite/test</code><code>.conf;</code>
<code> </code><code>access_log </code><code>/log/nginx/access/access</code><code>.log; </code>
<code>}</code>
用戶端證書格式轉換
<code># 将文本格式的證書轉換成可以導入浏覽器的證書</code>
<code>openssl pkcs12 -</code><code>export</code> <code>-clcerts -</code><code>in</code> <code>client.crt -inkey client.key -out client.p12</code>
三、将證書導入浏覽器,這裡以Chrome為例
1、在浏覽器視窗右上角找到設定
<a href="http://s3.51cto.com/wyfs02/M00/80/F0/wKiom1dFJK_iAIa0AAByQfijKWM484.png" target="_blank"></a>
2、在設定視窗中找到進階設定
<a href="http://s3.51cto.com/wyfs02/M00/80/EF/wKioL1dFJbHSnDwQAABp-IlVvZc593.png" target="_blank"></a>
3、找到管理證書
<a href="http://s4.51cto.com/wyfs02/M01/80/F0/wKiom1dFJMnR8d3zAACiVLwT94I491.png" target="_blank"></a>
4、點選導入證書,然後選擇證書路徑就可以了
<a href="http://s5.51cto.com/wyfs02/M01/80/EF/wKioL1dFJcqz2RcgAABKRZb2kgU814.png" target="_blank"></a>
5、在導入證書之後就可以正常通路到伺服器資料了
<a href="http://s1.51cto.com/wyfs02/M02/80/F1/wKiom1dFJTWTqdbeAACGSlVFFqo683.png" target="_blank"></a>
6、如果沒有成功導入用戶端證書就通路伺服器的話,那麼伺服器驗證用戶端證書這步就會失敗,然後傳回如下錯誤
<a href="http://s4.51cto.com/wyfs02/M02/80/F1/wKiom1dFJUPzkeUEAABN92QngcQ596.png" target="_blank"></a>
由于用的是自簽證書不被公有CA信任,是以https那裡會有紅叉。
附加内容: 如何配置級聯證書鍊
(2016/11/08)
為什麼我之前寫這篇的時候沒有寫上,而是之後加上這塊呢?
因為之前做的實驗用的是自簽名證書,所謂的自簽名證書就是CA也是自己做,自己給自己發證。
那麼我們在簽發服務端證書和用戶端證書的時候,是由自己所建立的根級CA下發的。 不存在一級、二級代理CA的概念。在Nginx上配置校驗用戶端證書時,隻需要制定根級CA的證書就夠了。
但是在實際運用過程中,我們很可能會在CA代理機構,申請受信任的證書,這個機構很可能就會是代理CA,也就是由根級CA授權的下級CA,有數字證書的簽發資格。
舉個例子,假如有一個二級代理CA簽發了一個證書,那麼當需要校驗這個證書的合法性時,需要用到簽發這個證書的二級代理CA的證書來校驗。 那麼二級代理CA的證書是否又可信呢? 那麼就需要給二級代理CA發證的,一級代理CA的證書來校驗,層層遞進,直到根CA憑證。這就是級聯證書的校驗模式。
這時候在配置Nginx校驗用戶端證書時,隻指定給發證的二級代理CA的證書就不行了。 還需要跟上能校驗二級代理CA憑證的根CA憑證。
在HTTPS雙向驗證中,指定CA憑證來校驗用戶端證書時,是用于校驗整個信任域。 比如: 你的頂級域名是 baidu.com。 那麼任何 xxx.baidu.com 的證書都可以被信任。
假設在startSSL申請了一個SSL證書
使用者: test.baidu.com
頒發者: StartCom Class 1 DV Server CA
打開這個CA憑證可以看到,它上面還有一級,它的頒發者是 StartCom Certification Authority
然後再打開這個CA的證書,檢視頒發者和使用者都相同,那它應該就是根級CA了。
test.baidu.com 作為用戶端證書,Nginx配置校驗:
1、打開代理CA和根級CA的證書,複制代理CA憑證中的内容,貼到根CA憑證内容的下方,儲存;
<a href="http://s5.51cto.com/wyfs02/M00/89/E6/wKioL1ghSIOSgKT2AAAnfLDazDY834.png" target="_blank"></a>
2、提供Nginx配置檔案
<code> </code><code>server_name </code><code>test</code><code>.baidu.com;</code>
<code> </code><code>ssl_certificate </code><code>/alidata/server/nginx/ssl/server</code><code>.baidu.com.crt;</code>
<code> </code><code>ssl_certificate_key </code><code>/alidata/server/nginx/ssl/server</code><code>.key;</code>
<code> </code><code>ssl_verify_depth 2;</code>
<code> </code><code>ssl_client_certificate </code><code>/alidata/server/nginx/ssl/ca/ca_and_proxyca</code><code>.crt;</code>
<code> </code><code>ssl_prefer_server_ciphers on;</code>
<code> </code><code>root </code><code>/alidata/www/default</code><code>;</code>
部分重點配置解釋:
ssl_verify_client on 開啟用戶端身份校驗
ssl_client_certificate 指定用于校驗用戶端證書的CA的證書,如果是代理級CA,那麼需要把内容并在一起。
ssl_verify_depth 指定校驗深度
證書常見的三種格式,pem、der、pkcs12
pem 格式也就是文本格式,可以直接用文本編輯器打開看到證書内容的,這也是最常見的格式。
der 這種格式無法直接通過文本編輯器打開檢視内容,通常用在JAVA環境。
pkcs12 用于導入浏覽器的格式
格式轉換:
<code># pem 轉 der</code>
<code>openssl x509 -inform pem -</code><code>in</code> <code>certificate.crt -out certificate.cer -outform DER</code>
<code># pem 格式的證書有含私鑰的,和不含私鑰的。</code>
<code># der 轉 pem</code>
<code>openssl x509 -inform der -</code><code>in</code> <code>certificate.cer -out certificate.pem</code>
<code># 私鑰轉化 der 轉 pem</code>
<code>openssl rsa -inform DER -outform PEM -</code><code>in</code> <code>privatekey.der -out privatekey.pem</code>
<code># pem 轉 pkcs12</code>
<code>openssl pkcs12 -</code><code>export</code> <code>-</code><code>in</code> <code>Cert.pem -out Cert.p12 -inkey key.pem</code>
<code># pkcs12 轉 pem</code>
<code>openssl pkcs12 -nocerts -nodes -</code><code>in</code> <code>cert.p12 -out private.pem</code>
<code>openssl pkcs12 -clcerts -nokeys -</code><code>in</code> <code>cert.p12 -out cert.pem</code>
<code># P7B 轉換為 PEM (P7B格式一般出現在windows server和tomcat中,無私鑰)</code>
<code>openssl pkcs7 -print_certs -</code><code>in</code> <code>incertificat.p7b -out outcertificate.cer</code>
<code># PFX 轉換為PEM (PFX格式一般出現在windows server中)</code>
<code>#提取私鑰</code>
<code>openssl pkcs12 -</code><code>in</code> <code>certname.pfx -nocerts -out key.pem -nodes</code>
<code>#提驗證書</code>
<code>openssl pkcs12 -</code><code>in</code> <code>certname.pfx -nokeys -out cert.pem</code>
<code># 從pem私鑰中提取公鑰</code>
<code>openssl rsa -</code><code>in</code> <code>rsa_private_key.pem -pubout -out rsa_public_key.pem</code>
本文轉自qw87112 51CTO部落格,原文連結:http://blog.51cto.com/tchuairen/1782945