检查是不是适用同源政策

Posted

技术标签:

【中文标题】检查是不是适用同源政策【英文标题】:Check if same origin policy applies检查是否适用同源政策 【发布时间】:2012-03-13 08:54:12 【问题描述】:

在实际尝试使用 ajax 方法之前,是否有一种“安全”的方法来检查同源策略是否适用于 URL?这是我所拥有的:

function testSameOrigin(url) 

    var loc = window.location,
        a = document.createElement('a');

    a.href = url;

    return a.hostname == loc.hostname &&
           a.port == loc.port &&
           a.protocol == loc.protocol;

这种方法可行,但它是一种基于wikipedia article 的手动猜测。有没有更好的方法来预先检查跨域配额? jQuery 可以使用。

【问题讨论】:

如果您执行跨域请求,它将失败并显示readystate=4statuscode=0,这类似于中止的请求。既然您无论如何都需要防范被中止的请求,为什么需要此检查?我觉得这个安全措施是从外部强制执行的,你无法控制它,所以从环境内部进行的任何检查都是错误的。所以我认为你不应该检查它,只是让请求失败。 【参考方案1】:

也试试这个解决方案。

function csrfSafeMethod(method) 
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));


function sameOrigin(url) 
  // test that a given url is a same-origin URL
  // url could be relative or scheme relative or absolute
  var host = window.document.location.host; // host + port
  var protocol = window.document.location.protocol;
  var srOrigin = '//' + host;
  var origin = protocol + srOrigin;
  // Allow absolute or scheme relative URLs to same origin
  return (url === origin || url.slice(0, origin.length + 1) === origin + '/') ||
    (url === srOrigin || url.slice(0, srOrigin.length + 1) === srOrigin + '/') ||
    // or any other URL that isn't scheme relative or absolute i.e relative.
    !(/^(\/\/|http:|https:).*/.test(url));


// if you want to check before you make a call
if (!csrfSafeMethod(data.type) && sameOrigin(data.url)) 
  // ...


// or if you want to set csrf token
$.ajax(
  beforeSend: function (xhr, settings) 
    if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) 
      xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
    
  
);

【讨论】:

【参考方案2】:

基于 Dagg Nabbit 的回答,这似乎更完整:

function sameOrigin(url) 
    var loc = window.location, a = document.createElement('a')
    a.href = url

    return a.hostname === loc.hostname &&
           a.port === loc.port &&
           a.protocol === loc.protocol &&
           loc.protocol !== 'file:'

我能想到的注意事项:

不考虑 document.domain 不考虑 CORS 在 IE7 中不起作用(如 zanona 所述) 无法在奇怪的环境(如 android)中访问任意 file:// 协议路径(请有人验证这一点,有关 android 的信息可能已过时 https://security.stackexchange.com/questions/25138/same-origin-policy-for-file-urls-in-android-browser)李>

【讨论】:

【参考方案3】:

在实际尝试使用 ajax 方法之前,是否有一种“安全”的方法来检查同源策略是否适用于 URL?这是我所拥有的:

function testSameOrigin(url) 

    var loc = window.location,
        a = document.createElement('a');

    a.href = url;

    return a.hostname == loc.hostname &&
           a.port == loc.port &&
           a.protocol == loc.protocol;

这是一种安全可靠的方法,前提是您正在做(或不做)某些事情。

这种工作,但它是一种基于***文章的手动猜测。

这应该在“正常”情况下完全有效。如果您打算使用cross-domain scripting,则需要对其进行修改。

如果您在脚本中修改document.domain,例如从“foo.example.com”和“bar.example.com”修改为“example.com”,您的testSameOrigin 函数将返回false for “@ 987654322@",实际上它应该返回true

如果您打算修改 document.domain,您可以在脚本中添加一个简单的检查。

如果您计划使用 CORS(请参阅上面的链接)来允许跨域通信,它也会返回一个误报。但如果您使用 CORS,您将拥有一个可以与之通信的域列表,您也可以将该列表添加到此函数中。

