您的当前位置:首页 > 热点 > sql 注入漏洞 正文

sql 注入漏洞

时间:2026-10-17 04:35:11 来源:网络整理 编辑:热点

核心提示

2019年,某安全团队在GitHub上扒出一段代码,一个电商网站的登录接口直接把用户输入的username拼进了SQL查询字符串里。攻击者只要在用户名框里填上 ' OR '1'='1,就能绕过密码验证

2019年,入漏某安全团队在GitHub上扒出一段代码,入漏一个电商网站的入漏登录接口直接把用户输入的username拼进了SQL查询字符串里。攻击者只要在用户名框里填上 ' OR '1'='1,入漏就能绕过密码验证,入漏以任意账户登录。入漏这不是入漏什么高深攻击,一个刚学Web安全三天的入漏人都能打出来。但它真实发生在月活几百万的入漏平台上。

SQL注入的入漏本质就一句话:用户输入的数据被当成了SQL代码来执行。数据库分不清哪部分是入漏开发者写的指令,哪部分是入漏用户填的内容。你让它查用户名,入漏它把用户输入也当命令跑了。入漏问题出在拼接上。入漏SELECT * FROM users WHERE name = '" + input + "' 这种写法,等于把钥匙和锁一起交给了陌生人。

它到底怎么发生的

拿一个搜索功能举例。后端代码可能是这样的:

query = "SELECT id, title FROM articles WHERE title LIKE '%" + keyword + "%'"

用户搜“Python”,没问题。用户搜 %' UNION SELECT username, password FROM users --,数据库执行的是两条查询的合并结果。文章列表里会混进用户名和密码哈希。页面上可能只显示标题,但攻击者用Burp Suite抓包看响应体,数据就到手了。

还有一种更隐蔽的——盲注。页面不返回数据,只返回“有结果”或“无结果”。攻击者用 AND SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='a' 这样的条件,一个字符一个字符地把密码猜出来。慢,但有效。sqlmap跑一晚上,再复杂的密码也能拖出来。

为什么这么多年了还没绝迹

我翻过不少中小型项目的代码。说实话,SQL注入漏洞的数量在下降,但远没到消失的程度。原因不复杂:老系统没人敢动,新系统赶工期。一个创业公司的后端,三个人两周要上线,ORM用起来嫌麻烦,直接拼字符串最快。等业务跑起来了,谁还记得当初那个搜索接口有问题?

另一个原因是ORMs不等于绝对安全。Hibernate的HQL注入、MyBatis里用${ }而不是#{ },照样能注入。开发者以为用了框架就进了保险箱,实际上只是换了个地方踩坑。

防御的核心思路

参数化查询。就这一个东西,能挡住绝大多数SQL注入。数据库驱动会把用户输入当作纯数据来处理,不参与SQL语法解析。PreparedStatement、PDO的prepare、Python的cursor.execute(sql, params),都是干这个的。

存储过程也常被提到,但前提是存储过程内部不能用动态SQL拼接。否则只是把注入点从应用层挪到了数据库层。

输入验证有用,但别指望它当主力。黑名单过滤SELECT、UNION这些关键词,绕过手法太多了:大小写混写、内联注释、编码变形。白名单校验字段类型和长度是好的,但它解决不了所有场景,比如搜索框就是需要用户输入任意文本。

最小权限原则也值得说。Web应用连数据库的账号,不该有DROP、FILE这类权限。万一被注入了,攻击者能做的事也有限。我见过一个系统,数据库连接用的是root,攻击者直接LOAD_FILE('/etc/passwd')把服务器文件读出来了。这种配置,相当于给每个访客配了一把万能钥匙。

一个真实案例的细节

2017年,某国内CMS爆出一个注入点,在评论功能的orderby参数上。这个参数通常不被参数化,因为排序字段名没法用占位符。开发者写的是 ORDER BY " + orderField + ",攻击者传入 (CASE WHEN (SELECT SUBSTRING(password,1,1) FROM admin)='a' THEN id ELSE title END),页面排序结果不同,据此判断条件真假。这个漏洞存在了三年多才被修复。修复方式也简单,把orderField限制在白名单数组里。

说到底,SQL注入是开发者对“数据”和“代码”边界模糊的产物。参数化查询不是银弹,但它是目前最可靠的那道墙。别在代码里拼SQL,就像别在高速公路上倒车——你可能侥幸没事,但出事就是大事。

上一篇:网站维护多久