SQL注入
威胁描述
SQL注入是一种注入型攻击,攻击者通过在用户输入中插入恶意SQL代码,使数据库执行非预期的查询。虽然SQL注入主要发生在后端,但前端开发者也需要了解其原理和防御措施,因为前端输入验证是防止SQL注入的第一道防线。SQL注入可能导致未授权访问数据库、数据泄露、数据篡改甚至服务器被完全控制。
类型分类
1. 联合查询注入
利用UNION操作符组合多个查询,获取额外数据。
2. 错误注入
通过触发数据库错误,获取数据库结构信息。
3. 布尔盲注
通过构造布尔表达式,根据返回结果推断数据。
4. 时间盲注
通过构造时间延迟查询,根据响应时间推断数据。
工作原理
- 应用程序接收用户输入并将其拼接到SQL查询中
- 攻击者构造包含恶意SQL代码的输入
- 应用程序未对输入进行适当验证或转义
- 恶意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或管理员权限
最佳实践
- 始终使用参数化查询或预处理语句,避免SQL拼接
- 在前端和后端都实施输入验证,但以后端验证为主
- 对用户输入进行转义,即使使用了参数化查询
- 为数据库用户分配最小必要权限
- 定期进行安全测试,包括SQL注入测试
- 保持数据库和应用程序的更新,以防止已知漏洞被利用
- 隐藏数据库错误信息,避免泄露数据库结构
- 实施数据库审计日志,记录所有查询操作
- 考虑使用ORM框架,它们通常内置了防SQL注入机制