【问题标题】:Is there any secure way to allow cross-site AJAX requests?是否有任何安全的方法来允许跨站点 AJAX 请求?
【发布时间】:2013-03-29 00:45:36
【问题描述】:

我目前正在开发一个网站所有者可以安装的脚本,该脚本允许用户突出显示一个单词并在一个小的弹出 div 中查看该单词的定义。我只是在业余时间做这个作为一种爱好,无意出售它或任何东西,但我希望它是安全的。

当文本被突出显示时,它会向我的域发送一个 AJAX 请求到一个 PHP 页面,然后在数据库中查找该单词并输出一个包含该信息的 div。我了解同源策略禁止我使用普通 AJAX 完成此操作,但我也不能使用 JSONP,因为我需要返回 HTML,而不是 JSON。

我研究过的另一个选项是添加

header("Access-Control-Allow-Origin: *");

到我的 PHP 页面。

由于我在安全方面确实没有太多经验,因为我这样做是一种爱好,有人可以向我解释使用 Access-Control-Allow-Origin: * 的安全风险吗? 或者有没有更好的方法我应该考虑这样做?

【问题讨论】:

    标签: php jquery ajax security cross-domain


    【解决方案1】:

    JSONP 应该满足您的需求。它是一种广泛部署的 Web 技术,旨在解决跨域问题。您还应该了解CORS,它解决了 JSONP 的一些缺点。我提供给您的链接还将包含有关这些技术的安全注意事项的信息。

    你写道:

    但我也不能使用 JSONP,因为我需要返回 HTML,而不是 JSON。

    为什么不呢?您可以像这样使用 JSONP 响应:

    callback({'content':'<div class="myclass">...</div>'});
    

    然后使用 DOM 操作将result.content 注入当前页面。

    【讨论】:

    • could someone explain to me the security risks in using Access-Control-Allow-Origin: * -- 没有解释。 -1
    • 也许我在决定回答时太快了。请给我几分钟的时间来详细说明这一点。
    • “[…] 我也不能使用 JSONP,因为我需要返回 HTML,而不是 JSON。”
    • @Gumbo 没明白你评论的意思。我已经在我的回答中解决了这个问题
    • @DarylGill:他没有阅读这个问题,或者更确切地说,在同一个句子中的“JSONP”和“HTML”处看到了红色。我介绍了安全风险,这真的不是那么重要......
    【解决方案2】:

    CORS 问题很简单 - 您希望任何人都能够远程 AJAX 您域中的内容吗?如果您的表单容易出现 CSRF,这可能会非常危险。这是一个直接从我脑海中摘取的例子。

    设置:

    • 一家银行,其网上银行服务器的 CORS 标头设置为接受所有 (ACAO: *)(称为 A)
    • 已登录的合法客户(称其为 B)
    • 恰好能够让客户端运行任何东西的黑客(称之为 E)

    AB 对话被视为合法。但是,如果黑客可以设法使标记 (B) 加载一个带有一些 JS 的站点,这些 JS 可以触发 AJAX 请求(很容易通过大型站点上的永久 XSS 缺陷),他/她可以让 B 向 A 发送请求通过 JSON,将被允许并视为正常请求

    你可以用这个做很多可怕的事情。假设银行有一个表单,输入如下:

    POST:
    * targetAccountID -> the account that will receive money
    * money -> the amount to be transferred
    

    如果标记已登录,我可以注入:

    $.ajax({ url: "http://A/money.transfer.php"; data { targetAccountID: 123; money: 9999; }; });
    

    突然间,任何访问该站点并登录到 A 的人都会看到他们的帐户耗尽了 9999 个单位。

    就是为什么在服用 CORS 时要加一点盐 - 实际上,不要打开超过您需要打开的次数。打开你的 API 就可以了。

    一个很酷的旁注,CORS 不适用于 IE9 之前的任何东西。所以你需要构建一个后备,可能是 iframe 或 JSONP。

    我不久前写过关于这个主题的文章:http://www.sebrenauld.co.uk/en/index/view/access-json-apis-remotely-using-javascript,顺便说一下,比维基百科更快乐。这是一个我非常珍视的话题,因为我不得不多次应对 API 开发。

    【讨论】:

    • CORS 不会阻止 CSRF。 CORS 的主要目的是让服务器选择允许哪些来源发送请求和读取响应。
    • @Gumbo:感谢您赞同我的观点。我从来没有说过 CORS 阻止了 CSRF - 我说的是,如果设置不当,CORS 可以将 POST 请求转换为有效的 CSRF 目标(否则这是非常罕见的)。
    • 实际上,“简单”的 POST 请求(例如可以通过提交普通的 HTML 表单生成)无论如何都容易受到 CSRF 的攻击,无论有无 CORS。为了防止这种情况,您需要类似反 CSRF 令牌之类的东西。此外,-1 表示实际上并未解决 OP 的预期用例。
    • @IlmariKaronen:它们需要用户输入。这个没有,这使得它很危险。另外,我到底没有解决什么问题?如果他愿意,CORS 允许他跨域进行常规 AJAX 调用以获取 HTML——这从来都不是问题。他询问了安全风险,我给了他确切的答案:如果设置不当,他会打开他的整个目录/arch 以接收可能是幻像的远程 HTTP POST 请求。如果您想指出的话,我到底错过了什么?
    • 不需要用户输入,客户端 JS 很容易构造 .submit() 一个不可见的表单(可能在 iframe 中),用户甚至不会注意到。至于您错过了什么,OP 询问使用 Access-Control-Allow-Origin: * 查找并返回单词定义的脚本是否安全。您告诉他们将它用于执行银行转账的脚本是安全的。这些不是一回事。
    【解决方案3】:

    CSRF(Cross Site Request Foregery)的概念可以引起你的关注 http://en.wikipedia.org/wiki/Cross-site_request_forgery 有多种方法可以限制这个问题,最常用的技术是使用csrf token

    此外,您还应该将基于 IP 的 Rate limiter 用于“限制执行从某个 ip 发出的数量请求”,以限制如果您是目标可以进行的 DoS 攻击,您可以寻求一些帮助How do I throttle my site's API users?

    【讨论】:

      【解决方案4】:

      Cross-Origin Resource Sharing (CORS)Access-Control-Allow-Origin 标头字段背后的规范,旨在允许通过XMLHttpRequest 进行跨域请求,但通过提供允许server to define which cross-origin requests are allowed and which are not 的接口来保护用户免受恶意站点读取响应。所以 CORS 不仅仅是Access-Control-Allow-Origin: *,它表示允许来自任何来源的 XHR 请求。

      现在回答您的问题:假设您的服务是公开的并且不需要任何身份验证,使用Access-Control-Allow-Origin: * 允许来自任何来源的 XHR 请求是安全的。但请确保仅在您希望允许该访问策略的那些脚本中发送该标头字段。

      【讨论】:

        【解决方案5】:

        “当文本被突出显示时,它会向我的域发送 AJAX 请求到 PHP 页面,然后在数据库中查找单词并输出包含信息的 div。我了解同源策略禁止我完成这与普通的 AJAX,但我也不能使用 JSONP,因为我需要返回 HTML,而不是 JSON。"

        正如 hek2mgl 所说,JSONP 可以很好地解决这个问题。您需要做的就是将您的 HTML 包装在 JSONP 包装器中,如下所示:

        displayDefinition({"word": "example", "definition": "<div>HTML text...</div>"});
        

        displayDefinition() 是一个 JS 函数,它显示一个带有给定 HTML 代码的弹出窗口(并且可能会缓存它以供以后使用)。

        “我研究过的另一个选项是将header("Access-Control-Allow-Origin: *"); 添加到我的 PHP 页面。由于我在安全方面真的没有太多经验,因为我这样做是一种爱好,有人可以向我解释一下安全性使用Access-Control-Allow-Origin: *的风险?”

        风险与 JSONP 基本相同;在任何一种情况下,您都允许任何网站向您的脚本发出任意 GET 请求(它们实际上可以这样做)并读取结果(使用普通 JSON,它们通常不能,尽管较旧的浏览器可能存在一些安全漏洞可以允许这个)。特别是,如果用户在登录您的网站时访问了恶意网站,并且如果您的网站可能通过 JSONP 或 CORS 暴露敏感的用户数据,则恶意网站可能会访问这些数据。

        对于您描述的用例,任何一种方法都应该是安全的,只要您仅将它用于该特定脚本,并且只要该脚本仅执行您描述的操作(查找单词并返回其定义) .

        当然,您也不应该将 CORS 或 JSONP 用于您不希望任何网站访问的脚本,例如银行转账表格。这样的脚本,如果它们可以修改服务器上的数据,通常还需要使用额外的防御措施,例如anti-CSRF tokens 来防止“盲目”的 CSRF 攻击,攻击者并不真正关心响应,而只关心副作用请求。显然,反 CSRF 令牌本身是敏感的用户特定数据,因此不应通过 CORS、JSONP 或任何其他绕过同源保护的方法获得。

        “或者我应该研究一个更好的方法来做到这一点?”

        另一种(虽然不一定更好)的方法是让您的 PHP 脚本将定义返回为 HTML,并让弹出窗口仅包含一个指向脚本的 iframe 元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-11-03
          • 1970-01-01
          • 2016-03-03
          • 2018-09-11
          • 2023-04-05
          • 2015-07-14
          • 1970-01-01
          • 2019-09-21
          相关资源
          最近更新 更多