Datasette 1.0a27 这次继续打磨 1.0,真正该看的不是版本号上的小步推进,而是安全默认值开始换代。PR #2689 已经把旧的 CSRF Token 方案替换为基于 Sec-Fetch-Site 的保护方式,连带删掉模板里的隐藏字段、移除相关插件钩子,并把文档和升级指南一起改了。

和旧稿相比,新来源补强的重点不在“Datasette 又做了一次安全更新”,而在三层更具体的信息:一是这次方案并非维护者临时起意,而是直接跟进了 Filippo Valsorda 的研究和 Go 1.25 在标准库里的实践;二是它不是在老机制上缝缝补补,而是明确让旧路线退场;三是它把受益者、限制条件和迁移代价都摆到了台面上。

从 Token 到 Sec-Fetch-Site,Datasette 正在换掉一整套老习惯

Datasette 过去长期依赖 Simon Willison 自己维护的 asgi-csrf 库来做 CSRF 防护。这是 Web 开发里最常见的一条路:服务端生成 Token,表单带着 Token 提交,服务端再检查是否匹配。安全上能工作,工程上一直不轻松。

麻烦主要有两类。第一类是模板负担。开发者得在表单里反复写:

<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">

第二类是例外处理。凡是本来就打算给浏览器外部、脚本或 API 客户端调用的接口,往往还要额外声明跳过 CSRF 检查。Datasette 以前为此提供了 skip_csrf(datasette, scope) 插件钩子。

这次 PR 的动作很直接:

  • 新增基于 Sec-Fetch-Site 的 CSRF 中间件
  • 删除模板中的 CSRF 隐藏字段
  • 移除 skip_csrf(datasette, scope) 插件钩子
  • 更新内部文档里的 CSRF 说明
  • 在升级指南中单列这次兼容性变化

这说明维护者的判断已经很明确:继续维护 Token 方案的复杂度,不再值得。对 Datasette 这种插件化、页面与 API 混合的系统来说,减少“每个入口都要人工接线”的安全机制,本身就是一次产品层面的收敛。

新线索最有价值的地方,是把技术来源和行业对照补齐了

旧稿如果只停留在“Datasette 改了 CSRF”,还不够完整。新来源给出的关键背景是:这套思路直接受到 Filippo Valsorda 研究的影响,而且已经在 2025 年 8 月进入 Go 1.25 的 net/http。这个对照很重要,因为它说明 Datasette 并不是在试验一套边缘做法,而是在跟进已经进入通用工程实践的安全机制。

Sec-Fetch-Site 的思路也和传统 Token 明显不同。它不要求应用自己分发、嵌入、核验额外令牌,而是利用浏览器已知的上下文:这次请求是同站发起、跨站发起,还是用户直接导航而来。服务器据此拦住不该被信任的跨站状态修改请求。

它带来的变化很朴素,但很现实:

  • 表单模板不再需要到处埋隐藏字段
  • 插件作者不必再频繁处理“这个接口要不要跳过 CSRF”
  • 默认策略更统一,减少靠记忆维护的角落
  • 对混合页面、插件和 API 的项目更省事

如果和常见方案做个对照,差别会更清楚:

方案开发者负担对浏览器能力依赖兼容旧环境更适合的场景
CSRF Token传统服务端表单、历史项目
SameSite Cookie现代站点的基础防线
Sec-Fetch-Site一般现代浏览器主导的 Web 应用

所以这次改动的意义,不在于 Datasette 发明了什么新防线,而在于它选了一个更接近今天浏览器现实的默认方案。对轻量项目来说,这是减负;对老系统来说,这更像一个参考方向,而不是可以立即照抄的标准答案。

谁会直接受影响,谁不能简单跟进

对普通 Datasette 使用者,这次变化几乎没有可见界面。真正会感到差别的是几类开发和维护角色。

插件作者会先碰到兼容性变化。skip_csrf 钩子已经被移除,任何依赖它来豁免接口的插件,都需要重新检查自己的行为是不是还成立。

维护内部后台和自定义模板的团队会得到最直接的好处。模板里不再需要塞 CSRF 隐藏字段,表单层面的样板代码会少一截,升级时也更容易判断哪些路径真的会触发状态修改。

安全团队和审计人员面对的检查项会变化。以前常见的问题是“某个表单或模板忘了埋 Token”;改成请求头判断后,这类问题会减少,但新的检查重点会变成:你的状态修改接口是不是都运行在正确的浏览器上下文假设下。

面向老旧浏览器、嵌入式 WebView、非浏览器客户端的系统则不能直接把这套方案当万能钥匙。这里也是新来源补得最实用的一块:Fetch Metadata 头主要依赖现代浏览器自动携带。如果请求来自脚本、爬虫、旧 WebView、内部工具或其他 HTTP 客户端,情况就未必整齐。

换句话说,这套机制更像“浏览器世界里的默认优解”,不是“所有 HTTP 流量的统一解法”。如果一个系统里浏览器请求和程序化调用混在一起,迁移前就必须把流量类型分清楚。

这次改动还有一个现实侧面:AI 已经参与到安全基础设施的重构里

Simon Willison 在 PR 说明里提到,这个改动跨了 10 个 commits,其中大部分代码工作由 Claude Code 完成,并由 GPT-5.4 参与交叉审阅,最终的 PR 描述则由他自己手写。

这段信息不能被理解成“AI 已经能替人做安全决策”。更准确的理解是:AI 工具已经足够成熟,能承担安全基础设施改造里的实现劳动,但设计理由、边界条件和责任归属,仍然得由维护者自己写清楚。

Willison 特别提到他开始重新手写 PR 描述,原因之一是让描述更简洁,另一个原因是提醒自己不要在 AI 参与后失去对改动理由的把握。这个姿态比“AI 帮我写了不少代码”更有价值,因为安全改动最怕的不是代码量大,而是团队已经没人能解释为什么这样改、在哪些条件下会失效。

对其他项目来说,这也是很现实的提示:以后不少框架级改动都可能进入“模型先改、人来定责”的流程。真正需要保住的,不是手写每一行代码,而是人类维护者对安全边界的解释权。