游客发表

sql注入

发帖时间:2026-10-17 05:12:29

2010年,一个叫“小旋风”的脚本小子在论坛上发帖,说他用一条 ' OR '1'='1 就登进了某地方教育局的后台。底下跟帖的人不信,他就贴了张截图——后台里整整齐齐列着几万条学生身份证号。这事当年没上新闻,但在圈子里传了很久。SQL注入的破坏力,从来不是理论上的。

它的原理简单到有点荒谬。你写一个登录框,用户输入账号密码,后台拼出一条SQL:

SELECT * FROM users WHERE name='$name' AND pwd='$pwd'

正常用户填 admin 和 123456,语句没毛病。但要是有人在密码框里填 ' OR 1=1 --,语句就变成了:

SELECT * FROM users WHERE name='admin' AND pwd='' OR 1=1 --'

1=1 永远成立,-- 把后面的引号和条件全注释掉了。数据库一看,条件为真,放行。密码是什么?不重要了。

我见过最离谱的案例,是某个电商网站的商品搜索接口。它把用户输入的关键词直接拼进 LIKE 子句,连引号都没转义。有人搜 %' UNION SELECT username,password FROM admin_users --,结果页面上直接回显出了管理员账号和MD5哈希。那个站后来被拖库,二十多万用户数据挂在网上卖。开发人员可能到现在都不知道,问题出在一行没过滤的搜索框上。

很多人以为参数化查询就万事大吉。确实,PreparedStatement 能防住绝大多数注入,但前提是你真的用了。我审过一套代码,框架是Spring,DAO层用了JPA,看着挺规范。结果有个“高级查询”功能,为了支持动态排序,把用户传的 orderBy 字段直接拼进了SQL。参数化只对值生效,对表名、列名、排序方向这些结构部分无效。攻击者传 orderBy=id,(SELECT ...),照样能注入。这种边角料,恰恰是审计时最容易漏的。

还有人迷信WAF。某次护网行动,红队打一个站,WAF拦了所有带 union、select 的请求。他们换成 /*!50000union*/ 这种MySQL内联注释,WAF没认出来,直接穿了。WAF是层皮,不是骨头。真正管用的,还是代码里老老实实做类型校验、白名单、参数化。别把命交给一个正则表达式。

说个我自己的观察。SQL注入这十几年,从手工 and 1=1 到sqlmap自动化,工具越来越傻瓜,但漏洞数量没怎么降。为什么?因为新系统还在用老办法拼SQL。ORM框架普及了,可总有人为了“灵活”开个后门,手动拼字符串。每次代码review看到 String sql = "select * from " + tableName,我血压都上来了。

防御这事,说到底就三条。第一,能用参数化就用参数化,别偷懒。第二,实在要拼结构部分,白名单校验,只允许字母数字下划线。第三,数据库账号最小权限,别让Web应用有 drop table 的能耐。做到这三点,99%的注入就没了。剩下的1%,是开发人员觉得“这次没关系”。

那个教育局的站,后来修复了。但小旋风的截图还在我硬盘里。每次有人跟我说“我们内网,没人会打”,我就把图翻出来给他看。安全这事,从来不是会不会,是值不值。

    热门排行

    友情链接