突發:宕機崩潰OOM
突發:宕機崩潰OOM
事故背景:我們的項目每年都進行一次三級等保認證,2024年*月*日認證公司對我們的項目進行滲透測試時,我們系統出現無法訪問和使用的情況。出現問題后我們聯系認證公司停止測試,系統依然沒有恢復。
事故分析:
1. 出現問題后我第一時間檢查了日志,發現了OOM
java.lang.OutOfMemoryError: Java heap space
at org.apache.tomcat.util.threads.TaskThreadFactory.newThread(TaskThreadFactory.java:42)
由于沒有dump日志所以不好排查OOM的原因,我便加上了啟動參數:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/heapdump-9001.hprof
然后聯系對方公司再測試一遍
- OOM再次出現,我拿到了heapdump-9001.hprof,開始用MemoryAnalyzer 進行分析,首先查看大對象(Dominator Tree)

大對象在這兒看,點進去發現最大的是 數據庫相關

最大的這個對象有1個多G,有200多萬條數據,都在內存里

怎么可能有200多萬呢,肯定是查錯了,難道SQL注入導致把數據庫里所有數據都查出來了?
再去數據庫查下,果然是所有數據:

- 再嘗試找找代碼是哪兒運行的,

點開LeakSuspects

找到

好多都是框架代碼,我們嘗試在里面找到 認識的業務相關代碼:

- 找到getFiles代碼:

這里都是拼接的SQL,有SQL注入問題,應該就是這兒的問題了。
- 那么對方公司是怎么注入的呢,每個請求在Ngnix Acess日志里有記錄,我嘗試到Ngnix里查找日志,發現了
/request?view&cgFormField=-1'%20OR%202%2B663-663-1=0%2B0%2B0%2B1%20or%20'BApebRcZ'='
添加日志發現 該參數傳入后,SQL變成了這樣:

注意兩個or 之間 變成了 1=1 永恒true,也就導致把所有數據都查出來了。
原因已經找到了,那么該如何解決呢,之前知道用預編譯prepareStatement就行, 但這里的代碼 不適合大動,查了下用StringEscapeUtils.escapeSql() 比較合適,改成這樣

同樣的參數再次測試

相當于整個字符串 是個value ,不會被惡意拆掉
事故復盤:
查看了該處代碼提交記錄,很久之前就是這么寫的,往年滲透測試時并沒有測出來。比起追究責任,更重要的是給我們提醒:
- 注意SQL注入問題,不要拼接原生SQL,可以用上面的注入字符串自測。
- 每個應用都應該加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath,免得出現宕機無法復現,無法排查問題

浙公網安備 33010602011771號