SQL 注入学习笔记:输入如何改变查询
记录 SQL 注入的形成原因、常见类型和输入点,以及参数化查询与最小权限的防御思路。
整理自个人 Notion 笔记 · 原笔记更新于
文章目录 8 个章节
第一课:SQL 注入
SQL 注入是什么?
用户输入本来应该只是”数据“,但是因为程序直接拼接 SQL,导致输入的一部分被数据库当成了 SQL 语句执行。
比如后端有一段不安全代码:
username = input();
sql = "SELECT * FROM users WHERE username = '" + username + "'"
正常输入:
alice
最后 SQL 是:
SELECT * FROM users
WHERE username = 'alice';
完全正常。
问题就在这里:
程序员控制的 SQL
+
用户可以控制的 username
如果用户输入能改变 SQL 的语法结构,就产生了 SQL 注入。
其中单引号' 非常重要
正常 SQL:
SELECT * FROM users
WHERE username = 'alice';
数据库认为:’alice’ 是个字符串,这里的' 相当于,字符串的边界。
但是如果用户本身出现:' ,就可能提前结束字符串,于是:
用户就有机会从“数据区域”跑进“SQL 语法区域”。
这就是理解 SQL 注入的最关键一步。
SQL 注入怎么“修改逻辑”的?
我们来看一个经典输入:
` OR 1=1 --
假设放进用户名。原来:
SELECT * FROM users
WHERE username = '用户输入'
AND password = 'xxx';
拼接之后就变成了:
SELECT * FROM users
WHERE username = '' OR 1=1 --AND passwrod = 'xxx'
-- 是SQL中的注释,也就是说,攻击者让数据库忽略了后面程序原本拼接的内容。
SQL 注入常见的几个类型
① 基于报错
输入影响 SQL 后,数据库会回显错误信息,我们根据回显的错误信息可以获取:
数据库类型
SQL结构
表字段信息
② UNION 型
SQL 有一个操作:
UNION
他的作用是:
把两个 SELECT 的查询结果组合起来
例如:
SELECT name FROM students
UNION
SELECT name FROM TEACHERS
如果应用中存在SQL注入,有时可以利用这个机制让原本查询的正常内容 + 其他数据(攻击者想要获取的)一起出现在响应里。
③ 布尔盲注
有些网站,SQL 执行了,但是不把数据库里的结果直接显示出来,这个时候可以观察:
条件成立 / 条件不成立
在网页行为上有没有区别。例如概念上:
条件 True
→ 页面正常
条件 False
→ 页面不同
通过不断问数据库:
是不是这个?
是不是那个?
逐渐获取信息。
④ 时间盲注
如果网页连 True / False 的结果都看不出来怎么办?
某些情况下可以观察服务器的响应时间:
条件成立
→ 延迟几秒
条件不成立
→ 正常返回
防御SQL注入的常见手段:
参数化查询:
先告诉 SQL 查询语句的结构,再告诉他对应的数据:
cursor.execute(
"SELECT * FROM users WHERE username = ?",
(username,)
)
最小权限:
假如网站数据库账户只需要:
SELECT
那就不要给他 DROP、CREATE等其他功能。
SQL 注入的核心防御不在于“过滤所有危险字符”,而是参数化的查询。
第二课:如何判断一个点是否可能存在 SQL 注入
什么是输入点?
网站上有很多地方可以控制数据,例如:
URL 参数
/product?id=10
搜索框:
搜索:
iphone
登录框:
username
password
Cookie
Cookie: user_id = 1001
HTTP Header
User-Agent
实战练习:
写下来,是为了更好地理解。
— 木之风