【问题标题】:Prevent requests to internal resources on a CDN阻止对 CDN 上的内部资源的请求
【发布时间】:2018-09-02 15:48:39
【问题描述】:

在这种情况下,防火墙的存在是有原因的:阻止外部请求访问内部资源。

假设我有两台 HTTP 服务器在运行:一台在 8080 端口,另一台在 8081 端口。

8080 端口上的服务器是一个可公开访问的基于 Node 的网站(在此示例中由 express 提供支持),并在每个请求上运行以下代码,这基本上是一种向用户请求数据的简单 CDN - 定义的 URL(在 X-Cool-URL 标头中)并将该请求的正文返回给我网站域下的用户。 requestrequest 模块,reqexpress 请求对象,resexpress 响应对象。 (很明显,这个特定的代码既不实用也不防错,但它是一个不错的例子。)

const url = req.get("X-Cool-URL"); // some example user input value
request(url, (error, response, body) => { // request said arbitrary resource
    res.send(body); // send response back to user
});

8081端口上的服务器是一个HTTP服务器,通过内部请求做事;通过端口 8081 的外部网络被防火墙阻止,这是有充分理由的。绝不应向其发送任意用户定义的数据。假设我不是这个 Web 服务器的程序员,并且无法控制或访问它的代码。该服务器对任何给定的请求输入究竟做什么是无关紧要的。重要的是,允许向其发送任意数据会带来安全风险。

...但我可以从任何外部命令行运行此命令。

curl -H "X-Cool-URL: http://localhost:8081/something/malicious" http://example.com:8080

这就带来了一个问题:用户只能使用我的公共网络服务器通过localhost:8081在内部网络下请求私有网络服务器。我仍然希望人们能够通过我的网络服务器在端口 8080 上请求其他公共域,我仍然希望能够作为开发人员在内部请求 8081,但我不希望其他人能够利用我的服务器任意访问8081,不受防火墙限制。我怎样才能让用户无法使用我的公共网络服务器来请求任何内部资源?

我想要保护的端口可能并不总是明确和已知的,因此简单地通过我的 Web 服务器阻止 8081 是不切实际的。仅阻止对localhost 的所有请求也是不切实际的,因为还有其他方法可以请求内部资源(例如使用127.0.0.1)。甚至可以设置指向本地资源的 DNS 记录,因此仅将一组 URL 列入黑名单也行不通。白名单也不是一种选择,因为它会破坏 CDN 的要点,让客户端能够请求任何外部资源。我对一种在每种情况下都能检测 URL 是否为内部 URL 的方法感兴趣。

【问题讨论】:

  • 你控制哪台服务器?服务于端口 8080 的代理还是服务于端口 8081 的代理?
  • 假设我只控制8080上的那个。

标签: node.js security networking request localhost


【解决方案1】:

案例1:你控制8080端口的代理服务器

因此,如果您控制的是代理服务器,而不是其背后的 Web 服务器,那么防止这样的事情实际上非常简单:您只需从请求中过滤某些 HTTP 标头,而 进程那些请求。

最安全的方法是使用您允许在X-Cool-URL 标头中使用的主机名白名单。然后只需检查 URL 是否与白名单匹配。或者,您可以使用黑名单进行过滤,但这有点麻烦,因为您不仅要考虑 localhost,还要考虑各种 IP 范围。您不希望 X-Cool-URL 指向 127.0.0.1、192.168.x.x 等任何内容。

案例 2:您在端口 8081 上控制后端服务器

如果您无法控制代理服务器过滤哪些请求以及它转发给您的 HTTP 请求,您将不得不检查请求的来源。您可以使用如下代码获取有关原始请求者的详细信息:

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

如果ip 地址不在您的允许范围内,请不要回复请求。这样,您可以授予运行在防火墙后面的其他服务器的访问权限,同时阻止来自代理的访问。

开发者权限

一旦您实现了这两种机制中的任何一种,您仍然希望允许开发人员访问后端。最简单的方法是使用只有您知道且不容易猜到的密钥。然后将此密钥作为附加的 HTTP 请求标头 (X-Cool-Secret) 或作为 X-Cool-URL 本身的一部分作为查询参数提供。

额外的思考

这样的场景本质上是不安全的。一旦您通过公共 Internet 提供对后端的访问权限,您就需要为攻击做好准备。即使您的代理可以过滤很多东西,仍然有可能有人找到通过它的方法。让代理和后端在同一台物理机(或 VM)上运行会增加额外的安全风险。一般经验法则:不要这样做。

允许从开发机器访问也是有风险的。密钥可能泄漏,密码可能被盗,IP 地址可能被欺骗。没有简单的方法可以防止复杂的攻击。这种公共访问有许多您通常应该避免的权衡。尝试使用 SSH 作为进入非军事区(防火墙和代理后面的所有东西)的安全隧道。这提供了一个更安全的环境,您可以在 Node/Express 中自行构建。

希望对您有所帮助。

【讨论】:

  • 感谢您的彻底回答,但不幸的是,这一切都不适用于这种情况。白名单的限制性太强,而黑名单的限制性也不够。至于第二种解决方案,情况是我没有有权访问 8081 服务器。否则,我将能够使用某种身份验证,正如您在“开发人员访问”中所引用的那样。在实际应用中,我可能会完全删除这个系统,考虑到它的安全漏洞,而且我的 Web 服务器实际上并不需要它来工作。我真的只是出于假设的好奇心才问这个问题。
  • 需要找到一个标准来区分允许和禁止的请求,并以此过滤传入的请求。最坏的情况是黑名单,尽管通过排除任何直接 IP 地址访问和众所周知的内部主机名可以使其相对安全。如果您对具体情况有更多详细信息,也许有更合适的解决方案。尽管如此,如果您不再等待任何其他人,如果您接受这个作为答案,我将不胜感激。
猜你喜欢
  • 1970-01-01
  • 2019-08-08
  • 2017-04-23
  • 2019-07-21
相关资源
最近更新 更多