HTTP協議冷知識大全

若是不用HTTPS,HTTP協議如何安全的傳輸密碼信息?

HTTP協議是純文本協議,沒有任何加密措施。經過HTTP協議傳輸的數據均可以在網絡上被徹底監聽。若是用戶登錄時將用戶名和密碼直接明文經過HTTP協議傳輸過去了,那麼密碼可能會被黑客竊取。 一種方法是使用非對稱加密。GET登錄頁面時,將公鑰以Javascript變量的形式暴露給瀏覽器。而後用公鑰對用戶的密碼加密後,再將密碼密文、用戶名和公鑰一塊兒發送給服務器。服務器會提早存儲公鑰和私鑰的映射信息,經過客戶端發過來的公鑰就能夠查出對應的私鑰,而後對密碼密文進行解密就能夠還原出密碼的明文。 爲了增強公鑰私鑰的安全性,服務器應該動態生成公鑰私鑰對,而且使用後當即銷燬。可是動態生成又是很是耗費計算資源的,因此通常服務器會選擇Pool方法提供有限數量的公鑰私鑰對池,而後每隔一段時間刷新一次Pool。javascript

文件路徑攻擊

不少操做系統都會使用..符號表示上層目錄。若是黑客在URL的路徑裏面使用..符號引用上層目錄,而服務器沒有作好防範的話就有可能致使黑客能夠直接訪問權限以外的文件。好比使用多級..符號就能夠引用到根目錄,進一步就能夠訪問任意文件。 因此不少服務器都禁止在URL路徑裏出現..符號以免被攻擊。 文件路徑攻擊也是不少黑客很是喜好使用的攻擊方法之一。若是你的服務器有必定的訪問量,打開你的nginx日誌,你就會偶爾發現有一些奇怪的URL裏面有一堆..符號,這種URL的出現就表示網絡上的黑客正在嘗試攻擊你的服務器。css

DNS欺騙

HTTP協議嚴重依賴於DNS域名解析。任意一個域名類網址的訪問都須要通過域名解析的過程獲得目標服務的IP地址才能成功繼續下去。 若是掌管DNS服務的運營商做惡將域名解析到不正確的IP,指向一個釣魚的網頁服務。用戶若是沒有覺察,就可能會將本身的敏感信息提交給冒牌的服務器。前端

謹慎使用外部的HTTP代理

HTTP代理做爲客戶端到服務器之間的中間路由節點,它起到傳話人和翻譯官的角色。 若是這個翻譯官不靠譜的話,客戶端是會拿到錯誤的返回數據的。它同DNS欺騙同樣,是能夠對客戶端進行釣魚攻擊的。 若是這個翻譯官口風不嚴的話,它可能會將它聽到的敏感信息泄露給別人。java

413 Request Entity Too Large

客戶端上傳圖片太大超過服務器限制時,服務器返回413錯誤。nginx

414 Request-URI Too Long

客戶端訪問的URI太長,超出了服務器容許限制,服務器返回414錯誤。json

202 Accepted

經常使用於異步請求。客戶端發送請求到服務器,服務器當即返回一個202 Accepted表示已經成功接收到客戶端的請求。 後面怎麼處理由服務器本身決定,通常服務器會給客戶端預留一個能夠查詢處理狀態的接口,客戶端能夠選擇輪訓該接口來知道請求的處理進度和結果。後端

POST提交數據的方式

application/x-www-form-urlencodedapi

提交數據表單時常用,Body內部存放的是轉碼後的鍵值對。跨域

POST http://xyz.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

a=1&b=2&c=3&c=4
複製代碼

application/json瀏覽器

提交結構化表單時使用,Body內部存放的是JSON字符串。ElasticSearch的查詢協議使用的是這種方式。

POST http://xyz.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{"a": 1, "b": 2, "c": [3, 4]}
複製代碼

multipart/form-data

上傳文件時常用。這種格式比較複雜,它是爲了支持多文件上傳混合表單數據而設計的一種特殊的格式。

<form action="http://example.com/upload" method="post" enctype="multipart/form-data">
  <p><input type="text" name="key1" value="value1">
  <p><input type="text" name="key2" value="value2">
  <p><input type="file" name="file1">
  <p><input type="file" name="file2">
  <p><button type="submit">Submit</button>
</form>
複製代碼

用戶填充了表單設置了待上傳的文件,點擊Submit,傳輸數據大體以下

POST /upload HTTP/1.1
Content-Length:xxxxx
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryKOThiwE6HubGib7j
Host:example.com
------WebKitFormBoundaryKOThiwE6HubGib7j
Content-Disposition: form-data; name="key1"

value1
------WebKitFormBoundaryKOThiwE6HubGib7j
Content-Disposition: form-data; name="key2"

