检查是不是适用同源政策
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=4
和statuscode=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.domain
s 都重写为“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 请求,这根本不是我要问的......我需要更清楚吗?以上是关于检查是不是适用同源政策的主要内容,如果未能解决你的问题,请参考以下文章