「抵擋爬蟲」修訂間的差異
跳至導覽
跳至搜尋
| (未顯示同一使用者於中間所作的 58 次修訂) | |||
| 行 1: | 行 1: | ||
[[分類:網路服務]] | [[分類:網路服務]] | ||
| + | [[Cloudflare]]頁中有「抵擋爬蟲」的段落 | ||
| + | ===DS720+ 檢測=== | ||
| + | ==== TCP 交握機制==== | ||
| + | <table style='border:none'> | ||
| + | <tr><th colspan=4 style='border:none;font-weight:normal'>TCP 交握過程</th></tr> | ||
| + | <tr><th style='border:none'>Client</th><th style='border:none'></th><th style='border:none;text-align:left'>Server</th><th style='border:none;'>State</th></tr> | ||
| + | <tr><th style='border:none;text-align:right;font-weight:normal;font-size:85%'>SYN</th><th style='border:none;font-size:70%'>--------------------></th><th style='border:none'></th><th style='border:none;font-weight:normal;font-size:70%'>LISTEN</th></tr> | ||
| + | <tr><th style='border:none'></th><th style='border:none;font-size:70%'><--------------------</th><th style='border:none;text-align:left;font-weight:normal;font-size:85%'>SYN+ACK</th><th style='border:none;font-weight:normal;font-size:70%'>SYN_RECV</th></tr> | ||
| + | <tr><th style='border:none;text-align:right;font-weight:normal;font-size:85%'>ACK</th><th style='border:none;font-size:70%'>--------------------></th><th style='border:none'></th><th style='border:none;font-weight:normal;font-size:70%'>ESTABLISHED</th></tr> | ||
| + | <tr><th style='border:none'></th><th style='border:none;font-weight:normal;font-size:70%'>ESTABLISHED</th><th style='border:none'></th></tr> | ||
| + | </table> | ||
| + | # 客戶端送:SYN(Synchronize,同步序號)。意思是:你好,我想建立連線。 | ||
| + | # 伺服器回:SYN + ACK(Acknowledgement,確認收到)。意思是:收到你的要求,我也願意建立連線。 | ||
| + | # 客戶端回:ACK。意思是:收到你的同意。 | ||
| + | # 然後 ESTABLISHED(已確立) 形成正式連線。 | ||
| + | 各種 TCP 狀態: | ||
| + | # LISTEN:程式正在監聽某個 Port ,等待別人連進來 | ||
| + | # SYN_RECV:半完成連線 | ||
| + | # ESTABLISHED:TCP 三向交握完成,雙方正在傳輸資料 | ||
| + | # FIN_WAIT1:本機想關閉連線,已送出 FIN ,等待對方 ACK 。例如:瀏覽器關閉網頁,通常停留很短。 | ||
| + | # FIN_WAIT2:對方已 ACK ,但還沒送 FIN | ||
| + | # LAST_ACK:本機收到對方 FIN ,已回 FIN ,等待最後 ACK | ||
| + | # TIME_WAIT:避免舊封包干擾新連線。Linux 預設會保留:60 秒左右(依系統設定) | ||
| − | + | ====找出佔用 CPU 的環節==== | |
| + | <ol> | ||
| + | <li>監看目前所有程式的執行狀況:top | ||
| + | <ul> | ||
| + | <li><code>PID</code>: 執行任務的 Process ID</li> | ||
| + | <li><code>USER</code>: 執行任務的使用者是誰</li> | ||
| + | <li><code>PR</code>: 任務的優先度 (Priority)</li> | ||
| + | <li><code>NI</code>: 任務的 Nice Value,負的值代表優先度高,正的值代表優先度低</li> | ||
| + | <li><code>VIRT</code>: 總共用到多少 kB 虛擬記憶體 (Virtual Memory)</li> | ||
| + | <li><code>RES</code>: 實體記憶體 (Resident Size) 大小 kB</li> | ||
| + | <li><code>SHR</code>: 總共用到多少 kB 的共享記憶體 (Shared Memory)</li> | ||
| + | <li><code>S</code>: 狀態 (Status) | ||
| + | <ul> | ||
| + | <li>R 代表執行中</li> | ||
| + | <li>D 代表不可中斷睡眠 (不可被 signal 打斷通常在等 I/O)</li> | ||
| + | <li>S 代表睡眠 (可被喚醒)</li> | ||
| + | <li>T 中斷中或停止,可能是被 <code>SIGSTOP</code> 或 <code>SIGTSTP</code> 停止,或是被 degubber 中斷 (ptrace)</li> | ||
| + | <li>Z 代表殭屍,通常發生在 Child 已經執行完,等待 Parent 結束或回收</li> | ||
| + | </ul> | ||
| + | </li> | ||
| + | <li><code>%CPU</code>: 占用到多少 CPU %,注意到一個核心是 100%,所以多核心是可以超過 100% 的</li> | ||
| + | <li><code>%MEM</code>: 占用到多少全部記憶體多少比例</li> | ||
| + | <li><code>TIME+</code>: 已經執行多少時間</li> | ||
| + | <li><code>COMMAND</code>: 任務的指令名稱</li> | ||
| + | </ul> | ||
| + | </li> | ||
| + | <li>找出目前最吃 CPU 的前 20 個行程:ps aux --sort=-%cpu | head -20 | ||
| + | <ol> | ||
| + | <li>ps aux:列出目前系統中的行程。</li> | ||
| + | <li>--sort=-%cpu:依照 CPU 使用率排序,負號 - 表示由大排到小。</li> | ||
| + | <li>| head -20:顯示前 20 行,因為第一行通常是標題列,所以輸出:標題列 + CPU 使用率最高的 19 個行程。</li> | ||
| + | </ol> | ||
| + | 常見欄位如下:<br/><span>USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND</span><br/><span>root 1234 85.3 1.2 123456 45678 ? R 10:01 2:33 php-fpm</span><br/><span>mysql 5678 40.1 8.5 987654 345678 ? Sl 09:50 12:10 mariadbd</span> | ||
| + | |||
| + | 各欄大意:<br/><span>USER:執行這個行程的使用者</span><br/><span>PID:行程編號</span><br/><span>%CPU:CPU 使用率</span><br/><span>%MEM:記憶體使用率</span><br/><span>VSZ:虛擬記憶體大小</span><br/><span>RSS:實際佔用的實體記憶體</span><br/><span>TTY:連接的終端機</span><br/><span>STAT:行程狀態</span><br/><span>START:啟動時間</span><br/><span>TIME:累積使用 CPU 的時間</span><br/><span>COMMAND:執行的指令</span> | ||
| + | </li> | ||
| + | <li>查連網統計:netstat(Network Statistics)<br/>常見參數: | ||
| + | <ul> | ||
| + | <li>-a:顯示所有連線與監聽的連接埠。</li> | ||
| + | <li>-t:顯示 TCP 協定相關資訊。</li> | ||
| + | <li>-u:顯示 UDP 協定相關資訊。</li> | ||
| + | <li>-n:以數字形式顯示位址與連接埠(不進行 DNS 反查,速度較快)。</li> | ||
| + | <li>-p:顯示佔用該連線的程式名稱與 PID(需具備 root 權限)。</li> | ||
| + | <li>-l:僅顯示正在「監聽(Listening)」的服務。</li> | ||
| + | </ul> | ||
| + | 應用的命令: | ||
| + | <ul> | ||
| + | <li>「netstat -antp | grep :80」查從 80 進來的工作都在幹嘛</li> | ||
| + | <li>「netstat -tn | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -20」 | ||
| + | <ol> | ||
| + | <li>netstat -tn:列出目前的 TCP 網路連線。輸出可能像這樣:<br/><span>Proto Recv-Q Send-Q Local Address Foreign Address State</span><br/><span>tcp 0 0 192.168.1.10:80 47.82.8.63:52344 ESTABLISHED</span><br/><span>tcp 0 0 192.168.1.10:443 66.249.66.1:44321 ESTABLISHED</span></li> | ||
| + | <li>grep ESTABLISHED:只保留 TCP 連線已成功建立,雙方正在或可以傳輸資料的狀態(ESTABLISHED)的連線。排除:LISTEN、TIME_WAIT、CLOSE_WAIT、SYN_SENT、FIN_WAIT等狀態的連線。</li> | ||
| + | <li>awk '{print $5}':取出第 5 欄,也就是遠端位址 Foreign Address。即 47.82.8.63:52344 。</li> | ||
| + | <li>cut -d: -f1:用冒號「:」當分隔符,只取第 1 段。取回 47.82.8.63 。</li> | ||
| + | <li>sort:把 IP 排序,讓相同 IP 排在一起,以便下一步的 uniq -c 能正確統計。</li> | ||
| + | <li>uniq -c:統計連續重複的行數。如「3 47.82.8.63」代表 47.82.8.63 出現 3 次。</li> | ||
| + | <li>sort -nr:依照數字由大到小排序。-n 用數字大小排序;-r 表示反向排序,也就是由大到小。</li> | ||
| + | <li>head -20:只顯示前 20 筆,也就是連線數最多的前 20 個遠端 IP。</li> | ||
| + | </ol> | ||
| + | 如果你的伺服器前面有 Cloudflare,這個指令看到的遠端 IP 可能會是 Cloudflare 節點 IP,不一定是真正訪客 IP。 | ||
| + | </li> | ||
| + | </ul> | ||
| + | <li>發現是阿里雲上的虛擬伺服器來打爆 DS720+ 。<li> | ||
| + | <li>封阿里雲常見的掃描來源網段:<br/>在「DSM / 控制台 / 安全性 / 防火牆 / 防火牆設定檔 / 編輯規則 / 新增」:<br/>「所有連接埠 | 拒絕 | 特定 IP => IP 範圍:從 47.79.0.0 到 47.79.255.255」。封鎖以下三個阿里雲網段: | ||
| + | <dl> | ||
| + | <dd>47.79.0.0/16</dd> | ||
| + | <dd>47.82.0.0/16</dd> | ||
| + | <dd>47.88.0.0/16</dd> | ||
| + | </dl> | ||
| + | </li> | ||
| + | <li>封鎖前後比較: | ||
| + | <table class='nicetable'> | ||
| + | <tr><th>狀態</th><th>封鎖前</th><th>封鎖後</th></tr> | ||
| + | <tr><td>ESTABLISHED</td><td>1115</td><td>27</td></tr> | ||
| + | <tr><td>CLOSE_WAIT</td><td>308</td><td>0</td></tr> | ||
| + | <tr><td>FIN_WAIT2</td><td>297</td><td>0</td></tr> | ||
| + | <tr><td>SYN_SENT</td><td>92</td><td>0</td></tr> | ||
| + | <tr><td>CPU</td><td>50~85%</td><td>明顯下降</td></tr> | ||
| + | <tr><td>寫入量</td><td>很高</td><td>幾乎歸零</td></tr> | ||
| + | </table> | ||
| + | </li> | ||
| + | </ol> | ||
| − | === | + | ====網路請求與交握流程==== |
| − | # | + | # <span>HTTP</span><br><span> ↓</span><br><span>Apache</span><br><span> ↓</span><br><span>PHP</span><br><span> ↓</span><br><span>MediaWiki</span><br><span> ↓</span><br><span>MariaDB</span> |
| + | # TCP 的正常流程:<span>ESTABLISHED</span><br><span> ↓</span><br><span>FIN_WAIT</span><br><span> ↓</span><br><span>TIME_WAIT</span><br><span> ↓</span><br><span>消失</span> | ||
| + | # http_response_code(503); 能瞬間降低負載。 | ||
| + | # sudo iostat -xm 1 | ||
| + | # netstat -ant | awk '{print $6}' | sort | uniq -c 回應 | ||
| + | 1 established) | ||
| + | 或 | ||
| + | 1 established) | ||
| + | 41 ESTABLISHED | ||
| + | 1 Foreign | ||
| + | 32 LISTEN | ||
| + | 985 TIME_WAIT | ||
| + | # 列出 cpu 佔用的前 20 名:「ps aux --sort=-%cpu | head -20」<br/>發現主要是 mariadbd 和數個 php-fpm worker => 11MB/s 寫入量來自「MediaWiki → PHP → MariaDB」鏈條 | ||
| − | ==== | + | ====檢查儲存裝置被頻繁寫入==== |
| + | 發現儲存裝置有 11MB/s 寫入量 | ||
| + | # 查資料庫請求的增量:「SHOW GLOBAL STATUS LIKE 'Questions';」 60 秒後 再執行一次,看增加多少 => 60 秒增加:76491 => 約 1,275 queries / 秒 | ||
| + | # 查是哪些請求:「SHOW FULL PROCESSLIST;」秀出運行中的全部請求<br/>如果太多,先用這個:<br/>---------- information_schema 資料庫中的 PROCESSLIST 資料表 ---------- | ||
| + | #*SELECT ID,USER,DB,COMMAND,TIME,STATE,LEFT(INFO,300) AS SQL_TEXT FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND<>'Sleep' ORDER BY TIME DESC;<br/>也查資料庫連線來源: | ||
| + | #*SELECT USER,DB,COMMAND,COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST GROUP BY USER,DB,COMMAND ORDER BY COUNT(*) DESC; | ||
| + | #*查到:<br/>REPLACE /* SqlBagOStuff::updateTable */ INTO `wiki_objectcache` (keyname,value,exptime) VALUES ('alWiki:messages:zh-tw','………','20380119031407') | ||
| + | #:11MB/s 寫入的原因很明確:objectcache 一直被 REPLACE<br/>---------- 查快取是否使用 wiki_objectcache ---------- | ||
# SELECT COUNT(*) FROM wiki_objectcache; 等一分鐘再查一次,如果數量持續增加,是使用 wiki_objectcache | # SELECT COUNT(*) FROM wiki_objectcache; 等一分鐘再查一次,如果數量持續增加,是使用 wiki_objectcache | ||
# 看 SHOW TABLE STATUS LIKE 'wiki_objectcache'; 中的: | # 看 SHOW TABLE STATUS LIKE 'wiki_objectcache'; 中的: | ||
| 行 18: | 行 141: | ||
#* Index_length | #* Index_length | ||
#* Update_time | #* Update_time | ||
| + | # 清快取表:「TRUNCATE TABLE wiki_objectcache;」 | ||
| + | # sudo synopkg restart MariaDB10 重啟資料庫服務 | ||
| + | # sudo synopkg restart WebStation 重啟網頁服務 | ||
| + | # sudo synosystemctl restart pkgctl-WebStation 只重啟 PHP-FPM | ||
於 2026年6月6日 (六) 20:55 的最新修訂
Cloudflare頁中有「抵擋爬蟲」的段落
DS720+ 檢測
TCP 交握機制
| TCP 交握過程 | |||
|---|---|---|---|
| Client | Server | State | |
| SYN | --------------------> | LISTEN | |
| <-------------------- | SYN+ACK | SYN_RECV | |
| ACK | --------------------> | ESTABLISHED | |
| ESTABLISHED | |||
- 客戶端送:SYN(Synchronize,同步序號)。意思是:你好,我想建立連線。
- 伺服器回:SYN + ACK(Acknowledgement,確認收到)。意思是:收到你的要求,我也願意建立連線。
- 客戶端回:ACK。意思是:收到你的同意。
- 然後 ESTABLISHED(已確立) 形成正式連線。
各種 TCP 狀態:
- LISTEN:程式正在監聽某個 Port ,等待別人連進來
- SYN_RECV:半完成連線
- ESTABLISHED:TCP 三向交握完成,雙方正在傳輸資料
- FIN_WAIT1:本機想關閉連線,已送出 FIN ,等待對方 ACK 。例如:瀏覽器關閉網頁,通常停留很短。
- FIN_WAIT2:對方已 ACK ,但還沒送 FIN
- LAST_ACK:本機收到對方 FIN ,已回 FIN ,等待最後 ACK
- TIME_WAIT:避免舊封包干擾新連線。Linux 預設會保留:60 秒左右(依系統設定)
找出佔用 CPU 的環節
- 監看目前所有程式的執行狀況:top
PID: 執行任務的 Process IDUSER: 執行任務的使用者是誰PR: 任務的優先度 (Priority)NI: 任務的 Nice Value,負的值代表優先度高,正的值代表優先度低VIRT: 總共用到多少 kB 虛擬記憶體 (Virtual Memory)RES: 實體記憶體 (Resident Size) 大小 kBSHR: 總共用到多少 kB 的共享記憶體 (Shared Memory)S: 狀態 (Status)- R 代表執行中
- D 代表不可中斷睡眠 (不可被 signal 打斷通常在等 I/O)
- S 代表睡眠 (可被喚醒)
- T 中斷中或停止,可能是被
SIGSTOP或SIGTSTP停止,或是被 degubber 中斷 (ptrace) - Z 代表殭屍,通常發生在 Child 已經執行完,等待 Parent 結束或回收
%CPU: 占用到多少 CPU %,注意到一個核心是 100%,所以多核心是可以超過 100% 的%MEM: 占用到多少全部記憶體多少比例TIME+: 已經執行多少時間COMMAND: 任務的指令名稱
- 找出目前最吃 CPU 的前 20 個行程:ps aux --sort=-%cpu | head -20
- ps aux:列出目前系統中的行程。
- --sort=-%cpu:依照 CPU 使用率排序,負號 - 表示由大排到小。
- | head -20:顯示前 20 行,因為第一行通常是標題列,所以輸出:標題列 + CPU 使用率最高的 19 個行程。
常見欄位如下:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1234 85.3 1.2 123456 45678 ? R 10:01 2:33 php-fpm
mysql 5678 40.1 8.5 987654 345678 ? Sl 09:50 12:10 mariadbd各欄大意:
USER:執行這個行程的使用者
PID:行程編號
%CPU:CPU 使用率
%MEM:記憶體使用率
VSZ:虛擬記憶體大小
RSS:實際佔用的實體記憶體
TTY:連接的終端機
STAT:行程狀態
START:啟動時間
TIME:累積使用 CPU 的時間
COMMAND:執行的指令 - 查連網統計:netstat(Network Statistics)
常見參數:- -a:顯示所有連線與監聽的連接埠。
- -t:顯示 TCP 協定相關資訊。
- -u:顯示 UDP 協定相關資訊。
- -n:以數字形式顯示位址與連接埠(不進行 DNS 反查,速度較快)。
- -p:顯示佔用該連線的程式名稱與 PID(需具備 root 權限)。
- -l:僅顯示正在「監聽(Listening)」的服務。
應用的命令:
- 「netstat -antp | grep :80」查從 80 進來的工作都在幹嘛
- 「netstat -tn | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -20」
- netstat -tn:列出目前的 TCP 網路連線。輸出可能像這樣:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 192.168.1.10:80 47.82.8.63:52344 ESTABLISHED
tcp 0 0 192.168.1.10:443 66.249.66.1:44321 ESTABLISHED - grep ESTABLISHED:只保留 TCP 連線已成功建立,雙方正在或可以傳輸資料的狀態(ESTABLISHED)的連線。排除:LISTEN、TIME_WAIT、CLOSE_WAIT、SYN_SENT、FIN_WAIT等狀態的連線。
- awk '{print $5}':取出第 5 欄,也就是遠端位址 Foreign Address。即 47.82.8.63:52344 。
- cut -d: -f1:用冒號「:」當分隔符,只取第 1 段。取回 47.82.8.63 。
- sort:把 IP 排序,讓相同 IP 排在一起,以便下一步的 uniq -c 能正確統計。
- uniq -c:統計連續重複的行數。如「3 47.82.8.63」代表 47.82.8.63 出現 3 次。
- sort -nr:依照數字由大到小排序。-n 用數字大小排序;-r 表示反向排序,也就是由大到小。
- head -20:只顯示前 20 筆,也就是連線數最多的前 20 個遠端 IP。
如果你的伺服器前面有 Cloudflare,這個指令看到的遠端 IP 可能會是 Cloudflare 節點 IP,不一定是真正訪客 IP。
- netstat -tn:列出目前的 TCP 網路連線。輸出可能像這樣:
- 發現是阿里雲上的虛擬伺服器來打爆 DS720+ 。
- 封阿里雲常見的掃描來源網段:
在「DSM / 控制台 / 安全性 / 防火牆 / 防火牆設定檔 / 編輯規則 / 新增」:
「所有連接埠 | 拒絕 | 特定 IP => IP 範圍:從 47.79.0.0 到 47.79.255.255」。封鎖以下三個阿里雲網段:- 47.79.0.0/16
- 47.82.0.0/16
- 47.88.0.0/16
- 封鎖前後比較:
狀態 封鎖前 封鎖後 ESTABLISHED 1115 27 CLOSE_WAIT 308 0 FIN_WAIT2 297 0 SYN_SENT 92 0 CPU 50~85% 明顯下降 寫入量 很高 幾乎歸零
網路請求與交握流程
- HTTP
↓
Apache
↓
PHP
↓
MediaWiki
↓
MariaDB - TCP 的正常流程:ESTABLISHED
↓
FIN_WAIT
↓
TIME_WAIT
↓
消失
- http_response_code(503); 能瞬間降低負載。
- sudo iostat -xm 1
- netstat -ant | awk '{print $6}' | sort | uniq -c 回應
1 established)
或
1 established)
41 ESTABLISHED
1 Foreign
32 LISTEN
985 TIME_WAIT
- 列出 cpu 佔用的前 20 名:「ps aux --sort=-%cpu | head -20」
發現主要是 mariadbd 和數個 php-fpm worker => 11MB/s 寫入量來自「MediaWiki → PHP → MariaDB」鏈條
檢查儲存裝置被頻繁寫入
發現儲存裝置有 11MB/s 寫入量
- 查資料庫請求的增量:「SHOW GLOBAL STATUS LIKE 'Questions';」 60 秒後 再執行一次,看增加多少 => 60 秒增加:76491 => 約 1,275 queries / 秒
- 查是哪些請求:「SHOW FULL PROCESSLIST;」秀出運行中的全部請求
如果太多,先用這個:
---------- information_schema 資料庫中的 PROCESSLIST 資料表 ----------- SELECT ID,USER,DB,COMMAND,TIME,STATE,LEFT(INFO,300) AS SQL_TEXT FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND<>'Sleep' ORDER BY TIME DESC;
也查資料庫連線來源: - SELECT USER,DB,COMMAND,COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST GROUP BY USER,DB,COMMAND ORDER BY COUNT(*) DESC;
- 查到:
REPLACE /* SqlBagOStuff::updateTable */ INTO `wiki_objectcache` (keyname,value,exptime) VALUES ('alWiki:messages:zh-tw','………','20380119031407')
- 11MB/s 寫入的原因很明確:objectcache 一直被 REPLACE
---------- 查快取是否使用 wiki_objectcache ----------
- SELECT ID,USER,DB,COMMAND,TIME,STATE,LEFT(INFO,300) AS SQL_TEXT FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND<>'Sleep' ORDER BY TIME DESC;
- SELECT COUNT(*) FROM wiki_objectcache; 等一分鐘再查一次,如果數量持續增加,是使用 wiki_objectcache
- 看 SHOW TABLE STATUS LIKE 'wiki_objectcache'; 中的:
- Data_length
- Index_length
- Update_time
- 清快取表:「TRUNCATE TABLE wiki_objectcache;」
- sudo synopkg restart MariaDB10 重啟資料庫服務
- sudo synopkg restart WebStation 重啟網頁服務
- sudo synosystemctl restart pkgctl-WebStation 只重啟 PHP-FPM