value2
------WebKitFormBoundaryKOThiwE6HubGib7j
Content-Disposition: form-data; name="file1"; filename="file1name.png"
Content-Type: image/png

file1 content here
------WebKitFormBoundaryKOThiwE6HubGib7j
Content-Disposition: form-data; name="file2"; filename="file2name.jpeg"
Content-Type: image/jpeg

file2 content here
------WebKitFormBoundaryKOThiwE6HubGib7j--
複製代碼

Cookie

瀏覽器請求的Cookie中每每會攜帶敏感信息。服務器通常會將當前用戶的會話ID存在cookie裏,會話的具體內容存在服務器端,會話的內容很敏感。

瀏覽器請求時會攜帶Cookie信息,服務器根據Cookie信息中的會話ID找到對應的會話內容。會話內容裏可能存儲了用戶的權限信息,拿到這部分權限信息後就可能隨意控制修改用戶的數據。

由於HTTP協議的不安全性,請求數據包很容易被竊聽,Cookie中的會話信息很容易被盜。解決方案之一就是在會話中記錄用戶的終端信息和IP地址信息,若是這些信息忽然發生改變,須要強制用戶從新認證。

不太高級的黑客是能夠僞造出和用戶真實請求一摸同樣的數據包的。最完全的解決方案仍是採用HTTPS協議。

普通的Cookie信息能夠經過Javascript腳本獲取到。若是黑客經過某種方式在網頁中植入不安全的腳本,將用戶的Cookie拿到而後發送到遠程的第三方服務器中,那麼Cookie中的信息就被泄露了。

Cookie的兩個重要屬性

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
複製代碼

被標記爲Secure的Cookie信息在HTTP請求中不會被傳送,它只會在HTTPS請求中傳送,避免數據被泄露。

被標記爲HttpOnly的Cookie信息是沒法經過Javascript API獲取到的,它只會在請求中傳送。這樣能夠避免黑客經過網頁腳本方式竊取Cookie中的敏感信息。

Cookie(甜點)如此好吃,黑客們總想經過Cookie作各類文章。

CSRF(Cross-Site Request Forgery)

CSRF跨站請求僞造有不少別名,好比One-Click Attack(一鍵攻擊),好比Session Riding(搭便車攻擊)

假設在在一個社區博客網站中,刪除我的的文章只須要一個URL就能夠,Cookie中的會話權限信息會自動附加到請求上。

# 123456爲文章的ID
http://example.com/blog/123456/delete
複製代碼

那麼當別人僞造了一個上面的連接地址誘惑你去點擊,好比經過站內信件、私聊、博客評論、圖片連接或者在別的什麼網站上隨機制造的一個連接。你不經意點了一下,就丟了你的文章。因此它被稱爲一鍵攻擊。由於這是借用了你當前登錄的會話信息來搞事,因此也被稱爲搭便車攻擊。

若是在一個金融系統中,轉帳要是也能夠經過一個簡單的URL進行的話,那這種危險就非同小可。

這就要求修改性的操做務必不得使用簡單的GET請求進行處理。可是即便這種狀況下你改爲了POST請求,黑客依然有辦法僞造請求,那就是經過iframe。

黑客在別的什麼網站上僞造了一個POST表單,誘惑你去submit。若是隻是普通的內嵌進HTML網頁的表單,用戶提交時會出現跨域問題。由於當前網站的域名和表單提交的目標域名不一致。可是若是經過iframe來內嵌表單,則能夠繞過跨域的問題,而用戶卻徹底沒有任何覺察。

爲了防範CSRF攻擊,聰明的網站的POST表單裏都會帶上CSRF_TOKEN這個隱藏字段。CSRF_TOKEN是根據用戶的會話信息生成的。當表單提交時,會將token和用戶的會話信息作比對。若是匹配就是有效的提交請求。

<form method="POST" action="/blog/delete">
<label for="blog_id">博客ID</label>
<input type="text" name="blog_id" value="12345">
<input type="hidden" name="csrf_token" value="xxxxxxxxxxxx">
</form>
複製代碼

黑客必須拿到CSRF_TOKEN才能夠借用用戶的會話信息實施CSRF攻擊,可是CSRF_TOKEN又必須由用戶的會話信息才能夠生成。黑客沒有用戶的會話信息,從而沒法實施CSRF攻擊。

XSS(Cross Site Scripting)

若是黑客能夠在你的網頁中植入任意Javascript腳本,那他就能夠隨意魚肉你的帳戶。經過Javascript能夠獲取Cookie的信息,能夠借用你的會話去調用一些隱祕的API,而這一些行爲都是在偷偷的進行,你根本徹底不知道。

<div>
# 用戶內容Start
<script>send_to_hacker(document.cookie)</script>
# 用戶內容END
</div>
複製代碼

