|
一个经典的关于案例是2017年Equifax泄露事件。攻击者通过一个公开的数据说法Web表单注入恶意SQL语句,窃取了1.43亿美国用户的库注社保号、信用卡数据。入攻这个漏洞在官方补丁发布后两个月仍未修复——因为运维团队觉得“那个表单看起来不重要”。正确你看,关于数据库注入从来不是数据说法高深的技术,它更像是库注一扇没锁的后门,而所有人都盯着前门的入攻大铁锁。 所谓的正确SQL注入,本质上就是关于攻击者在输入框里塞进一段SQL代码,让数据库把它当成正经指令执行。数据说法比如登录框让你输用户名,库注你输入' OR '1'='1,入攻如果程序没做过滤,正确数据库就会执行“WHERE username='' OR '1'='1'”,结果所有用户都被当成合法账号。就这么简单,一个引号加一个OR,就能绕过整个认证体系。 但真正让我后背发凉的是另一种情况——时间盲注。攻击者看不到任何报错信息,页面永远返回同一个结果。他只能靠数据库响应时间的细微差异来猜测数据。比如输入IF(SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='a',SLEEP(5),0),如果页面卡了5秒,说明密码第一位是'a'。这种攻击像拆炸弹一样需要耐心,但自动化工具让这个过程变得廉价。OWASP的测试数据显示,一个中等水平的工具每小时能尝试几万次盲注猜测。 防御手段其实早就成熟了。参数化查询是第一道防线——把SQL结构固定,只把输入当作纯数据传递。PreparedStatement在Java里用了二十年,但仍有开发图省事用字符串拼接。我见过某银行外包项目,代码审查时发现300多处拼接点,其中一半是“赶工期”留下的。另一个被忽视的入口是存储过程,很多团队认为存储过程天然免疫注入,实际上如果存储过程内部也用了动态SQL,照样中招。 还有个反直觉的事实:ORM框架并不等于安全。Hibernate的HQL虽然做了参数绑定,但如果你用了原生SQL查询接口,或者写了createNativeQuery,风险依旧。更隐蔽的是,某些ORM的自动排序功能会接受列名参数,攻击者可以传入id; DROP TABLE users--这种值。我见过一个团队用MyBatis,XML里写了${ }而不是#{ }——前者是字符串替换,后者才是预编译。就这一个字符的差别,整张用户表就暴露了。 最有效的自查方法其实很土:把所有输入框都填上',看页面有没有报错。如果弹出了数据库异常,恭喜你,找到漏洞了。再试' OR SLEEP(5)--,如果页面卡了5秒,说明盲注也成立。这套手动测试花不了十分钟,但很多开发连这一步都懒得做。 别指望WAF能兜底。绕WAF的姿势比想象中多——用注释符/**/分割关键字,用十六进制编码字符串,甚至利用数据库的UNION特性拼接字段。我见过一个案例,攻击者用/*!50000SELECT*/这种MySQL版本号注释语法,直接穿透了某知名WAF的规则库。规则总有疏漏,但代码层的参数化查询是物理层面的隔离。 说到底,数据库注入攻击的根源不在技术,而在人的惰性。每当你图方便在SQL里拼变量时,就等于给攻击者递了一把钥匙。而修复的成本往往不到半天——把拼接改成占位符,测试一遍核心流程,完事。但现实中,这个半天总被“下周再说”拖到漏洞曝光的那天。你手头的代码里,有多少个${ }在裸奔? |