本节摘要:功能做加法,安全做减法——它决定不了服务有多好,却能一票否决它。本节把全书散落的安全点收拢成一张上线自检清单:注入、越权、密钥泄露、调试模式暴露、传输加密、常见 Web 攻击面。每个条目都对应轻记账里已学过的具体防线,收官之前逐条打勾,v1.0 才配得上"上线"两个字。
阅读完本节,你应当能够:
安全不是"加一个防火墙"的一次性动作,而是假设敌人已进门的持续审计:假设用户会提交恶意输入,假设数据库会被拖走,假设任何一处校验的疏漏都会被发现。听起来吓人,好消息是轻记账一路走来已经埋好了大部分防线——本节一半的内容是把它们点名叫出来,另一半是补齐剩余的几块短板。

注入防线(5.1 落实)。所有数据库操作只用参数化查询:SQL 模板与数据分离,数据永远是数据、永远当不了代码。自查方法:全局搜索字符串拼接进 SQL 的写法,一处不留。
越权防线(5.4 落实)。每个按 id 操作资源的接口都两问:登录了吗(装饰器)、这条数据是你的吗(查询条件带归属)。自查方法:拿 A 用户的凭证对 B 用户的数据执行改删,必须得到 404 或 403。
凭证防线(5.4 落实)。密码加盐高迭代哈希;登录失败提示模糊;连续失败锁定。自查方法:确认数据库里没有任何字段能还原出明文密码。
配置防线(6.2 落实)。密钥全走环境变量,.env 进忽略清单,Git 历史里搜不到密钥;生产环境调试模式关闭。自查方法:在生产环境故意访问一个会报错的路径,响应必须是简洁的 500 页而非带源码上下文的调试页。
传输防线(6.3 落实)。HTTPS 全站启用,HTTP 强制跳转 HTTPS;登录接口绝不允许明文提交。自查方法:浏览器地址栏确认小锁图标,历史页面无混合内容告警。
CSRF 跨站请求伪造:恶意网站诱导已登录用户的浏览器向你的接口发请求——浏览器会自动带上 Cookie。传统表单站点的解法是"表单里埋一次性令牌、服务端核验";轻记账这类纯 JSON API 依赖 CORS 收紧(6.1 的生产配置)与会话 Cookie 的 SameSite 属性,两道闸都要检查。
依赖安全:你信任的第三方库也可能有漏洞。保持依赖清单定期更新,关注所用库的安全公告——2.3 说的"依赖是负债",其利息之一就是这份持续看守的责任。
日志与监控:记录登录失败、越权尝试、异常堆栈,日志是事故后唯一的时间机器。但日志本身也是敏感面:绝不记录明文密码与完整令牌。
最小权限:数据库账号不给超管权限;服务器上服务用独立低权限用户跑,不给 root——每一处都遵循"只给它需要的最小能力"。
把上述内容浓缩成打勾清单,逐条过一遍轻记账:
[ ] 全局无字符串拼接 SQL [ ] 所有资源接口带归属校验,跨用户操作返回 404 [ ] 密码字段全为加盐哈希,登录提示不区分账号与密码错误 [ ] 登录连续失败五次锁定十分钟 [ ] .env 不在 Git,历史无密钥,生产密钥为独立强随机值 [ ] 生产调试模式关闭,报错页无源码信息 [ ] HTTPS 启用,HTTP 跳转,无混合内容 [ ] CORS 收紧至正式域名,Cookie 带 SameSite [ ] 依赖为近期版本,无已知高危公告 [ ] 日志在记录,且无敏感明文
十项全勾才许宣布上线。变式一:以攻击者视角写一份"轻记账渗透笔记"——只写思路不写代码:先探什么接口、试什么输入、看什么报错,你会发现每一步都撞在自己修过的墙上。变式二:把清单做成 CI 脚本的一部分(能自动化的项:密钥扫描、依赖检查),安全从"上线前检查"进化为"每次提交都查"。
安全知识最容易停留在口号层面,把它整理成"攻击手法 → 成因 → 防御手段 → 代码层面的动作"四栏,才落得了地。
| 漏洞类型 | 成因 | 防御手段 | 代码层面的动作 |
|---|---|---|---|
| SQL 注入 | 把用户输入拼进 SQL 字符串 | 参数化查询 | 一律用 ORM 或占位符,禁止字符串拼接 |
| XSS | 把用户输入原样输出到页面 | 输出转义 + 内容安全策略 | 模板引擎自动转义,慎用"不转义"标记 |
| CSRF | 利用用户已登录的身份发起请求 | 令牌校验 + SameSite Cookie | 表单与接口带一次性令牌 |
| 越权访问 | 只验证登录、不验证归属 | 每次数据访问都校验归属 | 查询条件带上当前用户标识 |
| 敏感信息泄露 | 密钥进仓库、日志打明文密码 | 密钥走环境变量、日志脱敏 | 提交前扫描、日志过滤 |
| 依赖供应链风险 | 第三方库存在已知漏洞 | 依赖扫描与定期升级 | 锁定版本 + 定期跑扫描工具 |
# 依赖漏洞扫描:把已知漏洞清单拉出来(应加入持续集成流程) python -m pip_audit -r requirements.txt # 输出示例:django 3.2.0 → 已知漏洞 GHSA-xxxx,建议升级到 3.2.15 及以上 # 密钥与敏感信息扫描:检查工作区是否误提交密钥 python -m detect_secrets scan --all-files
把上面这张表压缩成可执行的一次自检,每次发版前过一遍,成本不到十分钟:
比具体清单更重要的是三条习惯:默认不信任输入——所有进入系统的数据都要校验,包括"内部"系统传来的;最小权限——服务账号、数据库账号、内部接口调用都只给刚好够用的权限;假设已被攻破——设计时问一句"如果这一层被拿下,攻击者能走到哪一步",据此做隔离与限速。
这三条习惯的共同点是把安全从事后补救前移到设计阶段。等系统上线后再补安全,代价通常是重写。
清单打完,v1.0 正式上线。全书"轻记账成长记"就此闭环——从二十行脚本到安全上线的小服务,你走过的每一站,都是全栈开发者地图上的一个坐标。