器攻擊與防御實戰(zhàn)指南:從DDoS到WebShell的排查與加固)
干服務(wù)器運維這行越久越明白一件事你永遠不知道下一分鐘攻擊會從哪個方向來。我接手過一臺被挖礦腳本占滿CPU的Web服務(wù)器半夜替電商客戶處理過CC攻擊打到帶寬爆掉的告警也親眼見過同事因為一條文件上傳漏洞整個后臺被重裝成別人的“肉雞”。服務(wù)器攻擊與防御這件事表面上是工具和規(guī)則的對抗本質(zhì)上是對攻擊者思路的還原——你只有知道對方怎么進來的才知道該把門鎖在哪里。這篇文章不打算從教科書定義講起而是結(jié)合我自己在服務(wù)器運維、安全加固和應(yīng)急排查中踩過的坑把最常見的攻擊手法、防御落地步驟、排查實錄和避坑清單一次說清楚。適合剛接觸服務(wù)器的新手也適合做運維和開發(fā)的朋友對照著查漏補缺。1. 先從攻擊面說起一臺服務(wù)器到底哪里最容易被盯上很多人對攻擊的理解是“黑客用工具掃一下端口然后黑進來”真實情況復(fù)雜得多。一臺服務(wù)器就像一個房子門、窗、煙囪、空調(diào)外機全是入口攻擊者只挑最容易撬的那個。所以做防御的第一步不是急著裝一堆安全軟件而是先搞清楚自己門前到底有什么“可燃物”。1.1 從一次半夜告警看攻擊入口去年底有一次凌晨三點監(jiān)控平臺突然報警一臺承載官網(wǎng)的ECS實例帶寬跑滿了。登錄上去一看公網(wǎng)入方向流量接近2Gbps但CPU和內(nèi)存占用都不高。第一反應(yīng)是DDoS流量攻擊可仔細看防火墻日志流量并不是單一來源而是幾十個IP輪番發(fā)起大量GET請求每個請求都帶著不同的隨機UA頭。這實際上是CC攻擊——通過大量應(yīng)用層請求耗盡Web服務(wù)的連接池和帶寬。為什么會有這種攻擊很多時候不是有人專門針對你而是你的服務(wù)器被掃描工具發(fā)現(xiàn)后成了批量攻擊列表里的一個節(jié)點。服務(wù)器上開放的端口越少、暴露的服務(wù)越少被盯上的概率就越低。所以我現(xiàn)在的項目中第一件事永遠是資產(chǎn)清點這臺服務(wù)器上跑了哪些服務(wù)監(jiān)聽哪些端口哪些端口是必須對公網(wǎng)開放的哪些其實只在內(nèi)網(wǎng)用。提示你永遠不知道你的服務(wù)器IP被掃描了多少次。只要公網(wǎng)可達掃描器每幾分鐘就會來一輪這是常態(tài)。1.2 端口、服務(wù)與資產(chǎn)清點的具體做法資產(chǎn)清點聽起來簡單實際做起來需要耐心。我通常用下面的辦法用ss -tlnp或netstat -tlnp查看當前監(jiān)聽的端口和對應(yīng)的進程這一步是摸清家底。對照業(yè)務(wù)清單逐一確認每個端口是否必須對外開放不認識的進程要查清來源。對公網(wǎng)開放的端口做服務(wù)版本登記比如 Nginx 1.20、OpenSSH 8.2、MySQL 5.7版本號是后續(xù)判斷漏洞影響范圍的關(guān)鍵。記錄域名、證書、CDN、回源IP之間的關(guān)系防止出現(xiàn)“CDN背后裸奔”的情況。有一次我排查一臺數(shù)據(jù)庫服務(wù)器發(fā)現(xiàn)3306端口對公網(wǎng)開放。一問才知道是當初為了方便本地調(diào)試直接在安全組里加了0.0.0.0/0放行規(guī)則。這種端口暴露在公網(wǎng)上等同于把金庫大門敞開著任何人都能拿工具嘗試暴力破解。1.3 攻擊面梳理的隱患盤點攻擊面不光是端口還包括幾個容易被忽略的點默認口令和弱口令。很多人覺得“密碼長一點就安全”但像root/123456、admin/admin這種組合在暴力破解工具字典里排在最前面。管理后臺暴露在公網(wǎng)。比如 WordPress 后臺、Tomcat Manager、phpMyAdmin任何一個都可以成為突破口。敏感信息泄露。網(wǎng)頁源碼注釋、接口報錯信息、備份文件.bak/.sql被直接放在web目錄下等于把地圖送給了攻擊者。第三方組件版本過舊。比如某個開源CMS用了老版本已知漏洞直接可查攻擊者根本不需要多高深的技術(shù)。把這些點記下來之后攻擊面才算真正清楚。接下來看具體攻擊手法時就有的放矢了。2. 常見攻擊手法與底層邏輯防御的前提是理解攻擊。我挑了幾個在真實業(yè)務(wù)中高頻出現(xiàn)的類型每個都結(jié)合我處理過的案例來講盡量不說空話。2.1 流量型攻擊DDoS與CC攻擊的典型特征DDoS和CC攻擊經(jīng)常被混為一談其實觸發(fā)層級完全不同。DDoS主要打網(wǎng)絡(luò)層和傳輸層比如SYN Flood、UDP Flood目的是把帶寬和交換機處理能力耗盡讓正常用戶連不上。CC攻擊打的是應(yīng)用層模擬真實用戶請求不停請求某個動態(tài)接口或搜索接口把CPU、數(shù)據(jù)庫連接池打滿網(wǎng)站響應(yīng)變慢甚至直接502。我在處理一次CC攻擊時發(fā)現(xiàn)攻擊方只盯著一個URL重復(fù)請求這個URL是會員中心的查詢接口。當時上游WAF沒有配頻控導(dǎo)致每個請求都正常轉(zhuǎn)發(fā)到后端數(shù)據(jù)庫連接瞬間被打穿。后面加了針對該接口的單IP每秒請求數(shù)限制同時在Nginx層做了隊列深度控制情況立刻緩解。注意CC攻擊比DDoS更隱蔽因為流量特征和正常用戶很像光看帶寬看不出問題要看每個請求的頻次、UA分布、來源IP聚合度。2.2 文件上傳攻擊為什么總被低估文件上傳攻擊是我在Web安全項目里最常遇到的漏洞之一?;驹硎墙柚蟼鞴δ芄粽呱蟼饕粋€包含惡意代碼的文件比如PHP一句話木馬、JSP后門如果服務(wù)器把文件解析執(zhí)行了攻擊者就拿到了WebShell相當于在服務(wù)器里安了一個“遠程遙控器”。真實的攻擊流程通常是這樣的攻擊者找到一個上傳點頭像上傳、附件上傳、導(dǎo)入功能上傳一個偽裝成圖片的腳本文件訪問這個文件路徑使腳本被解析執(zhí)行然后通過WebShell執(zhí)行系統(tǒng)命令。我去幫一個客戶排查時發(fā)現(xiàn)他們的上傳目錄里躺著一個名為avatar.jpg的文件后綴是jpg但文件頭尾被拼接了PHP代碼。原因就是上傳時只校驗了Content-Type前端可控沒有校驗文件真實內(nèi)容而且上傳目錄還開了腳本執(zhí)行權(quán)限。防御上我目前比較認可的組合是白名單后綴校驗加上MIME類型校驗、文件重命名脫離可控路徑、上傳目錄禁止執(zhí)行腳本、文件存儲和Web解析目錄分離。這四個動作做完大部分文件上傳繞過手段就失效了。2.3 SSRF攻擊內(nèi)網(wǎng)跳板是怎么打出來的SSRF服務(wù)端請求偽造是很多應(yīng)用層漏洞里比較特殊的一個。它利用的是服務(wù)器自身發(fā)起的請求讓服務(wù)器去訪問攻擊者指定的內(nèi)網(wǎng)或外部地址。由于請求是從服務(wù)器發(fā)出的很多防火墻規(guī)則會認為這是“可信流量”于是攻擊者就能借服務(wù)器這個“跳板”探測內(nèi)網(wǎng)。最典型的場景是圖片處理功能用戶提交一個URL服務(wù)器去抓取圖片。如果這個功能沒有做域名白名單和IP限制攻擊者可以傳http://127.0.0.1:3306來探測本機數(shù)據(jù)庫端口甚至傳http://10.0.0.5/來掃描內(nèi)網(wǎng)其他主機。我遇到過一臺服務(wù)器通過這種漏洞被讀取了內(nèi)網(wǎng)云元數(shù)據(jù)接口從而拿到了臨時憑證。防御的核心不是簡單屏蔽localhost而要限制請求目標只允許訪問特定協(xié)議不留file協(xié)議、特定端口白名單、特定域名白名單并禁止302跳轉(zhuǎn)跟隨、禁止訪問內(nèi)網(wǎng)IP段。2.4 反序列化攻擊看起來沒事的接口最危險反序列化攻擊在一線業(yè)務(wù)里不算高頻但一旦發(fā)生往往就是管理員權(quán)限級別的淪陷。很多開發(fā)對“序列化”不敏感覺得就是把對象變成字符串存起來但反序列化是把字符串恢復(fù)成對象的過程如果數(shù)據(jù)源不可信攻擊者就能構(gòu)造惡意內(nèi)容在恢復(fù)過程中觸發(fā)危險方法。Java、PHP、Python都有對應(yīng)的反序列化利用鏈。比如Java里常見的攻擊點是把序列化后的對象直接交給ObjectInputStream.readObject()處理攻擊者構(gòu)造好某個存在漏洞的類讓服務(wù)器在反序列化時執(zhí)行命令。排查這類問題時我一般會重點看代碼里是否對反序列化數(shù)據(jù)做了簽名校驗以及是否引入了容易被利用的組件庫。防御上最有效的方法是不接受不可信來源的反序列化數(shù)據(jù)如果必須接受使用白名單類過濾比如ObjectInputFilter或改成JSON等安全格式傳輸。這個問題最大的難點在于它不是“一眼就能看出來”的漏洞代碼審查時要留意所有接收二進制數(shù)據(jù)的入口。2.5 注入類與WebShellXSS、SQL注入的防御思路XSS和SQL注入屬于老生常談但我不打算略過因為實際項目里“換了馬甲”的注入依然很多。XSS的核心是用戶輸入被當作頁面內(nèi)容輸出導(dǎo)致腳本在他人瀏覽器里執(zhí)行。SQL注入的核心是用戶輸入被拼進SQL語句導(dǎo)致數(shù)據(jù)庫被拖走或篡改。兩者的共同點是對輸入過于信任。前幾年我審計過一個后臺登錄后的搜索框直接把參數(shù)拼到SQL里當時用 OR 11 --一測試就出數(shù)據(jù)。后來整改時統(tǒng)一封裝了參數(shù)化查詢開始引入ORM約束。對于XSS主要還是輸出端的編碼轉(zhuǎn)義要到位前端框架自帶的防XSS機制不要隨意關(guān)閉。3. 防御體系落地方案從基線加固到縱深防御攻擊手法學(xué)完接下來就是動手防。防御不能靠單點必須一層一層疊起來這也就是常說的縱深防御。3.1 系統(tǒng)層基線加固系統(tǒng)層的基礎(chǔ)打不牢上層做再多都白搭。我建議按下面的順序逐項落實禁用root遠程登錄改用普通用戶加sudoSSH使用密鑰認證。定期應(yīng)用系統(tǒng)更新和安全補丁關(guān)鍵漏洞要優(yōu)先修復(fù)。關(guān)閉不必要的系統(tǒng)服務(wù)用firewalld或iptables只放行必要端口。設(shè)置合理的文件權(quán)限web目錄的寫入權(quán)限盡量收窄。修改默認端口或使用Fail2ban等工具對暴力破解做自動封禁。我實際操作中會把SSH端口改到高位并開啟密鑰登錄雖然不能徹底防住掃描但能把自動爆破的流量擋掉一大半。改端口不是安全手段只是減小暴露面真正的防線是密鑰和訪問來源限制。# 以CentOS/RHEL系為例允許指定IP段訪問SSH端口 firewall-cmd --permanent --add-rich-rulerule familyipv4 source address10.10.0.0/16 port port2222 protocoltcp accept firewall-cmd --permanent --remove-servicessh firewall-cmd --reload3.2 網(wǎng)絡(luò)層與接入層防御網(wǎng)絡(luò)層防御重點在入口也就是防火墻和安全組。這里有兩個容易踩的坑第一個是安全組規(guī)則配得過于寬松比如把某個端口對所有IP開放第二個是只關(guān)注入方向忽略了出方向服務(wù)器被入侵后向外發(fā)起的攻擊流量沒人管。我在給一個項目做加固時直接把出方向默認拒絕只放行必要的DNS、HTTPS和軟件源端口。這樣即使WebShell執(zhí)行成功了攻擊者想連外網(wǎng)下載工具也會因為出方向被限制而失敗較多。接入層方面有條件就上WAF配合IP黑白名單、地區(qū)封禁、頻率限制和CC防護規(guī)則。如果預(yù)算有限先用Nginx層的限速和訪問控制頂上# 限制同一IP每分鐘請求數(shù)超過后返回503 limit_req_zone $binary_remote_addr zonereq_one:10m rate30r/m; server { listen 80; server_name example.com; location /api/ { limit_req zonereq_one burst20 nodelay; proxy_pass http://backend; } }3.3 應(yīng)用層控制輸入、輸出、權(quán)限三板斧到應(yīng)用層防御動作要落到代碼和配置里主要盯三件事輸入校驗所有外部參數(shù)做合法性校驗包括長度、類型、取值范圍。能走白名單就不要用黑名單。輸出編碼動態(tài)內(nèi)容輸出到頁面時做好HTML實體編碼防止XSS拼接SQL時全部參數(shù)化。權(quán)限控制接口遵循最小權(quán)限同一個接口不能既是普通用戶入口又是管理員入口。文件讀寫權(quán)限也要注意。我見過有項目把/data/upload配成了777權(quán)限導(dǎo)致WebShell上傳后還能被修改執(zhí)行。我通常會把上傳目錄的owner固定為某個低權(quán)限用戶并禁止腳本解析。3.4 運維層監(jiān)控、日志與備份監(jiān)控和日志是防御體系中偏“事后”的環(huán)節(jié)但很多攻擊在爆發(fā)之前都是有前兆的。我推薦的監(jiān)控指標包括CPU和內(nèi)存使用率、帶寬出入方向、數(shù)據(jù)庫慢查詢、Web日志中4xx/5xx狀態(tài)碼占比、登錄失敗次數(shù)、關(guān)鍵文件完整性。日志采集上我習(xí)慣用“三份日志”方案操作系統(tǒng)日志、Web訪問日志、應(yīng)用日志分別落盤和集中存儲。Web訪問日志至少保留90天建議每日做日志切割防止單文件過大導(dǎo)致問題。備份則要保證“異地多版本”至少有一個ecph存到對象存儲里不能和服務(wù)器在同一臺機器上否則服務(wù)器被勒索加密時備份也會被一起加密。提示備份之前先測恢復(fù)。不要等到服務(wù)器真的掛了才發(fā)現(xiàn)備份文件是壞的這個坑我替客戶踩過一次數(shù)據(jù)恢復(fù)不了時整個人是崩潰的。4. 攻擊模擬、排查與應(yīng)急實錄紙上談兵結(jié)束這才是真正考驗運維能力的地方。我平時會做大量的攻擊模擬和故障演練為的是真出事時不慌。4.1 如何模擬一次DDoS/CC攻擊并驗證防御效果不推薦在線上環(huán)境直接做破壞性測試我一般在預(yù)發(fā)布環(huán)境或單獨的測試機上進行。先用壓測工具模擬高并發(fā)請求觀察Nginx配置的限速是否生效再用ab/Wrk這類的工具構(gòu)造高頻請求驗證WAF的CC防護規(guī)則是否響應(yīng)。模擬時要關(guān)注三個指標一是服務(wù)器是否還能正常響應(yīng)非被攻擊的接口二是CPU和內(nèi)存是否處于安全水位三是誤殺率也就是正常用戶請求有沒有被誤傷。有一次我配了過于嚴格的限速策略每IP每分鐘只許5個請求測試時發(fā)現(xiàn)正常用戶翻頁都會觸發(fā)503業(yè)務(wù)直接沒法用。后來把rate放寬到60r/m才找到平衡點。4.2 服務(wù)器被“打掛”后如何快速定位原因服務(wù)器出現(xiàn)過一次“打掛”的情況很多人的第一反應(yīng)是“是不是被DDoS了”。實際上不一定可能是代碼死循環(huán)、數(shù)據(jù)庫連接泄漏、磁盤寫滿等多種原因。我一般按下面的順序排查先用uptime和top/htop看系統(tǒng)負載如果CPU或內(nèi)存被占滿初步判斷是計算資源耗盡。用ss -antp查看連接數(shù)如果大量SYN_RECV或ESTABLISHED連接異常大概率是流量型攻擊或連接池失控。用sar或iftop看流量和帶寬結(jié)合時間點和Web日志里的請求集中度判斷是DDoS、CC還是爬蟲。最后看應(yīng)用日志如果有大量超時或異常報錯優(yōu)先查代碼層面的瓶頸。有一次客戶報“H5頁面打不開”我查下來發(fā)現(xiàn)是磁盤被日志寫滿了df -h顯示使用率100%。這不是攻擊而是日志輪轉(zhuǎn)配置沒生效造成的“自傷”。所以排查時先別急著甩鍋給攻擊多個指標對比著看才靠譜。4.3 疑似被入侵后的止血與溯源流程一旦確認服務(wù)器被拿下時間就是生命。我建議按下面的流程走每一步都要留下證據(jù)立即將被感染的主機從對外服務(wù)中摘除可以停機或斷開外網(wǎng)避免攻擊者持續(xù)控制。保留現(xiàn)場給系統(tǒng)盤做鏡像或快照保護內(nèi)存和日志不被破壞。收集入侵線索last登錄記錄、/var/log/auth.log或 secure日志、crontab任務(wù)、啟動項、異常進程和安全工具的告警信息。查WebShell在web目錄下搜索最近修改的php/jsp/aspx文件重點檢查后綴偽裝、內(nèi)容中包含eval/system/base64函數(shù)調(diào)用的文件。溯源分析判斷是通過哪里進來的弱口令漏洞供應(yīng)鏈找到根因后再做系統(tǒng)重裝或修復(fù)。查找WebShell時可以先用命令掃描定位可疑文件后再人工判斷# 搜索web目錄下最近7天內(nèi)修改過的腳本文件 find /data/www -name *.php -mtime -7 # 搜索常見的危險函數(shù)調(diào)用需配合人工確認 grep -rlE eval\(|assert\(|system\(|shell_exec\(|passthru\( /data/www --include*.php注意WebShell掃描的結(jié)果只能作為線索不是命中就一定是惡意文件。部分框架源碼本身就會調(diào)用這些函數(shù)必須人工確認。4.4 常見問題速查表我在多個項目里梳理過一批高頻問題整理成表格方便對照排查。問題現(xiàn)象可能原因排查方法帶寬被占滿CPU不高DDoS流量攻擊iftop看IP分布聯(lián)系機房或云廠商上高防CPU高但帶寬正常CC攻擊或Web代碼死循環(huán)看Web日志請求集中度配合Nginx限速數(shù)據(jù)庫連接數(shù)打滿SQL查詢未優(yōu)化或連接池泄漏show processlist分析慢SQL重啟后觀察登錄日志中有大量失敗記錄暴力破解啟用密鑰登錄配合Fail2ban自動封禁頁面被植入非法廣告WebShell或篡改全線掃描WebShell檢查文件修改時間上傳目錄出現(xiàn)可疑腳本文件上傳漏洞立即禁用目錄腳本解析整改上傳校驗內(nèi)網(wǎng)被外部訪問SSRF或端口暴露收嚴出網(wǎng)策略檢查應(yīng)用層URL請求校驗服務(wù)器被加密文件后綴勒索病毒先隔離斷網(wǎng)從備份恢復(fù)排查感染源這張表里的每一項我都實際處理過對照著查能省很多時間。但真正的經(jīng)驗不是這張表本身而是判斷問題時的思路先看整體指標再縮小范圍最后落到具體日志和代碼。5. 幾個讓我印象深刻的踩坑經(jīng)歷說了這么多還是想分享幾個特別典型的坑。第一個是“改了安全組就萬事大吉”的心態(tài)。有次客戶配置好安全組覺得防護到位了結(jié)果沒留意服務(wù)器本機的防火墻是關(guān)閉狀態(tài)。安全組過濾的是云平臺層面的流量但服務(wù)器本地防火墻關(guān)了等于外面的防線再強內(nèi)部的門沒鎖。后來我都是安全組和本機防火墻兩手抓缺少任何一個都不算數(shù)。第二個坑是“日志沒有同步出事后無從查起”。有一次某臺服務(wù)器被入侵我想看攻擊者的進入路徑結(jié)果發(fā)現(xiàn)這臺機器根本沒開日志收集原有的auth日志因為磁盤滿了被輪轉(zhuǎn)清掉。從那以后我接手的每臺服務(wù)器第一件事就是確認日志有沒有集中存儲時間同步有沒有配好。沒有日志的服務(wù)器出了事就是“無頭懸案”。第三個坑是“只防外部不看內(nèi)部”。很多團隊默認內(nèi)部網(wǎng)絡(luò)是安全的導(dǎo)致數(shù)據(jù)庫、Redis、管理后臺的密碼常年不換防火墻也不設(shè)內(nèi)部隔離。結(jié)果攻擊者通過一個前臺文件上傳漏洞進來后在內(nèi)網(wǎng)橫向移動如入無人之境。防御一定要有縱深內(nèi)部服務(wù)和外部流量一樣要做鑒權(quán)和訪問控制。6. 最后的幾點個人體會做了這些年服務(wù)器攻擊與防御相關(guān)的工作我最大的體會是安全不是裝幾個軟件、開幾個服務(wù)就完事的它是一個持續(xù)的、需要融進日常操作習(xí)慣的事情。哪怕一臺服務(wù)器只跑一個小網(wǎng)站也應(yīng)該按照“清點資產(chǎn)—收緊暴露面—持續(xù)監(jiān)控—及時響應(yīng)”的節(jié)奏來維護。如果你剛接手一臺服務(wù)器可以從今天就開始做三件事檢查開放端口和登錄方式、確認日志是否集中存儲和輪轉(zhuǎn)、給系統(tǒng)盤和數(shù)據(jù)庫做一次可驗證的備份。這三件事花不了幾個小時但能在很多場景下救命。我在實際運維中遇到的事故多數(shù)都不是因為攻擊者技術(shù)多高明而是因為基礎(chǔ)工作長期欠賬。把地基打好絕大多數(shù)攻擊都會在門口被擋下來。