跳到主要内容

SQL注入

威胁描述

SQL注入是一种注入型攻击,攻击者通过在用户输入中插入恶意SQL代码,使数据库执行非预期的查询。虽然SQL注入主要发生在后端,但前端开发者也需要了解其原理和防御措施,因为前端输入验证是防止SQL注入的第一道防线。SQL注入可能导致未授权访问数据库、数据泄露、数据篡改甚至服务器被完全控制。

类型分类

1. 联合查询注入

利用UNION操作符组合多个查询,获取额外数据。

2. 错误注入

通过触发数据库错误,获取数据库结构信息。

3. 布尔盲注

通过构造布尔表达式,根据返回结果推断数据。

4. 时间盲注

通过构造时间延迟查询,根据响应时间推断数据。

工作原理

  1. 应用程序接收用户输入并将其拼接到SQL查询中
  2. 攻击者构造包含恶意SQL代码的输入
  3. 应用程序未对输入进行适当验证或转义
  4. 恶意SQL代码被执行,造成危害

示例代码

1. 简单SQL注入

// 前端代码
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;

// 不安全的后端代码(Node.js + MySQL)
const sql = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
connection.query(sql, (error, results) => {
// 处理结果
});

// 攻击者输入
// username: ' OR '1'='1
// password: 任意值

// 执行后的SQL
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '任意值'

2. 联合查询注入

// 攻击者输入
// search: ' UNION SELECT username, password FROM users --

// 执行后的SQL
SELECT * FROM products WHERE name LIKE '%' UNION SELECT username, password FROM users --%'

3. 前端未验证的输入

<!-- 前端表单 -->
<form action="/search" method="GET">
<input type="text" name="query" placeholder="搜索...">
<button type="submit">搜索</button>
</form>

<!-- 攻击者输入到搜索框 -->
' OR 1=1; DROP TABLE users; --

防御措施

1. 前端输入验证

在前端对用户输入进行基本验证,过滤潜在危险字符:

// 验证输入是否只包含字母和数字
function validateInput(input) {
const regex = /^[a-zA-Z0-9\s]*$/;
return regex.test(input);
}

// 表单提交时验证
document.getElementById('searchForm').addEventListener('submit', function(e) {
const query = document.getElementById('query').value;
if (!validateInput(query)) {
alert('输入包含非法字符');
e.preventDefault();
}
});

2. 后端参数化查询

使用参数化查询或预处理语句,避免SQL拼接:

// 安全的后端代码(Node.js + MySQL)
const sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
connection.query(sql, [username, password], (error, results) => {
// 处理结果
});

3. 输入转义

如果无法使用参数化查询,对用户输入进行转义:

// 对输入进行转义
const safeUsername = connection.escape(username);
const safePassword = connection.escape(password);
const sql = `SELECT * FROM users WHERE username = ${safeUsername} AND password = ${safePassword}`;

4. 最小权限原则

为数据库用户分配最小必要权限,限制潜在损失:

  • 只读用户用于查询操作
  • 只写用户用于插入操作
  • 避免使用root或管理员权限

最佳实践

  1. 始终使用参数化查询或预处理语句,避免SQL拼接
  2. 在前端和后端都实施输入验证,但以后端验证为主
  3. 对用户输入进行转义,即使使用了参数化查询
  4. 为数据库用户分配最小必要权限
  5. 定期进行安全测试,包括SQL注入测试
  6. 保持数据库和应用程序的更新,以防止已知漏洞被利用
  7. 隐藏数据库错误信息,避免泄露数据库结构
  8. 实施数据库审计日志,记录所有查询操作
  9. 考虑使用ORM框架,它们通常内置了防SQL注入机制