游客发表
2017年,入防美国征信巨头Equifax被曝出数据泄露,护方1.43亿用户的入防社保号、信用卡信息被拖走。护方事后调查发现,入防攻击者利用的护方正是其网站上一个未修复的SQL注入漏洞。这不是入防什么高深攻击,就是护方往查询参数里塞了点恶意字符串。
SQL注入的入防本质是——开发者把用户输入直接拼进了SQL语句。你输入的护方内容被数据库当成了代码执行,而不是入防单纯的数据。比如登录框里输入 ' OR '1'='1,护方如果程序没做处理,入防这条语句就变成了 SELECT * FROM users WHERE name='' OR '1'='1',护方恒真,入防直接绕过密码验证。
防护手段第一条:参数化查询。这是最硬的防线。用预处理语句,先把SQL骨架发给数据库,占位符定死,用户输入只作为参数传进去。数据库知道哪些是结构、哪些是数据,再怪异的输入也只会被当成字符串。Java里的PreparedStatement、Python的execute带参数、PHP的PDO预处理,都是这个思路。写代码时养成习惯,任何涉及用户输入的SQL,一律参数化,没有例外。
第二条:对输入做严格校验。参数化防了结构注入,但有些场景你连参数内容本身都要限制。比如一个id字段,预期是正整数,那就用正则或类型转换强制它只能是数字。再比如排序字段,通常只允许白名单里的几个列名。输入校验不是防御的全部,但它能砍掉一大半攻击面——很多注入漏洞根本轮不到数据库层面,在入口就被挡回去了。
第三条:最小权限原则。给数据库连接用的账号,别用root或sa。只给它增删改查所需的最小表权限,甚至只给存储过程的执行权限。这样就算注入成功,攻击者能操作的范围也极其有限。很多小团队图省事,一个高权限账号跑天下,这是给自己埋雷。
还有一条常被忽略:错误信息别回显给用户。数据库报错时,那些堆栈、表名、字段名,都是攻击者的地图。生产环境里,统一捕获异常,返回一个模糊的“系统繁忙”,详细日志只写进服务端文件。
我见过一些老系统,代码里全是拼接字符串的SQL,几百个地方要改。这种时候别硬来,先做一层统一的过滤入口,对入参做转义和危险关键字检查,再逐步重构。但记住,转义只是权宜之计,不是长久方案——不同数据库的转义规则不一样,容易漏。真正靠谱的还是参数化。
另外,别迷信WAF(Web应用防火墙)。它能拦掉一部分已知攻击模式,但绕过WAF的SQL注入案例一抓一大把。WAF是减速带,不是保险箱。核心代码的健壮性才是根本。
说个实际的测试方法:在输入框里随便输入一个单引号 ',如果页面报错或者行为异常,说明你的程序很可能存在注入点。多试几种组合,比如 ' AND 1=1 和 ' AND 1=2,如果两者返回结果不同,那基本可以确认注入存在。这套手动测试,五分钟就能给一个表单做初步体检。
SQL注入这毛病,从上世纪90年代末被发现到现在,二十多年了,依然年年霸榜OWASP Top 10。原因不是技术难,而是开发者换了一茬又一茬,安全意识却没跟上。每次看到新项目里又出现拼接SQL,我都觉得这不是代码问题,是流程问题——代码审查没做、安全培训没到位、上线前没有自动扫描。
最后补一句:把数据库操作封装成数据访问层,统一管理,别在业务代码里到处写裸SQL。这样既方便加防护,也方便审计。代码写干净了,注入自然就少了。
友情链接