前面的話
本文將詳細介紹HTTP主要內容
概述
Web 的誕生,源於三大技術的誕生,它們都是當年 Web 之父 Tim Berners-Lee 自己 開發的,世界上第一個網站誕生的時間是 1991 年,三大技術的誕生也就是在此之前的不久:
1、可以指向任何網頁的 URL
2、html
3、HTTP 協議
HTTP 是超文字傳輸協議 Hypertext Transfer Protocol 的縮寫。從伺服器上到瀏覽器裡,這個過程是基於 HTTP 協議來傳輸資料的。Web 內容都是儲存在 Web 伺服器上的,Web 伺服器都是基於 HTTP 協議的,因此也被稱為 HTTP 伺服器。HTTP 伺服器儲存了各種型別的資料,如果 HTTP 的客戶端發出請求的話,伺服器就會返回資料給客戶端,叫做響應
HTTP 的伺服器和客戶端是全球資訊網( World Wide Web )的基本單元。最常見的客戶端就是瀏覽器。瀏覽一個頁面的時候,瀏覽器會向伺服器發出一個 HTTP 請求。等到伺服器響應返回之後,瀏覽器再去處理響應資料,以美觀的形式展示給使用者
【特性】
HTTP 是一個無狀態的協議。所謂無狀態( stateless )意思就是:對於之前的互動沒有記錄。每次互動能用的資訊就只有這次互動所攜帶的資訊
換句話說,HTTP 協議是沒有辦法記住之前的一次請求的,所以也沒有辦法根據前一次請求來輔助後一次請求。當一個Web 應用看起來似乎可以記住之前的互動,例如,可以記住你的使用者名稱,其實它採用的技巧已經超出了 HTTP 本身。HTTP 的資訊就好像是可以自銷燬的,每次讀取完畢,立刻就消失了。總之,HTTP 就是無狀態的,也就是不能記錄或者維持某種狀態的。
【資源和URL】
HTTP 故事的開始是瀏覽器發出請求。但是請求的是什麼呢?是伺服器上的資源,英文叫 Resource
對應的每一個資源,都有一個 URL ,也就是統一資源定位地址,指向這個資源。不過資源分兩種:一種是靜態資源,也就是各種檔案了,最常見的就是靜態 HTML ,但是也可以是 PDF ,json 檔案等等。另外一種,就是動態資源,也就是 URL 指向的地方不是一個檔案,而是一段程式碼的入口,伺服器經過運算後,才返回運算結果給客戶端。所以, 我們有 https://xiaohuochai.cc/static/main.css ,這個 URL 就是指向一個靜態資源的。如果是 https://xiaohuochai.cc/posts 這個可能就是指向動態資源的,後臺對應的可能就是一個 API
請求和響應
【請求】
1、請求行
第一行的內容被叫做請求行 Request Line ,具體形式如下
GET/POST [url] HTTP/[version] GET / HTTP/1.1
這一行就是以HTTP 方法( HTTP Method )打頭,一般是 GET 或者 POST ,當然還有其他不太常用的方法。 當我們用 GET 發請求的時候,一般我們就是想要從伺服器上 GET (拿到)一些內容,而不是想去修改伺服器資料。POST 正好就是用來修改伺服器上的資料的。到底要 GET 或者要修改的資源,就是後面的 URL 這一項來指定了。上面例子中,請求的 URL 是 /
。最後就是跟 HTTP
字樣,再跟上到底是使用的哪個版本的 HTTP 協議,目前一般都是 HTTP 1.1 了
2、請求頭部
[header 名]:[header 值]
> Host: haoqicat.com > User-Agent: curl/7.43.0 > Accept: */*
都是以冒號隔開的鍵值對。上面三項:
Host 代表被請求的主機,也就是 haoqicat.com User-Agent 代表使用者使用的客戶端,我們這裡用的是 curl Accept 後面指明客戶端可以接受的返回資源的型別,* 代表所有型別都接受
3、負載資料
header 之下,一個 request 中還可能包含負載資料( payload )。這一項,請求中不一定會包含。GET 請求都是不帶負載資料的,POST 請求帶負載資料。這個挺好理解,POST 方法的請求都是要改動伺服器資料的,當然要在請求中攜帶資料過去。
比如,頁面上有一個表單 form ,填寫幾項資料,然後一點提交,這個就會發出一個 POST 請求,而填寫的資料, 就會作為 payload 成為請求的一部分
【響應】
1、狀態行
對於請求有請求行,響應的第一行也很特別,叫做狀態行 ( status line ) ,基本格式如下
HTTP[版本號] [狀態碼] [狀態資訊]
HTTP/1.1 200 OK
簡單介紹一下狀態碼
20x 的狀態碼都代表某種成功狀態。最常見的 200 ,它的意義,就正如它後面跟的狀態資訊 一樣,代表一切 OK 。 30x 的狀態碼,意味著資源已經被移動到其他地方了,但是響應中給出了應該跳轉到哪裡去找到這個資源。這個行為的術語就叫做 redirect (重定向)。 40x 的程式碼也都是代表一種客戶端請求錯誤 。一個最常見的狀態碼 404 ,它的意義也跟它後面緊跟的狀態資訊所說的 一樣:Page Not Found (頁面未找到)。 50x 的狀態嗎也很常見。返回的如果是這一系列的狀態碼,就意味著 伺服器端在處理請求的時候出錯 。50x 出現,對於開發者,一般意味著伺服器端程式碼出了錯誤。
2、響應頭部
[ header 名]: [ header 值]
Server: nginx/1.4.6 (Ubuntu) Date: Fri, 09 Dec 2016 09:23:59 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding
3、響應主體
響應主體,response body ,也可以叫做 payload
<!DOCTYPE html> <html> <head> <title>xiaohuochai</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1" /> ... </head> <body> ... </body> </html>
【查詢字串】
GET 請求中攜帶一些資料到伺服器端的方法並不唯一,但是一種非常簡單也非常常用的方式就是,使用查詢字串來傳遞資料,或者叫傳遞引數
如果開啟 chrome 瀏覽器,開啟 chrome 開發者工具的 Network 標籤。然後瀏覽器中訪問
http://xiaohuochai.com/?name=xiaohuochai
上面的 ?name=xiaohuochai
就是所謂的查詢字串,這裡面傳遞了一個引數,也就是 name
,引數值是 xiaohuochai
也可以傳遞多組引數的,每組之間以 &
隔開
http://xiaohuochai.com/?name=xiaohuochai&email=peter@peter.com
甚至可以寫成這樣
?order=desc&shoe[color]=blue&shoe[type]=converse
伺服器端如果是 express ,就可以很方便的用 req.query 來接收傳遞過來的引數
如果想新增一個備用郵箱,可以使用+
來進行連線
?name=peter&email=happypeter1983@gmail.com+b@b.com
方法
每次發請求的時候,處理請求的 url 之外,還必然有一個請求方法
HTTP方法包括如下
GET ,最常用的一種,用於從伺服器上“得到”某個資源
POST,往伺服器上寫入資料,跟 GET 作用相反
PUT,也是寫入資料,通常的用法是 POST 建立新資料,PUT 用來更新已有資料
DELETE,刪除伺服器上的資料
HEAD,跟 GET 一樣,也是請求伺服器上的資源,但是隻要響應的 Headers ,這個不太常用,不用管
其他的還有 TRACE,OPTIONS,PATCH 等,都不常用
【RestFul】
上面的列出的各種 HTTP 方法的使用場合其實沒有嚴格的規定的,如果作為開發者,非要用 GET 請求來寫資料到 伺服器,也不是不可以做到的。但是尊重 HTTP 方法(有時候也叫做 HTTP 動詞)的本來用法,是個好的習慣。
Nodejs 開發領域非常常用的 RESTful 架構,就是尊重 HTTP 方法本意的一個典範:
GET /posts # 讀取所有文章 GET /posts/:id # 讀取一篇文章 POST /posts # 釋出一篇文章 PUT /posts/:id # 更新一篇文章 DELTE /posts/:id # 刪除一篇文章 ...
在 RESTful 的思路里面,HTTP 的方法的本意和用它真正發出請求執行的行為是非常吻合的
會話
會話就是伺服器和瀏覽器的保有共同的資訊的這段時間。換句話,會話開始和結束,就意味著伺服器從認識一個瀏覽器到不再認識這個瀏覽器
會話可以讓無狀態的 HTTP 協議保持特定的狀態。這種在客戶端與伺服器之間傳遞會話 id的機制,能讓伺服器建立一種各次請求之間的持續連線狀態。Web 開發人員利用這種人造的狀態,來構建一些”有狀態“的應用場景:例如使用者處於一直登陸的狀態,購物車裡面之前新增的商品,後續訪問中還有等等。不過即使這樣,每一個 HTTP 請求本質上來說還是無狀態的,各次請求之間並不知道彼此的存在。
【技術機制】
實現會話的方法不唯一,最常見的一個方式是這樣:
1、準備建立會話的時候,伺服器會在自己的記憶體裡建立一個新的變數,例如這個變數叫做 session-3254
2、伺服器把這個會話的 id 也就是 3254 傳送到瀏覽器,瀏覽器會把這個 id 儲存到 cookie 中
3、每次瀏覽器再去訪問伺服器的時候,都會攜帶 cookie 中存放的 3254 這個會話 id 值,這樣瀏覽器就認識這個瀏覽器了
4、伺服器端的 session-3254 變數中可以存放任意的會話資料,例如:使用者名稱,購物車裡有哪幾件商品等等
5、每次瀏覽器訪問伺服器,都可以憑藉自己的會話 id 去伺服器的 session-3254 變數中去認領屬於我的資訊
每一個請求都會包含這個會話 id ,這樣伺服器就能唯一確認客戶端啦。 這樣,直到會話過期,客戶端和伺服器都是互相認識的
【會話過期】
伺服器上有多少個瀏覽器在訪問,就會在自己記憶體中建立多少了類似 session-3254 這樣的變數。但是,還有一點非常重要,在一個會話裡發出的會話 id 是唯一的,而且有一個很短的過期時間。那什麼情況下會話就會過期呢?
1、手動刪掉 cookie 中的會話 id (在 chrome devtools 裡,右鍵 cookies 然後刪除它)
2、點一個網站的退出登入按鈕
3、關閉網站有時候也通常能結束會話
【會話劫持】
會話 id 作為一個唯一的令牌來唯一標識一個會話。通常,會話 id 是作為 cookie 儲存在計算機上的一個隨機字串.。很多 web 應用的使用者認證系統所在做的事情,當使用者的使用者名稱和密碼匹配之後,會話 id 會儲存在使用者的瀏覽器裡,這樣下一個請求就不用重新認證了
不幸的是,如果一個攻擊者拿到了這個會話 id ,他就會跟我共享這一個會話,那伺服器就會把他當成我,我的所有許可權,他都不需要知道我的使用者名稱密碼,都可以獲得了
這種情況就需要安全的 HTTP 也就是 HTTPS 來幫忙啦。通過 HTTPS 傳送的請求和響應在傳送前都會被加密。這意味著如果一個惡意的黑客監聽 HTTP 通訊,他得到的資訊都是加密的,就是截獲了也看不懂是個啥
XSS
跨站指令碼(英語:Cross-site scripting,通常簡稱為:XSS)是一種網站應用程式的安全漏洞攻擊,是程式碼注入的一種。它允許惡意使用者將程式碼注入到網頁上,其他使用者在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及使用者端指令碼語言。
XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令程式碼到網頁,使使用者載入並執行攻擊者惡意製造的網頁程式。這些惡意網頁程式通常是JavaScript,但實際上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻擊成功後,攻擊者可能得到更高的許可權(如執行一些操作)、私密網頁內容、會話和cookie等各種內容
如網站上有個評論框,然後惡意訪客在裡面輸入了
Hello World <script>alert('Hello World')</script>
網站的行為被篡改了,或者說網站已經被 XSS 了
惡意使用者可以使用 HTML 和 javascript 程式碼對伺服器或者以後訪問這個頁面的使用者發起毀滅性的攻擊。舉個例子,一個攻擊者可以使用 javascript 程式碼去獲取所有在他之後訪問這個頁面的使用者的會話 id ,然後偽裝成這個使用者
【解決辦法】
1、消除有問題的輸入。比如script
標籤,或者使用一個更安全的輸入格式,比如 Markdown,這樣就可以阻止 HTML 和 javascript 同時出現在使用者的輸入裡
2、在顯示之前轉義使用者輸入的所有資料
總結起來一句話,總是對使用者輸入的內容做無害處理
【CSP】
CSP 的實質就是白名單制度,開發者明確告訴客戶端,哪些外部資源可以載入和執行,等同於提供白名單。它的實現和執行全部由瀏覽器完成,開發者只需提供配置。
CSP 大大增強了網頁的安全性。攻擊者即使發現了漏洞,也沒法注入指令碼,除非還控制了一臺列入了白名單的可信主機
兩種方法可以啟用 CSP。一種是通過 HTTP 頭資訊的Content-Security-Policy
的欄位
Content-Security-Policy: script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:
另一種是通過網頁的<meta>
標籤
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
下面是admin.xiaohuochai.cc的csp配置
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https://pic.xiaohuochai.site https://static.xiaohuochai.site; style-src 'self' 'unsafe-inline'; frame-src https://demo.xiaohuochai.site https://xiaohuochai.site;";
CSRF
跨站請求偽造(Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制使用者在當前已登入的Web應用程式上執行非本意的操作的攻擊方法。跟跨網站指令碼(XSS)相比,XSS 利用的是使用者對指定網站的信任,CSRF 利用的是網站對使用者網頁瀏覽器的信任
跨站請求攻擊,簡單地說,是攻擊者通過一些技術手段欺騙使用者的瀏覽器去訪問一個自己曾經認證過的網站並執行一些操作(如發郵件,發訊息,甚至財產操作如轉賬和購買商品)。由於瀏覽器曾經認證過,所以被訪問的網站會認為是真正的使用者操作而去執行。這利用了web中使用者身份驗證的一個漏洞:簡單的身份驗證只能保證請求發自某個使用者的瀏覽器,卻不能保證請求本身是使用者自願發出的
【防禦措施】
1、檢查Referer欄位
HTTP頭中有一個Referer欄位,這個欄位用以標明請求來源於哪個地址。在處理敏感資料請求時,通常來說,Referer欄位應和請求的地址位於同一域名下。而如果是CSRF攻擊傳來的請求,Referer欄位會是包含惡意網址的地址,這時候伺服器就能識別出惡意的訪問。
這種辦法簡單易行,工作量低,僅需要在關鍵訪問處增加一步校驗。但這種辦法也有其侷限性,因其完全依賴瀏覽器傳送正確的Referer欄位。雖然http協議對此欄位的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,亦無法保證瀏覽器沒有安全漏洞影響到此欄位。並且也存在攻擊者攻擊某些瀏覽器,篡改其Referer欄位的可能
2、新增校驗token
由於CSRF的本質在於攻擊者欺騙使用者去訪問自己設定的地址,所以如果要求在訪問敏感資料請求時,要求使用者瀏覽器提供不儲存在cookie中,並且攻擊者無法偽造的資料作為校驗,那麼攻擊者就無法再執行CSRF攻擊。這種資料通常是表單中的一個資料項。伺服器將其生成並附加在表單中,其內容是一個偽亂數。當客戶端通過表單提交請求時,這個偽亂數也一併提交上去以供校驗。正常的訪問時,客戶端瀏覽器能夠正確得到並傳回這個偽亂數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽亂數的值,伺服器端就會因為校驗token的值為空或者錯誤,拒絕這個可疑請求
3、使用JWT。並將其儲存在本地儲存localStorage中
DDOS
典型的 DDoS 攻擊,全稱是 Distributed Denial of Service,翻譯成中文就是分散式拒絕服務。一般來說是指攻擊者利用“肉雞”對目標網站在較短的時間內發起大量請求,大規模消耗目標網站的主機資源,讓它無法正常服務。線上遊戲、網際網路金融等領域是 DDoS 攻擊的高發行業
如何應對DDOS攻擊?
1、高防伺服器
高防伺服器主要是指能獨立硬防禦 50Gbps 以上的伺服器,能夠幫助網站拒絕服務攻擊,定期掃描網路主節點等,這東西是不錯,就是貴
2、黑名單
設定黑名單,但也會封鎖正常流量,影響到正常業務
3、DDOS清洗
對使用者請求資料進行實時監控,及時發現DOS攻擊等異常流量,在不影響正常業務開展的情況下清洗掉這些異常流量
4、CDN
在現實中,CDN 服務將網站訪問流量分配到了各個節點中,這樣一方面隱藏網站的真實 IP,另一方面即使遭遇 DDoS 攻擊,也可以將流量分散到各個節點中,防止源站崩潰
HTTP2
HTTP/2(超文字傳輸協議第2版,最初命名為HTTP 2.0),簡稱為h2(基於TLS/1.2或以上版本的加密連線)或h2c(非加密連線),是HTTP協議的的第二個主要版本,使用於全球資訊網。 HTTP/2是HTTP協議自1999年HTTP 1.1釋出後的首個更新,主要基於SPDY協議。它由網際網路工程任務組(IETF)的Hypertext Transfer Protocol Bis(httpbis)工作小組進行開發。該組織於2014年12月將HTTP/2標準提議遞交至IESG進行討論,於2015年2月17日被批准
HTTP/2標準於2015年5月以RFC 7540正式發表。多數主流瀏覽器已經在2015年底支援了該協議。此外,根據W3Techs的資料,在2017年5月,在排名前一千萬的網站中,有13.7%支援了HTTP/2
HTTP/2的出現,相比於 HTTP 1.x ,大幅度的提升了 web 效能。在與 HTTP/1.1 完全語義相容的基礎上,進一步減少了網路延遲
【多路複用】
多路複用允許同時通過單一的 HTTP/2 連線發起多重的請求-響應訊息
眾所周知 ,在 HTTP/1.1 協議中,瀏覽器客戶端在同一時間,針對同一域名下的請求有一定數量限制。超過限制數目的請求會被阻塞。chrome下是6個,這也是為何一些站點會有多個靜態資源 CDN 域名的原因之一
而HTTP/2 的多路複用(Multiplexing) 則允許同時通過單一的 HTTP/2 連線發起多重的請求-響應訊息
因此 HTTP/2 可以很容易的去實現多流並行而不用依賴建立多個 TCP 連線,HTTP/2 把 HTTP 協議通訊的基本單位縮小為一個一個的幀,這些幀對應著邏輯流中的訊息。並行地在同一個 TCP 連線上雙向交換訊息
【二進位制分幀】
HTTP/2 所有效能增強的核心在於新的二進位制分幀層,它定義瞭如何封裝 HTTP 訊息並在客戶端與伺服器之間傳輸
這裡所謂的“層”,指的是位於套接字介面與應用可見的高階 HTTP API 之間一個經過優化的新編碼機制:HTTP 的語義(包括各種動詞、方法、標頭)都不受影響,不同的是傳輸期間對它們的編碼方式變了。HTTP/1.x 協議以換行符作為純文字的分隔符,而 HTTP/2 將所有傳輸的資訊分割為更小的訊息和幀,並採用二進位制格式對它們編碼
【首部壓縮】
每個 HTTP 傳輸都承載一組標頭,這些標頭說明了傳輸的資源及其屬性。 在 HTTP/1.x 中,此後設資料始終以純文字形式,通常會給每個傳輸增加 500–800 位元組的開銷。如果使用 HTTP Cookie,增加的開銷有時會達到上千位元組。為了減少此開銷和提升效能,HTTP/2 使用 HPACK 壓縮格式壓縮請求和響應標頭後設資料
【伺服器端推送】
HTTP/2 新增的另一個強大的新功能是,伺服器可以對一個客戶端請求傳送多個響應。 換句話說,除了對最初請求的響應外,伺服器還可以向客戶端推送額外資源,而無需客戶端明確地請求