Skip to content

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。


相关文档 ​

本区 ​

其他域 ​