发布到 Django 表单的时间比使用 Service Worker 后台同步生成的时间晚得多:CSRF 问题

POSTing to a Django form much later than it was generated with Service Worker background sync: CSRF issues

我有一个 Django 表单,我可以通过 service worker 离线使用它。如果用户在离线时完成表单,提交的数据将存储在 IndexedDB 中,然后注册一个 background-sync;当浏览器重新上线时,sync 事件在 service worker 中被触发,然后可以从 IndexedDB 读取数据并通过 fetch().

将表单提交到后端

但是,我打开了 Django 的 CSRF 保护。这要求我提交带有合法 CSRF 令牌的表单,该令牌存储在 cookie 中,但也存储在表单的 body 中(或更好的 X-CSRFToken header)以及部分fetch() 请求。不幸的是,因为这是在服务工作者中发生的,所以我无法读取 cookie 来获取 CSRF 令牌。有一项提案 allow service workers to read cookies 但尚未完成且当前已暂停,因此不可用。

我考虑过使用 postMessage 从 service worker 到主页请求该主页读取 cookie 并将其发回,但是 background-sync 可能 运行没有主页的时间postMessage到.

可能会存储在服务工作者生成和缓存表单时有效的 CSRF 令牌,但我不知道 CSRF 令牌保持多长时间有效,或者验证 Django

有解决这个问题的明智方法吗?显然我不想禁用 CSRF 保护。

默认情况下,Django CSRF 令牌的有效期为一年:https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-CSRF_COOKIE_AGE。 Django 执行例如referer 验证,然后比较两个令牌是否等价。

您可以存储 CSRF 令牌(如您所说,当表单被缓存时,或者在离线时捕获表单提交时保存),然后,如果稍后提交该表单时 CSRF 失败valdiation 和 returns 错误页面,确保错误页面中包含有效的 CSRF 令牌,然后 background/offline 脚本可以读取并重新提交相同的数据,这有望成功。