当前位置: 当前位置:首页 > 综合 > sql注入漏洞原理正文

sql注入漏洞原理

作者:探索 来源:焦点 浏览: 【大 中 小】 发布时间:2026-10-17 06:14:28 评论数:

一个登录框,入漏输入 admin' or 洞原'1'='1,点击登录,入漏直接进了后台。洞原这不是入漏魔术,是洞原十几年前就存在的漏洞,到今天依然在无数站点上反复出现。入漏sql注入的洞原本质,就是入漏把用户的输入当成了sql代码来执行。

拿个最简单的洞原例子说。某网站查询用户信息的入漏sql语句是:SELECT * FROM users WHERE username = '$name' AND password = '$pass'。开发者本意是洞原让$name和$pass只作为字符串值存在。但如果用户在用户名框里输入admin' -- ,入漏拼接后的洞原sql就变成了SELECT * FROM users WHERE username = 'admin' -- ' AND password = '任意'。两个横线在mysql里是入漏注释符,后面的密码校验条件直接被注释掉了。系统只验证用户名是admin就放行,密码形同虚设。

更狠的玩法是union注入。比如一个商品详情页,网址是product.php?id=1,后台查询是SELECT name, price FROM products WHERE id = $id。你在id后面加上union select username, password from users,页面就会把管理员的账号密码当作商品名和价格渲染出来。这招不需要任何工具,浏览器地址栏就能操作。我第一次看到朋友演示时,后背发凉——原来网站后台离裸奔就差一个参数。

为什么到今天还有这漏洞?根子在于代码拼接。很多老项目是用字符串相加的方式构造sql,比如php里$sql = "SELECT * FROM news WHERE id = " . $_GET['id'];。这种写法把输入直接焊死在查询语句里,等于把门钥匙交给了陌生人。参数化查询能解决大部分问题——PREPARE stmt FROM 'SELECT * FROM news WHERE id = ?',用占位符把数据和代码隔开,但改老代码要动架构,不少团队嫌麻烦,或者根本不知道自己的代码里有这种写法。

还有个隐蔽场景是搜索框。有些开发者对搜索关键词做了转义,但忘了对排序字段处理。比如ORDER BY $_GET['sort'],这个位置不能参数化,只能白名单校验。攻击者传入IF(1=1, id, price),然后观察页面排序变化,就能逐字符猜出数据库内容。这叫盲注,不需要页面回显数据,只靠真伪判断就能把整个库拖出来。慢是慢点,但自动化脚本跑一晚上,什么秘密都没了。

防御思路其实就两条:第一,用户输入永远只当数据看,绝不当代码执行。能用参数化就用参数化,不能用的地方(比如表名、排序字段)必须做严格白名单。第二,数据库账号别用root,给应用一个只读权限的账号,就算注入成功也拿不到敏感表。我见过某电商后台,数据库账号是sa权限,攻击者直接xp_cmdshell执行系统命令,等于拿到了服务器控制权。那已经不是拖库的问题了,是整台机器沦陷。

sql注入不是高深技术,但它考验的是开发者对数据边界的敬畏。每次写sql前多问一句:这个输入如果变成代码会怎样?答案往往就在那一瞬间的犹豫里。