-
HTTP協議
- 一次http請求的過程
- 用戶輸入url,瀏覽器本地解析url,如果在host文件中存有對應ip則訪問對應ip,否則將域名交給DNS服務器,DNS服務器返回對應IP地址,應用層向ip地址發送http請求,然后是傳輸層TCP的三次握手確認連接,第一次是客戶端向服務器發送syn,第二次是服務器發送syn和ack到客戶端,第三次是客戶端發送syn與ack確認,此時TCP握手成功,然后到網絡層,通過ARP協議,使用ip解析出MAC地址,然后通過MAC地址在數據鏈路層傳輸數據,服務器接收到數據包后,由web服務器處理該請求,查找客戶端請求的資源,並返回響應報文。
- 斷開連接需要TCP4次揮手,任意一方可開始,機器1發送fin=1到機器2表示數據傳輸完畢,斷開請求,機器2返回ack=1確認收到關閉請求,等待機器2的信息傳送完畢后,機器2發送fin=1到機器1,此時機器2會有定時器等待機器1返回ack=1,如果沒有返回,會重發fin=1,機器1返回ack=1確認關閉請求。
- http與https的區別
- https需要去CA申請證書
- http運行在TCP之上,所有傳輸內容都是明文,HTTPS運行在SSL/TLS之上,SSL/TLS運行在TCP之上,所有傳輸內容都是加密的
- http默認端口80,HTTPS默認端口443
- GET和POST區別
- GET方法是從服務器獲取資源
- POST方法是向指定URI提交數據,數據放在body中
- GET請求的URL有長度限制,而POST請求數據會放在消息體中,沒有長度限制
- GET請求會被瀏覽器主動cache,而post不會
- GET請求在發送過程中產生一個TCP數據包,POST請求會產生兩個數據包。對於GET請求,瀏覽器會將header和data一起發送,服務器返回響應,而POST請求,瀏覽器是先發送header,服務器響應100 continue,瀏覽器再發送data。
- 一次http請求的過程
-
TCP協議
- TCP三次握手與四次揮手,本文第一條
- 如何可以繞過三次握手?
- Linux3.7內核版本之后,提供了TCP Fast Open功能,可以減少TCP連接建立的時延
- 客戶端發送 SYN 報文,該報文包含 Fast Open 選項,且該選項的 Cookie 為空,這表明客戶端請求 Fast Open Cookie;
-
支持 TCP Fast Open 的服務器生成 Cookie,並將其置於 SYN-ACK 數據包中的 Fast Open 選項以發回客戶端;
-
客戶端收到 SYN-ACK 后,本地緩存 Fast Open 選項中的 Cookie。
- 所以第一次發起請求時,還是需要正常的三次握手,之后如果再次向服務器建立連接的過程:
- 客戶端發送 SYN 報文,該報文包含「數據」(對於非 TFO 的普通 TCP 握手過程,SYN 報文中不包含「數據」)以及此前記錄的 Cookie;
- 支持 TCP Fast Open 的服務器會對收到 Cookie 進行校驗:如果 Cookie 有效,服務器將在 SYN-ACK 報文中對 SYN 和「數據」進行確認,服務器隨后將「數據」遞送至相應的應用程序;如果 Cookie 無效,服務器將丟棄 SYN 報文中包含的「數據」,且其隨后發出的 SYN-ACK 報文將只確認 SYN 的對應序列號;
- 如果服務器接受了 SYN 報文中的「數據」,服務器可在握手完成之前發送「數據」,這就減少了握手帶來的 1 個 RTT 的時間消耗;
- 客戶端將發送 ACK 確認服務器發回的 SYN 以及「數據」,但如果客戶端在初始的 SYN 報文中發送的「數據」沒有被確認,則客戶端將重新發送「數據」;
- 此后的 TCP 連接的數據傳輸過程和非 TFO 的正常情況一致
- 之后發起 HTTP GET 請求的時候,可以繞過三次握手,這就減少了握手帶來的 1 個 RTT 的時間消耗
- /proc/sys/net/ipv4/tcp_fastopen
- 0 關閉
- 1 作為客戶端使用 Fast Open 功能
- 2 作為服務端使用 Fast Open 功能
- 3 無論作為客戶端還是服務器,都可以使用 Fast Open 功能
- Linux3.7內核版本之后,提供了TCP Fast Open功能,可以減少TCP連接建立的時延
- UDP與TCP的區別
- TCP半連接隊列和全連接隊列
- TCP三次握手的時候,Linux內核會維護兩個隊列:
- 半連接隊列,也稱SYN隊列
- 全連接隊列,也稱accept隊列
- 服務端收到客戶端發起的SYN請求后,內核會把該連接存儲到半連接隊列,並向客戶端返回ACK,服務端收到第三次握手的ACK后,內核會把連接從半連接隊列移除,然后創建新的完全的連接,並將其添加到accept隊列,等待進程調用accept函數時把連接取出來.
- 不管是半連接還是全連接隊列,都有最大長度限制,超過限制時,內核會直接丟棄,或返回RST包
- 全連接隊列:
- 查看TCP全連接隊列的大小:服務端使用ss命令
- ss
- -l 顯示正在監聽(listening)的socket
- -n 不解析服務名稱
- -t 只顯示tcp socket
- 在LISTEN狀態時(ss -lnt),Recv-Q/Send-Q表示的含義如下:
- Recv-Q:當前全連接隊列的大小
- Send-Q:當前全連接最大隊列長度
- 非LISTEN狀態時(ss -nt)
- Recv-Q:已收到但未被應用進程讀取的字節數
- Send-Q:已發送但未收到確認的字節數
- ss
- 當服務端並發處理大量請求時,如果TCP全連接隊列過小,就容易溢出。發生了全連接隊列溢出時,后續的請求就會被丟棄,出現服務端請求數量上不去的現象
- 丟棄連接是Linux的默認行為,我們可以選擇向客戶端發送RST復位報文,告訴客戶端連接建立失敗。
/proc/sys/net/ipv4/tcp_abort_on_overflow
這個文件默認為0- 0:表示如果全連接隊列滿了,就扔掉連接
- 1:表示如果全連接隊列滿了,就發送一個reset包給client,表示廢除握手過程和連接
- 通常情況下,tcp_abort_on_overflow應該設置為0,更有利於應對突發流量
- 如何增大TCP全連接隊列?
- TCP全連接隊列最大值取決於somaxconn和backlog的最小值
- somaxconn 是 Linux 內核的參數,默認值是 128,可以通過 /proc/sys/net/core/somaxconn 來設置其值;
- backlog 是 listen(int sockfd, int backlog) 函數中的 backlog 大小,Nginx 默認值是 511,可以通過修改配置文件設置其長度;
- nginx中backlog設置成5000的demo:
設置完后需要重啟
- TCP全連接隊列最大值取決於somaxconn和backlog的最小值
- 查看TCP全連接隊列的大小:服務端使用ss命令
- 半連接隊列:
- 服務端沒有命令單獨查看半連接隊列,但可以抓住TCP半連接隊列的特點,就是服務端處於SYN_RECV狀態的TCP連接,就是在半連接隊列中
- 因此,計算TCP半連接隊列長度的命令如下:模擬半連接隊列的溢出場景,實際上就是一直對服務端發送TCP SYN包,但是不回第三次握手的ACK,這樣就會有大量的處於SYN_RECV狀態的TCP連接,其實這就是所謂的SYN洪泛,SYN攻擊,DDos攻擊
- netstat -natp | grep SYN_RECV | wc -l
- 半連接隊列的溢出處理是怎么做的?
- 如果半連接隊列滿了,並且沒有開啟 tcp_syncookies,則會丟棄;
- 若全連接隊列滿了,且沒有重傳 SYN+ACK 包的連接請求多於 1 個,則會丟棄
- 如果沒有開啟 tcp_syncookies,並且 max_syn_backlog 減去 當前半連接隊列長度小於 (max_syn_backlog >> 2),則會丟棄;
- 半連接隊列最大值
- 當 max_syn_backlog > min(somaxconn, backlog) 時, 半連接隊列最大值 max_qlen_log = min(somaxconn, backlog) * 2;
- 當 max_syn_backlog < min(somaxconn, backlog) 時, 半連接隊列最大值 max_qlen_log = max_syn_backlog * 2;
- syncookies
- 如果 SYN 半連接隊列已滿,開啟 syncookies 功能就可以在不使用 SYN 半連接隊列的情況下成功建立連接
- syncookies 是這么做的:服務器根據當前狀態計算出一個值,放在己方發出的 SYN+ACK 報文中發出,當客戶端返回 ACK 報文時,取出該值驗證,如果合法,就認為連接建立成功,如下圖所示。
-
syncookies 參數主要有以下三個值:
-
0 值,表示關閉該功能;
-
1 值,表示僅當 SYN 半連接隊列放不下時,再啟用它;
-
2 值,表示無條件開啟功能;
-
- 因此,應對SYN攻擊時,只需要設置為1即可
- 防御SYN攻擊的方法:
- 增大半連接隊列
- 通過源碼得知,如果想增大半連接隊列,不能單純增加tcp_max_syn_backlog,還需一同增大somaxconn和backlog,也就是增大全連接隊列,增大tcp_max_syn_backlog和somaxconn的方法就是修改Linux內核參數:路徑分別為:/proc/sys/net/ipv4/tcp_max_syn_backlog
/proc/sys/net/core/somaxconn
- 通過源碼得知,如果想增大半連接隊列,不能單純增加tcp_max_syn_backlog,還需一同增大somaxconn和backlog,也就是增大全連接隊列,增大tcp_max_syn_backlog和somaxconn的方法就是修改Linux內核參數:路徑分別為:/proc/sys/net/ipv4/tcp_max_syn_backlog
- 開啟tcp_syncookies功能
- 路徑為/proc/sys/net/ipv4/tcp_syncookies
- 減少SYN+ACK重傳次數
- 當收到SYN攻擊時,就會有大量處於SYN_RECV的TCP連接,服務端此時會重傳SYN+ACK,當重傳次數達到上限后,就會斷開連接,因此,我們可以通過減少SYN+ACK的重傳次數,加快連接斷開來抵御攻擊
- /proc/sys/net/ipv4/tcp_synack_retries
- 增大半連接隊列
- TCP三次握手的時候,Linux內核會維護兩個隊列: