【问题标题】:Django React CSRF IssuesDjango React CSRF 问题
【发布时间】:2019-05-31 11:07:19
【问题描述】:

使用 Django 作为后端并使用 React 作为前端来构建我的第一个应用程序。

在本地,我分别在 8000 和 3000 端口上运行。

我在网上找到了一个简短的 sn-p 代码,可帮助我测试我的 CSRF 和 CORS 策略是否设置正确:

const API_HOST = 'http://localhost:8000';

let _csrfToken = null;

async function getCsrfToken() {
  if (_csrfToken === null) {
    const response = await fetch(`${API_HOST}/csrf/`, {
      credentials: 'include',
    });
    const data = await response.json();
    _csrfToken = data.csrfToken;
  }
  return _csrfToken;
}

async function testRequest(method) {
  const response = await fetch(`${API_HOST}/ping/`, {
    method: method,
    headers: (
      method === 'POST'
        ? {'X-CSRFToken': await getCsrfToken()}
        : {}
    ),
    credentials: 'include',
  });
  const data = await response.json();
  return data.result;
}


class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      testGet: 'KO',
      testPost: 'KO',
    };
  }

  async componentDidMount() {
    this.setState({
      testGet: await testRequest('GET'),
      testPost: await testRequest('POST'),
    });
  }

  render() {
    return (
      <div>
        <p>Test GET request: {this.state.testGet}</p>
        <p>Test POST request: {this.state.testPost}</p>
      </div>
    );
  }
}

export default App;

编辑澄清:远程 GET 请求通过,只有 POST 失败

当我在本地运行此代码时,我得到了正确的响应,即当响应返回有效时,“KO”变为“OK”。

这只适用于我的机器。如果我尝试从网络中的任何其他机器访问它,我会收到以下错误:

403 禁止

Django的调试原因是“CSRF cookie not set”。

但是,在控制台中,我可以看到标头确实在发送 X-CSRFToken。

我有一个“实时”版本的后端,我也尝试过使用它,结果与本地相同。

只有在我自己的计算机上尝试时,我才能获得成功的测试,这两个开发服务器都坐在那里。

Django 设置:

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ['localhost:3000', 'My_Public_Ip:3000']

我怀疑我的问题在那个白名单中的某个地方,但我现在不知所措。

如果有人可以帮助我了解正在发生的事情,如果他们没有答案,那可能会引发“啊哈”时刻。

【问题讨论】:

  • 我不知道您如何准确发送 cors 标头 - 实际上不允许使用列表,因此您应该始终返回确切的域。但它会在控制台中生成正常响应和错误,其中包含有关 cors 的信息,而不是 403。我猜你在检索该 csrf 令牌时做错了,尝试调试这部分。
  • 我没有完全按照。标头是这样发送的: headers: ( method === 'POST' ? {'X-CSRFToken': await getCsrfToken()} : {} ), credentials: 'include', });我可以确认正在发送令牌(至少在我的理解中是这样),我将截屏并将其添加到 OP。
  • 截图显示发送一个名为X-CSRFToken的标头,但不是cookie本身。你能确认当一切都在本地正常工作时,还会发送一个 cookie 吗?也许您还可以为工作请求添加请求标头的屏幕截图?
  • @BernhardVallant 我已经更新了屏幕,现在在下面尝试你的答案。

标签: django reactjs django-cors-headers


【解决方案1】:

您是否尝试过从实际 cookie 中获取 CSRF 令牌,而不是向服务器发出请求? 因为实际上您现在正在做的是每次尝试获取任何内容时都获取 CSRF 令牌。

在您的 JavaScript 中尝试以下内容:

import Cookies from 'js-cookie;

async function testRequest(method) {
    const headers = {};
    const csrftoken = Cookies.get('csrftoken'); // or the value from settings.CSRF_COOKIE_NAME
    if (csrftoken) {
        headers['X-CSRFTOKEN'] = csrftoken;
    }
    const response = await fetch(`${API_HOST}/ping/`, {
        method,
        headers,
        credentials: 'include',
    });
    const data = await response.json();
    return data.result;
}

【讨论】:

  • 我已经设法让它在本地工作,类似于我已经拥有的代码,但是当我远程尝试时,我遇到了与以前相同的问题,Django 拒绝了该请求,给出的原因是 CSRF cookie 未设置。我的浏览器确实在 cookie 部分设置了 cookie。接下来我将不得不看看@Bernhard Vallant 的建议是否是我的错误所在。
【解决方案2】:

除了@tgdn 建议从 cookie 中获取令牌之外,我还建议检查您的 SameSite 策略设置以获取 CSRF- 和 Session- Cookie,因为将其设置为 StrictLax 将还禁止在跨域请求中发送 cookie(这可能导致您的会话丢失/被注销等...)。

【讨论】:

  • 好吧,也许是晚上的时间或我正在对抗的流感,但我似乎无法理解设置此设置的正确位置。根据文档所说,如果我理解正确,默认设置是限制最少的?
  • 使用None 禁用它是最不严格的。也许尝试一下,看看它是否能解决您的问题...Lax 仍然不允许在跨域请求中发送 cookie owasp.org/index.php/SameSite ...根据您的新屏幕截图SameSite=Lax 似乎已被应用。跨度>
  • 我还没有修复它,但你最后的评论终于让我全部点击了。它在本地工作,因为我的两个开发服务器都在本地主机上运行,​​只是一个不同的端口,所以 SameSite 永远不会启动,但只要我远程尝试它就会启动。我会在找到设置位置后立即报告!
  • 快速更新,我忘了说我的GET请求通过了,即使是远程,也是POST请求失败,会更新OP。
  • 似乎适合 SameSite 策略应该阻止 CSRF-prove 请求,例如 POST
猜你喜欢
  • 1970-01-01
  • 2011-06-30
  • 1970-01-01
  • 2017-07-01
  • 2016-04-19
  • 2011-03-11
  • 2021-11-05
  • 2011-07-26
  • 1970-01-01
相关资源
最近更新 更多