当前位置: 当前位置:首页 > 知识 > 网站sql注入正文

网站sql注入

作者:休闲 来源:知识 浏览: 【大 中 小】 发布时间:2026-10-17 06:13:40 评论数:

去年冬天,网站一个做外贸的网站朋友半夜给我打电话,说网站被搞了。网站打开首页,网站所有产品图片还在,网站但价格全变成了“1”,网站后台多了个陌生管理员账号。网站他问我怎么回事,网站我说八成是网站SQL注入。他一脸懵:网站不就填个表单吗,网站怎么还能被人改数据库?网站

SQL注入的原理其实很朴素。网站跟数据库打交道,网站靠的网站是SQL语句。比如用户登录,网站代码大概会拼出这么一句:

SELECT * FROM users WHERE username = '输入的网站用户名' AND password = '输入的密码'

正常输入没事。但如果有人在用户名框里填上 ' OR '1'='1,整句话就变成了:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '任意值'

数据库一看,'1'='1' 永远成立,条件直接通过,连密码都不用对。这就是最经典的注入——把用户输入当成代码执行了。

问题出在“拼接”上。很多早期代码图省事,直接把用户输入塞进SQL字符串里。数据库分不清哪部分是程序写的,哪部分是用户填的,它只认语法。用户填的内容一旦包含引号、分号、注释符,就能篡改原语句的逻辑。

我见过一个更隐蔽的案例。某电商网站的商品详情页,URL长这样:product.php?id=123。后端代码拿 $_GET['id'] 直接拼进查询。攻击者把 123 换成 123 UNION SELECT username, password FROM users,页面正常显示商品信息的下方,居然把管理员账号密码打印出来了。这种叫联合查询注入,利用的是页面会把查询结果渲染到HTML里的特性。

还有盲注。页面不显示数据库内容,但攻击者可以通过构造条件,观察页面返回“正常”还是“异常”,一个字符一个字符地把数据猜出来。比如判断数据库名第一个字母是不是 a,是就返回正常页面,不是就返回错误页。慢,但有效。sqlmap这类工具就是干这个的,自动化跑几千次请求,把库表字段全拖下来。

防御手段其实不复杂,但必须做对。最有效的是参数化查询,也叫预编译语句。SQL语句的骨架先发给数据库编译好,用户输入只作为参数传进去,数据库不会再把它当代码解析。比如Java的 PreparedStatement、Python的 cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))。只要用了这个,注入基本就没了。

但现实里很多人偷懒。ORM框架用得好好的,非要手写拼接;或者用了参数化,却在 ORDER BY 后面直接拼字段名——因为预编译不支持动态表名和列名。这时候得用白名单,把允许的字段名写死,用户传别的就拒绝。

另一个常见坑是转义函数。PHP的 mysql_real_escape_string 能转义引号,但如果数据库字符集设置不对,比如用了GBK,攻击者可以用宽字节注入绕过转义。所以转义不是万能的,参数化才是正道。

我那朋友的网站后来查清楚了。登录框没做过滤,攻击者用 ' OR 1=1 -- 直接进了后台,然后上传了个webshell,把数据库里的价格全改了。修复花了三天:改代码用参数化查询,加WAF规则拦截明显注入特征,后台密码重置,数据库权限收紧到只允许必要操作。他后来跟我说,以前觉得安全是运维的事,现在知道写代码的人第一行就得想着这事。

SQL注入1998年就被公开讨论过,二十多年了还在OWASP Top 10里。不是技术难防,是写代码的人总觉得“我这个内部系统没人会打”。可扫描器不管这些,它每天在互联网上无差别地扫,你的表单、URL参数、Cookie、HTTP头,任何一个进数据库的入口都是目标。别等首页被挂马了才想起来查代码。