有很多網站只經過HTTPS對外提供服務,但用戶在訪問某個網站的時候,在瀏覽器裏卻每每直接輸入網站域名(例如www.example.com
),而不是輸入完整的URL(例如https://www.example.com
),不過瀏覽器依然能正確的使用HTTPS發起請求。這背後多虧了服務器和瀏覽器的協做,以下圖所示。web
簡單來說就是,瀏覽器向網站發起一次HTTP請求,在獲得一個重定向響應後,發起一次HTTPS請求並獲得最終的響應內容。全部的這一切對用戶而言是徹底透明的,因此在用戶眼裏看來,在瀏覽器裏直接輸入域名卻依然能夠用HTTPS協議和網站進行安全的通訊,是個不錯的用戶體驗。chrome
一切看上去都是那麼的完美,但其實否則,因爲在創建起HTTPS鏈接以前存在一次明文的HTTP請求和重定向(上圖中的第一、2步),使得攻擊者能夠以中間人的方式劫持此次請求,從而進行後續的攻擊,例如竊聽數據,篡改請求和響應,跳轉到釣魚網站等。瀏覽器
以劫持請求並跳轉到釣魚網站爲例,其大體作法以下圖所示:緩存
這個攻擊的精妙之處在於,攻擊者直接劫持了HTTP請求,並返回了內容給瀏覽器,根本不給瀏覽器同真實網站創建HTTPS鏈接的機會,所以瀏覽器會誤覺得真實網站經過HTTP對外提供服務,天然也就不會向用戶報告當前的鏈接不安全。因而乎攻擊者幾乎能夠神不知鬼不覺的對請求和響應動手腳。安全
既然創建HTTPS鏈接以前的這一次HTTP明文請求和重定向有可能被攻擊者劫持,那麼解決這一問題的思路天然就變成了如何避免出現這樣的HTTP請求。咱們指望的瀏覽器行爲是,當用戶讓瀏覽器發起HTTP請求的時候,瀏覽器將其轉換爲HTTPS請求,直接略過上述的HTTP請求和重定向,從而使得中間人攻擊失效,規避風險。其大體流程以下:服務器
那麼問題來了,瀏覽器是如何作到這一點的呢?它怎麼知道那個網站應該發HTTPS請求,那個網站應該用HTTP請求呢?此時就該HSTS粉墨登場了。框架
HSTS的全稱是HTTP Strict-Transport-Security,它是一個Web安全策略機制(web security policy mechanism)。性能
HSTS最先於2015年被歸入到ThoughtWorks技術雷達,而且在2016年的最新一期技術雷達裏,它直接從「評估(Trial)」階段進入到了「採用(Adopt)「階段,這意味着ThoughtWorks強烈主張業界積極採用這項安全防護措施,而且ThoughtWorks已經將其應用於本身的項目。網站
HSTS最爲核心的是一個HTTP響應頭(HTTP Response Header)。正是它可讓瀏覽器得知,在接下來的一段時間內,當前域名只能經過HTTPS進行訪問,而且在瀏覽器發現當前鏈接不安全的狀況下,強制拒絕用戶的後續訪問要求。搜索引擎
HSTS Header的語法以下:
Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload]
其中:
max-age
是必選參數,是一個以秒爲單位的數值,它表明着HSTS Header的過時時間,一般設置爲1年,即31536000秒。includeSubDomains
是可選參數,若是包含它,則意味着當前域名及其子域名均開啓HSTS保護。preload
是可選參數,只有當你申請將本身的域名加入到瀏覽器內置列表的時候才須要使用到它。關於瀏覽器內置列表,下文有詳細介紹。只要在服務器返回給瀏覽器的響應頭中,增長Strict-Transport-Security
這個HTTP Header(下文簡稱HSTS Header),例如:
Strict-Transport-Security: max-age=31536000; includeSubDomains
就能夠告訴瀏覽器,在接下來的31536000秒內(1年),對於當前域名及其子域名的後續通訊應該強制性的只使用HTTPS,直到超過有效期爲止。
完整的流程以下圖所示:
只要是在有效期內,瀏覽器都將直接強制性的發起HTTPS請求,可是問題又來了,有效期過了怎麼辦?其實不用爲此過多擔憂,由於HSTS Header存在於每一個響應中,隨着用戶和網站的交互,這個有效時間時刻都在刷新,再加上有效期一般都被設置成了1年,因此只要用戶的先後兩次請求之間的時間間隔沒有超過1年,則基本上不會出現安全風險。更況且,就算超過了有效期,可是隻要用戶和網站再進行一次新的交互,用戶的瀏覽器又將開啓有效期爲1年的HSTS保護。
在沒有HSTS保護的狀況下,當瀏覽器發現當前網站的證書出現錯誤,或者瀏覽器和服務器之間的通訊不安全,沒法創建HTTPS鏈接的時候,瀏覽器一般會警告用戶,可是卻又容許用戶繼續不安全的訪問。以下圖所示,用戶能夠點擊圖中紅色方框中的連接,繼續在不安全的鏈接下進行訪問。
理論上而言,用戶看到這個警告以後就應該提升警戒,意識到本身和網站之間的通訊不安全,可能被劫持也可能被竊聽,若是訪問的剛好是銀行、金融類網站的話後果更是不堪設想,理應終止後續操做。然而現實很殘酷,就個人實際觀察來看,有很多用戶在遇到這樣的警告以後依然選擇了繼續訪問。
不過隨着HSTS的出現,事情有了起色。對於啓用了瀏覽器HSTS保護的網站,若是瀏覽器發現當前鏈接不安全,它將僅僅警告用戶,而再也不給用戶提供是否繼續訪問的選擇,從而避免後續安全問題的發生。例如,當訪問Google搜索引擎的時候,若是當前通訊鏈接存在安全問題,瀏覽器將會完全阻止用戶繼續訪問Google,以下圖所示。
細心的你可能發現了,HSTS存在一個比較薄弱的環節,那就是瀏覽器沒有當前網站的HSTS信息的時候,或者第一次訪問網站的時候,依然須要一次明文的HTTP請求和重定向才能切換到HTTPS,以及刷新HSTS信息。而就是這麼一瞬間卻給攻擊者留下了可乘之機,使得他們能夠把這一次的HTTP請求劫持下來,繼續中間人攻擊。
針對上面的攻擊,HSTS也有應對辦法,那就是在瀏覽器裏內置一個列表,只要是在這個列表裏的域名,不管什麼時候、何種狀況,瀏覽器都只使用HTTPS發起鏈接。這個列表由Google Chromium維護,FireFox、Safari、IE等主流瀏覽器均在使用。
不少地方均可以進行HSTS的配置,例如反向代理服務器、應用服務器、應用程序框架,以及應用程序中自定義Header。你能夠根據實際狀況進行選擇。
常見的是在代理服務器中進行配置,以Nginx爲例,只需在配置文件中加上下面這條指令便可:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
不過須要特別注意的是,在生產環境下使用HSTS應當特別謹慎,由於一旦瀏覽器接收到HSTS Header(假若有效期是1年),可是網站的證書又剛好出了問題,那麼用戶將在接下來的1年時間內都沒法訪問到你的網站,直到證書錯誤被修復,或者用戶主動清除瀏覽器緩存。所以,建議在生產環境開啓HSTS的時候,先將max-age
的值設置小一些,例如5分鐘,而後檢查HSTS是否能正常工做,網站可否正常訪問,以後再逐步將時間延長,例如1周、1個月,並在這個時間範圍內繼續檢查HSTS是否正常工做,最後才改到1年。
根據官方說明,你的網站在具有如下幾個條件後,能夠提出申請加入到這個列表裏。
includeSubDomains
參數preload
參數https://hstspreload.org
)提交申請,或者瞭解更多詳細的內容。從提交申請到完成審覈,成功加入到內置列表 ,中間可能須要等待幾天到幾周不等的時間。可經過官網https://hstspreload.org
或在Chrome地址欄裏輸入chrome://net-internals/#hsts
查詢狀態。
隨着愈來愈多的網站開始使用HTTPS,甚至是開啓全站HTTPS,數據在傳輸過程當中的安全性可以獲得極大的保障,與此同時,經過HSTS的幫助,避免SSL Stripping或者中間人攻擊,可以使得數據通訊變得更加安全。但願本篇文章經過對HSTS的解析,能使得更多的開發團隊將HSTS運用到本身的項目中。