WAF配置后还是能绕过SQL注入?预编译查询没用?

♫玉萱 阅读 22

我给API加了预编译查询和WAF规则,但测试时发现用OR 1=1 UNION SELECT这种payload还是能获取数据库表名。WAF规则用了黑名单过滤了单引号和分号,但用户输入“%df%”时居然返回了敏感数据…

尝试过在Express中间件用正则替换特殊字符,但POST数据里的JSON参数还是被解析成SQL语句了。数据库是MySQL,代码用的是:


app.use((req, res, next) => {
  const safeInput = req.body.input.replace(/[';]/g, '');
  req.safeData = safeInput;
  next();
});

现在搞不清楚到底是WAF没拦截,还是预编译没生效?有没有更好的防御组合方案?

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
UX栾同
UX栾同 Lv1
你这个问题其实暴露了几个防御漏洞,我来拆解下:

首先那个中间件写法就有问题,只过滤单引号和分号太弱了。而且直接在req.body上做替换会破坏JSON结构,建议改成这样处理:

app.use((req, res, next) => {
if (req.body) {
const sanitized = {};
Object.keys(req.body).forEach(key => {
sanitized[key] = String(req.body[key]).replace(/['";\x00-x1fx7f-xff]/g, '');
});
req.safeData = sanitized;
}
next();
});


但重点不是这个!你的主要问题出在预编译查询没正确使用。检查下你的SQL语句是不是还在用字符串拼接?正确的预编译应该像这样:

// 错误写法(还是会被注入)
connection.query(SELECT * FROM users WHERE id = ${req.params.id});

// 正确预编译写法
connection.execute('SELECT * FROM users WHERE id = ?', [req.params.id]);


WAF只是第二道防线,不能完全依赖。我建议的组合方案:
1. 确保所有SQL查询都用参数化查询(这才是防注入的根本)
2. 在ORM层做类型校验(比如id必须是数字)
3. 用更严格的WAF规则,推荐用libinjection这类语法分析库
4. 对于中文等宽字符,MySQL要设置正确的字符集(建议utf8mb4)

另外%df%的问题可能是字符集导致的,检查下数据库连接的charset参数是不是设成了utf8。
点赞
2026-03-07 06:06
FSD-锦锦
问题应该出在几个地方,咱们一个一个来看。首先你提到WAF规则用了黑名单过滤单引号和分号,但这种简单的字符替换其实很容易被绕过。比如用户输入“%df%”这种情况,可能是利用了编码或者宽字节注入的技巧,MySQL在某些字符集下会把多字节字符解析成单引号,导致你的过滤失效。

其次,预编译查询理论上是防御SQL注入的最佳实践,但从你的描述来看,可能并没有真正用对。如果你只是简单地把用户输入拼接到SQL语句里,那预编译就完全没发挥作用。正确的做法是使用参数化查询,确保用户输入的内容永远不会被当成SQL代码执行。

再来看你的Express中间件逻辑,这里有几个问题。第一,你只对 req.body.input 做了简单的正则替换,但POST请求里的JSON数据可能有多个字段,每个字段都需要处理。第二,这种方式本质上还是黑名单过滤,而黑名单永远不可能穷尽所有攻击方式,攻击者总能找到新的绕过方法。

推荐的解决方案是这样:首先确保所有SQL查询都使用真正的预编译查询。以Node.js为例,假设你用的是 mysql2 模块,代码应该写成类似这样:

const mysql = require('mysql2/promise');

async function queryDatabase(input) {
const connection = await mysql.createConnection({host: 'localhost', user: 'root', database: 'test'});
const [rows] = await connection.execute('SELECT * FROM users WHERE username = ?', [input]);
return rows;
}


这里的关键点是问号占位符和参数数组,这样可以确保用户输入的内容始终作为数据处理,而不是SQL代码。

其次,WAF的规则需要升级。单纯依赖黑名单是不够的,建议引入白名单机制,限制用户输入只能包含特定的字符集。比如用户名字段通常只允许字母、数字和下划线,可以用正则 /^[a-zA-Z0-9_]+$/ 来校验。

另外,针对你提到的“%df%”返回敏感数据的问题,很可能是数据库的字符集配置有问题。检查一下MySQL的连接字符集,确保它设置为 utf8mb4,并且不要使用容易出问题的字符集比如 GBKlatin1

最后一点,也是最容易被忽略的,就是API的权限控制。即使SQL注入被成功利用了,如果数据库用户权限配置得当,比如只给查询权限而不给结构访问权限,攻击者也很难获取表名或者其他敏感信息。

总结一下,防御SQL注入的最佳实践应该是多层防护:正确使用预编译查询、严格校验输入、合理配置WAF规则、确保数据库字符集安全、以及最小化数据库用户权限。每一层都做好了,才能最大程度降低风险。
点赞 4
2026-02-18 18:05