前面的話
本文將詳細介紹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 新增的另一個強大的新功能是,服務器可以對一個客戶端請求發送多個響應。 換句話說,除了對最初請求的響應外,服務器還可以向客戶端推送額外資源,而無需客戶端明確地請求
