sql注入防御
去年某电商平台被拖库,入防泄露了百万用户数据。入防事后复盘,入防攻击入口就是入防一个没做参数化查询的搜索接口。开发图省事,入防直接拿用户输入拼SQL字符串,入防结果被人用 很多人以为用了ORM就万事大吉。入防我见过一个项目用MyBatis,入防但XML里写的入防是 防御的核心就一条:让用户输入永远只是数据,不能变成SQL代码。参数化查询(Prepared Statement)是干这个的。数据库驱动会把SQL语句的结构先编译好,参数位置留空,用户输入到了那里,只被当作一个值,就算里面包着引号和分号,也翻不出浪花。Java里的 但光靠参数化还不够。有些场景没法用参数化,比如动态表名、动态排序字段。用户点“按价格排序”,你总不能在 存储过程也常被当成防御手段。理论上它能把SQL和参数分开,但很多团队写的存储过程内部还是拼字符串,那就白搭。而且存储过程维护麻烦,改个逻辑要动数据库,现代开发里用得越来越少。与其依赖它,不如把参数化查询写扎实。 还有一层容易被忽略:数据库权限。Web应用连数据库的账号,不该有 WAF有用,但别当主力。云WAF能拦掉大部分自动化扫描和常见payload,可遇到编码绕过、分块传输、注释混淆,照样可能漏。而且WAF规则一更新,攻击者就研究新绕过。把它当辅助,别当唯一防线。 代码审计和自动化扫描得定期做。SonarQube、CodeQL能揪出拼SQL的坏味道,sqlmap可以拿来做渗透测试。但工具报告得有人看,误报得有人排除。我见过扫描器报了高危,开发回一句“这是内部接口”就关掉了,结果那个接口后来真被利用了。 最后说个细节:错误信息别回显给用户。数据库报错里可能带表名、字段名甚至SQL片段,等于给攻击者送情报。统一返回“系统繁忙”或者自定义错误码,把详细堆栈记到日志里。日志也别记原始SQL,万一记了用户输入的密码,二次泄露更麻烦。 SQL注入防御没什么高深技术,就是别偷懒。参数化查询、白名单、最小权限、错误处理,每一条都做到位,攻击面就小到可以忽略。那些被拖库的案例,翻来覆去都是因为某一行代码用了字符串拼接。写代码的时候多打一个问号,比事后补救便宜得多。' OR '1'='1 这种老掉牙的入防payload绕过了登录验证,接着一步步提权,入防最终把整个库拖走。入防这事说明一个事实:SQL注入没死,入防它只是入防藏在了那些偷懒的代码里。${ param} 而不是 #{ param}。这俩符号长得像,入防效果天差地别——${ } 是直接字符串替换,等于把用户输入原样塞进SQL。攻击者输入 1' UNION SELECT password FROM users--,照样能跑。ORM不是护身符,关键看你怎么用。PreparedStatement、Python的 cursor.execute(sql, params)、Node.js的 connection.query('SELECT * FROM t WHERE id = ?', [id]),都是这个思路。ORDER BY ? 里传 price 吧?数据库不认。这时候得用白名单。表名和字段名限定在预设的合法集合里,用户传 price 就映射到 price,传别的直接拒绝。别用黑名单,黑名单永远漏。DROP、FILE、xp_cmdshell 这些权限。只给 SELECT、INSERT、UPDATE、DELETE,而且限定到具体表。万一注入没防住,攻击者也只能在有限范围内折腾,拖不走整个库,更别想执行系统命令。这是纵深防御的底线。
-
上一篇
-
下一篇
- 最近发表
- 随机阅读
- 搜索
-
- 友情链接
-