如何确保只有特定域可以从您的 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 发出请求?