HTTP 協議是以 ASCII 碼進行傳輸的,創建在 TCP/IP 協議上的應用層規範。規範把 HTTP 分爲三個部分:狀態行、請求頭、請求主體。HTTP 定義了與服務器交互的不一樣方法,經常使用的有以下四種:GET
、POST
、DELETE
、PUT
。 URL 全稱是資源描述符,一個 URL 地址用於描述一個網絡上的資源,而 HTTP 中的 POST
、DELETE
、PUT
、GET
就對應着對這個資源的 增、刪、改、查 四個操做。其餘請求方式還有:HEAD
、 OPTIONS
、 TRACE
、 PATCH
。算法
GET
用於信息的獲取。(安全和冪等)注:安全意味着該操做用於獲取信息而非修改信息。冪等意味着對同一 URL 的多個請求應返回一樣的結果。POST
表示可能修改服務器上的資源的請求。(非安全、非冪等)HEAD
與 GET
方法相似,但不返回 message body內容,僅僅是得到獲取資源的部分信息(content-type、content-length)(安全和冪等)PUT
用於建立、更新資源。(非安全、冪等)DELETE
刪除資源。(非安全、冪等)OPTIONS
用於 URL 驗證,驗證接口服務是否正常。(安全、冪等)TEACE
回顯服務器收到的請求,這樣客戶端能夠看到(若是有)哪一些改變或者添加已經被中間服務器實現.(安全、冪等)PATCH
用於建立、更新資源,於PUT相似,區別在於PATCH表明部分更新; 後來提出的接口方法,使用時可能去要驗證客戶端和服務端是否支持;(非安全、冪等)GET 提交的數據量受 URL 長度的限制,HTTP 協議沒有對 URL 長度進行限制,這個限制是瀏覽器和服務器對他的限制;理論上 POST 也是沒有大小限制的,HTTP 協議也沒有進行大小限制,出於安全考慮,服務器會作必定的限制。編程
HTTP 協議中規定 POST 提交的數據必須在 Body 部分中,但協議並未規定數據須要採用何種數據格式或編碼方式,服務端一般經過請求頭中的 Content-Type
字段來獲知請求中的消息主體是以何種方式編碼,再對主體進行解析。 POST 提交數據的方案,包含:Content-Type 和消息主體編碼方式兩部分:json
application/x-www-form-urlencoded
:最多見的 POST 數據提交方式,瀏覽器的原生
multipart/form-data
:使用表單上傳文件時,必須讓表單的 enctype
等於 multipart/form-data
。這種方式通常用於上傳文件。application/json
text/xml
application/x-protobuf
只要服務器能夠根據 Content-Type 和 Content-Encoding 正確解析出請求便可。設計模式
HTTP 響應跟 HTTP 請求相似,也是由三部分構成:狀態行、響應頭、響應正文。 狀態行由協議版本、數字形式的狀態代碼、響應的狀態描述構成,各元素以空格分割。常見的狀態碼:瀏覽器
200 OK
客戶端請求成功301 Moved Permanently
請求永久重定向302 Moved Temporarily
請求臨時重定向304 Not Modified
文件未修改,能夠直接使用緩存文件400 Bad Request
因爲客戶端請求有語法錯誤,沒法被服務器所理解401 Unauthorized
請求未經受權(狀態代碼必須和WWW-Authenticate報頭域一塊兒使用)403 Forbidden
服務器收到請求,但拒絕提供服務。服務器一般會在響應正文中給出不提供服務的緣由。404 Not Found
請求的資源不存在。500 Internal Server Error
服務器發生不可預知的錯誤,致使沒法完成客戶端的請求。503 Service Unavailable
服務器當前不可處理客戶端的請求,在一段時間後服務器可能會恢復正常。HTTP 條件 GET 是HTTP 協議爲了減小沒必要要的寬帶浪費,提出的一種方案。 使用時機:客戶端以前已經訪問過該網站,並想再次訪問。 使用方法:客戶端向服務端發送一個包詢問是否在上次訪問網站後的時間後更改了頁面,若是服務器沒有更新,顯然不須要把整個網頁傳給客戶端,客戶端只須要使用本地緩存便可,若是服務器對照客戶端給出的時間已經更新了客戶端請求的網頁,則發送這個更新了的網頁給用戶。緩存
通常狀況下,HTTP 協議採用「請求-應答」模式,當使用普通模式,即非 Keep-Alive 模式時,每一個請求/應答客戶端和服務器都要新建一個鏈接,完成以後當即斷開鏈接(HTTP 協議爲無鏈接的協議);當使用 Keep-Alive 模式(又稱持久鏈接、鏈接重用)時,Keep-Alive 功能使客戶端到服務端的鏈接持續有效,當出現對服務器的後續請求時,Keep-Alive 功能避免了創建或者從新創建鏈接。 在 HTTP 1.0 中: 若是客戶端瀏覽器支持 Keep-Alive,那麼就在 HTTP 請求頭中添加一個字段 Connection-Keep-Alive
。 在 HTTP 1.1 中:默認全部鏈接都被保持。安全
Keep-Alive: timeout=5, max=100
,表示這個TCP通道能夠保持5秒,max=100,表示這個長鏈接最多接收100次請求就斷開.Keep-Alive
沒有改變這個結果,Keep-Alive
沒法保證客戶端和服務端的鏈接必定是活躍的,惟一能保證的是當鏈接被斷開時將會收到一個通知。Content-Length
指示的大小,2.動態生成的文件沒有 Content-Length ,它是分塊傳輸(chunked),這時候就要根據 chunked 編碼來判斷,chunked 編碼的數據在最後有一個空 chunked 塊,代表本次傳輸數據結束.Transform-Encoding
是一個用來標明 HTTP 報文傳輸格式的頭部值,當前的 HTTP 規範裏只定義了一種傳輸格式 - chunked
. 若是一個 HTTP 消息請求或應答消息的 Transform-Encoding
消息頭的值是 chunked ,那麼消息體由數量未定的塊組成,並以最後一個大小爲 0 的塊爲結束。服務器
chunked
和 multipart
兩個名詞在乎義上有相似的地方,不過在 HTTP 協議當中這兩個概念則不是一個類別的。multipart 是一種 Content-Type
,標示 HTTP 報文內容的類型,而 chunked
是一種傳輸格式,標示報頭將以何種方式進行傳輸。chunked
傳輸不能事先知道傳輸內容的大小,只能靠最後的空 chunked
塊來判斷結束,因此對於下載請求,是沒法知道下載進度的。chunked
優點在於服務端能夠邊生成內容邊發送,無需事先知道所有內容。HTTP/2 是不支持 Transfer-Encoding: chunked
的,由於 HTTP/2 有本身的 streaming 傳輸方式:Source:MDN - Transfer-Encoding
默認狀況下,HTTP 協議中每一個傳輸層鏈接只能承載一個 HTTP 請求和響應,瀏覽器會在收到上一個請求的響應以後再發送下一個請求。在使用持久鏈接的狀況下,某個鏈接上消息的傳遞相似於: 請求1 -> 響應1 -> 請求2 -> 響應2 -> 請求3 -> 響應3
。 使用 HTTP Pipelining 是將多個 HTTP 請求打包傳遞的技術,在傳送過程當中無需等待服務端的迴應,某個鏈接上消息的傳遞相似於:請求1 -> 請求2 -> 請求3 -> 響應1 -> 響應2 -> 響應3
。微信
客戶端打開與服務端的鏈接發送請求到服務端響應客戶端請求的全過程稱之爲會話。cookie
會話跟蹤是對同一個用戶對服務器的連續的請求和接收響應的監視。
客戶端跟服務端的通訊若是是採用 HTTP 協議通訊,而 HTTP 協議是無狀態的,它沒法保存用戶的狀態(信息),即一次響應後就斷開了,下次請求須要從新鏈接,此時須要判斷是否爲同一個用戶,因此須要會話跟蹤技術實現這種需求。
如何防止 CSRF
跨站攻擊:
Referer
Referer
中, 經過檢查 Referer
的值,咱們就能夠判斷這個請求是合法的仍是非法的,可是問題出在服務器不是任什麼時候候都能接受到 Referer
的值,因此 Referer Check
通常用於監控 CSRF
攻擊的發生,而不用來抵禦攻擊。CSRF
攻擊。若是防護 XSS: 將用戶的輸入使用 HTML 解析庫進行解析,獲取其中的數據。而後根據用戶原有的標籤屬性,從新構建 HTML 元素樹。構建的過程當中,全部的標籤、屬性都只從白名單中拿取。
HTTPS 即 HTTP over SSL/TLS ,是一種在加密通道進行 HTTP 內容傳輸的協議。
ClientHello
消息到服務端,消息中包含了它的 TLS (Transport Layer Security) 的版本、可用的加密算法和壓縮算法。ServerHello
消息,消息中包含了服務端 TLS 的版本,服務端所選擇的加密算法和壓縮算法,以及數字證書認證機構(Certificate Authority,縮寫 CA)簽發的服務器公開證書,證書中包含了公鑰。客戶端會使用這個公鑰來加密接下來的握手過程,直到協商生成一個新的對稱密鑰。證書中還包含了該證書所應用的域名範圍(Common Name,簡稱 CN),用於客戶端驗證身份。finished
消息給服務端,使用對稱密鑰加密此次通訊的一個散列值。finished
消息,也使用協商好的對稱密鑰加密。TLS 的完整過程須要三個算法(協議),密鑰交互算法、對稱加密算法、消息認證算法
HTTPS 過程當中有一個很重要的步驟,就是服務器要有 CA 證書機構頒發的證書,客戶端根據本身信任的 CA 列表驗證服務器的身份。 現代瀏覽器中,證書的驗證過程依賴於證書信任鏈:即一個證書須要依靠上一個證書來證實本身的可信的,最頂層的證書是根證書,擁有根證書的機構被稱爲 根 CA(通常操做系統自帶)。
所謂中間人攻擊,指攻擊者與通訊的兩端都創建獨立的聯繫,並交換其所接受到的數據,使通訊的雙方都認爲他們正在經過私密的鏈接直接與對方進行通話,事實上整個會話都會被攻擊者徹底控制。在中間人攻擊中,攻擊者能夠攔截雙方的通訊並插入新的內容。
SSL 剝離即阻止用戶使用 HTTPS 訪問網站。因爲並非全部網站都只支持 HTTPS,大部分網站會同時支持 HTTP 和 HTTPS 兩種協議。用戶在訪問網站時,也可能會在地址欄中輸入 http://
的地址,第一次的訪問徹底是明文的,這就給了攻擊者可乘之機。經過攻擊 DNS 響應,攻擊者能夠將本身變成中間人。
用於強制瀏覽器使用 HTTPS 訪問網站的一種機制。它的基本機制是在服務器返回的響應中,加上一個特殊的頭部,指示瀏覽器對於此網站,強制使用 HTTPS 進行訪問。 HSTS 有一個很明顯的缺點,是須要等待第一個服務器的影響中的頭部才能生效,但若是第一次訪問該網站就被攻擊呢?爲了解決這個問題,瀏覽器中會帶上一些網站的域名,被稱爲 HSTS preload list。對於在這個 list 的網站來講,直接強制使用 HTTPS。
HSTS 只解決了 SSL 剝離的問題,然而即便在全程使用 HTTPS 的狀況下,咱們仍然有可能被監聽。 第一步是須要攻擊 DNS 服務器。第二步是攻擊者本身的證書須要被用戶信任,這一步對於用戶來講是很難控制的,須要證書頒發機構可以控制本身不濫發證書。
HPKP 技術是爲了解決僞造證書攻擊而誕生的。 HPKP(Public Key Pinning Extension for HTTP)在 HSTS 上更進一步,HPKP 直接在返回頭中存儲服務器的公鑰指紋信息,一旦發現指紋和實際接受到的公鑰有差別,瀏覽器就能夠認爲正在被攻擊。 和 HSTS 相似,HPKP 也依賴於服務器的頭部返回,不能解決第一次訪問的問題,瀏覽器自己也會內置一些 HPKP 列表。
注意:TCP 並不能保證數據必定會被對方接收到,由於這是不可能的。TCP 能作到的是:若是有可能就把數據遞送給對方,不然就通知用戶(使用放棄重傳並中斷鏈接這一方式實現)。所以準確說 TCP 也不是 100% 可靠的協議,他所能提供的是數據的可靠遞送或故障的可靠通知。
所謂三次握手,是指創建一個 TCP
鏈接,客戶端和服務端須要傳送三個包。 三次握手的目的是鏈接服務器指定端口,創建 TCP
鏈接,並同步鏈接雙方的序列號和確認號,交換 TCP
窗口大小信息,在 socket
編程中,客戶端執行 connect()
觸發三次握手。
第一次握手:(SYN = 1,seq = x)
TCP
的 SYN
標誌位置 1 的包,指明客戶端須要鏈接的端口和初始序號 X, 保存在包頭的序列號(Sequence Number)字段裏。SYN_SEND
狀態。第二次握手:(SYN = 1,ACK = 1,seq = y,ACKnum = x + 1)
SYN
和 ACK
均爲 1,服務端選擇本身的 ISN
序號,放到 seq
域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN
加1,即 X+1
SYN_RCVD
狀態。第三次握手:(ACK = 1,ACKnum = y + 1)
SYN
標誌位爲 0,ACK
標誌位爲 1,而且把服務端發送的 ACK
的序號字段 + 1。ESTABLISHED
狀態,當服務器端接收到這個包時,也進入 ESTABLISHED
狀態,TCP
握手結束。三次握手示意圖:
TCP
的拆除須要發送四個包,所以稱爲四次揮手,也叫改進的三次握手。客戶端和服務端都可主動發起揮手動做,在 socket
編程中,任意一端執行 close()
便可產生揮手操做。
第一次揮手:(FIN = 1,seq = x)
FIN
標誌位爲 1 的包,表示本身沒有數據可發送了,但仍能夠接收數據。FIN_WAIT_1
狀態。第二次揮手:(ACK = 1,ACKnum = x + 1)
FIN
包,併發送一個確認包,代表本身接收到了客戶端關閉鏈接的請求,但尚未準備好關閉鏈接。CLOSE_WAIT
狀態,客戶端接收到這個確認包後,進入 FIN_WAIT_2
狀態,等待服務端關閉鏈接。第三次揮手:(FIN = 1,seq = y)
FIN
置爲 1。LAST_ACK
狀態,等待來自客戶端的最後一個 ACK
。第四次揮手:(ACK = 1,ACKnum = y + 1)
TIME_WAIT
狀態。等待可能出現的要求重傳的 ACK
包.CLOSED
狀態。ACK
,覺得服務端已經正常關閉鏈接,因而本身也關閉鏈接,進入 CLOSED
狀態。四次揮手示意圖:
SYN
攻擊?在三次握手過程當中的第二次握手時,服務器發送 SYN_ACK
以後,收到客戶端的 ACK
以前的 TCP
鏈接稱爲半鏈接。此時服務器處於 SYN_RCVD
狀態,當收到 ACK
後,服務器才能轉入 ESTABLISHED
狀態。 SYN
攻擊指的是,"攻擊客戶端" 在短期內僞造大量不存在的 IP 地址,向服務端不斷地發送 SYN
包,服務器回覆確認包,並等待客戶的確認。因爲源地址是不存在的,服務器須要不斷的重發直至超時,這些僞造的 SYN
包將長時間佔用未鏈接隊列,正常的 SYN
請求被丟棄,致使目標系統運行緩慢,嚴重者會引發網絡堵塞甚至系統癱瘓。 SYN
攻擊是一種典型的 Dos/DDos
攻擊
SYN
攻擊?當服務器出現大量的半鏈接狀態時,特別是源 IP 地址是隨機的,基本能夠判定這是一次 SYN
攻擊。在 Linux/Unix
上可使用系統自帶的 netstats
命令來檢測 SYN
攻擊。
SYN
攻擊?SYN
攻擊不能徹底被阻止,除非將 TCP
協議從新設計。能夠儘量減輕 SYN
攻擊的危害:
SYN cookie
技術TCP 的鏈接,其實是一種純軟件層面的概念,在物理層並無「鏈接」這種概念。若是出現一些意外致使某端出現異常而另外一端沒法感知,一直維護着這個鏈接,長時間會致使很是多的半鏈接狀態的 TCP 鏈接,形成端系統資源的消耗和浪費,爲了解決這個問題,在傳輸層能夠利用 TCP 的 KeepAlive 機制來避免。
TCP KeepAlive 的基本原理:隔一段時間給鏈接對端發送一個探測包,若是收到對方迴應的 ACK,則認爲鏈接仍是存活的,在超過必定重試次數以後仍是沒有收到對方的迴應,則丟棄該 TCP 鏈接。
TCP KeepAlive 的侷限:首先 TCP KeepAlive 檢測的方式是發送一個 probe 包,會給網絡帶來額外的流量,另外 TCP KeepAlive 只能再內核層級檢測鏈接的存活與否,而鏈接的存活不必定表明服務可用,例如當一個服務器 CPU 佔用 100% 已經卡死不能響應請求了,此時 TCP KeepAlive 依然會認爲鏈接是存活的。所以 TCP KeepAlive 對於應用層程序的價值是相對較小的。
UDP
是一個簡單的傳輸層協議,和 TCP
相比,UDP
有以下幾個顯著的特性:
UDP
缺少可靠性。UDP
自己不提供確認序列號、超時重傳等機制。UDP
數據報可能在網絡中被複制,被從新排序。即 UDP
不保證數據報會到達其最終目的地,也不保證各個數據報的前後順序,也不保證每一個數據報只到達一次。UDP
數據報是有長度的。每一個 UDP
數據報都有長度,若是一個數據報正確地到達目的地,那麼該數據報的長度將隨數據一塊兒傳遞給接收方。而 TCP
是一個字節流協議,沒有任何協議上的記錄邊界。UDP
是無鏈接的。UDP
客戶端和服務器之間不存在長期的關係,UDP
發送數據報以前也不須要通過握手建立鏈接的過程UDP
支持多播和廣播。IP 協議位於 TCP/IP 協議的第三層 - 網絡層。與傳輸層協議相比,網絡層的責任是提供點到點的服務,而傳輸層(TCP/UDP)則提供端到端的服務。
- | - |
---|---|
7 | 應用層 |
6 | 表示層 |
5 | 會話層 |
4 | 傳輸層 |
3 | 網絡層 |
2 | 數據鏈路層 |
1 | 物理層 |
廣播與多播僅用於 UDP(TCP 是面向鏈接的)
一共有四種廣播地址:
255.255.255.255
,又稱組播,使用 D 類地址,D類地址分配的 28bit 均用做多播組號而再也不表示其餘
邊界網關協議(BGP)是運行於 TCP 上的一種自治系統的路由協議
Socket 是對 TCP/IP 協議族的一種封裝,是應用層與 TCP/IP 協議族通訊的中間軟件抽象層。從設計模式的角度看,Socket 其實就是一個門面模式,它把複雜的 TCP/IP 協議族隱藏在 Socket 接口後面,對用戶來講,一組簡單的接口就是所有,讓 Socket 去組織數據,以符合指定的協議。 Socket 還能夠認爲是一種網絡間不一樣計算機上的進程通訊的一種方法,利用三元組(IP 地址、協議、端口)就能夠惟一標識網絡中的進程,網絡中的進程通訊能夠利用這個標誌與其餘進程進行交互。 Socket 起源於 Unix,Unix/Linux 基本哲學之一就是:一切皆文件,均可以用「打開(open)-> 讀寫(write/read)-> 關閉(close)」模式來進行操做,所以 Socket 也被處理爲一種特殊的文件。
一個簡單的 Server 的流程包括:
大致的程序與調用的函數邏輯:
socket()
建立套接字bind()
分配套接字地址listen()
等待鏈接請求accept()
容許鏈接請求read()/write()
數據交換close()
關閉鏈接一個沒有雞湯只有乾貨的公衆號