Web 應用安全性: HTTP簡介

前端小智發表於2019-03-07

圖片描述

這是關於web安全性系列文章的第2篇,第一篇可點選以下檢視:

  1. Web 應用安全性: 瀏覽器是如何工作的

HTTP是一個美好的東西:一個存在了20多年而沒有太多變化的協議。

正如我們在前一篇文章中看到的,瀏覽器通過HTTP協議與web應用程式互動,這是我們深入研究這個主題的主要原因。如果使用者在網站上輸入他們的信用卡資訊,攻擊者就能在資料到達伺服器之前攔截資料,我們肯定會有麻煩。

瞭解HTTP是如何工作的,我們如何保護客戶端和伺服器之間的通訊,以及該協議提供了哪些與安全相關的特性,這是改進安全狀態的第一步。

但是,在討論HTTP時,我們應該始終區分語義和技術實現,因為它們是HTTP工作方式的兩個非常不同的方面。

兩者之間的關鍵區別可以用一個非常簡單的類比來解釋:20年前,人們像現在一樣關心他們的親人,儘管他們互動的方式已經發生了巨大的變化。我們的父母可能會開著車去他們姐姐家,這樣就能趕上和家人在一起。

相反,現在更常見的是在 WhatsApp 上留言、打電話或使用 Facebook 群組,這在以前是不可能的。這並不是說人們或多或少地交流或關心,而是說他們交流的方式改變了。

HTTP 也不例外:協議背後的語義沒有太大的變化,而客戶端和伺服器之間通訊的技術實現已經經過多年的優化。如果您檢視 1996 年的 HTTP 請求,它看起來與我們在前一篇文章中看到的請求非常相似,儘管這些資料包通過網路的方式非常不同。

概述

如前所述,HTTP遵循請求/響應模型,其中連線到伺服器的客戶端發出請求,伺服器對其進行響應。

HTTP訊息(請求或響應)包含多個部分:

  • 請求行
  • 請求頭
  • 請求體

第一部分:請求行,用來說明請求型別,要訪問的資源以及所使用的HTTP版本。

GET /players/lebron-james HTTP/1.1

GET說明請求型別為 GET,/players/lebron-james 為要訪問的資源,該行的最後一部分說明使用的是 HTTP1.1 版本。

第二部分:請求頭部,緊接著請求行(即第一行)之後的部分,用來說明伺服器要使用的附加信。:

GET /players/lebron-james HTTP/1.1
Host: nba.com
Accept: */*
Coolness: 9000

例如,在此請求中,客戶端已為請求附加了3個附加標頭:HostAcceptCoolness

等一下,Coolness 是什麼

報頭不必使用特定的保留名稱,但通常建議依賴於 HTTP 規範標準化的名稱:越偏離標準,交換中的另一方就越不理解你。

例如,Cache-Control 是一個標頭檔案,用於定義響應是否是可快取的:大多數代理和反向代理都完全按照 HTTP 規範來理解它。如果將 Cache-Control 頭重新命名為 Awesome-Cache-Control,代理將不再知道如何快取響應,因為它們不是按照你剛剛提出的規範構建的。

但有時候,在訊息中包含“自定義”標題可能是有意義的,因為你可能希望新增實際上不屬於 HTTP 規範的後設資料:伺服器可以決定在其響應中包含技術資訊,以便客戶端可以同時執行請求並獲取有關回復的伺服器狀態的重要資訊:

...
X-Cpu-Usage: 40%
X-Memory-Available: 1%
...

使用自定義標頭時,始終首選為它們新增一個鍵,以便它們不會與將來可能成為標準的其他標頭衝突:從歷史上看,這一直很有效,直到每個人都開始使用“非標準” X 字首 反過來,這成為常態。 X-Forwarded-ForX-Forwarded-Proto標 頭是負載平衡器和代理廣泛使用和理解的自定義標頭的示例,即使它們不是 HTTP 標準的一部分。

如果你需要新增自己的自定義頭,那麼現在通常最好使用一個自動生成的字首,例如 Acme-Custom-Header 頭或 A-Custom-Header 頭。

在標題之後,一個請求可能包含一個主體,它與標題之間用空行隔開:

POST /players/lebron-james/comments HTTP/1.1
Host: nba.com
Accept: */*
Coolness: 9000

Best Player Ever

我們的請求完成了:第一行(位置和協議資訊)、請求頭和請求體。注意,請求體是完全可選的,在大多數情況下,它只在我們想要向伺服器傳送資料時使用——這就是上面的示例使用 POST 的原因。

響應沒有太大的不同:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, max-age=3600

{"name": "Lebron James", "birthplace": "Akron, Ohio", ...}

響應釋出的第一個資訊是它使用的協議版本以及該響應的狀態。請求頭也一樣,如果需要的話,在正文後面加一個換行符。

如前所述,該協議經過了多次修訂,並隨著時間的推移新增了一些特性(新的標頭檔案、狀態程式碼等),但是底層結構並沒有太大的變化(請求行、請求頭和正文)。真正改變的是客戶端和伺服器如何交換這些訊息——讓我們更仔細地研究一下。

HTTP vs HTTPS vs H2

