Django React CSRF 问题

Django React CSRF Issues

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

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

我在网上找到了一小段代码来帮助我测试我的 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".

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

我有一个 "live" 版本的后端,我也尝试利用它获得与本地相同的结果。

只有在我自己的计算机上进行测试才能获得成功的测试,两个开发服务器都位于该计算机上。

Django 设置:

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

我怀疑我的问题出在该白名单中的某处,但此时我不知道是什么问题。

如果有人可以帮助我了解正在发生的事情,如果他们没有答案,那可能会触发一个 "aha" 时刻。

您是否尝试过从实际的 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;
}

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