SQL审计实战经验分享与关键问题解决思路
SQL审计踩坑记:这锅我不背
前两天被后端同事叫过去,说是我写的前端代码导致SQL注入问题。我当时就懵了,心想前端怎么会导致SQL注入呢?折腾了半天才发现,原来是接口调用的时候参数处理不当惹的祸。
这里我踩了个坑,一开始以为是后端的问题,还跟后端同事争论了半天。后来仔细看了下接口调用的地方,发现确实是我这边在拼接参数的时候太随意了。具体来说,就是在调用搜索接口的时候,直接把用户输入的内容拼接到请求参数里,没有做任何转义处理。
排查过程:从甩锅到认错
最开始我先检查了前端的代码,发现是这么写的:
function search(keyword) {
const url = https://jztheme.com/api/search?keyword=${keyword};
fetch(url)
.then(res => res.json())
.then(data => console.log(data));
}
看起来好像没啥问题,对吧?但其实这里有个大坑:如果用户输入的是 1' OR '1'='1 这种恶意字符串,就会导致后端SQL语句出问题。
我试着在控制台输出了实际发出去的请求,果然看到了完整的恶意payload。后端同事给我解释说,他们那边虽然有基本的防护,但如果前端传过来的参数已经是个完整SQL片段,还是会有风险。
解决方案:双重保险才靠谱
最后的解决办法分两步走:前端做好基础的参数校验和转义,后端依然保持严格的SQL审计和参数化查询。
先说前端的改动,我把原来的代码改成了这样:
function escapeSql(str) {
return str.replace(/'/g, "\'")
.replace(/"/g, '\"')
.replace(/;/g, '')
.replace(///g, '\/')
.replace(/\/g, '\\');
}
function search(keyword) {
const safeKeyword = encodeURIComponent(escapeSql(keyword));
const url = https://jztheme.com/api/search?keyword=${safeKeyword};
fetch(url)
.then(res => res.json())
.then(data => console.log(data));
}
这里有几个关键点要注意:
- 用了正则表达式把特殊字符都转义了一遍
- 配合
encodeURIComponent确保传输安全 - 即使这样处理完,还是要提醒后端同事做好防护
后端那边的改进主要是用了预编译语句,类似这样:
$stmt = $pdo->prepare("SELECT * FROM articles WHERE title LIKE :keyword");
$stmt->execute(['keyword' => "%{$keyword}%"]);
$results = $stmt->fetchAll();
技术细节补充:为啥要这么干
有人可能会问,既然后端已经做了SQL参数化处理,前端还需要这么麻烦吗?我的理解是:安全这件事,从来都是越谨慎越好。
首先,前端做一层过滤可以提前拦截大部分明显恶意的请求,减轻后端压力。其次,即使后端有防护,万一哪天升级或者修改代码时不小心漏掉了,前端这一层还能兜底。
这里还要特别提醒一点:千万不要以为用了HTTPS就万事大吉。HTTPS只能保证传输过程中的加密,对于SQL注入这种应用层的安全问题完全无能为力。
遗留的小问题:完美很难
改完之后其实还有个小瑕疵:如果用户正常搜索包含特殊字符的内容,比如程序员常用的 SELECT * FROM users; 这种合法的技术讨论,会被过度转义。不过考虑到实际情况,这种情况出现的概率很小,暂时就这么着吧。
以上是我踩坑后的总结,如果你有更好的方案欢迎评论区交流。毕竟安全这个东西,多学点总没错。

暂无评论