HTTP 已經經歷了 2 個相當大的語義變化: HTTP/1.0 和 HTTP/1.1。

那,“HTTPS 和 HTTP2 在哪裡?”

HTTPS 和 HTTP2 (縮寫為 H2)是更多的技術更改,因為它們引入了在網際網路上傳遞訊息的新方法,而不會嚴重影響協議的語義。

HTTPS 是 HTTP的一種“安全”擴充套件,它涉及在客戶機和伺服器之間建立一個公共祕密,確保我們與正確的一方進行通訊,並對與公共祕密交換的訊息進行加密(稍後將對此進行詳細介紹)。HTTPS 的目標是提高HTTP 協議的安全性,而 H2 的目標是為其帶來更快的速度。

H2 使用二進位制而不是純文字訊息,支援多路複用,使用 HPACK 演算法壓縮報頭……長話短說,H2 是對HTTP/1.1 的效能提升。

網站所有者不願意切換到 HTTPS,因為它涉及客戶端和伺服器之間的額外往返(如上所述,需要在兩方之間建立共同的祕密),從而減慢使用者體驗:使用 H2 加密 預設情況下,他們就沒有藉口了,因為多路複用和伺服器推送等功能使其 效能優於普通的 HTTP/1.1

HTTPS

HTTPS (HTTP Secure)的目標是讓客戶端和伺服器通過 TLS(傳輸層安全性)安全地進行通訊,TLS 是SSL(安全套接字層)的繼承者。

TLS 所針對的問題相當簡單,可以用一個簡單的比喻:你的另一半中午打電話給你,當你在一個會議上,並詢問你告訴他們你的網上銀行賬戶的密碼,因為他們需要執行一個銀行轉賬,以確保你兒子的教育費用按時支付。重要的是你現在就告訴他們,否則第二天早上你的孩子可能會被學校拒之門外。

你們現在面臨著兩個挑戰:

  • 身份驗證: 確保你真的在和你的另一半說話,因為有可能別人會假裝他們
  • 加密: 在同事無法理解和記錄下密碼的情況下進行通訊

這正是 HTTPS 試圖解決的問題。

為了驗證你正在與誰交談,HTTPS 使用公鑰證書,這只是宣告特定伺服器背後身份的證書:當你通過 HTTPS 連線到 IP 地址時,該地址背後的伺服器將向你提供其證書,以驗證其身份。回到我們的類比,這可能只是你讓你的另一半拼寫他們的社會保險號。一旦驗證了數字的正確性,你就獲得了額外的信任級別。

但是,這並不能阻止“攻擊者”學習受害者的社會安全號碼,偷走你伴侶的智慧手機並給你打電話。 我們如何驗證來電者的身份?

你不是直接讓你的另一半拼他們的社會保險號,而是打電話給你的媽媽(她正好住在你隔壁),讓她去你的公寓,確保你的另一半拼的是他們的社會保險號。這增加了額外的信任級別,因為你不認為你的母親是一個威脅,並依賴她來驗證呼叫者的身份。

在 HTTPS 術語中,你的媽媽稱為 CA,證書頒發機構 (Certificate Authority)的簡稱:CA 的工作是驗證特定伺服器後面的身份,並頒發具有自己的數字簽名的證書:這意味著,當我連線到特定域時,我不會出示由域所有者生成的證書(稱為自簽名證書),而是由 CA 頒發。

權威機構的職責是確保他們驗證域名後面的身份並相應地頒發證書:當你“訂購”證書時(通常稱為 SSL 證書,即使現在使用 TLS 代替 ), 當局可能會給人打電話或要求你更改 DNS 設定,以驗證你是否可以控制相關域。 驗證過程完成後,它將頒發證書,然後你可以在 Web 伺服器上安裝該證書。

像瀏覽器這樣的客戶端將連線到您的伺服器並獲得此證書,以便他們可以驗證它看起來是真實的:瀏覽器與CA有某種“關係”,因為它們跟蹤可信CA的列表。 為了驗證證書是否真的值得信賴。 如果證書未由受信任的機構簽名,則瀏覽器將向使用者顯示一條資訊量大的警告:

圖片描述

確保你和你的另一半之間的通訊安全已經完成了一半:現在我們已經解決了身份驗證(驗證呼叫者的身份),我們需要確保我們可以安全地通訊,而不會在此過程中被其他人竊聽。正如我提到的,你正在開會,需要拼寫你的網上銀行密碼。你需要找到一種方法來加密你的交流,這樣只有你和你的伴侶才能理解你的談話。

您可以通過在雙方之間建立共享金鑰來實現此目的,並通過該金鑰加密訊息:例如,你可以根據婚禮日期決定使用 Caesar cipher 的變體。

圖片描述

如果雙方都有一段穩定的關係,就像你和你的靈魂伴侶一樣,這將會很有效,因為他們可以在別人不知道的共同記憶的基礎上創造一個金鑰。但是,瀏覽器和伺服器不能使用相同的機制,因為它們事先不瞭解彼此。

取而代之的是 Diffie-Hellman 金鑰交換協議的變體,它確保沒有預先知道的各方建立共享的金鑰,而其他人無法“嗅探”它。這需要用到一點數學知識,這是留給讀者的一個練習。

