用例: 在同域的情况下,我想使用jsonp进行数据传输,因为它在请求中比任何ajax或iframe传输更早发生。此外,我希望将此数据缓存为常规js文件。
我不想将此数据公开给其他域。
所以,我想到了以下防止csrf的技巧:
这是一个双重偏执的解决方案,因为我不确定这两个中的任何一个是否是防弹的。
问题是:
为了避免我们从零开始,这是一个我认为有用的文件:
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
(但可能是我错过了那里的东西)
特别有趣:“在URL中披露令牌”,我认为我还没有完全理解其后果。
编辑:
人们可以想到的其他解决方案:
3.推荐人检查。不够安全,afaik。特别是,如果js文件缓存在浏览器上
4.加密。可能不值得努力..
编辑II:
澄清:“同域情况”只是意味着html页面和jsonp是从同一个域提供的。客户端机器可以在任何地方。
编辑III:
我希望能像安装json或html / xml(用ajax或iframe请求)而不是jsonp一样安全。您可能知道,json和html / xml受同源策略保护,而jsonp则不受保护。
我想使用csrf令牌来实现与jsonp相同的保护。显然,csrf标记将与html页面一起提供。
编辑IV:
这就是2号技巧的样子。
Page html:
<script type="text/javascript">
var token1 = 'upoihjvpaoijpoj';
</script>
<script type="text/javascript" src="xyz/jsonp.js?token2=o8976987698540"></script>
然后在xyz / json.js中?token2 = ..:
if (token1 == 'upoihjvpaoijpoj') {
json_callback(data);
}
编辑V:
这个问题很复杂,所以至少我应该添加一个真实世界的例子。当我发布这个问题时,我不记得确切的用例,所以我只是写一下这个问题。
一个典型的例子是一个下拉菜单,我们希望用单独的请求加载菜单内容,因为它们在每个页面上都是相同的。但是,菜单可能包含一些只应显示给特定登录用户的链接。让我们假设这是一个生死攸关的事情,未经授权的访问者可能永远不会看到这些链接。
第一个想法是加载带有XHR请求的菜单。在服务器端,我们可以检查cookie / session thingie以检查用户是否已登录,并提供个性化菜单。
但是,只有页面的其余部分已经存在,XHR才能开始加载。另一方面,Javascript可以在浏览器解析html头后立即开始加载。因此,如果我们使用javascript / jsonp而不是XHR来提供菜单数据,我们可能希望获得性能优势。
现在的CSRF情景:
menudata.js看起来像这样:
spawnMenu({...});
或者“spawnMenu”可以是基于请求参数的动态选择的字符串。 如果menudata.js在evil.com上执行,则运行此站点的攻击者可以提供具有该名称的功能,然后“打电话回家”并窃取个性化菜单数据。
现在这个想法(最初问题的第2点)是在menudata.js中做这样的事情:
if (secret_var === 'opijpoijpoizvnpoiq92823pjnfn') {
spawnMenu({...});
}
一开始看起来很不错。 evil.com不知道secret_var,所以当menudata.js执行时,它什么都不做。
然而,我听说有一些讨厌的技巧,你可以“重写”js的基本部分。例如,替换将东西强制转换为字符串的通常方式。甚至可能取代比较运算符?通过这种方式,evil.com上的脚本可以欺骗我们漂亮的小支票。
答案 0 :(得分:0)
脱离我的头顶......
配置您的网络服务器,以限制对您网络中客户端的网络服务的访问。
重构Web服务以拒绝来自未知主机的请求。
为您的网络服务使用SSL,并要求在访问时进行身份验证。
在客户端和您的Web服务之间插入代理,以限制基于网络,地址或域的访问。
修改
参考您的意见:
1和2 - 推荐人可能会被欺骗。欺骗IP地址要困难得多。
3 - 是的,并且使用SSL进行身份验证会使“中间人”攻击更加困难。 (我很想说不可能,但那会很狂妄。: - )
4 - 如果您无法访问或无法配置您的Web服务器,我会将此作为选项提供。
但是,由于我误解了或者你改变了问题的条件,这些大多没有实际意义。
最初,您表示这是“相同的域名情况”,我认为客户和网络服务存在于有限的可控位置(即在同一网络内)。
由于您希望Web服务的客户端位于任何位置,因此只有选项3可用。
但是,已经存在一种限制访问Web服务(或其部分)的标准方法。
对于每个授权客户端,生成唯一的“API密钥”,并要求对受保护功能的任何调用都包含此令牌。然后,Web服务拒绝在没有有效密钥的情况下调用受保护区域。
使用SSL(https)限制窥探密钥的可能性,如果(如果)某人破坏了您的安全性(例如通过与他人共享其唯一密钥),只需通过从密钥列表中删除该密钥来撤销该密钥。授权访问密钥。
重新编辑
最后,在重新阅读原始问题之后,它似乎对您无效,因为它似乎是在现有网页的上下文中请求数据,这意味着您需要公开API密钥在JavaScript源代码中。
因此,如果出现以下情况,您最初的想法似乎是最好的选择:
但是(这是一个巨大的但是!),
无法确保原始网页请求来自用户,而非用于欺骗您服务的自动流程。
一旦浏览器检索到数据,任何使用各种监控工具(如firebug)的人都会对其进行检查。
如果数据随后在网页中显示,则可以轻松删除(通过复制/粘贴)。
因此,从实际的角度来看,使用您正在使用的工具来保护数据不受拦截和检查是不可能的。
答案 1 :(得分:0)
只要您的csrf令牌按请求更改(因此有人收听不能进行重播攻击),您应该没问题。
不确定突然的downvotes,但我已经与Foursquare,Netflix和(lol)AOL做了很多安全工作。 CSFR令牌与Cookie不同。攻击者无法猜出您的CSRF令牌。这是在登录期间发送给客户端或内嵌在网页中。它不会自动发送所有请求,如cookie,因此攻击者无法强制您的浏览器使用img标记或其他一些时髦的业务发送它。它包含在您的应用程序前端框架中。
答案 2 :(得分:0)
使用一些伪代码解决简单的接缝。
在每个请求上做。
if(!session['csrf-token']) {
session['csrf-token'] = randomString();
}
在您想要可缓存数据的页面上。
<script src="/some_cacheable_data.js?<%= session['csrf-token'] %>"></script>
在渲染javascript。
if(params['csrf-token'] == sesssion['csrf-token']) {
renderData();
}
答案 3 :(得分:0)
如果可以通过JSONP访问数据,则无法保护其他第三方。我能想到的唯一解决方案是使用越界通道,即:直接API调用或各种类型的秘密令牌。每次访问后,您最多可以使CSRF令牌失效,但这可能导致可能的拒绝服务。