HTTPS 理論詳解與實踐
Introduction
前置閱讀:Web應用安全基礎
在進行 HTTP 通信時,信息可能會監聽、服務器或客戶端身份偽裝等安全問題,HTTPS 則能有效解決這些問題。在使用原始的HTTP連接的時候,因為服務器與用戶之間是直接進行的明文傳輸,導致了用戶面臨著很多的風險與威脅。攻擊者可以用中間人攻擊來輕易的 截獲或者篡改傳輸的數據。攻擊者想要做些什么并沒有任何的限制,包括竊取用戶的Session信息、注入有害的代碼等,乃至于修改用戶傳送至服務器的數據。
我們并不能替用戶選擇所使用的網絡,他們很有可能使用一個開放的,任何人都可以竊聽的網絡,譬如一個咖啡館或者機場里面的開放WiFi網絡。普通的 用戶很有可能被欺騙地隨便連上一個叫免費熱點的網絡,或者使用一個可以隨便被插入廣告的網路當中。如果攻擊者會竊聽或者篡改網路中的數據,那么用戶與服務 器交換的數據就好不可信了,幸好我們還可以使用HTTPS來保證傳輸的安全性。HTTPS最早主要用于類似于經融這樣的安全要求較高的敏感網絡,不過現在日漸被各種各樣的網站鎖使用,譬如我們常用的社交網絡或者搜索引擎。 HTTPS協議使用的是TLS協議,一個優于SSL協議的標準來保障通信安全。只要配置與使用得當,就能有效抵御竊聽與篡改,從而有效保護我們將要去訪問 的網站。用更加技術化的方式說,HTTPS能夠有效保障數據機密性與完整性,并且能夠完成用戶端與客戶端的雙重驗證。
隨著面臨的風險日漸增多,我們應該將所有的網絡數據當做敏感數據并且進行加密傳輸。已經有很多的瀏覽器廠商宣稱要廢棄所有的非HTTPS的請求,乃 至于當用戶訪問非HTTPS的網站的時候給出明確的提示。很多基于HTTP/2的實現都只支持基于TLS的通信,所以我們現在更應當在全部地方使用 HTTPS。目前如果要大范圍推廣使用HTTPS還是有一些障礙的,在一個很長的時間范圍內使用HTTPS會被認為造成很多的計算資源的浪費,不過隨著現代硬件 與瀏覽器的發展,這點計算資源已經不足為道。早期的SSL協議與TLS協議只支持一個IP地址分配一個整數,不過現在這種限制所謂的SNI的協議擴展來解 決。另外,從一個證書認證機構獲取證書也會打消一些用戶使用HTTPS的念頭,不過下面我們介紹的像Let's Encrypt這樣的免費的服務就可以打破這種障礙。
Why HTTPS?
HTTP日常使用極為廣泛的協議,它很優秀且方便,但還是存在一些問題,如:
-
明文通信,內容可以直接被竊聽
-
無法驗證報文的完整性,可能被篡改
-
通信方身份不驗證,可能遇到假的客戶端或服務器
中間人攻擊與內容竊聽
HTTP 不會對請求和響應的內容進行加密,報文直接使用明文發送。報文在服務器與客戶端流轉中間,會經過若干個結點,這些結點中隨時都可能會有竊聽行為。因為通信一定會經過中間很多個結點,所以就算是報文經過了加密,也一樣會被竊聽到,不過是竊聽到加密后的內容。要竊聽相同段上的通信還是很簡單的,比如可以使用常用的抓包工具 Wireshark。這種情況下,保護信息安全最常用的方式就是采取加密了,加密方式可以根據加密對象分以下幾種:
(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 網站服務器的證書的有效性,再得到其確認后,再開始與服務器進行通信。
Definition
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 協議使用,也可以給它們增強安全性。整個架構如下圖所示:
Performance
HTTPS 使用 SSL 通信,所以它的處理速度會比 HTTP 要慢。
一是通信慢。它和 HTTP 相比,網絡負載會變慢 2 到 100倍。除去和 TCP 連接、發送 HTTP 請求及響應外,還必須進行 SSL 通信,因此整體上處理通信量會不可避免的增加。
二是 SSL 必須進行加密處理。在服務器和客戶端都需要進行加密和解密的去處處理。所以它比 HTTP 會更多地消耗服務器和客戶端的硬件資源。
Reference
SSL/TLS Protocol
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 stateHandshake Protocol Change Cipher Spec</pre>
初始當前狀態(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:第三方可信證書頒發機構
其實,非對稱加密方式還存在一個很大的問題:它無法證明非對稱本身是真實的非對稱。比如,打算跟銀行的服務器建立非對稱加密方式的通信時,怎么證明收到的非對稱就是該服務器的密鑰呢?畢竟,要調包非對稱是極為簡單的。這時,數字證書認證機構(CA,Certificated Authority)就出場了。
數字證書認證機構是具有權威性、公正性的機構。它的業務流程是:首先,服務器的開發者向數字證書認證機構提出非對稱( 服務器非對稱 )的申請。數字證書認證機構在核實申請者的身份之后,會用自己的非對稱( 數字簽名非對稱 )對申請的非對稱做數字簽名,再將 服務器非對稱 、數字簽名以及申請者身份等信息放入公鑰證書。服務器則將這份由數字證書認證機構頒發的公鑰證書發送給客戶端,以進行非對稱加密方式通信。公鑰證書也可做數字證書或簡稱為為證書。證書就相當于是服務器的身份證。
客戶端接到證書后,使用 數字簽名非對稱 對數字簽名進行驗證,當驗證通過時,也就證明了:1、真實有效的數字證書認證機構。2、真實有效的 服務器非對稱 。然后就可能與服務器安全通信了。其實這里還是有一個問題的。那就是如何將 數字簽名非對稱 安全地轉給客戶端?難道再去另一個認證機制那確認(現在是真有的)?無疑,安全轉交是一件困難的事。因此,常用的認證機關的非對稱會被很多瀏覽器內置在里面。
Extended Validation SSL Certificate
證書作用這一是證明服務器是否規范,另一個作用是可以確認服務器背后的企業是否真實。具有這種特性的證書就是 EV SSL (Extended Validation SSL Certificate)證書。EV SSL 證書是基于國際標準的嚴格身份驗證頒發的證書。通過認證的網站能獲得更高的認可度。
EV SSL 證書在視覺上最大的特色在于激活瀏覽器的地址欄的背景色是綠色。而且在地址欄中顯示了 SSL 證書中記錄的組織名稱。這個機制原本是為了防止用戶被釣魚攻擊的,但效果如何還真不知道,目前來看,很多用戶根本不清楚這是啥玩意兒。
混合加密
非對稱加密很安全,但與對稱加密相比,由于非對稱加密的算法復雜性,導致它的加密和解密處理速度都比對稱加密慢很多,效率很低。所以可以充分利用它們各自的優勢,結合起來。先用非對稱加密,交換對稱加密會用的密鑰,之后的通信交換則使用對稱方式。這就是混合加密。
使用非對稱加密方式安全地交換在稍后的對稱加密中要使用的密鑰
確保交換的密鑰是安全的前提下,使用對稱加密方式進行通信
而下面所講的具體的SSL協議的過程就是混合加密的一種體現。
TLS HandShake
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對數據進行加密傳輸了。
基于RSA的握手
[明文] 客戶端發送隨機數 client_random 和支持的加密方式列表
[明文] 服務器返回隨機數 server_random ,選擇的加密方式和服務器證書鏈
[RSA] 客戶端驗證服務器證書,使用證書中的公鑰加密 premaster secret 發送給服務端
服務端使用私鑰解密 premaster secret
兩端分別通過 client_random , server_random 和 premaster secret 生成 master secret ,用于對稱加密后續通信內容
基于Diffie–Hellman的握手
使用Diffie–Hellman算法交換premaster secret 的流程
HTTPS Tools
OpenSSL
OpenSSL 是用 C 寫的一套 SSL 和 TLS 開源實現。這也就意味著人人都可以基于這個構建屬于自己的認證機構,然后給自己的頒發服務器證書。不過然并卵,其證書不可在互聯網上作為證書使用。這種自認證機構給自己頒發的證書,叫做自簽名證書。自己給自己作證,自然是算不得數的。所以瀏覽器在訪問這種服務器時,會顯示“無法確認連接安全性”等警告消息。
OpenSSL 在2014年4月,被爆出一個內存溢出引出的 BUG,駭客利用這點能拿到服務器很多信息,其中就包括私鑰,也就使得 HTTPS 形同虛設。當時全世界大概有一百萬左右的服務器有受到此漏洞的影響。由于 OpenSSL 舉足輕重的作用,再加上足夠致命的問題,使得這個 BUG 被形容為“互聯網心臟出血”。這是近年來互聯網最嚴重的安全事件。
記得OpenSSL的Heartbleed漏洞才出來的時候,筆者所在的安全公司忙成了一團糟,到處幫忙修補漏洞。
Let's Encrypt:免費SSL
Let’s Encrypt是由ISRG(Internet Security Research Group)提供的免費SSL項目,現由Linux基金會托管,他的來頭很大,由Mozilla、思科、Akamai、IdenTrust和EFF等組織 發起,現在已經得到Google、非死book等大公司的支持和贊助,目的就是向網站免費簽發和管理證書,并且通過其自身的自動化過程,消除了購買、 安裝證書的復雜性,只需幾行命令,就可以完成證書的生成并投入使用,甚至十幾分鐘就可以讓自己的http站點華麗轉變成Https站點。
Installation
(1)執行以下命令
git clone https://github.com/letsencrypt/letsencryptcd letsencrypt
./letsencrypt-auto certonly --email xxx@xx.com </pre>
提示:
如果提示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 challengeDomain: www.on-img.com
Type: urn:acme:error:connection
Detail: Failed to connect to host for DVSNI challenge</pre> </li>- </ol>
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></pre>
auto-sni :自動構建基于HTTPS的NodeJS服務端
(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);</pre>
SSL Configuration Generator
現在很多用戶使用的還是低版本的瀏覽器,它們對于SSL/TLS協議支持的也不是很好,因此怎么為服務器選定一個正確的HTTPS也比較麻煩,幸好Mozilla提供了一個在線生成配置的 工具 ,很是不錯:
SSL Server Test
在你正確配置了你的站點之后,非常推薦使用 SSL Labs 這個在線測試工具來檢查下你站點到底配置的是否安全。
HTTPS Configuration
Apache
<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)</pre>
Nginx
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>; ....
}</pre>
Lighttpd
$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;" ) ...
}</pre>
HAProxy
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</pre>
AWS ELB
{ "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.來自: https://segmentfault.com/a/1190000004985253 </pre>