如何确保只有特定域可以从您的 REST api 查询?

Posted

技术标签:

【中文标题】如何确保只有特定域可以从您的 REST api 查询?【英文标题】:How to make sure that only a specific domain can query from your REST api? 【发布时间】:2017-05-26 13:34:46 【问题描述】:

我有一个具有 REST api 的应用程序。我想要它,以便可以对 REST api 发出的唯一请求是来自应用程序本身的请求。我怎样才能做到这一点? 我也在使用 node.js+express 服务器。

编辑:该应用完全是一个公共网络应用。

【问题讨论】:

您的应用是网络应用,对吧(不是移动应用)?无论如何,您无法确保 100% 的成功(用户可以轻松地在您的应用程序之外模拟您的请求)。 CORS 保护是一种提高浏览器内部这种安全性的技术,但没有什么能阻止用户使用curl 之类的工具覆盖Origin 标头。确实,CORS 保护的目标更多是保护用户,而不是服务器。对于 API/资源保护,您应该提供令牌认证(可能是 oauth)、SSL 之类的东西。 oauth 是如何工作的,难道不能有人从应用程序中获取客户端密钥,然后用它提出自己的请求吗? 我在考虑检查请求来自的 ip 和域,检查它是否与托管应用程序的域相同。够了吗? 在 Ajax 请求中,ip 将是用户 IP。这就是问题所在。 【参考方案1】:

只需在您的请求中定义标头,它的作用是,它只允许来自某个域的请求,并立即拒绝任何其他域。

response.set('Access-Control-Allow-Origin', 'domain.tld');

编辑:如果您真的热衷于网络抓取,您可以创建一个功能来仔细检查客户端的来源。

function checkOrigin (origin) 
   if (origin === "your.domain.tld") 
     return true;
    else 
     return false;
   

/* Handling it in response */
if (checkOrigin(response.headers.origin)) 
  // Let client get the thing from API
 else 
  response.write("Send them error that they're not allowed to use the API");
  response.end();

如果我没记错的话,上面的例子应该适用于默认的 HTTP/HTTPS 模块,也应该适用于 Express。

编辑 2:为了支持我认为它也适用于 Express 的说法,我在他们的文档中找到了这个引文;

req (request) 和 res (response) 是 Node 提供的完全相同的对象,因此您可以调用 req.pipe()、req.on('data', callback) 以及其他任何你不需要做的事情涉及快递。

【讨论】:

我认为网络抓取技术可以解决这个问题。 responde.headers.origin 不适合您的域名时,您可以只使用response.end() 作为二级保护。 我已经更新了我的帖子,向您展示您将如何去做。 response.headers.origin 是托管应用程序的域,而不是客户端用户 ip? 用户不能使用 curl 等工具更改域的值,使其与实际托管的位置相同吗?【参考方案2】:

我建议使用来自客户端的 API 密钥。 CORS 过滤器太容易绕过了。

【讨论】:

客户端如何获取 api 密钥,因为整个东西是一个网站。所以网站是公开的。 这是解决问题的正常方法。如果您打算使用大多数公共 API,那么您的客户端必须具有 API 密钥才能访问它。这是为了限制请求的数量以及可以访问它的应用程序。谷歌地图、steam 和 flickr 等 API 都使用它:) 但是,难道就不能有人拿那个公共客户端 api 密钥并在他们自己的请求中使用它吗? @omega 可以,但此时您可能需要进行速率监控或一些统计数据检查。如果您看到可疑活动,请使用该密钥警告用户、限制速率或撤消访问权限。【参考方案3】:

保护How to implement a secure REST API with node.js的简单方法

以上帖子的概述:

因为用户可以创建资源(也称为 POST/PUT 操作),所以您需要保护您的 api。您可以使用 oauth,也可以构建自己的解决方案,但请记住,如果密码真的很容易发现,所有解决方案都可能被破解。基本思想是使用用户名、密码和令牌(也称为 apitoken)对用户进行身份验证。这个 apitoken 可以使用 node-uuid 生成,密码可以使用 pbkdf2 散列

然后,您需要将会话保存在某处。如果您将其保存在内存中的普通对象中,如果您终止服务器并再次重新启动它,则会话将被破坏。此外,这是不可扩展的。如果您使用 haproxy 在机器之间进行负载平衡,或者您只是使用工作人员,则此会话状态将存储在单个进程中,因此如果同一用户被重定向到另一个进程/机器,则需要再次进行身份验证。因此,您需要将会话存储在一个公共位置。这通常使用 redis 完成。

当用户通过身份验证(用户名+密码+apitoken)时,会为会话生成另一个令牌,即 accesstoken。同样,使用 node-uuid。向用户发送访问令牌和用户 ID。 userid (key) 和 accesstoken (value) 存储在 redis 中,并带有过期时间,例如1 小时。

现在,每次用户使用 rest api 进行任何操作时,都需要发送用户 ID 和访问令牌。

【讨论】:

有没有办法让用户不必使用用户名/密码登录。

以上是关于如何确保只有特定域可以从您的 REST api 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何确保只有我的 javascript 客户端 Web 应用程序向 REST API 发出请求?

Iphone:如何从您的应用程序在 google maps api 中启动路线

如何访问托管在其他域的 Rest API 数据。跨域问题

如何激活keycloak的REST API?

如何确保请求从固定页面命中 REST api?

如何唯一标识您的 Android 应用程序以获取 REST API