SQL 注入与前端安全
理解 SQL 注入原理及前端在防护中的角色
问题
SQL 注入是常见的安全漏洞,前端在其中扮演什么角色?如何配合后端进行防护?
解答
SQL 注入原理
SQL 注入是攻击者通过输入恶意 SQL 代码,篡改原有查询逻辑的攻击方式。
-- 正常查询
SELECT * FROM users WHERE username = 'admin' AND password = '123456'
-- 注入攻击:输入用户名为 admin'--
SELECT * FROM users WHERE username = 'admin'--' AND password = '任意值'
-- 密码验证被注释掉,直接登录成功
前端的角色
前端是第一道防线,但不是安全保障。前端验证可以被绑过(禁用 JS、直接调接口)。
// 前端输入验证 - 只能提升用户体验,不能保证安全
function validateInput(input) {
// 检查危险字符
const dangerousChars = /['";\\-]/g;
if (dangerousChars.test(input)) {
return { valid: false, message: '输入包含非法字符' };
}
// 检查常见注入关键词
const sqlKeywords = /\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|OR|AND)\b/gi;
if (sqlKeywords.test(input)) {
return { valid: false, message: '输入包含非法关键词' };
}
return { valid: true };
}
// 使用示例
const userInput = document.getElementById('username').value;
const result = validateInput(userInput);
if (!result.valid) {
alert(result.message);
return;
}
前端应该做的事
// 1. 输入长度限制
<input type="text" maxlength="50" />
// 2. 输入类型约束
<input type="email" /> // 邮箱格式
<input type="number" /> // 只能输入数字
// 3. 正则验证
function validateUsername(username) {
// 只允许字母、数字、下划线
return /^[a-zA-Z0-9_]{3,20}$/.test(username);
}
// 4. 转义特殊字符(展示用,不是安全措施)
function escapeHtml(str) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return str.replace(/[&<>"']/g, char => map[char]);
}
真正的防护在后端
// Node.js + MySQL 示例
// ❌ 错误:字符串拼接
const query = `SELECT * FROM users WHERE username = '${username}'`;
// ✅ 正确:参数化查询
const query = 'SELECT * FROM users WHERE username = ?';
connection.query(query, [username], (err, results) => {
// 处理结果
});
// ✅ 正确:使用 ORM(如 Sequelize)
const user = await User.findOne({
where: { username: username }
});
完整的登录表单示例
<form id="loginForm">
<input
type="text"
id="username"
maxlength="20"
pattern="[a-zA-Z0-9_]+"
required
/>
<input
type="password"
id="password"
maxlength="50"
required
/>
<button type="submit">登录</button>
</form>
<script>
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value;
// 前端基本验证
if (!/^[a-zA-Z0-9_]{3,20}$/.test(username)) {
alert('用户名格式不正确');
return;
}
// 发送请求,安全由后端保证
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const result = await response.json();
// 处理登录结果
});
</script>
关键点
- 前端验证可被绑过:攻击者可以禁用 JS 或直接调用 API,前端验证只是用户体验优化
- 后端必须用参数化查询:这是防止 SQL 注入的根本方法,永远不要拼接 SQL 字符串
- 前端职责是过滤和提示:限制输入格式、长度,给用户友好的错误提示
- 纵深防御:前端验证 + 后端参数化查询 + 最小权限原则 + 输入白名单
- 永远不信任用户输入:无论前端还是后端,都要对输入进行验证
目录