c# - Django:在 C# .net 中执行 PUT 时 CSRF 令牌丢失或不正确
问题描述
我正在为 C# 中的某个应用程序构建一个插件,该插件必须与 Django 休息接口进行通信。如您所知,Django 使用 CSRF 令牌来提高安全性。
对 Django 进行 POST/PUT 调用时遇到问题。该调用将始终返回“CSRF 失败:CSRF 令牌丢失或不正确。”。我在浏览器中测试了调用(Web 界面也可以编辑数据,并且会调用相同的 PUT 请求),令我惊讶的是,X-CSRFToken 标头中使用了不同的 csrf 令牌值,而不是存储在 cookie 中的值. X-CSRFToken 标头是否应该使用新生成的令牌?X-CSRFToken 值在此调用后不再使用(旧的 csrftoken 值仍用于所有后续调用......)。
显然,我还阅读了有关 csrf 令牌的 Django 文档。尽管我认为我理解它是如何工作的,但我不明白为什么将新令牌用于 POST/PUT。有很多示例在我的 C# 插件中使用没有意义。
我在做 PUT 之前做什么:
- 通过请求正文中包含 csrfmiddlewaretoken 的登录页面来获取 CSRF 令牌。
- 以令牌作为值存储 cookie “csrftoken”(遗憾的是,cookie 不会自动存储)
- 使用凭据登录用户(POST)(csrfmiddlewaretoken={token} 也作为参数传递)
完成上述操作后,所有 GET 调用都可以正常工作。当我尝试执行 POST 或 PUT 时会出现问题。这是我的 PUT 代码,忽略 json 和 url 生成,因为这些不是问题:
// The _csrftoken used here, is the one I fetch at the beginning
Client().DefaultRequestHeaders.Add("X-CSRFToken", _csrftoken);
// The content is json
var response = Client().PutAsync(url, content).GetAwaiter().GetResult();
// The returned content is: {"detail":"CSRF Failed: CSRF token missing or incorrect."}"
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
// 403 is returned
if (response.IsSuccessStatusCode) { ... }
上面的代码具有以下状态:
- 用户已登录(sessionid cookie 可用)
- csrf 令牌可从登录获得(csrftoken cookie 也可用)
我试图解决的问题:
- 传递 csrfmiddlewaretoken={token} 作为参数
- 存储一个 X-CSRFToken cookie
- 使用我从 Web 界面中完成的 PUT 复制的 X-CSRFToken
- 尝试 HttpWebRequest 而不是 PutAsync
- 通过从 Web 界面中完成的 PUT 复制所有标头/参数/cookie 从 Web 界面复制 PUT
- ...
有人可以帮我理解我做错了什么吗?
非常感谢你能给我的任何帮助。
解决方案
所以这里的问题是我们试图在浏览网页的上下文之外使用 API,并且纯粹作为一个 api 来执行 GET/POST/.. 调用。这在您使用 CSRF 令牌时不起作用,因为这些令牌在浏览 html 页面中的 cookie 和元数据形式时会传递。
因此,只有在浏览上下文中使用 API 时,才能使用带有 CSRF 令牌的 API。如果您想在该上下文之外使用 API,则需要使用不同形式的身份验证,例如 OAuth2。
为了在没有浏览上下文的情况下工作,您必须为每个 POST/PUT/DELETE 获取一个 html 页面,以获取一个新的 CSRF 令牌,您必须将其与调用一起传递。显然这会带来很多开销,而且这不是您想要使用 API 的方式。
我要求 API 开发人员提供 OAuth2 身份验证。
推荐阅读
- asp.net - asp.net core 2,身份 w/windows 身份验证,但数据库管理角色
- go - 努力用 gogradle 编译 go 项目
- android - Android Studio 使状态栏背景完全透明并更改图标颜色
- android - 拦截调用以刷新令牌 GRPC
- d3.js - DC.js - 选择菜单作为复合图表的过滤器
- shiny - Shiny 无法连接到 ODBC
- android - 如何在不隐藏片段的情况下从选项卡主机中隐藏一个指示器
- sql - SQL Server studio 函数变量范围错误
- teamcity - TeamCity 动态参数
- c# - 根据对象的水平移动速度设置动画器浮动