当前位置:首页 > 综合

sql安全漏洞

2019年,全漏某电商平台的全漏后端开发在用户查询接口里拼了一条SQL:"SELECT * FROM orders WHERE user_id = " + userId。攻击者把userId传成1 OR 1=1,全漏整张订单表被拖走了。全漏这不是全漏什么高深攻击,一个刚学Web安全三天的全漏人就能干。问题出在代码本身——它把用户输入当成了SQL语句的全漏一部分,而不是全漏数据。

SQL注入的全漏本质就一句话:数据和指令没分开。数据库引擎分不清哪段是全漏开发者写的逻辑,哪段是全漏用户塞进来的内容。你写WHERE name = '$name',全漏用户输入' OR '1'='1,全漏引号闭合,全漏条件恒真,全漏整张表就暴露了。更狠的用UNION SELECT把其他表的数据拼进结果集,或者用; DROP TABLE直接删库。2008年Heartland支付系统被注入攻击,一亿多张信用卡信息泄露,根因就是拼接SQL。

很多人以为参数化查询能解决一切。Prepared Statement确实把SQL模板提前编译好,参数只当数据传,不参与语法解析。但现实里翻车的情况不少。比如ORDER BY后面没法用占位符——ORDER BY ?在很多数据库里不生效,开发只能拼接列名,注入点就来了。表名、列名、LIMIT值这些位置,参数化查询覆盖不到。我见过一个项目,搜索排序功能用白名单校验列名,但忘了校验排序方向,攻击者传ASC; DELETE FROM logs--,照样出事。

存储过程也常被当成银弹。可如果存储过程内部还在拼SQL,比如EXEC('SELECT * FROM users WHERE name = ''' + @name + ''''),那跟直接拼接没区别。Oracle的DBMS_SQL、SQL Server的EXEC,用不好就是自掘坟墓。还有ORM框架,Hibernate的HQL注入、MyBatis的${ }和#{ }混用,都是真实案例里反复出现的坑。${ }直接替换字符串,#{ }才走预编译。很多开发图省事,该用#的地方写了$,漏洞就这么来的。

盲注是另一个维度。页面不回显数据,也不报错,攻击者靠布尔条件或时间延迟来推断信息。AND SUBSTRING(database(),1,1)='a',逐字符猜库名。MySQL的SLEEP(5)、SQL Server的WAITFOR DELAY,都是时间盲注的常用手法。这种攻击流量小、隐蔽性强,WAF不一定拦得住。我见过一个金融系统,错误信息全被吞掉,返回统一500页面,但响应时间差了3秒,攻击者硬是把管理员密码哈希跑出来了。

防御这事,参数化查询是底线,但不够。最小权限原则得落实——Web应用连数据库的账号,不该有DROP、FILE权限。MySQL的LOAD_FILE()能读服务器文件,INTO OUTFILE能写webshell,权限给大了就是灾难。WAF能挡一部分自动化扫描,但别指望它兜底。代码审计和SAST工具要跑,尤其是那些拼接SQL的历史代码,改不动就得加白名单校验。输入验证用正则限制格式,比如userId只允许数字,这比事后过滤引号靠谱得多。

说个细节。有些团队用mysql_real_escape_string转义,觉得万事大吉。但字符集不匹配的时候,宽字节注入能绕过转义。GBK编码下,%df%27被转义成%df%5c%27,%5c是反斜杠,和%df组成一个多字节字符,单引号就逃出来了。这种坑,不踩一次根本记不住。

SQL注入活了二十多年,不是技术难防,是开发习惯难改。新框架层出不穷,但底层还是那套字符串拼接的逻辑。只要有人图方便,漏洞就永远存在。

分享到: