注入攻击
注入是历史最悠久也最致命的漏洞:用户输入被当作代码执行。面试必考 SQL 注入。
SQL 注入
-- 危险: 用户输入直接拼接
SELECT * FROM users WHERE name = 'admin' OR '1'='1' -- 恒真, 绕过登录
-- 变体: 时间盲注
SELECT ... WHERE id = 1 AND SLEEP(5) -- 逐字符探测| 类型 | 原理 |
|---|---|
| 联合注入 | UNION 拼接查询其他表 |
| 报错注入 | 构造报错带出数据 |
| 布尔/时间盲注 | 无回显时逐字符探测 |
根因:SQL 语句和数据混在一个字符串里,数据库无法区分。
防护:参数化查询
# 正确: 参数化, 数据与语句分离
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
# 错误: 字符串拼接
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")- 参数化查询(预编译)是根治:语句结构固定,输入只当数据
- ORM(SQLAlchemy)默认参数化,但要小心原生 SQL 和 raw 方法
- 转义是次选(容易漏),白名单校验是辅助(ID 校验数字)
命令注入
# 危险: 拼接 shell 命令
os.system("ping " + host) # host = "1.1.1.1; rm -rf /"
# 正确: 参数列表, 不走 shell
subprocess.run(["ping", host])- 根因:用户输入进入 shell 解释器
- 防护:用参数列表传参(不经 shell)、白名单校验输入、最小权限运行
其他注入
| 类型 | 机制 | 防护 |
|---|---|---|
| NoSQL 注入 | 操作符注入($ne、$gt) | 类型校验、白名单 |
| LDAP/XPath 注入 | 查询拼接 | 参数化/转义 |
| 模板注入(SSTI) | 模板引擎执行 | 不信任用户模板、沙箱 |
面试追问
- SQL 注入原理? 用户输入拼进 SQL,数据和代码混淆。数据库把输入当语句执行
- 怎么根治? 参数化查询:语句和数据分离。ORM 默认安全,原生 SQL 要小心
- 盲注是什么? 无回显时用布尔/时间差异逐字符探测数据
- 命令注入怎么防? 参数列表传参(不经 shell)、白名单、最小权限
- ORM 一定安全吗? 不一定:raw SQL、拼接查询(filter 里拼字符串)仍有风险