当前位置:首页 > 时尚

sql注入防范措施

2019年某电商平台的入防一次促销活动前夜,安全团队在日志里发现了一条奇怪的范措请求:id=1 AND 1=1。值班工程师没太在意,入防以为是范措测试流量。两小时后,入防数据库里三张核心表被拖走,范措包括用户手机号和加密后的入防支付信息。攻击者用的范措就是最基础的SQL注入——把SQL片段塞进本该只传数字的参数里。这件事后来在内部复盘时被反复提及,入防因为漏洞本身不复杂,范措复杂的入防是没人把那条日志当回事。

SQL注入的范措本质是代码和数据没分家。应用程序把用户输入拼进SQL语句时,入防数据库分不清哪部分是范措开发者写的逻辑,哪部分是入防用户塞进来的内容。比如登录查询写成 "SELECT * FROM users WHERE name='" + userName + "'",用户输入 ' OR '1'='1,整条语句就变成永真条件,绕过了密码校验。这种拼接方式在二十年前的PHP教程里随处可见,现在依然能在一些老旧系统里找到。

参数化查询是堵住这个口子最直接的办法。它强制SQL语句的结构先被数据库解析,用户输入的值只能作为数据填充,无法改变语句逻辑。Java里的 PreparedStatement、Python的 cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))、C#的 SqlParameter,都是这个思路。我见过一个团队把项目里所有拼接SQL的地方替换成参数化查询后,渗透测试报告里的高危项从十七个降到零。代价是改代码花了三周,但比数据泄露后应急响应的时间短得多。

有些场景参数化查询覆盖不到,比如 ORDER BY 后面的列名、LIMIT 后面的数字。这些位置数据库不允许绑定参数,只能拼接。这时候白名单校验就派上用场。用户传 sort=price,代码里预先定义 ["price", "created_at", "sales"],不在列表里直接拒绝。别用黑名单过滤关键词,攻击者用 UNION/**/SELECT 或者大小写混写就能绕过。白名单是“只允许这些”,黑名单是“禁止那些”,前者比后者可靠得多。

存储过程也能降低风险,前提是过程内部不动态拼接SQL。我见过一个项目用存储过程做查询,但过程体里写 EXEC('SELECT * FROM ' + @tableName),这等于把注入点从应用层挪到了数据库层,该注还是注。存储过程的价值在于权限收敛——应用账号只被授予执行特定过程的权限,而不是直接读写表。这样即使有注入,攻击者能做的事也有限。

最小权限原则常被忽略。很多应用连接数据库用的账号是 db_owner 甚至 sa。一旦注入成功,攻击者能 DROP TABLE、能读系统表、能执行 xp_cmdshell。如果应用账号只有特定几张表的 SELECT/INSERT/UPDATE 权限,注入的危害就被限制在业务数据范围内,不会直接沦陷整个数据库服务器。

WAF和RASP能挡掉一部分自动化扫描和常见payload,但它们不该是唯一防线。攻击者用编码变形、分块传输、注释混淆就能绕过不少规则。WAF更像楼道里的监控摄像头,能记录和报警,但门锁本身得靠代码写对。我倾向于把WAF当兜底,参数化查询和白名单当主力。

最后说个细节:错误信息别直接返回给前端。数据库报错里常带表名、列名、甚至部分SQL语句,攻击者靠这些信息就能摸清结构。统一返回“系统繁忙”之类的提示,详细错误写进日志。日志里也别记完整SQL,记参数化后的模板和参数值就行,避免日志本身成为泄露渠道。

SQL注入不是新问题,但每年OWASP Top 10里它都没缺席。原因不复杂——旧代码多、开发图省事、安全测试滞后。把参数化查询用对,加上输入白名单和权限收敛,能解决九成以上的注入风险。剩下的靠监控和响应速度。安全这事,没有一劳永逸,只有持续修补。

分享到: