Github Repophp
前置閱讀:Web應用安全基礎html
在進行 HTTP 通訊時,信息可能會監聽、服務器或客戶端身份假裝等安全問題,HTTPS 則能有效解決這些問題。在使用原始的HTTP鏈接的時候,由於服務器與用戶之間是直接進行的明文傳輸,致使了用戶面臨着不少的風險與威脅。攻擊者能夠用中間人攻擊來輕易的 截獲或者篡改傳輸的數據。攻擊者想要作些什麼並無任何的限制,包括竊取用戶的Session信息、注入有害的代碼等,乃至於修改用戶傳送至服務器的數據。python
咱們並不能替用戶選擇所使用的網絡,他們頗有可能使用一個開放的,任何人均可以竊聽的網絡,譬如一個咖啡館或者機場裏面的開放WiFi網絡。普通的 用戶頗有可能被欺騙地隨便連上一個叫免費熱點的網絡,或者使用一個能夠隨便被插入廣告的網路當中。若是攻擊者會竊聽或者篡改網路中的數據,那麼用戶與服務 器交換的數據就好不可信了,幸虧咱們還可使用HTTPS來保證傳輸的安全性。HTTPS最先主要用於相似於經融這樣的安全要求較高的敏感網絡,不過如今日漸被各類各樣的網站鎖使用,譬如咱們經常使用的社交網絡或者搜索引擎。 HTTPS協議使用的是TLS協議,一個優於SSL協議的標準來保障通訊安全。只要配置與使用得當,就能有效抵禦竊聽與篡改,從而有效保護咱們將要去訪問 的網站。用更加技術化的方式說,HTTPS可以有效保障數據機密性與完整性,而且可以完成用戶端與客戶端的雙重驗證。git
隨着面臨的風險日漸增多,咱們應該將全部的網絡數據當作敏感數據而且進行加密傳輸。已經有不少的瀏覽器廠商宣稱要廢棄全部的非HTTPS的請求,乃 至於當用戶訪問非HTTPS的網站的時候給出明確的提示。不少基於HTTP/2的實現都只支持基於TLS的通訊,因此咱們如今更應當在所有地方使用 HTTPS。目前若是要大範圍推廣使用HTTPS仍是有一些障礙的,在一個很長的時間範圍內使用HTTPS會被認爲形成不少的計算資源的浪費,不過隨着現代硬件 與瀏覽器的發展,這點計算資源已經不足爲道。早期的SSL協議與TLS協議只支持一個IP地址分配一個整數,不過如今這種限制所謂的SNI的協議擴展來解 決。另外,從一個證書認證機構獲取證書也會打消一些用戶使用HTTPS的念頭,不過下面咱們介紹的像Let's Encrypt這樣的免費的服務就能夠打破這種障礙。github
HTTP平常使用極爲普遍的協議,它很優秀且方便,但仍是存在一些問題,如:算法
明文通訊,內容能夠直接被竊聽express
沒法驗證報文的完整性,可能被篡改apache
通訊方身份不驗證,可能遇到假的客戶端或服務器npm
HTTP 不會對請求和響應的內容進行加密,報文直接使用明文發送。報文在服務器與客戶端流轉中間,會通過若干個結點,這些結點中隨時均可能會有竊聽行爲。由於通訊必定會通過中間不少個結點,因此就算是報文通過了加密,也同樣會被竊聽到,不過是竊聽到加密後的內容。要竊聽相同段上的通訊仍是很簡單的,好比可使用經常使用的抓包工具 Wireshark。這種狀況下,保護信息安全最經常使用的方式就是採起加密了,加密方式能夠根據加密對象分如下幾種:segmentfault
(1)通訊加密
HTTP 協議基於 TCP/IP 協議族,它沒有加密機制。但能夠經過 SSL(Secure Socket Layer,安全套接層)創建安全的通訊線路,再進行 HTTP 通訊,這種與 SSL 結合使用的稱爲 HTTPS(HTTP Secure,超文本傳安全協議)。
(2)內容加密
還能夠對通訊內容自己加密。HTTP 協議中沒有加密機制,但能夠對其傳輸的內容進行加密,也就是對報文內容進行加密。這種加密方式要求客戶端對 HTTP 報文進行加密處理後再發送給服務器端,服務器端拿到加密後的報文再進行解密。這種加密方式不一樣於 SSL 將整個通訊線路進行加密,因此它仍是有被篡改的風險的。
(1)接收到的內容可能被作假
HTTP 協議是沒法證實通訊報文的完整性的。所以請求或響應在途中隨時可能被篡改而不自知,也就是說,沒有任何辦法確認,發出的請求/響應和接收到的請求/響應是先後相同的。好比瀏覽器從某個網站上下載一個文件,它是沒法肯定下載的文件和服務器上有些話的文件是同一個文件的。文件在傳輸過程當中被掉包了也是不知道的。這種請求或響應在傳輸途中,被攔截、篡改的攻擊就是中間人攻擊。好比某運營商或者某些DNS提供商會偷偷地在你的網頁中插入廣告腳本,就是典型的例子。
(2) 防篡改
也有一些 HTTP 協議肯定報文完整性的方法,不過這些方法很不方便,也不太可靠。用得最多的就是 MD5 等散列值校驗的方法。不少文件下載服務的網站都會提供相應文件的 MD5 散列值,一來得用戶親自去動手校驗(中國估計只有 0.1% 不到的用戶懂得怎麼作吧),二來若是網站提供的 MD5 值也被改寫的話呢?因此這種方法不方便也不可靠。
(1) DDOS攻擊與釣魚網站
在 HTTP 通訊時,因爲服務器不確認請求發起方的身份,因此任何設備均可以發起請求,服務器會對每個接收到的請求進行響應(固然,服務器能夠限制 IP 地址和端口號)。因爲服務器會響應全部接收到的請求,因此有人就利用這一點,給服務器發起海量的無心義的請求,形成服務器沒法響應正式的請求,這就是 Dos 攻擊(Denial Of Service,拒絕服務攻擊)。因爲客戶端也不會驗證服務器是否真實,因此遇到來自假的服務器的響應時,客戶端也不知道,只能交由人來判斷。釣魚網站就是利用了這一點。
(2) 身份認證
HTTP 協議沒法確認通訊方,而 SSL 則是能夠的。SSL 不只提供了加密處理,還提供了叫作「證書」的手段,用於肯定通訊方的身份。證書是由值得信任的第三方機構頒發(已得到社會承認的企業或組織機構)的,用以證實服務器和客戶端的身份。並且僞造證書從目前的技術來看,是一件極爲難的事情,因此證書每每能夠肯定通訊方的身份。以客戶端訪問網頁爲例。客戶端在開始通訊以前,先向第三機機構確認 Web 網站服務器的證書的有效性,再獲得其確認後,再開始與服務器進行通訊。
HTTPS = HTTP + 加密 + 認證 + 完整性保護,HTTPS 也就是 HTTP 加上加密處理、認證以及完整性保護。使用 HTTPS 通訊時,用的是 https://,而不是 http://。另外,當瀏覽器訪問 HTTPS 的 Web 網站時,瀏覽器地址欄會出現一個帶鎖的標記。要注意,HTTPS 並不是是應用層的新協議,而是 HTTP 通訊接口部分用 SSL 協議代替而已。原本,HTTP 是直接基於 TCP 通訊。在 HTTPS 中,它先和 SSL 通訊,SSL 再和 TCP 通訊。因此說 HTTPS 是披了層 SSL 外殼的 HTTP。SSL 是獨立於 HTTP 的協議,因此其餘相似於 HTTP 的應用層 SMTP 等協議均可以配合 SSL 協議使用,也能夠給它們加強安全性。整個架構以下圖所示:
HTTPS 使用 SSL 通訊,因此它的處理速度會比 HTTP 要慢。
一是通訊慢。它和 HTTP 相比,網絡負載會變慢 2 到 100倍。除去和 TCP 鏈接、發送 HTTP 請求及響應外,還必須進行 SSL 通訊,所以總體上處理通訊量會不可避免的增長。
二是 SSL 必須進行加密處理。在服務器和客戶端都須要進行加密和解密的去到處理。因此它比 HTTP 會更多地消耗服務器和客戶端的硬件資源。
SSL協議,是一種安全傳輸協議,最初是由 Netscape 在1996年發佈,因爲一些安全的緣由SSL v1.0和SSL v2.0都沒有公開,直到1996年的SSL v3.0。TLS是SSL v3.0的升級版,目前市面上全部的Https都是用的是TLS,而不是SSL。本文中不少地方混用了SSL與TLS這個名詞,你們可以理解就好。
下圖描述了在TCP/IP協議棧中TLS(各子協議)和HTTP的關係:
其中Handshake protocol,Change Ciper Spec protocol和Alert protocol組成了SSL Handshaking Protocols。
Record Protocol有三個鏈接狀態(Connection State),鏈接狀態定義了壓縮,加密和MAC算法。全部的Record都是被當前狀態(Current State)肯定的算法處理的。
TLS Handshake Protocol和Change Ciper Spec Protocol會致使Record Protocol狀態切換。
empty state -------------------> pending state ------------------> current state Handshake Protocol Change Cipher Spec
初始當前狀態(Current State)沒有指定加密,壓縮和MAC算法,於是在完成TLS Handshaking Protocols一系列動做以前,客戶端和服務端的數據都是明文傳輸的;當TLS完成握手過程後,客戶端和服務端肯定了加密,壓縮和MAC算法及其參數,數據(Record)會經過指定算法處理。
數據在傳輸過程當中,很容易被竊聽。加密就是保護數據安全的措施。通常是利用技術手段把數據變成亂碼(加密)傳送,到達目的地後,再利用對應的技術手段還原數據(解密)。加密包含算法和密鑰兩個元素。算法將要加密的數據與密鑰(一串數字)相結合,產生不可理解的密文。因而可知,密鑰與算法一樣重要。對數據加密技術能夠分爲兩類:對稱加密(對稱密鑰加密)和非對稱加密(非對稱密鑰加密)。SSL 採用了 非對稱加密(Public-key cryptography)的加密處理方式。
如今的加密方法中,加密算法都是公開的,網上都有各類算法原理解析的內容。加密算法雖然是公開的,算法用到的密鑰倒是保密的,以此來保持加密方法的安全性。加密和解密都會用到密鑰。有了密鑰就能夠解密了,若是密鑰被攻擊者得到,加密也就沒有意義了。
對稱加密的意思就是,加密數據用的密鑰,跟解密數據用的密鑰是同樣的。對稱加密的優勢在於加密、解密效率一般比較高。缺點在於,數據發送方、數據接收方須要協商、共享同一把密鑰,並確保密鑰不泄露給其餘人。此外,對於多個有數據交換需求的個體,兩兩之間須要分配並維護一把密鑰,這個帶來的成本基本是不可接受的。
非對稱加密方式能很好地解決對稱加密的困難。非對稱加密方式有兩把密鑰。一把叫作私有密鑰(private key),另外一把叫作非對稱(public key)。私有密鑰是一方保管,而非對稱則誰均可以得到。這種方式是須要發送密文的一方先得到對方的非對稱,使用已知的算法進行加密處理。對方收到被加密的信息後,再使用本身的私有密鑰進行解密。這種加密方式有意思是的加密算法的神奇,通過這個公開的算法加密後的密文,即便知道非對稱,也是沒法對密文還原的。要想對密文進行解決,必需要有私鑰才行。因此非對稱加密是很是安全的,即便竊聽到密文和非對稱,卻仍是沒法進行解密。
非對稱加密算法用的通常是 RSA 算法(這多是目前最重要的算法了)。這個算法由3個小夥子在1977年提出,它的主要原理是:將兩個大素數相乘很簡單,但想要這個乘積進行因式分解極其困難,所以能夠將乘積公開做爲非對稱。不過隨着目前的分佈式計算和量子計算機的快速發展,說不定在未來也許能破解這個算法了。
在測試的時候咱們能夠本身建立配置一個證書用於HTTPS認證,不過若是你要提供服務給普通用戶使用,那麼仍是須要從可信的第三方CA機構來獲取可信的證 書。對於不少開發者而言,一個免費的CA證書是個不錯的選擇。當你搜索CA的時候,你可能會遇到幾個不一樣等級的證書。最多見的就是Domain Validation(DV),用於認證一個域名的全部者。再往上就是所謂的Organization Validation(OV)與Extended Validation(EV),包括了驗證這些證書的請求機構的信息。雖然高級別的證書須要額外的消耗,不過仍是很值得的。
證書大概是這個樣子:
證書版本號(Version) 版本號指明X.509證書的格式版本,如今的值能夠爲:
0: v1
1: v2
2: v3
也爲未來的版本進行了預約義
證書序列號(Serial Number) 序列號指定由CA分配給證書的惟一的"數字型標識符"。當證書被取消時,其實是將此證書的序列號放入由CA簽發的CRL中,這也是序列號惟一的緣由。
簽名算法標識符(Signature Algorithm) 簽名算法標識用來指定由CA簽發證書時所使用的"簽名算法"。算法標識符用來指定CA簽發證書時所使用的:
公開密鑰算法
hash算法,example: sha256WithRSAEncryption
須向國際知名標準組織(如ISO)註冊
簽發機構名(Issuer) 此域用來標識簽發證書的CA的X.500 DN(DN-Distinguished Name)名字。包括:
國家(C)
省市(ST)
地區(L)
組織機構(O)
單位部門(OU)
通用名(CN)
郵箱地址
有效期(Validity) 指定證書的有效期,包括:
證書開始生效的日期時間
證書失效的日期和時間
每次使用證書時,須要檢查證書是否在有效期內。
證書用戶名(Subject) 指定證書持有者的X.500惟一名字。包括:
國家(C)
省市(ST)
地區(L)
組織機構(O)
單位部門(OU)
通用名(CN)
郵箱地址
證書持有者公開密鑰信息(Subject Public Key Info) 證書持有者公開密鑰信息域包含兩個重要信息:
證書持有者的公開密鑰的值
公開密鑰使用的算法標識符。此標識符包含公開密鑰算法和hash算法。
擴展項(extension) X.509 V3證書是在v2的基礎上一標準形式或普通形式增長了擴展項,以使證書可以附帶額外信息。標準擴展是指由X.509 V3版本定義的對V2版本增長的具備普遍應用前景的擴展項,任何人均可以向一些權威機構,如ISO,來註冊一些其餘擴展,若是這些擴展項應用普遍,也許之後會成爲標準擴展項。
簽發者惟一標識符(Issuer Unique Identifier) 簽發者惟一標識符在第2版加入證書定義中。此域用在當同一個X.500名字用於多個認證機構時,用一比特字符串
來惟一標識簽發者的X.500名字。可選。
證書持有者惟一標識符(Subject Unique Identifier) 持有證書者惟一標識符在第2版的標準中加入X.509證書定義。此域用在當同一個X.500名字用於多個證書持有者時,
用一比特字符串來惟一標識證書持有者的X.500名字。可選。
簽名算法(Signature Algorithm) 證書籤發機構對證書上述內容的簽名算法,example: sha256WithRSAEncryption
簽名值(Issuer's Signature) 證書籤發機構對證書上述內容的簽名值
其實,非對稱加密方式還存在一個很大的問題:它沒法證實非對稱自己是真實的非對稱。好比,打算跟銀行的服務器創建非對稱加密方式的通訊時,怎麼證實收到的非對稱就是該服務器的密鑰呢?畢竟,要調包非對稱是極爲簡單的。這時,數字證書認證機構(CA,Certificated Authority)就出場了。
數字證書認證機構是具備權威性、公正性的機構。它的業務流程是:首先,服務器的開發者向數字證書認證機構提出非對稱(服務器非對稱
)的申請。數字證書認證機構在覈實申請者的身份以後,會用本身的非對稱(數字簽名非對稱
)對申請的非對稱作數字簽名,再將 服務器非對稱
、數字簽名以及申請者身份等信息放入公鑰證書。服務器則將這份由數字證書認證機構頒發的公鑰證書發送給客戶端,以進行非對稱加密方式通訊。公鑰證書也可作數字證書或簡稱爲爲證書。證書就至關因而服務器的身份證。
客戶端接到證書後,使用 數字簽名非對稱
對數字簽名進行驗證,當驗證經過時,也就證實了:一、真實有效的數字證書認證機構。二、真實有效的服務器非對稱
。而後就可能與服務器安全通訊了。其實這裏仍是有一個問題的。那就是如何將 數字簽名非對稱
安全地轉給客戶端?難道再去另外一個認證機制那確認(如今是真有的)?無疑,安全轉交是一件困難的事。所以,經常使用的認證機關的非對稱會被不少瀏覽器內置在裏面。
證書做用這一是證實服務器是否規範,另外一個做用是能夠確認服務器背後的企業是否真實。具備這種特性的證書就是 EV SSL (Extended Validation SSL Certificate)證書。EV SSL 證書是基於國際標準的嚴格身份驗證頒發的證書。經過認證的網站能得到更高的承認度。
EV SSL 證書在視覺上最大的特點在於激活瀏覽器的地址欄的背景色是綠色。並且在地址欄中顯示了 SSL 證書中記錄的組織名稱。這個機制本來是爲了防止用戶被釣魚攻擊的,但效果如何還真不知道,目前來看,不少用戶根本不清楚這是啥玩意兒。
非對稱加密很安全,但與對稱加密相比,因爲非對稱加密的算法複雜性,致使它的加密和解密處理速度都比對稱加密慢不少,效率很低。因此能夠充分利用它們各自的優點,結合起來。先用非對稱加密,交換對稱加密會用的密鑰,以後的通訊交換則使用對稱方式。這就是混合加密。
使用非對稱加密方式安全地交換在稍後的對稱加密中要使用的密鑰
確保交換的密鑰是安全的前提下,使用對稱加密方式進行通訊
而下面所講的具體的SSL協議的過程就是混合加密的一種體現。
TLS的握手階段是發生在TCP握手以後。握手其實是一種協商的過程,對協議所必需的一些參數進行協商。
上圖中的方括號爲可選信息。
(1)Client Hello
因爲客戶端(如瀏覽器)對一些加解密算法的支持程度不同,可是在TLS協議傳輸過程當中必須使用同一套加解密算法才能保證數據可以正常的加解密。在TLS 握手階段,客戶端首先要告知服務端,本身支持哪些加密算法,因此客戶端須要將本地支持的加密套件(Cipher Suite)的列表傳送給服務端。除此以外,客戶端還要產生一個隨機數,這個隨機數一方面須要在客戶端保存,另外一方面須要傳送給服務端,客戶端的隨機數需 要跟服務端產生的隨機數結合起來產生後面要講到的Master Secret。
(2)Server Hello
從Server Hello到Server Done,有些服務端的實現是每條單獨發送,有服務端實現是合併到一塊兒發送。Sever Hello和Server Done都是隻有頭沒有內容的數據。
服務端在接收到客戶端的Client Hello以後,服務端須要將本身的證書發送給客戶端。這個證書是對於服務端的一種認證。例如,客戶端收到了一個來自於稱本身是 www.alipay.com的數據,可是如何證實對方是合法的alipay支付寶呢?這就是證書的做用,支付寶的證書能夠證實它是alipay,而不是 財付通。證書是須要申請,並由專門的數字證書認證機構(CA)經過很是嚴格的審覈以後頒發的電子證書。頒發證書的同時會產生一個私鑰和公鑰。私鑰由服務端 本身保存,不可泄漏。公鑰則是附帶在證書的信息中,能夠公開的。證書自己也附帶一個證書電子簽名,這個簽名用來驗證證書的完整性和真實性,能夠防止證書被 串改。另外,證書還有個有效期。
在服務端向客戶端發送的證書中沒有提供足夠的信息的時候,還能夠向客戶端發送一個Server Key Exchange。 此外,對於很是重要的保密數據,服務端還須要對客戶端進行驗證,以保證數據傳送給了安全的合法的客戶端。服務端能夠向客戶端發出Cerficate Request消息,要求客戶端發送證書對客戶端的合法性進行驗證。跟客戶端同樣,服務端也須要產生一個隨機數發送給客戶端。客戶端和服務端都須要使用這兩個隨機數來產生Master Secret。
最後服務端會發送一個Server Hello Done消息給客戶端,表示Server Hello消息結束了。
(3)Client Key Exchange
若是服務端須要對客戶端進行驗證,在客戶端收到服務端的Server Hello消息以後,首先須要向服務端發送客戶端的證書,讓服務端來驗證客戶端的合法性。
在此以前的全部TLS握手信息都是明文傳送的。在收到服務端的證書等信息以後,客戶端會使用一些加密算法(例如:RSA, Diffie-Hellman)產生一個48個字節的Key,這個Key叫PreMaster Secret,不少材料上也被稱做PreMaster Key, 最終經過Master secret生成session secret, session secret就是用來對應用數據進行加解密的。PreMaster secret屬於一個保密的Key,只要截獲PreMaster secret,就能夠經過以前明文傳送的隨機數,最終計算出session secret,因此PreMaster secret使用RSA非對稱加密的方式,使用服務端傳過來的公鑰進行加密,而後傳給服務端。
接着,客戶端須要對服務端的證書進行檢查,檢查證書的完整性以及證書跟服務端域名是否吻合。ChangeCipherSpec是一個獨立的協議,體如今數據包中就是一個字節的數據,用於告知服務端,客戶端已經切換到以前協商好的加密套件的狀態,準備使用以前協商好的加密套件加密數據並傳輸了。在ChangecipherSpec傳輸完畢以後,客戶端會使用以前協商好的加密套件和session secret加密一段Finish的數據傳送給服務端,此數據是爲了在正式傳輸應用數據以前對剛剛握手創建起來的加解密通道進行驗證。
(4)Server Finish
服務端在接收到客戶端傳過來的PreMaster加密數據以後,使用私鑰對這段加密數據進行解密,並對數據進行驗證,也會使用跟 客戶端一樣的方式生成session secret,一切準備好以後,會給客戶端發送一個ChangeCipherSpec,告知客戶端已經切換到協商過的加密套件狀態,準備使用加密套件和 session secret加密數據了。以後,服務端也會使用session secret加密後一段Finish消息發送給客戶端,以驗證以前經過握手創建起來的加解密通道是否成功。
根據以前的握手信息,若是客戶端和服務端都能對Finish信息進行正常加解密且消息正確的被驗證,則說明握手通道已經創建成功,接下來,雙方可使用上面產生的session secret對數據進行加密傳輸了。
[明文] 客戶端發送隨機數client_random
和支持的加密方式列表
[明文] 服務器返回隨機數server_random
,選擇的加密方式和服務器證書鏈
[RSA] 客戶端驗證服務器證書,使用證書中的公鑰加密premaster secret
發送給服務端
服務端使用私鑰解密premaster secret
兩端分別經過client_random
,server_random
和premaster secret
生成master secret
,用於對稱加密後續通訊內容
使用Diffie–Hellman算法交換premaster secret 的流程
OpenSSL 是用 C 寫的一套 SSL 和 TLS 開源實現。這也就意味着人人均可以基於這個構建屬於本身的認證機構,而後給本身的頒發服務器證書。不過然並卵,其證書不可在互聯網上做爲證書使用。這種自認證機構給本身頒發的證書,叫作自簽名證書。本身給本身做證,天然是算不得數的。因此瀏覽器在訪問這種服務器時,會顯示「沒法確認鏈接安全性」等警告消息。
OpenSSL 在2014年4月,被爆出一個內存溢出引出的 BUG,駭客利用這點能拿到服務器不少信息,其中就包括私鑰,也就使得 HTTPS 形同虛設。當時全世界大概有一百萬左右的服務器有受到此漏洞的影響。因爲 OpenSSL 舉足輕重的做用,再加上足夠致命的問題,使得這個 BUG 被形容爲「互聯網心臟出血」。這是近年來互聯網最嚴重的安全事件。
記得OpenSSL的Heartbleed漏洞纔出來的時候,筆者所在的安全公司忙成了一團糟,處處幫忙修補漏洞。
Let’s Encrypt是由ISRG(Internet Security Research Group)提供的免費SSL項目,現由Linux基金會託管,他的來頭很大,由Mozilla、思科、Akamai、IdenTrust和EFF等組織 發起,如今已經獲得Google、Facebook等大公司的支持和贊助,目的就是向網站免費簽發和管理證書,而且經過其自身的自動化過程,消除了購買、 安裝證書的複雜性,只需幾行命令,就能夠完成證書的生成並投入使用,甚至十幾分鍾就可讓本身的http站點華麗轉變成Https站點。
(1)執行如下命令
git clone https://github.com/letsencrypt/letsencrypt cd letsencrypt ./letsencrypt-auto certonly --email xxx@xx.com
提示:
若是提示git命令無效的話,須要安裝一下GIt,直接執行命令 yum install git-all 完成安裝,
2.若是是RedHat/CentOs6系統的話,須要提早安裝EPEL(Extra Packages for Enterprise Linux),執行命令 yum install epel-release
整個過程須要主機鏈接外網,不然會致使報如下錯誤
IMPORTANT NOTES: - The following errors were reported by the server: Domain: on-img.com Type: urn:acme:error:connection Detail: Failed to connect to host for DVSNI challenge Domain: www.on-img.com Type: urn:acme:error:connection Detail: Failed to connect to host for DVSNI challenge
Let's encrypt 是由python編寫的開源項目,基於python2.7環境,若是系統安裝的是python2.6,會提示升級 。也能夠執行如下命令(官方不推薦) ./letsencrypt-auto certonly --email xxx@xx.com --debug
(2)接下來提示輸入域名 多個用空格隔開
出現如下提示說明證書生成成功
進入 /etc/letsencrypt/live/on-img.com/
下,on-img.com 是第二部中填寫的域名,到時候換成本身的域名便可。
cert.pem 服務器證書
privkey.pem 是證書私鑰
若是是雲服務器+負載均衡的話,直接添加以上證書,綁定負載均衡,直接訪問https:// xxx.com。若是是本身配置的Nginx的,須要如下配置 :
server { listen 443 ssl; / server_name xxx.com; //這裏是你的域名 index index.html index.htm index.php default.html default.htm default.php; root /opt/wwwroot/ //網站目錄 ssl_certificate /etc/letsencrypt/live/test.com/fullchain.pem; //前面生成的證書,改一下里面的域名就行,不建議更換路徑 ssl_certificate_key /etc/letsencrypt/live/test.com/privkey.pem; //前面生成的密鑰,改一下里面的域名就行,不建議更換路徑 ........ }
若是是使用的Apache服務器,
在生成證書後也須要修改一下apache的配置文件 /usr/local/apache/conf/httpd.conf ,查找httpd-ssl將前面的#去掉。
而後再執行:
cat >/usr/local/apache/conf/extra/httpd-ssl.conf<<EOF Listen 443 AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLProxyCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLHonorCipherOrder on SSLProtocol all -SSLv2 -SSLv3 SSLProxyProtocol all -SSLv2 -SSLv3 SSLPassPhraseDialog builtin SSLSessionCache "shmcb:/usr/local/apache/logs/ssl_scache(512000)" SSLSessionCacheTimeout 300 SSLMutex "file:/usr/local/apache/logs/ssl_mutex" EOF
並在對應apache虛擬主機配置文件的最後下面添加上SSL部分的配置文件:
<VirtualHost *:443> DocumentRoot /home/wwwroot/www.vpser.net //網站目錄 ServerName www.vpser.net:443 //域名 ServerAdmin licess@vpser.net //郵箱 ErrorLog "/home/wwwlogs/www.vpser.net-error_log" //錯誤日誌 CustomLog "/home/wwwlogs/www.vpser.net-access_log" common //訪問日誌 SSLEngine on SSLCertificateFile /etc/letsencrypt/live/www.test.net/fullchain.pem //改一下里面的域名就行,不建議更換路徑 SSLCertificateKeyFile /etc/letsencrypt/live/www.test.net/privkey.pem //改一下里面的域名就行,不建議更換路徑 <Directory "/home/wwwroot/www.vpser.net"> //網站目錄 SetOutputFilter DEFLATE Options FollowSymLinks AllowOverride All Order allow,deny Allow from all DirectoryIndex index.html index.php </Directory> </VirtualHost>
(1)安裝
npm install auto-sni
(2)建立服務器
var createServer = require("auto-sni"); var server = createServer({ email: ..., // Emailed when certificates expire. agreeTos: true, // Required for letsencrypt. debug: true, // Add console messages and uses staging LetsEncrypt server. (Disable in production) domains: ["mysite.com", ["test.com", "www.test.com"]], // List of accepted domain names. (You can use nested arrays to register bundles with LE). forceSSL: true, // Make this false to disable auto http->https redirects (default true). ports: { http: 80, // Optionally override the default http port. https: 443 // // Optionally override the default https port. } }); // Server is a "https.createServer" instance. server.once("listening", ()=> { console.log("We are ready to go."); }); //使用Express var createServer = require("auto-sni"); var express = require("express"); var app = express(); app.get("/test", ...); createServer({ email: ..., agreeTos: true }, app);
如今不少用戶使用的仍是低版本的瀏覽器,它們對於SSL/TLS協議支持的也不是很好,所以怎麼爲服務器選定一個正確的HTTPS也比較麻煩,幸虧Mozilla提供了一個在線生成配置的工具,非常不錯:
在你正確配置了你的站點以後,很是推薦使用SSL Labs這個在線測試工具來檢查下你站點到底配置的是否安全。
<VirtualHost *:443> ... SSLEngine on SSLCertificateFile /path/to/signed_certificate_followed_by_intermediate_certs SSLCertificateKeyFile /path/to/private/key SSLCACertificateFile /path/to/all_ca_certs # HSTS (mod_headers is required) (15768000 seconds = 6 months) Header always set Strict-Transport-Security "max-age=15768000" ... </VirtualHost> # intermediate configuration, tweak to your needs SSLProtocol all -SSLv3 SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off # OCSP Stapling, only in httpd 2.3.3 and later SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off SSLStaplingCache shmcb:/var/run/ocsp(128000)
server { listen 80 default_server; listen [::]:80 default_server; # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate ssl_certificate /path/to/signed_cert_plus_intermediates; ssl_certificate_key /path/to/private_key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits ssl_dhparam /path/to/dhparam.pem; # intermediate configuration. tweak to your needs. ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; ssl_prefer_server_ciphers on; # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) add_header Strict-Transport-Security max-age=15768000; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on; ## verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; resolver <IP DNS resolver>; .... }
$SERVER["socket"] == ":443" { protocol = "https://" ssl.engine = "enable" ssl.disable-client-renegotiation = "enable" # pemfile is cert+privkey, ca-file is the intermediate chain in one file ssl.pemfile = "/path/to/signed_cert_plus_private_key.pem" ssl.ca-file = "/path/to/intermediate_certificate.pem" # for DH/DHE ciphers, dhparam should be >= 2048-bit ssl.dh-file = "/path/to/dhparam.pem" # ECDH/ECDHE ciphers curve strength (see `openssl ecparam -list_curves`) ssl.ec-curve = "secp384r1" # Compression is by default off at compile-time, but use if needed # ssl.use-compression = "disable" # Environment flag for HTTPS enabled setenv.add-environment = ( "HTTPS" => "on" ) # intermediate configuration, tweak to your needs ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" ssl.honor-cipher-order = "enable" ssl.cipher-list = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS" # HSTS(15768000 seconds = 6 months) setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=15768000;" ) ... }
global # set default parameters to the intermediate configuration tune.ssl.default-dh-param 2048 ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS ssl-default-bind-options no-sslv3 no-tls-tickets ssl-default-server-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS ssl-default-server-options no-sslv3 no-tls-tickets frontend ft_test mode http bind :443 ssl crt /path/to/<cert+privkey+intermediate+dhparam> bind :80 redirect scheme https code 301 if !{ ssl_fc } # HSTS (15768000 seconds = 6 months) rspadd Strict-Transport-Security:\ max-age=15768000
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Example ELB with Mozilla recommended ciphersuite", "Parameters": { "SSLCertificateId": { "Description": "The ARN of the SSL certificate to use", "Type": "String", "AllowedPattern": "^arn:[^:]*:[^:]*:[^:]*:[^:]*:.*$", "ConstraintDescription": "SSL Certificate ID must be a valid ARN. http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns" } }, "Resources": { "ExampleELB": { "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Listeners": [ { "LoadBalancerPort": "443", "InstancePort": "80", "PolicyNames": [ "Mozilla-intermediate-2015-03" ], "SSLCertificateId": { "Ref": "SSLCertificateId" }, "Protocol": "HTTPS" } ], "AvailabilityZones": { "Fn::GetAZs": "" }, "Policies": [ { "PolicyName": "Mozilla-intermediate-2015-03", "PolicyType": "SSLNegotiationPolicyType", "Attributes": [ { "Name": "Protocol-TLSv1", "Value": true }, { "Name": "Protocol-TLSv1.1", "Value": true }, { "Name": "Protocol-TLSv1.2", "Value": true }, { "Name": "Server-Defined-Cipher-Order", "Value": true }, { "Name": "ECDHE-ECDSA-CHACHA20-POLY1305", "Value": true }, { "Name": "ECDHE-RSA-CHACHA20-POLY1305", "Value": true }, { "Name": "ECDHE-ECDSA-AES128-GCM-SHA256", "Value": true }, { "Name": "ECDHE-RSA-AES128-GCM-SHA256", "Value": true }, { "Name": "ECDHE-ECDSA-AES256-GCM-SHA384", "Value": true }, { "Name": "ECDHE-RSA-AES256-GCM-SHA384", "Value": true }, { "Name": "DHE-RSA-AES128-GCM-SHA256", "Value": true }, { "Name": "DHE-RSA-AES256-GCM-SHA384", "Value": true }, { "Name": "ECDHE-ECDSA-AES128-SHA256", "Value": true }, { "Name": "ECDHE-RSA-AES128-SHA256", "Value": true }, { "Name": "ECDHE-ECDSA-AES128-SHA", "Value": true }, { "Name": "ECDHE-RSA-AES256-SHA384", "Value": true }, { "Name": "ECDHE-RSA-AES128-SHA", "Value": true }, { "Name": "ECDHE-ECDSA-AES256-SHA384", "Value": true }, { "Name": "ECDHE-ECDSA-AES256-SHA", "Value": true }, { "Name": "ECDHE-RSA-AES256-SHA", "Value": true }, { "Name": "DHE-RSA-AES128-SHA256", "Value": true }, { "Name": "DHE-RSA-AES128-SHA", "Value": true }, { "Name": "DHE-RSA-AES256-SHA256", "Value": true }, { "Name": "DHE-RSA-AES256-SHA", "Value": true }, { "Name": "ECDHE-ECDSA-DES-CBC3-SHA", "Value": true }, { "Name": "ECDHE-RSA-DES-CBC3-SHA", "Value": true }, { "Name": "EDH-RSA-DES-CBC3-SHA", "Value": true }, { "Name": "AES128-GCM-SHA256", "Value": true }, { "Name": "AES256-GCM-SHA384", "Value": true }, { "Name": "AES128-SHA256", "Value": true }, { "Name": "AES256-SHA256", "Value": true }, { "Name": "AES128-SHA", "Value": true }, { "Name": "AES256-SHA", "Value": true }, { "Name": "DES-CBC3-SHA", "Value": true } ] } ] } } }, "Outputs": { "ELBDNSName": { "Description": "DNS entry point to the stack (all ELBs)", "Value": { "Fn::GetAtt": [ "ExampleELB", "DNSName" ] } } } } ``` ![](https://coding.net/u/hoteam/p/Cache/git/raw/master/2016/7/3/6803.png)