16 · 服务端安全纵深:注入 / SSRF / 密钥 / 供应链
C03 讲了"你是谁、能做什么"(认证授权)。本篇讲攻击面防御:SQL 注入、SSRF、密钥管理、依赖供应链、纵深防御。
速览卡
| 项 | 内容 |
|---|---|
| 一句话定位 | 后端最容易挨打的四个口子,以及"纵深防御"的整体思路 |
| 核心内容 | SQL 注入、SSRF、密钥管理、依赖与供应链、纵深防御、最小权限 |
| 读完能回答 | SQL 注入怎么防?为什么不能随便让服务端去抓外部 URL?密钥放哪安全? |
| 相关板块 | C03 · 认证与授权 | C14 · 文件上传 | C12 · 错误处理日志配置 |
一、SQL 注入:用参数化,永远不拼字符串
python
# ❌ 危险:字符串拼接 SQL
query = f"SELECT * FROM users WHERE name = '{name}'"
# ✅ 安全:参数化查询
stmt = select(User).where(User.name == name)| 原则 | 说明 |
|---|---|
| 永远参数化 | ORM 或 ? 占位符 |
| 永不拼用户输入 | 输入一旦进 SQL 字符串 = 注入 |
| 校验类型 | 数值就按数值传,别当字符串 |
一句话:任何用户输入都不能拼进 SQL。用 ORM/参数化,这条做到就挡住了绝大多数注入。
二、SSRF:别让服务端帮你访问任意 URL
SSRF(服务端请求伪造):攻击者让后端去请求内网/云元数据地址。
python
# ❌ 危险:用户传 URL,服务端去抓
data = requests.get(user_url).content
# ✅ 安全:白名单/校验域名 + 禁止内网地址
ALLOWED_HOSTS = {"img.example.com"}
if urlparse(user_url).hostname not in ALLOWED_HOSTS:
raise HTTPException(403, "forbidden")| 防护 | 做法 |
|---|---|
| 白名单域名 | 只允许访问配置过的域名 |
| 禁止内网/元数据 | 拦截 127.0.0.1、169.254.169.254(云元数据) |
| 出网代理 | 统一出口,网络层兜底 |
为什么危险:后端能访问云元数据(
169.254.169.254/latest/meta-data),一旦放开任意 URL,攻击者能偷到云凭证。
三、密钥管理
| 错误做法 | 正确做法 |
|---|---|
| 密钥写代码/仓库 | 环境变量 / .env(不入 git) |
| 密钥写镜像 | 运行时注入 |
| 所有环境一个密钥 | dev/test/prod 分开 |
| 长期有效 | 轮换 + 最小权限 |
原则:密钥=最高敏感资产。泄露密钥的常见路径就是"提交进 git",用
.gitignore拦住.env,生产走密钥服务。
四、依赖与供应链
| 风险 | 防护 |
|---|---|
| 依赖漏洞 | pip-audit / npm audit 进 CI |
| 恶意包 | 锁定版本、校验锁文件 |
| 过期依赖 | 定期升级 + 安全通告订阅 |
bash
pip-audit -r requirements.txt # 扫依赖漏洞类比前端:和
npm audit一样,依赖是供应链攻击口,CI 里必须扫。
五、纵深防御:不要只靠一层
安全没有"一招破敌",是多层叠加,任何一层被绕过还有下一层兜底。
text
入口:限流 + WAF
网关:鉴权 + 白名单
业务:参数校验 + 权限校验(数据层兜底)
数据:加密存储 + 最小权限账号5.1 最小权限
- 数据库账号只给需要的权限(别用 root)
- 服务只监听需要的端口
- 密钥只给需要的服务
5.2 数据层兜底(IDOR)
C03 提到:越权检查必须放数据层。接口校验了还不够,查询时按当前用户过滤:
python
# 不只查 order_id,还要限定属于当前用户
stmt = select(Order).where(Order.id == order_id, Order.user_id == current_user.id)自检清单
- [ ] 全部数据访问用参数化,能说清为什么
- [ ] 知道 SSRF 是什么,服务端抓 URL 时做白名单 + 禁内网
- [ ] 密钥全部走环境变量/密钥服务,确认
.env在.gitignore - [ ] CI 里跑了依赖漏洞扫描
- [ ] 能说出"纵深防御 + 最小权限 + 数据层兜底"的落地方式
常见误区
- 误区:有 ORM 就不会注入。 ORM 不等于安全,手写 SQL 或
raw()一样会注入。 - 误区:只校验接口不校验数据层。 越权(IDOR)必须在数据层兜底,接口校验可被绕过。
- 误区:密钥在本地没事。 一旦提交 git 就永久泄露,历史记录里删不掉。
- 误区:安全是"加个 HTTPS"就行。 HTTPS 只保护传输,注入/SSRF/供应链都不管。
动手练习
练习 A:修一个注入
找一个你写过的拼接 SQL,改成参数化,并写一个测试证明特殊输入不再注入。
练习 B:SSRF 演练
给"抓取图片"接口加域名白名单 + 禁内网,测试 169.254.169.254 被拦截。
练习 C:越权兜底
给"查订单详情"加数据层 user_id 过滤,用别人的 id 验证 404/403。
相关文档
本区
- 03 · 认证与授权 —— 认证授权与 IDOR
- 14 · 文件上传与对象存储 —— 上传攻击面
- 12 · 错误处理日志配置 —— 不泄露细节的错误体
其他域
- 08 · 前端安全 —— 前端侧攻击面对照
- S · 安全域(规划中) —— 密码学/合规完整体系见 docs/PLAN.md