jsonp可以用csrf令牌保护吗?

时间:2011-06-03 14:28:14

标签: jsonp csrf

用例: 在同域的情况下,我想使用jsonp进行数据传输,因为它在请求中比任何ajax或iframe传输更早发生。此外,我希望将此数据缓存为常规js文件。

我不想将此数据公开给其他域。

所以,我想到了以下防止csrf的技巧:

  1. 作为带有请求的GET参数发送的csrf令牌。
  2. 在jsonp执行之前存储在变量中的另一个csrf标记。因此,如果jsonp发现该变量具有正确的值,它将只调用该函数。
  3. 这是一个双重偏执的解决方案,因为我不确定这两个中的任何一个是否是防弹的。

    问题是:

    • 在GET参数中发送csrf令牌是否安全?或者我该怎样做才能确保安全?
    • 来自不同域的某人是否可以查看js的源代码,以规避技巧编号(2)?

    为了避免我们从零开始,这是一个我认为有用的文件:
    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情景:

    • 用户登录oursite.com,后者创建会话cookie。
    • 然后,同一个用户访问攻击者网站evil.com,其中包含一个脚本标记,用于请求(个性化)oursite.com/menudata.js。
    • 由于同源策略,evil.com上的脚本无法直接检查menudata.js的内容。相反,它只会执行menudata.js。

    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上的脚本可以欺骗我们漂亮的小支票。

4 个答案:

答案 0 :(得分:0)

脱离我的头顶......

  1. 配置您的网络服务器,以限制对您网络中客户端的网络服务的访问。

  2. 重构Web服务以拒绝来自未知主机的请求。

  3. 为您的网络服务使用SSL,并要求在访问时进行身份验证。

  4. 在客户端和您的Web服务之间插入代理,以限制基于网络,地址或域的访问。

  5. 修改

    参考您的意见:

    1和2 - 推荐人可能会被欺骗。欺骗IP地址要困难得多。

    3 - 是的,并且使用SSL进行身份验证会使“中间人”攻击更加困难。 (我很想说不可能,但那会很狂妄。: - )

    4 - 如果您无法访问或无法配置您的Web服务器,我会将此作为选项提供。

    但是,由于我误解了或者你改变了问题的条件,这些大多没有实际意义。

    最初,您表示这是“相同的域名情况”,我认为客户和网络服务存在于有限的可控位置(即在同一网络内)。

    由于您希望Web服务的客户端位于任何位置,因此只有选项3可用。

    但是,已经存在一种限制访问Web服务(或其部分)的标准方法。

    对于每个授权客户端,生成唯一的“API密钥”,并要求对受保护功能的任何调用都包含此令牌。然后,Web服务拒绝在没有有效密钥的情况下调用受保护区域。

    使用SSL(https)限制窥探密钥的可能性,如果(如果)某人破坏了您的安全性(例如通过与他人共享其唯一密钥),只需通过从密钥列表中删除该密钥来撤销该密钥。授权访问密钥。

    重新编辑

    最后,在重新阅读原始问题之后,它似乎对您无效,因为它似乎是在现有网页的上下文中请求数据,这意味着您需要公开API密钥在JavaScript源代码中。

    因此,如果出现以下情况,您最初的想法似乎是最好的选择:

    • 使用非显而易见的算法(如MD5随机数据)生成每个密钥
    • 密钥嵌入在JavaScript源代码中,用于通过AJAX访问受保护的数据
    • 一旦使用密钥,它立即变为无效,无法再次使用

    但是(这是一个巨大的但是!),

    1. 无法确保原始网页请求来自用户,而非用于欺骗您服务的自动流程。

    2. 一旦浏览器检索到数据,任何使用各种监控工具(如firebug)的人都会对其进行检查。

    3. 如果数据随后在网页中显示,则可以轻松删除(通过复制/粘贴)。

    4. 因此,从实际的角度来看,使用您正在使用的工具来保护数据不受拦截和检查是不可能的。

答案 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令牌失效,但这可能导致可能的拒绝服务。