圖片描述

一旦金鑰建立起來,客戶端和伺服器就可以進行通訊,而不必擔心有人會截獲它們的訊息。即使攻擊者這樣做,他們也沒有解密訊息所需的公共金鑰。

HTTPS無處不在

還在爭論你是否應該在你的網站上支援HTTPS? 我沒有好訊息:瀏覽器已經開始推動使用者遠離不支援HTTPS 的網站,以“強迫”網路開發者提供完全加密的瀏覽體驗。

“HTTPS無處不在” 的口號背後,瀏覽器開始反對未加密的連線——谷歌是第一個給網路開發者最後期限的瀏覽器供應商,它宣佈從 Chrome 68(2018年7月) 開始將把HTTP網站標記為“不安全”:

圖片描述

對於不使用HTTPS的網站來說,更令人擔憂的是,一旦使用者在網頁上輸入任何內容,“不安全”標籤就會變成紅色——這一舉動應該會鼓勵使用者在與不支援HTTPS的網站交換資料之前三思而後行。

圖片描述

將此與在HTTPS上執行並配備有效證書的網站的外觀進行比較:

圖片描述

從理論上講,網站不一定是安全的,但在實踐中,這會嚇跑使用者 - 這是理所當然的。 當 H2 還沒普遍時,堅持使用未加密的純HTTP通訊是有意義的,如今幾乎沒有理由這樣做。

GET 和 POST

正如我們前面看到的,HTTP請求以一個特殊的請求行開始:

首先,客戶端告訴伺服器它正在使用什麼動詞來執行請求:常見的 HTTP 動詞包括 GETPOSTPUTDELETE,但列表可以繼續使用不常見(但仍然是標準的)動詞,如 TRACEOPTIONS,或 HEAD

理論上,沒有一種方法比其他方法更安全;實際上,事情並沒有那麼簡單。

GET 請求通常不帶主體,因此引數包含在 URL 中(如 www.example.com/articles?article_id=1),而 POST 請求通常用於傳送(“post”)包含在內的資料。

另一個區別在於這些動詞帶有的副作用:GET 是一個冪等動詞,意思是無論你要傳送多少個請求,你都不會改變網路伺服器的狀態。 相反,POST 不是冪等的:對於你傳送的每個請求,你可能正在更改伺服器的狀態(例如,考慮釋出新的付款 - 現在您可能理解為什麼站點要求你在執行時不重新整理頁面 交易)。

冪等性:指一次和多次請求某一個資源應該具有同樣的副作用,也就是一次訪問與多次訪問,對這個資源帶來的變化是相同的。

為了說明這些方法之間的一個重要區別,我們需要看一看 web 伺服器的日誌,這些日誌你可能已經很熟悉了:

192.168.99.1 - [192.168.99.1] - - [29/Jul/2018:00:39:47 +0000] "GET /?token=1234 HTTP/1.1" 200 525 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 404 0.002 [example-local] 172.17.0.8:9090 525 0.002 200
192.168.99.1 - [192.168.99.1] - - [29/Jul/2018:00:40:47 +0000] "GET / HTTP/1.1" 200 525 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 393 0.004 [example-local] 172.17.0.8:9090 525 0.004 200
192.168.99.1 - [192.168.99.1] - - [29/Jul/2018:00:41:34 +0000] "PUT /users HTTP/1.1" 201 23 "http://example.local/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" 4878 0.016 [example-local] 172.17.0.8:9090 23 0.016 201

如你所見,web伺服器記錄請求路徑:這意味著,如果你在 URL 中包含敏感資料,那麼它將被 web 伺服器洩露並儲存在你的日誌中的某個位置—你的金鑰將以明文的形式出現,這是我們絕對需要避免的。假設攻擊者能夠訪問你的一箇舊日誌檔案,該檔案可能包含信用卡資訊、私有服務的訪問令牌等等:這將是一場徹底的災難。

Web 伺服器不記 錄HTTP標頭或主體,因為要儲存的資料太大 - 這就是為什麼通過請求主體而不是URL傳送資訊通常更安全。 從這裡我們可以得出 POST(和類似的,非冪等方法)比 GET 更安全,即使更多的是使用特定動詞時資料的傳送方式而不是特定動詞本身比其他動詞更安全:如果你 將敏感資訊包含在 GET 請求的主體中,然後你不會遇到比使用 POST 時更多的問題,即使這種方法被認為是不尋常的。

我們信任 HTTP 報頭

在本文中,我們研究了HTTP,它的演變以及它的安全擴充套件如何整合身份驗證和加密,以使客戶端和伺服器通過安全通道進行通訊:這不是所有 HTTP 在安全性方面提供的。

正如我們將在下一篇文章中看到的,HTTP安全標頭檔案提供了一種改進應用程式安全狀態的方法,下一篇文章將致力於理解如何利用它們。

你的點贊是我持續分享好東西的動力,歡迎點贊!

一個笨笨的碼農,我的世界只能終身學習!

更多內容請關注公眾號《大遷世界》

圖片描述

相關文章