You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅Chrome扩展中Django POST请求出现CSRF验证失败问题

解决Chrome扩展中POST请求的CSRF Referer校验失败问题

我来帮你分析下这个问题——Chrome扩展环境发起跨域请求时,默认不会自动携带Referer头,这正是服务器返回CSRF Failed: Referer checking failed - no Referer的核心原因。而你提到的其他场景(localhost、本地HTML、终端)都会自动生成合法的Referer,所以请求能正常通过。

先回顾下你的问题场景:

  • 你用来发起POST请求的代码:
var session_id; // to use for token based authentication
// prep
$(document).ready(function(){
  // sending a csrftoken with every ajax request
  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }
  if (!chrome.cookies) {
    chrome.cookies = chrome.experimental.cookies;
  }
  const csrf_from_cookies = {'url': 'https://dummy-site-xyz.com/', 'name': 'csrftoken'};
  chrome.cookies.get(csrf_from_cookies, function(res){
    csrftoken = res.value;
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.url)) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
  });
  const sessionid = {'url': 'https://dummy-site-xyz.com/', 'name': 'sessionid'};
  chrome.cookies.get(sessionid, function(res) {
    session_id = res.value;
  });
});
// the request
$.ajax({
  type: "POST",
  crossDomain: true,
  url: 'https://dummy-site-xyz.com/profile/api/v1/awesome/key',
  data: {'sessionid': 'dummy_session_id'},
  success: function(data){
    // pass
  },
  error: function( jqXHR, textStatus, errorThrown ){
    console.log(jqXHR.responseJSON);
  }
});
  • 你的manifest.json权限配置:
"permissions": [
  . . .
  "https://dummy-site-xyz.com/*",
  . .
],

下面是具体的解决步骤:

1. 手动添加Referer头到请求中

Chrome扩展允许手动设置Referer头,只要目标站点在你的权限列表里。修改你的AJAX请求,添加headers字段:

$.ajax({
  type: "POST",
  crossDomain: true,
  url: 'https://dummy-site-xyz.com/profile/api/v1/awesome/key',
  headers: {
    'Referer': 'https://dummy-site-xyz.com/' // 必须匹配目标站点的域名
  },
  data: {'sessionid': session_id}, // 注意:这里要用实际获取到的session_id,不是硬编码的'dummy_session_id'!
  success: function(data){
    // 处理返回数据
  },
  error: function( jqXHR, textStatus, errorThrown ){
    console.log(jqXHR.responseJSON);
  }
});

2. 修复异步操作的时序问题

你当前的代码中,获取csrftoken和sessionid是异步操作,但AJAX请求直接在外部发起——这很可能导致请求发起时,这两个变量还没被赋值!

建议用Promise封装cookie获取逻辑,确保拿到所有必要参数后再发起请求:

// 封装获取cookie的Promise
function getCookie(name) {
  return new Promise((resolve, reject) => {
    chrome.cookies.get({url: 'https://dummy-site-xyz.com/', name: name}, (res) => {
      res ? resolve(res.value) : reject(new Error(`Cookie ${name} not found`));
    });
  });
}

// 等待两个cookie都获取完成后再发请求
$(document).ready(function(){
  Promise.all([getCookie('csrftoken'), getCookie('sessionid')])
  .then(([csrftoken, session_id]) => {
    // 配置全局AJAX的CSRF头
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type)) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });

    // 发起POST请求
    $.ajax({
      type: "POST",
      crossDomain: true,
      url: 'https://dummy-site-xyz.com/profile/api/v1/awesome/key',
      headers: {
        'Referer': 'https://dummy-site-xyz.com/'
      },
      data: {'sessionid': session_id},
      success: function(data){
        console.log('获取密钥成功:', data);
      },
      error: function( jqXHR, textStatus, errorThrown ){
        console.log(jqXHR.responseJSON);
      }
    });
  })
  .catch(err => console.error('获取Cookie失败:', err));
});

3. 调整Manifest配置(可选但推荐)

如果是Chrome 88及以上版本,推荐用host_permissions替代permissions来声明站点权限,同时可以配置内容安全策略(CSP)确保Referer头正常发送:

{
  "manifest_version": 3, // 如果你用的是V3版本
  "host_permissions": [
    "https://dummy-site-xyz.com/*"
  ],
  "content_security_policy": {
    "extension_pages": "script-src 'self'; object-src 'none'; referrer 'strict-origin-when-cross-origin'"
  }
}

strict-origin-when-cross-origin是较安全的Referer策略,既符合服务器校验要求,又不会泄露过多URL信息。如果服务器不接受这个值,可以换成unsafe-url(但不推荐,会发送完整URL)。

4. 尝试用原生Fetch API替代jQuery AJAX(可选)

原生Fetch在Chrome扩展环境中的头处理更灵活,还能利用credentials: 'include'自动携带cookie,省去手动传递sessionid的步骤:

function getCookie(name) {
  return new Promise((resolve, reject) => {
    chrome.cookies.get({url: 'https://dummy-site-xyz.com/', name: name}, (res) => {
      res ? resolve(res.value) : reject(new Error(`Cookie ${name} not found`));
    });
  });
}

$(document).ready(function(){
  getCookie('csrftoken')
  .then(csrftoken => {
    fetch('https://dummy-site-xyz.com/profile/api/v1/awesome/key', {
      method: 'POST',
      headers: {
        'X-CSRFToken': csrftoken,
        'Referer': 'https://dummy-site-xyz.com/',
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: new URLSearchParams({
        'sessionid': session_id
      }),
      credentials: 'include' // 自动携带目标站点的cookie
    })
    .then(res => res.json())
    .then(data => console.log('获取密钥成功:', data))
    .catch(err => console.error('请求失败:', err));
  })
  .catch(err => console.error('获取CSRF Token失败:', err));
});

按照以上步骤调整后,应该就能解决Referer缺失导致的CSRF校验失败问题了。

内容的提问来源于stack exchange,提问作者Fallen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:06:09