這類攻擊在一些UGC網站中很是常見,常見的博客類網站就是UGC網站,用戶能夠經過編輯內容來生成網頁。

黑客也是用戶。他能夠編輯一段Javascript腳本做爲內容提交上去。若是服務器沒有作好防範,這段腳本就會在生成的網頁中運行起來。當其它用戶在登錄的狀態下來瀏覽這個網頁的時候,就悲劇了。

防範XSS通常是經過對輸出的內容進行內容替換作到的。在HTML頁面中不一樣的位置會有不一樣的內容替換規則。 比較常見的是使用HTML entity編碼將HTML標籤之間的內容中的一些特殊的字符進行轉碼。

<div>
# safe now
&lt;script&gt;send_to_hacker(document.cookie)&lt;/script&gt;
</div>
複製代碼

還有些UGC內容在HTML標籤的屬性中、Javascript的變量中、URL、css代碼中,他們轉碼的規則並不同,具體方法能夠去Google相關文檔。

跨域

跨域是個很頭痛的問題。

當你有多個後端服務,可是隻有一個前端的時候,你想作先後端分離,就會遇到跨域問題。你發現你的前端js調用後端服務時控制檯告訴你不ok。而後只好把這些服務都掛在了同一個nginx域名下面,經過url前綴區分。

這時候你會想,跨域太TM討厭了。既然跨域這麼討厭,那爲何瀏覽器非要限制跨域呢?

仍是安全緣由。

讓咱們回到上文的搭便車攻擊(Session Riding),也就是騎着別人的會話來搞事情。

假設如今你的瀏覽器開了一個站點A,登錄了進去,因而cookie便記錄了會話id。 而後你又不當心開了另外一個站點B,這個站點頁面一打開就開始執行一些惡意代碼。這些代碼的邏輯是調用站點A的API來獲取站點A的數據,由於能夠騎着(Ride)站點A的會話cookie。而這些數據正好是用戶私密性的。因而用戶在站點A上的私有信息就被站點B上的代碼竊走了。這就是跨域的風險。

可是有時候咱們又但願共享數據給不一樣的站點,該怎麼辦呢?

答案是JSONP & CORS

JSONP(JSON Padding)

JSONP經過HTML的script標記實現了跨域共享數據的方式。JSONP經過在網頁裏定義一個回調方法,而後在頁面上插入一個動態script標籤,指向目標調用地址。服務器會返回一段javascript代碼,通常是some_callback(data)這種形式的回調。該段代碼會在瀏覽器裏自動執行,因而網頁就獲得了跨域服務器返回的數據。

<script>
function some_callback(data) {
    console.log(data)
}
</script>
<script src="http://example.com/someapi?callback=some_callback"></script>
複製代碼

由於JSONP是不攜帶cookie信息的,因此能有效避免搭便車攻擊。JSONP是否能夠獲取到數據還須要服務器對這種調用提供顯示支持,服務器必須將數據以javascript代碼的形式返回才能夠傳遞給瀏覽器。

CORS(Cross-Origin Resource Sharing)

JSONP的不足在於它只能發送GET請求,而且不能攜帶cookie。而CORS則能夠發送任意類型的請求,能夠選擇性攜帶cookie。

CORS是經過Ajax發送的跨域請求技術。CORS的請求分爲兩種,一種是簡單請求,一種是複雜請求。簡單請求就是頭部不多很簡單的GET/HEAD/POST請求。複雜請求就是非簡單請求。

瀏覽器發現Ajax的請求是跨域的,就會在請求頭添加一個Origin參數,指明當前請求的發起站點來源。服務器根據Origin參數來決定是否受權。

若是是簡單請求,Ajax直接請求服務器。服務器會當成普通的請求直接返回內容,不一樣的是還會在響應頭部添加幾個重要的頭部,其中最重要的頭部是Access-Control-Allow-Origin: http://example.com

瀏覽器若是在響應中沒有讀到這個頭部,就會通知Ajax請求失敗。雖然服務器返回了數據,瀏覽器也不讓腳本讀到數據,這就保證了跨域的安全。服務器就是經過請求的Origin參數來決定要不要響應Access-Control-Allow-Origin頭部來決定是否容許指定網站的跨域請求。

若是是複雜請求,要走一個預檢的流程。預檢就是瀏覽器先向服務器發送一個Method爲Options的請求,若是服務器容許跨域請求,瀏覽器再發起這個Ajax請求。因此CORS的複雜請求會比簡單請求額外耗費一個TTL的時間。

CORS的細節請參見大神阮一峯的博文《跨域資源共享CORS詳解》

閱讀相關文章,關注公衆號【碼洞

相關文章
相關標籤/搜索