|
2017年,一家美国征信公司的数据库被人拖走了,1.43亿条包含社保号、驾照信息的记录在暗网上明码标价。事后调查发现,攻击者用的不是什么零日漏洞,而是通过该公司一个面向开发者的网页查询接口,在参数里拼了一段恶意SQL——就这么简单,像用万能钥匙捅开了自家后门。 SQL注入这招数老得掉渣,1998年就有人在Phrack杂志上公开讨论过。可二十多年过去,它依然盘踞在OWASP Top 10榜单上。这玩意儿本质上是把用户输入当成了代码执行。你让用户填个用户名,他填了' OR '1'='1,数据库就懵了——这到底是条件判断还是字符串? 我见过最荒唐的一次渗透测试,目标是个政府招标网站。登录框连基本的参数化查询都没做,我随手在密码框里敲了句' OR 1=1 --,回车后直接以管理员身份进了后台。那一刻我甚至有点失落,像是准备了全套撬锁工具,结果发现门根本没锁。 很多开发者觉得SQL注入是古董,早该被淘汰了。可现实是,只要还有人在写拼接字符串的SQL,这漏洞就永远有饭吃。我认识一个白帽子,专门盯着那些新上线的创业公司打。他说这些公司最爱犯的错就是“赶时间”——产品经理催着上线,开发随手把用户输入拼进查询语句,先跑通再说。等拿到融资,用户量上来了,再回头补窟窿?早被爬虫和脚本小子薅秃了。 防御手段其实不复杂。参数化查询是基本功,像Java的PreparedStatement、Python的cursor.execute带占位符,都能把数据和代码强行分开。再就是输入校验,别信任何来自客户端的东西——但这条原则被重复了无数次,依然有人把前端验证当安全措施。 有一次我给某金融公司做代码审计,发现他们的ORM框架已经默认参数化了,可某个老模块里硬是有人手写了原生SQL,还用了字符串拼接。问那个开发为什么这么干,他说“当时赶进度,参考了网上的一段老代码”。你看,漏洞就是这么传下来的,像某种数字时代的家族遗传病。 数据库权限也该收一收。很多应用连接数据库用的还是root或sa权限,好像数据库账号不花钱似的。就算被注入了,攻击者也只能在权限范围内折腾。你要是给应用账号只留SELECT、INSERT、UPDATE的权限,他连xp_cmdshell都调不了,想写个webshell都没地方下手。 真正让我觉得无奈的是,有些公司连基本的WAF都不部署。不是说WAF万能,但至少能拦下那些扫描器的自动探测。可他们觉得“我们系统小,没人盯上”。这话我听过太多次了,直到某个半夜三点,他们的数据库被勒索软件加密,才想起当初那个安全顾问的建议。 SQL攻击最阴险的地方在于,它不需要什么高深技巧,甚至不需要理解数据库原理。只要会点HTTP抓包,改几个参数,再拿sqlmap跑一遍,小学生都能当黑客。前两年有个新闻,一个16岁少年用SQL注入黑了学校教务系统,就为了提前看期末考试成绩。你说他技术多牛?不见得,但他知道那个教务系统是十几年前的老古董,肯定没修过漏洞。 代码是死的,人是活的。只要还有人在写代码,就难免犯错。可这错误犯了几十年还在犯,那就不是技术问题,是态度问题了。我见过最讽刺的一幕,某安全大会上,演讲者现场演示SQL注入,台下坐着几百个开发者。演示结束后提问环节,有人举手问:“我们公司用的是MySQL,这招管用吗?”——那一刻我真想冲上去摇着他的肩膀喊:你关心的不应该是数据库品牌,而是你写SQL的方式! |