SQL 注入 (SQLi)
Published: Sat Feb 01 2025 | Modified: Fri Feb 06 2026 , 2 minutes reading.
1. 定义
SQL 注入 (SQL Injection, SQLi) 发生在不受信任的用户输入被动态拼接到结构化查询语言 (SQL) 语句中时。这允许攻击者操纵查询结构,从而查看、修改或删除他们未被授权访问的数据。
2. 技术原理
SQL 解释器会同时处理指令和数据。如果应用通过字符串拼接来构建查询:
query = "SELECT * FROM users WHERE username = '" + user_input + "'";攻击者可以输入 ' OR '1'='1。生成的查询将变为:
SELECT * FROM users WHERE username = '' OR '1'='1';由于 '1'='1' 永远为真,数据库将返回表中的所有行,从而绕过用户名检查。
SQLi 的类型:
- 带内 (In-band, 经典型): 结果直接返回在网页中(如基于 UNION 的注入)。
- 盲注 (Blind): 不直接返回数据,但应用的行为会发生变化(基于时间或布尔值)。
- 带外 (Out-of-band): 通过 DNS 或 HTTP 请求将数据导出(较罕见,取决于数据库)。
3. 攻击流程 (基于 Union)
sequenceDiagram
participant Attacker
participant App
participant DB as 数据库
Attacker->>App: GET /search?q=' UNION SELECT username, password FROM users--
Note over App: 代码构建查询:<br/>SELECT title FROM products WHERE name = '' UNION ... --'
App->>DB: 执行畸形查询
Note over DB: 'UNION' 合并了来自 'products' 和 'users' 的结果
DB-->>App: 返回产品列表 + 用户凭据
App-->>Attacker: 在搜索结果中显示管理员密码4. 真实案例:TalkTalk 遭受黑客攻击 (2015)
目标: TalkTalk (英国电信运营商)。 漏洞类别: 盲 SQL 注入。
事件回顾: 攻击者在 TalkTalk 域名上发现了一些未维护的旧网页,这些网页仍然连接着核心客户数据库。这些页面使用的 GET 参数存在 SQL 注入漏洞。
攻击技术: 他们使用 SQLMap(一种自动化工具)利用了盲 SQLi 漏洞。
- 注入 SQL 命令来提取数据库架构信息。
- 导出了 156,959 名客户 的个人资料和 15,000 多个银行账号。
影响: TalkTalk 被处以 40 万英镑 的罚款(当时创下了纪录),并估计在业务流失和补救方面损失了 7700 万英镑。这凸显了“僵尸”遗留代码带来的巨大风险。
5. 深度防御策略
A. 预处理语句 (参数化查询)
这是唯一的主要防御手段。 使用数据库驱动提供的参数化功能,而不是字符串拼接。
机制: SQL 查询结构先被发送到数据库并编译。用户输入随后发送,且仅被视为数据,而非可执行的代码。
Java/JDBC 示例:
String query = "SELECT * FROM users WHERE username = ?"; PreparedStatement pstmt = connection.prepareStatement(query); pstmt.setString(1, userInput); // 安全 ResultSet results = pstmt.executeQuery();
B. 存储过程
将查询封装在数据库内部。但请注意,存储过程本身必须使用参数,并避免在过程内部生成动态 SQL。
C. 最小权限原则
Web 应用使用的数据库账号应仅拥有以下权限:
- 仅访问其所需的特定表。
- 仅执行必要的命令(
SELECT,INSERT,UPDATE)。 - 绝不拥有
DROP TABLE,GRANT或管理员权限。 - 绝不允许访问操作系统文件系统(如
xp_cmdshell)。
