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. 防御三要素:预编译、权限最小、输入校验
相关推荐
蓝速科技4 分钟前
口岸政务窗口双屏翻译机落地应用指南
运维·数据结构·数据库·人工智能·科技·政务
风哥2号7 分钟前
数据库教程FGMT20‑Oracle容灾体系架构与数据库升级迁移方案
数据库·oracle·架构
wudongfang66628 分钟前
mysql全量同步数据改增量
数据库·mysql
志栋智能40 分钟前
超自动化安全的变更与配置安全管理
数据库·安全·自动化
toooooop840 分钟前
thinkphp查询数据表最后的自增id
前端·javascript·数据库
风哥2号44 分钟前
数据库教程FGMT19‑Oracle多租户容器架构与新特性总结
数据库·oracle·架构
garmin Chen1 小时前
MySQL精简面试题
数据库·后端·mysql·面试
anxiao_m1 小时前
局域网文件传输工具有哪些?4款主流工具实测对比测评
大数据·网络·数据库
墨香幽梦客1 小时前
API集成中的高可用(HA)设计:如何避免单点故障拖垮业务?
数据库
拓人间精准客1 小时前
全维度大数据:助贷机构破冰数据合规与触达难的5个支点
大数据·数据库·sass·tob