HSTS在瀏覽器上的應用詳解
緣起:啟用HTTPS也不夠安全
有不少網站只通過HTTPS對外提供服務,但用戶在訪問某個網站的時候,在瀏覽器里卻往往直接輸入網站域名(例如www.example.com),而不是完整的URL(例如https://www.example.com),不過瀏覽器依然能正確的使用HTTPS發起請求。這背后多虧了服務器和瀏覽器的協作,如下圖所示。
圖1:服務器和瀏覽器在背后幫用戶做了很多工作
簡單來講就是,瀏覽器向網站發起一次HTTP請求,在得到一個重定向響應后,發起一次HTTPS請求并得到最終的響應內容。所有的這一切對用戶而言是完全透明的,所以在用戶看來,在瀏覽器里直接輸入域名卻依然可以用HTTPS協議和網站進行安全的通信,是個不錯的用戶體驗。
一切看上去都是那么的完美,但其實不然,由于在建立起HTTPS連接之前存在一次明文的HTTP請求和重定向(上圖中的第1、2步),使得攻擊者可以以中間人的方式劫持這次請求,從而進行后續的攻擊,例如竊聽數據、篡改請求和響應、跳轉到釣魚網站等。
以劫持請求并跳轉到釣魚網站為例,其大致做法如下圖所示:
圖2:劫持HTTP請求,阻止HTTPS連接,并進行釣魚攻擊
- 第1步:瀏覽器發起一次明文HTTP請求,但實際上會被攻擊者攔截下來
- 第2步:攻擊者作為代理,把當前請求轉發給釣魚網站
- 第3步:釣魚網站返回假冒的網頁內容
- 第4步:攻擊者把假冒的網頁內容返回給瀏覽
這個攻擊的精妙之處在于,攻擊者直接劫持了HTTP請求,并返回了內容給瀏覽器,根本不給瀏覽器同真實網站建立HTTPS連接的機會,因此瀏覽器會誤以為真實網站通過HTTP對外提供服務,自然也就不會向用戶報告當前的連接不安全。于是乎攻擊者幾乎可以神不知鬼不覺的對請求和響應動手腳。
解決之道:使用HSTS
既然建立HTTPS連接之前的這一次HTTP明文請求和重定向有可能被攻擊者劫持,那么解決這一問題的思路自然就變成了如何避免出現這樣的HTTP請求。我們期望的瀏覽器行為是,當用戶讓瀏覽器發起HTTP請求的時候,瀏覽器將其轉換為HTTPS請求,直接略過上述的HTTP請求和重定向,從而使得中間人攻擊失效,以規避風險。其大致流程如下:
圖3:略過HTTP請求和重定向,直接發送HTTPS請求
- 第1步:用戶在瀏覽器地址欄里輸入網站域名,瀏覽器得知該域名應該使用HTTPS進行通信
- 第2步:瀏覽器直接向網站發起HTTPS請求
- 第3步:網站返回相應的內容那么問題來了,瀏覽器是如何做到這一點的呢?它怎么知道哪個網站應該發HTTPS請求,哪個網站應該用HTTP請求呢?此時就該HSTS閃亮登場了。
HSTS
HSTS的全稱是HTTP Strict-Transport-Security,它是一個Web安全策略機制(web security policy mechanism)。
HSTS最早于2015年被納入到ThoughtWorks技術雷達,并且在2016年的最新一期技術雷達里,它直接從“評估”階段進入到了“采用”階段,這意味著ThoughtWorks強烈主張業界積極采用這項安全防御措施,并且ThoughtWorks已經將其應用于自己的項目。
HSTS最為核心的是一個HTTP響應頭(HTTP Response Header)。正是它可以讓瀏覽器得知,在接下來的一段時間內,當前域名只能通過HTTPS進行訪問,并且在瀏覽器發現當前連接不安全的情況下,強制拒絕用戶的后續訪問要求。
HSTS Header的語法如下:
- Strict-Transport-Security: <max-agemax-age=>[; includeSubDomains][; preload]
其中:
- max-age是必選參數,是一個以秒為單位的數值,它代表著HSTS Header的過期時間,通常設置為1年,即31536000秒。
- includeSubDomains是可選參數,如果包含它,則意味著當前域名及其子域名均開啟HSTS保護。
- preload是可選參數,只有當你申請將自己的域名加入到瀏覽器內置列表的時候才需要使用到它。關于瀏覽器內置列表,下文有詳細介紹。
讓瀏覽器直接發起HTTPS請求
只要在服務器返回給瀏覽器的響應頭中,增加Strict-Transport-Security這個HTTP Header(下文簡稱HSTS Header),例如:
- Strict-Transport-Security: max-age=31536000; includeSubDomains
就可以告訴瀏覽器,在接下來的31536000秒(1年)內,對于當前域名及其子域名的后續通信應該強制性的只使用HTTPS,直到超過有效期為止。
完整的流程如下圖所示:
圖4:完整的HSTS流程
只要是在有效期內,瀏覽器都將直接強制性的發起HTTPS請求,但是問題又來了,有效期過了怎么辦?其實不用為此過多擔心,因為HSTS Header存在于每個響應中,隨著用戶和網站的交互,這個有效時間時刻都在刷新,再加上有效期通常都被設置成了1年,所以只要用戶的前后兩次請求之間的時間間隔沒有超過1年,則基本上不會出現安全風險。更何況,就算超過了有效期,只要用戶和網站再進行一次新的交互,用戶的瀏覽器又將開啟有效期為1年的HSTS保護。
強制拒絕不安全的鏈接,不給用戶選擇的機會
在沒有HSTS保護的情況下,當瀏覽器發現當前網站的證書出現錯誤,或者瀏覽器和服務器之間的通信不安全,無法建立HTTPS連接的時候,瀏覽器通常會警告用戶,但是卻又允許用戶繼續不安全的訪問。如下圖所示,用戶可以點擊圖中紅色方框中的鏈接,繼續在不安全的連接下進行訪問。
圖5:瀏覽器依然允許用戶進行不安全的訪問
理論上而言,用戶看到這個警告之后就應該提高警惕,意識到自己和網站之間的通信不安全,可能被劫持也可能被竊聽,如果訪問的恰好是銀行、金融類網站的話后果更是不堪設想,理應終止后續操作。然而現實很殘酷,就我的實際觀察來看,有不少用戶在遇到這樣的警告之后依然選擇了繼續訪問。
不過隨著HSTS的出現,事情有了轉機。對于啟用了瀏覽器HSTS保護的網站,如果瀏覽器發現當前連接不安全,它將僅僅警告用戶,而不再給用戶提供是否繼續訪問的選擇,從而避免后續安全問題的發生。例如,當訪問Google搜索引擎的時候,如果當前通信連接存在安全問題,瀏覽器將會徹底阻止用戶繼續訪問Google,如下圖所示。
圖6:瀏覽器徹底阻止用戶繼續進行不安全的訪問
道高一尺魔高一丈:攻擊者依然有可乘之機
細心的你可能發現了,HSTS存在一個比較薄弱的環節,那就是瀏覽器沒有當前網站的HSTS信息的時候,或者第一次訪問網站的時候,依然需要一次明文的HTTP請求和重定向才能切換到HTTPS,以及刷新HSTS信息。而就是這么一瞬間卻給攻擊者留下了可乘之機,使得他們可以把這一次的HTTP請求劫持下來,繼續中間人攻擊。
Preload List:讓防御更加徹底
針對上面的攻擊,HSTS也有應對辦法,那就是在瀏覽器里內置一個列表,只要是在這個列表里的域名,無論何時、何種情況,瀏覽器都只使用HTTPS發起連接。這個列表由Google Chromium維護,FireFox、Safari、IE等主流瀏覽器均在使用。
一些Tips
Tip 1:如何配置HSTS
很多地方都可以進行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年。
Tip 2:如何加入到HSTS Preload List
根據官方說明,你的網站在具備以下幾個條件后,可以提出申請加入到這個列表里。
- 具備一個有效的證書
- 在同一臺主機上提供重定向響應,以及接收重定向過來的HTTPS請求
- 所有子域名均使用HTTPS
在根域名的HTTP響應頭中,加入HSTS Header,并滿足下列條件:
- 具備一個有效的證書
- 必須包含includeSubDomains參數
- 必須包含preload參數 當你準好這些之后,可以在HSTS Preload List的官網上(https://hstspreload.org)提交申請,或者了解更多詳細的內容。
Tip 3:如何查詢域名是否加入到了Preload List
從提交申請到完成審核,成功加入到內置列表,中間可能需要等待幾天到幾周不等的時間??赏ㄟ^官網https://hstspreload.org或在Chrome地址欄里輸入chrome://net-internals/#hsts查詢狀態。
總結
隨著越來越多的網站開始使用HTTPS,甚至是開啟全站HTTPS,數據在傳輸過程中的安全性能夠得到極大的保障。與此同時,通過HSTS的幫助,避免遭受到SSL Stripping或者中間人的攻擊,能夠使得數據通信變得更加安全。本篇文章希望通過對HSTS的解析,使得更多的開發團隊將HSTS運用到自己的項目中。
【本文是51CTO專欄作者“ThoughtWorks”的原創稿件,微信公眾號:思特沃克,轉載請聯系原作者】