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. 防御三要素:预编译、权限最小、输入校验
相关推荐
城管不管3 小时前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
倔强的石头1063 小时前
向量数据库从相似度检索走向融合数据底座
数据库
今天AI了吗4 小时前
Python 基础语法(一):常量、变量、输入输出与运算符
开发语言·数据库·人工智能·python·sql·深度学习·机器学习
lilian2336 小时前
Harmony os 技术实战|拼豆制图27:用单字符编码承载 50 张 70×70 图纸
前端·数据库·华为·harmonyos
皮卡丘不断更6 小时前
手机优先的 Personal Ledger:把账目、学习和复盘放到同一个入口
数据库·sqlite·fastapi·开源项目·个人效率
保卫大狮兄7 小时前
设备管理从台账到报废,完整生命周期一次讲清
数据库·设备管理·设备
数据安全技术观察7 小时前
数据动态脱敏:让脱敏策略跟着数据目录走
大数据·网络·数据库
小席是个热心肠8 小时前
Redis的自我学习
数据库·redis·学习
2601_965798478 小时前
Salient Theme Setup Guide for Fast Creative WordPress Sites
数据库·web3·php·wordpress
@Mike@9 小时前
09-数据库学习笔记(数据库索引与过滤器)
数据库·笔记