Cloudflare 吃掉了我的 'Set-cookie'?
突然想起来好像很久没有更新了, "前几天(?)"本来还想更新一下的来着, 但是找不到什么好什么好写的, 于是就作罢了. 就在昨天, 本来想更新一下 gal 的, 但是发现了一个严重的问题, 我的 Django 后台登陆不上了. 现象如下:

既然他说 csrf 验证失败, 那先看看 csrf 什么情况, f12 打开浏览器的控制面板, 选中表单的 post 请求, 发现一切正常, 刷新页面 csrf token 也会发生变化, 好像没什么问题. 因为我的网站套了一层 cf 的 cdn, 总之先怀疑一下这个 cdn, 关闭 cdn 的缓存看看, 问题依旧.
上服务器看看, 因为我的网站后端是使用 docker 部署的 headless django, 删除并重启一下 django 的容器看看(别把数据库的卷也删了, 不然你的数据库直接就清空了), 问题依旧. 服务器上本地 curl 一下 Django 端口看看, 重定向到 cf 的 https 协议的 CDN 上了, 要继续测试问题的话得直接连接源服务器看看. 反正我用的是 Caddy 的反向代理服务(自从有了 Caddy, 现在我打死都不用 Nginx 了), 自带免费 tls 证书申请功能, 所以也是 https 的协议, 直接把域名指向源服务器就可以绕过 CDN 了, 怎么指向呢, 也很简单, 在 host 文件里添加一条记录就可以了. 在浏览器中关闭 DNS 安全功能(这个功能甚至会绕过系统的 host, 好强的安全性), 重新试下登录, 丝滑且流畅, 嘛, 直觉果然没错, 又是 cf CDN 导致的问题(毕竟之前被"坑"过好几回).
竟然找到问题所在了, 在仔细看看, 是什么原因导致的, 对比一下有 CDN 和没有 CDN 的区别, post 请求乍看起来好像没什么区别, 翻开 cookie 一看 CDN 这里就只有一个 cf 的防护 cookie, 并没有 CSRF cookie. 这是个什么情况, 再看看网页请求, 很明显的, CDN 这边的请求没有 set-cookie 这个响应头, 这也就导致了在 CDN 这边没有 CSRF cookie 了, Django 自然也就拒绝验证了. 突然就想起来之前写的那个关于 CSRF 的文章了, 我在那篇文章里也提到了, 在现代的 WEB 中表单中的 CSRF Token 和浏览器存储的 CSRF Cookie 几乎已经成为必选项了, 在这里 Django 的默认的安全设置也是这样的.
至于为什么 Clouflare 突然就吃掉了响应头中的 Set-cookie 嘛(这个响应头就是给浏览器设置 Cookie 的), 我在这篇帖子中找到的答案 express - CloudFlare set-cookie not passing through to browser - Stack Overflow

虽然用户到 cf CDN 的请求是加密的 HTTPS, 但是说到底 CDN 也就只是一层反向代理而已, 如果在源服务器和 CDN 中的连接中是未加密的 HTTP, 那么 Django 也会按照安全设置在 HTTP 连接中拒绝发送 Cookie 了. 我的解决方法是设置 "SSL/TLS 加密模式" 为 "完全(严格)", 并且在服务器上使用 cf 给的证书, 这样就可以保证 CDN 和源服务器之间也使用安全的 HTTPS 了.

这个模式会强制使用 cf 提供的自签证书(只有 cf 自己认可, 直接访问源站的话会提示证书错误), 这样源服务器和 cf CDN 之间就是使用的加密连接了, 同时这个设置也可以防护源站伪造(如果你的 cf 证书不泄漏的话).

不过, 我还是有个问题, 我之前在"完全"模式下, 使用的明明是被大众认可的证书, 为什么 cf 却不认呢, 非要使用自签证书吗? 搞不懂 cf 的逻辑.
所以这次真的不是我懒才没有更新的, 嗯, 一定是的, 后台上不去多多少少也算是"半个不可抗力"了, 所以这不能怪我, 嗯, 是这样的. (其实只是服务器上的 Django 上不去了而已, 又不是数据库上不去了, 可以在自己的电脑上再开一个 Django, 把数据库指向服务器上的, 就可以直接在本地修改服务器上的数据了)
0721 (指日期) 更新, 问题依旧, 这次 caddy 的免费证书和 cf 给的证书都试了, 两个都不能穿过 cdn 获得 cookie. 我的互联网活菩萨, 你又在搞什么名堂?
最后, 至于为什么我之前会去折腾 CSRF 这个东西嘛, 主要是因为在写一个新东西, 需要(只是我想怎么做)使用原生 WEB 技术, 所以各个方面都去了解了一下. 对于现代的 WEB 服务框架而言的话, 这些东西都是开箱即用的, Next.js 中的表单自带 CSRF, 类似的 server action 也是加密的(server action 可以在客户端调用服务端的函数). 因为我之前也没怎么学过原生 js(主要是太抽象了, 这个玩意, 各种历史遗留和设计缺陷), 不懂? 请看下面的 meme



原生 js 和 React.js 简直就像两种不同的"语言"...