API 网关 Lambda CORS 处理程序。安全获取 Origin

API Gateway Lambda CORS handler. Getting Origin securely

我想为多个来源实施 CORS,我知道我需要通过 lambda 函数来实现,因为我无法通过 MOCK 方法来实现

exports.handler = async (event) => {
  const corsUrls = (process.env.CORS_URLS || '').split(',')
  const requestOrigin = (event.headers && event.headers.origin) || ''

  if (corsUrls.includes(requestOrigin)) {
    return {
      statusCode: 204,
      headers: {
        "Access-Control-Allow-Headers": 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Requested-With',
        'Access-Control-Allow-Origin': requestOrigin,
        'Access-Control-Allow-Methods': 'POST,DELETE,OPTIONS'
      }
    }
  }

  return {
    statusCode: 403,
    body: JSON.stringify({
      status: 'Invalid CORS origin'
    })
  }
}

首先,上面看起来还可以吗?然后我从 headers event.headers.origin 获取来源。但我发现我可以手动将 header 设置为 "bypass" cors。有没有可靠的方法来检测源域?

验证多个来源的唯一方法是像您一样,使用您的 lambda 读取来源 header,将其与您想要允许的域列表进行比较,如果匹配,return Origin header 返回给客户端的值作为响应中的 Access-Control-Allow-Origin header。

一条信息:Origin header 是用户代理自动设置的 header 之一。因此任何人都无法通过编程或扩展进行更改。有关详细信息,请查看 MDN.

Firstly, does the above looks ok?

我第一眼看你的代码很好,除了你的观点 But I find that I can just set that header manually to "bypass" cors,我没发现它有什么大问题。

Then I am getting origin from headers event.headers.origin. But I find that I can just set that header manually to "bypass" cors. Is there a reliable way to detect the origin domain?

您当前使用的代码是我能想到的唯一方法来检测源域。尽管如您所说,您可以手动设置 header,并且 header 正确或有效的保证为 0。它不应该用作安全的信任层。对于浏览器,它们限制了 header 的设置方式(参见 Forbidden header name). But if you control the HTTP client (ex. curl, postman 等),您可以轻松地发送任何您想要的 header。没有什么技术可以阻止我向您的网络服务器发送任何 header 具有我想要的任何值。

因此,归根结底,这可能不是一个大问题。如果有人篡改 header,他们就会面临安全风险和意外行为。有很多方法可以绕过 CORS,like this, or this, or this 也许吧。因此,尽管您已尽最大努力实施它,但最终还是有可能绕过 CORS。尽管所有这些技巧都是 hack,普通用户可能不会使用。与更改来源相同 header,普通用户不太可能这样做。

您还可以研究一些其他技巧来尝试更多地执行它。您可以查看 refer header,看看它是否与原点 header 相同。同样,可以为任何 header 发送任何内容,但会使它变得更难一些,并更多地执行你想要的东西。

如果您假设您的来源 header 应该始终等于您的 API 网关 API 的域,那么您可以研究的另一件事是 event.requestContext object API 网关给你。 object 具有 resourceIdstageaccountIdapiId 以及其他一些附加的有趣属性。您可以考虑构建一个系统,该系统也将验证这些值,并根据这些值确定 API 网关中的哪个 API 发出请求。这可能需要确保您已将每个域分离到一个单独的 API 网关 API.

无论如何我看不到 event.requestContext 中的那些值可能被篡改,因为 AWS 在将事件 object 传递给您之前设置了它们。它们源自 AWS,并且不能轻易被用户篡改(除非请求的整个组成发生变化)。与随请求一起发送的 header 相比,防篡改肯定少得多,AWS 会传递给您。

当然,您可以将这些解决方案中的多个组合在一起,以创建一个更能执行您的政策的解决方案。请记住,安全性是一个范围,因此您可以在这个范围内走多远取决于您。

我还鼓励您记住,CORS 并不完全意味着在 Internet 上隐藏信息。我分享的关于如何使用简单的后端系统或插件绕过 CORS 的方法表明它并非完全万无一失,如果有人真的想伪造 headers,他们将能够做到。但当然,在一天结束时,你可以让实现这一目标变得尽可能困难。但这需要实施和编写大量代码并进行大量检查才能实现。

您真的必须问问自己 object 的目标和目标是什么。我认为这真的决定了你的下一步。您可能会确定您当前的设置已经足够好,无需进一步更改。您可能会确定您正在尝试保护敏感数据不被发送到未经授权的来源,在这种情况下,CORS 可能不是一个可靠的解决方案(由于能够将 header 设置为任何内容)。或者您可能会确定您可能想要更多地锁定事情并使用一些其他信号来更多地执行您的政策。


tldr 您当然可以将 Origin header 设置为您想要的任何值,因此不应完全信任它。如果您假设您的来源 header 应该始终等于您的 API 网关 API 的域,您可以尝试使用 event.requestContext object 来获取更多信息关于 API 中的 API 网关以获得有关请求的更多信息。您还可以查看 Refer header 看看是否可以将其与 Origin header.

进行比较

更多信息: