SQL注入原理
要搞懂原理,得先把自己切换成**"后端程序员"** 和**"黑客"**两个视角。
1. 程序员的视角(正常业务流程)
你做了一个购物网站,用户点击"Gifts"分类,浏览器会发送:
https://网站.com/filter?category=Gifts
后端的代码(比如用 Java/Python 写的)收到这个请求,为了去数据库里把商品拿出来,它会直接拼接一条 SQL 语句:
sql
SELECT * FROM products WHERE category = 'Gifts' AND released = 1;
(翻译:去 products 表里,把分类是 Gifts,并且已经发布的商品找出来。released = 1 表示已发布,0 是未发布的隐藏商品。)
这条 SQL 发给数据库,数据库执行完,把 Gifts 商品返回给用户。一切都很完美。
2. 黑客的视角(坏人的大脑)
黑客看到 URL 里的 category=Gifts,心想:"这个 Gifts 是不是直接进到数据库里被执行了?"
于是黑客把 Gifts 删掉,改成了这段 payload(攻击代码):
sql
' OR 1=1--
3.拼接后的 SQL 变成了什么样?
后端程序没做任何检查,直接把黑客的代码拼了进去。数据库收到的新 SQL 变成了这样:
sql
SELECT * FROM products WHERE category = '' OR 1=1--' AND released = 1;
我们把这句被污染的 SQL 拆开来看:
-
category = '':第一个单引号是程序员写的,第二个单引号是黑客输入的。这代表"分类是一个空字符串"。 -
OR 1=1:这是绝杀! 在逻辑里,1=1永远是真理(True)。空字符串 OR True,结果永远是真。 -
--:在 SQL 语法里,两个减号代表**"注释"**。它后面的所有内容,数据库都会当作没看见。
所以,数据库实际执行的逻辑变成了:
去 products 表里,把商品找出来。不管它是啥分类(因为 1=1 永远成立),也别管它有没有发布(因为后面的 released=1 被注释掉了)。
结果就是:所有隐藏的、未发布的商品,全被黑客看到了。 这就叫 SQL 注入(SQLi)。
4.本质:数据和代码没有分离
SQL 注入(SQLi)最根本的原因,是后端程序把用户的输入(数据) ,当成了 SQL 语句的一部分(代码) 去执行了。
数据库在解析 SQL 语句时,它分不清哪部分是程序员原本写的指令,哪部分是用户恶意传进来的字符。
如果只是看到隐藏商品,那叫逻辑漏洞。真实的 SQL 注入危害极大:
-
拖库 :黑客可以用
UNION SELECT联合查询,直接把数据库里的管理员账号密码全部查出来。 -
读写文件:在某些高权限配置下,黑客可以通过 SQL 注入直接往服务器里写一个木马(WebShell),从而控制整个服务器。
-
执行系统命令 :最严重的情况,黑客可以通过数据库直接调用操作系统的命令(比如
xp_cmdshell)。
5.防御:为什么预编译是终极解法?
防止 SQL 注入最核心、最彻底的方法就是:预编译(Prepared Statement / 参数化查询)。
-
工作原理 :预编译的做法是,先把这个 SQL 语句的"骨架"发给数据库(比如
SELECT * FROM products WHERE category = ?)。数据库收到后,先把这句话的语法结构彻底编译并锁死。 -
为什么防得住 :之后,程序再把用户输入的内容作为"参数"填进问号里。此时,数据库只会把用户输入当作纯纯的数据(字符串) ,哪怕用户输入了
' OR 1=1--,数据库也只会去表里找有没有名字叫' OR 1=1--的分类,而不会把它当成代码去执行。
除了预编译,还有哪些辅助防御?
-
输入校验:比如规定年龄只能是数字,分类只能是白名单里的英文。
-
最小权限原则:连接数据库的账号,只给它增删改查的权限,绝对不给它读取系统文件或执行命令的权限。
-
WAF(Web应用防火墙) :在流量入口拦截掉包含
' OR 1=1这种特征的恶意请求。