SQL 注入

一、SQL 注入 基础定义

SQL 注入(SQL Injection)是Web 应用中最普遍、危害最高 的代码注入漏洞。当应用程序直接将用户输入拼接到 SQL 语句 并交给数据库执行,且未做安全过滤时,攻击者可构造恶意输入,欺骗数据库执行非预期操作,实现窃取、篡改、删除、越权等攻击。


二、核心原理(根本原因)

1. 漏洞本质

用户输入被当作 SQL 代码执行,而非纯数据。

2. 触发条件

  • 用户输入可控(表单、URL、Cookie、HTTP 头)
  • 输入直接拼接进 SQL 语句
  • 未做过滤、转义、预编译处理

3. 危险代码示例

复制代码
// 高危写法:直接字符串拼接
String username = request.getParameter("username");
String pwd = request.getParameter("password");
String sql = "SELECT * FROM users WHERE username='" + username + "' AND pwd='" + pwd + "'";

4. 经典登录绕过

攻击者输入用户名:

复制代码
' OR '1'='1 -- 

最终执行 SQL:

复制代码
SELECT * FROM users WHERE username='' OR '1'='1' -- ' AND pwd=''

1=1 恒成立 → 直接登录成功


三、常见注入类型与攻击方式

1. 联合查询注入(Union Query Inject)

  • 条件:页面有回显

  • 作用:直接读取其他表数据

  • 语句:

    ' UNION SELECT username, password FROM users --

2. 布尔盲注(Boolean Blind)

  • 条件:无数据回显,仅显示成功 / 失败

  • 原理:通过 AND 1=1 / AND 1=2 判断真假

  • 语句:

    ' AND substring(username,1,1)='a' --

3. 时间盲注(Time Blind)

  • 条件:无回显、无报错

  • 原理:用 SLEEP() 看延迟判断结果

  • 语句:

    ' AND IF(1=1, SLEEP(5), 0) --

4. 报错注入(Error-based Inject)

  • 条件:页面显示数据库报错信息

  • 原理:强制触发异常,从错误中暴数据

  • 语句:

    ' AND (SELECT COUNT(*),CONCAT((SELECT username FROM users LIMIT 1),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x) --

5. 堆叠查询注入(Stacked Queries)

  • 条件:数据库支持多语句执行

  • 作用:执行 DROP、DELETE、ALTER 等高危操作

  • 语句:

    '; DROP TABLE users; --

6. 宽字节注入

  • 条件:使用 GBK 编码
  • 原理:%df' 吃掉转义符 \
  • 典型场景:PHP + MySQL 转义过滤被绕过

四、SQL 注入的危害

  1. 数据窃取:账号密码、身份证、手机号、订单、商业机密
  2. 数据篡改:修改金额、权限、状态、配置
  3. 数据破坏:删表、删库、清空数据
  4. 服务器入侵:读取服务器文件、写入 Webshell、提权
  5. 合规风险:违反《网络安全法》《个人信息保护法》,面临巨额罚款

五、防御措施

1. 预编译语句(参数化查询)------ 首选、最有效

将 SQL 结构与用户数据完全分离,输入永远不被解析为代码。

✅ Java

复制代码
String sql = "SELECT * FROM users WHERE username=? AND password=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);

✅ Python

复制代码
sql = "SELECT * FROM users WHERE username=%s AND password=%s"
cursor.execute(sql, (username, password))

✅ PHP

复制代码
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute([$username]);

2. 使用安全 ORM 框架

  • MyBatis:必须用 #{} ,禁止 ${}

  • Hibernate / JPA / Django ORM:默认安全

    SELECT * FROM users WHERE username=#{username}

    SELECT * FROM users WHERE username=${username}

3. 输入验证与白名单

  • 用户名:字母数字

  • 手机号:11 位数字

  • 邮箱:标准格式

    if (!username.matches("^[a-zA-Z0-9]{4,16}$")) {
    return "非法输入";
    }

4. 特殊字符转义

' " \ ; -- # () 等进行转义处理。

5. 数据库最小权限原则

  • 业务账号禁止 DROP、DELETE、ALTER、FILE
  • 禁止用 root/admin 连接业务库

6. 关闭错误回显

生产环境不输出数据库原生报错,避免信息泄露。

7. WAF 防护

使用防火墙拦截典型注入特征:UNION SELECT' OR 1=1 等。

8. 安全审计

定期扫描:SQLMap、AWVS、漏扫平台及时更新数据库补丁


六、核心总结

  • 漏洞本质:用户输入被当作 SQL 代码执行
  • 防御核心:永不直接拼接 SQL
  • 最佳方案:参数化查询 + ORM + 最小权限

七、思维导图


八、考试 / 面试必背高频考点

  1. SQL 注入的根本原因:用户输入直接拼接 SQL
  2. 最有效防御:参数化查询(预编译)
  3. MyBatis 安全写法:#{} ,不安全:${}
  4. 盲注分为:布尔盲注、时间盲注
  5. 防御三要素:预编译、权限最小、输入校验
相关推荐
ccddsdsdfsdf2 小时前
DBeaver怎么链接mongoDB
数据库·mongodb
丷丩2 小时前
Postgresql基础实践教程(十一)各种Join
数据库·postgresql·join
星夜夏空993 小时前
FreeRTOS学习(4)——内存映射
数据库·学习·mongodb
TheRouter3 小时前
AI Agent 记忆体系建设实战:短期、长期与工作记忆的工程实现
数据库·人工智能·oracle
Omics Pro4 小时前
首个!外源天然产物综合性代谢图谱
数据库·人工智能·算法·机器学习·r语言
JAVA面经实录9175 小时前
Hibernate面试题库
数据库·oracle·hibernate
迷枫7125 小时前
DM8 目录结构与常用排查入口梳理
服务器·数据库
Mr.Daozhi6 小时前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具
小程故事多_806 小时前
Claude Code自定义workflow skills用法
数据库·人工智能·智能体
大鹏说大话6 小时前
SQL 排序与分组实战:解决“分组后取最新数据“
android·java·数据库