有没有更好的方法来预先检查跨域配额? jQuery 可以使用。

可能不是,尽管值得一提的是,您从史蒂夫的回答中看到的控制台可能是“观察者的困境”......这些错误看起来像是控制台试图检查另一个窗口导致的,不一定来自脚本。

假设您没有搞乱document.domain 或使用 CORS,您的原始解决方案可能会更好,因为它不需要发出额外的请求来确定服务器是否可用。即使您正在执行一些跨域脚本,修改您现在拥有的功能以适应它可能是您最好的选择。

【讨论】:

虽然这是检查 CORS 请求的好方法,但它在 IE7 上中断,而生成的锚不会返回有关链接的任何信息,因此例如在 IE7 中评估诸如 <a href='main.html'></a> 之类的链接会返回 a.href => "main.html" a.hostname => "" 等。我仍在试图弄清楚如何在 IE7 中处理这个问题。但找不到任何好的解决方案。因为它永远不会创建完整的 href。 您会添加什么 document.domain 检查?简单地将loc.hostname 替换为document.domain 是否正确? @BT a.hostname 仍将是“foo.example.com”,document.domain 将只是“example.com”。它必须是一个特殊情况检查,即如果你知道你将两个document.domains 都重写为“example.com”,主机名检查将类似于a.hostname == loc.hostname || a.hostname == "foo.example.com" 我遇到过a.port != loc.port 的情况,因为第一个出现为 80,第二个出现为空白。【参考方案4】:

有趣的问题!我四处搜索,除了您发布的内容之外找不到任何其他内容,但是当我在弄乱一些测试代码时确实遇到了这个问题。如果您只是想要一种简单的方法来测试 URL 而无需发出请求,我会按照您的方式进行操作。如果您不在乎提出测试请求,您可以试试这个:

向您想要的任何 URL 发出简单的 ajax 请求:

var ajaxRequest = $.ajax(
  url: 'http://www.google.com',
  async: false
);

它返回一个jqXHR 对象,然后您可以检查它:

ajaxRequest.isRejected(); // or...
ajaxRequest.isResolved();

现在,唯一的问题是 isRejected() 将评估为 true 对于每个页面未加载的情况(即 404 Not Found 等),但您可以检查状态代码:

ajaxRequest.status;

当您尝试破坏同源策略时,上面的行似乎会返回 0,但在其他情况下,它将返回适当的错误代码(再次,即 404)。

所以总结一下,也许你可以尝试做一些类似的事情:

function testSameOrigin(testUrl) 

  var ajaxRequest = $.ajax(
    url: testUrl,
    async: false
  );

  return ajaxRequest.isRejected() && ajaxRequest.status === 0;

无论如何都不是一个明确的答案,但我希望它可以帮助你弄清楚你在寻找什么!

【讨论】:

是的,这是一个有趣的方法。在我原来的情况下,我想通过尝试“验证” URL 来消除在执行被拒绝的 ajax 调用时遇到的令人讨厌的控制台错误。我最近还发现,对本地文件(文件:协议)执行 ajax 请求也每次都失败。所以这是另一个需要检查的情况...... 您可以通过将isLocal 标志设置为true api.jquery.com/jQuery.ajax/#jQuery-ajax-settings 来对本地文件使用ajax 【参考方案5】:

另一种执行跨域脚本的方法是使用JSON-P。 您也可以阅读此article。 否则,同源策略不允许跨域脚本。

【讨论】:

我不确定为什么所有的答案都是关于如何制作或不制作跨浏览器的 ajax 请求,这根本不是我要问的......我需要更清楚吗?

以上是关于检查是不是适用同源政策的主要内容,如果未能解决你的问题,请参考以下文章

同源政策的可疑目的

浏览器同源政策及其规避方法

浏览器同源政策及其规避方法

浏览器同源政策及其规避方法

浏览器同源政策及其规避方法

浏览器同源政策及其规避方法(转)