保护未经身份验证的 REST API

Posted

技术标签:

【中文标题】保护未经身份验证的 REST API【英文标题】:Securing non authenticated REST API 【发布时间】:2016-10-28 11:12:44 【问题描述】:

我一直在阅读有关保护 REST API 的内容,并阅读过有关 oAuth 和 JWT 的内容。两者都是非常好的方法,但据我了解,它们都在用户通过身份验证或换句话说“登录”后工作。这是基于用户凭据生成 oAuth 和 JWT,一旦获得 oAuth 令牌或 JWT,用户就可以执行其授权的所有操作。

但我的问题是,登录和注册 api 怎么样?如何保护它们?如果有人阅读我的 javascript 文件以查看我的 ajax 调用,他们可以轻松找出端点和传递的参数,并且他们可以通过一些 REST 客户端多次点击它,更严重的是,他们可以编写一个点击我的注册 api 的程序说一千次,这将创建一千个垃圾邮件用户,或者他们甚至可以暴力破解登录 api。那么如何保护它们呢?

我正在用 yii2 编写我的 API。

【问题讨论】:

即使你缩小了 JS 文件,有人能从 JavaScript 中读取你的 api 端点吗? 缩小并不能解决问题。您可以轻松地将整个代码复制粘贴到 IDE 中,自动格式化代码将格式化所有代码。 好的,那传统的基于过滤器的身份验证可以在请求发出后触发。 它是如何工作的?可以举个例子吗? “保护他们”是什么意思?谁在试图阻止?还是您的意思只是防止拒绝服务攻击等? 【参考方案1】:

Yii 2.0 框架有一个名为yii\filters\RateLimiter 的内置过滤器,它实现了基于leaky bucket algorithm 的速率限制算法。它将允许您限制在某个时间间隔内接受的最大请求数。例如,您可以限制登录和注册端点在 10 分钟的时间间隔内最多接受 100 个 API 调用。当超过该限制时,将引发yii\web\TooManyRequestsHttpException 异常(429 状态代码)。

您可以在 Yii2 RESTful API related documentation 或 SO post 中了解更多信息。

到目前为止,我自己并没有使用它,但从我在官方文档中读到的内容来看,我的意思是:

请注意,RateLimiter 需要 $user 实施 yii\filters\RateLimitInterface。 RateLimiter 将什么都不做,如果 $user 未设置或未实施 yii\filters\RateLimitInterface.

我猜它的设计目的是仅通过使用与用户相关的数据库表(高级模板中引入的默认表)与登录用户一起工作。我不确定,但我知道它需要将允许的请求数和相关时间戳存储到您需要在用户类中定义的 saveAllowance 方法中的一些持久存储中。因此,我认为您将不得不按照@LajosArpad 的建议通过 IP 地址跟踪您的来宾用户,然后可能重新设计您的用户类以保存他们的身份,以便您可以启用它。

快速谷歌搜索让我找到这个扩展:yii2-ip-ratelimiter,你也可以看看。

【讨论】:

我确实发现了RateLimiter,正如您自己指出的那样,它需要一个用户,并在此基础上应用了限制。更多的 RateLimiter 是针对整个应用程序的,而不仅仅是我猜的一些 api。所以我想到的一个更好的解决方案是创建两个由同一个数据库支持的 Yii 应用程序。一个仅用于这些不受保护的服务,它访问不包含用户名密码的用户表,而是包含 IP,类似地另一个包含我的普通应用程序逻辑用户的 Yii 应用程序。 我建议 2 个模块。 apiauth 每个都有自己的用户类,就像我前段时间在 example 中所做的那样。第一个传递资源,而auth 传递令牌并有两个控制器:第一个持有不需要身份验证的操作,而第二个需要它,如注销或撤销操作(参见here) 关于 RateLimiter,它是一种你可以附加到任何你需要的控制器的行为,你可以改变它的工作方式,就像我解释的那样。在我的演示应用程序中作为示例(我将在某一天完成)我只会将它附加到 AccountController 并且我会在可能的 REDIS DB 中通过 IP 跟踪用户以获得更好的性能。但这就是我对自己的应用的看法 我明白了,不过你的演示应用做得很好。我的应用程序的架构将是相同的,而不是基础,我将使用材料设计。我将使用您的存储库作为参考:) 我还将研究模块,关于如何制作 2 个模块。或者我可以使用高级模板并将后端和前端用于这两项工作。 使用 REDIS DB 是完成这项工作的好主意。事实上,我可以自己进行这种架构更改。 @Salem 你对 Yii 人有很好的了解。我刚刚开始使用它,所以不太了解它是如何工作的。【参考方案2】:

您的网址将很容易确定。您应该有一个 IP 地址黑名单,当某个 IP 地址行为可疑时,只需将其添加到黑名单中即可。你定义什么是可疑的,但如果你不确定,你可以从以下开始:

使用此架构创建类似于数据库表的内容:

ip_addresses(ip, is_suspicious, login_attempts, register_attempts)

is_suspicious 表示它被列入黑名单。 login_attemtps 和 register_attempts 应该是 json 值,显示该 IP 地址尝试登录/注册的历史记录。如果最近 20 次尝试均未成功并且在一分钟内,则该 IP 地址应被列入黑名单。列入黑名单的 IP 地址应收到响应,即无论他们的请求是什么,它们都被列入黑名单。因此,如果他们拒绝提供您的服务或试图破解某些东西,那么您就会拒绝他们提供您的服务。

例如,使用 sha1 保护密码。该算法足够安全,并且比 sha256 更快,例如,这可能是一种矫枉过正。如果您的 API 涉及银行帐户或类似的极其重要的东西,足以让坏人使用服务器公园来破解它,然后强制用户创建非常长的密码,包括数字、特殊字符、大小写字母。

【讨论】:

这是一个很好的建议,非常适合登录和注册。我认为如果在最后 2 分钟内以某种方式进行了 5 次注册尝试,我将列入黑名单。同样,如果 10 次登录尝试和所有失败都在 2 分钟内完成,我也会将它们列入黑名单。但是@Lajos 如果黑客使用代理服务器进行攻击,我们该怎么办?你对此有什么建议吗? @EricB.,代理服务器有 IP 地址。您最初可以将大量代理服务器列入黑名单,每当遇到可疑情况时,您可以检查请求来自的 IP 地址。此外,还有一种方法可以自动取消屏蔽一些代理服务器,请参见:***.com/questions/690025/… 感谢@Lajos 的这个建议。它有很大帮助。我一定会试试这个。此外,如果没有更好的答案,我会接受你的答案。 请不要遵循这个答案关于密码存储的建议!您要保护的数据并不重要。您正在保护用户的密码。这些密码可以在其他地方重复使用。从 SHA1 哈希中检索密码不需要服务器公园。另见:security.stackexchange.com/q/211/47590 @MvdD,我想请你告诉我,如果每个 IP 地址的尝试次数非常有限,他将如何解密 sha1 加密的密码?【参考方案3】:

对于 javascript,您应该使用 OAuth 2.0 隐式授权流程,如 Google 或 Facebook。 登录和注册使用 2 个基本网页。不要忘记为他们添加验证码。

对于一些特殊的客户端,例如移动应用程序或 webServer: 如果您确定您的二进制文件是安全的,您可以为其创建自定义登录 API。在此 API 中,您必须尝试验证您的客户端。

一个简单的解决方案,可以参考:

使用AES或3DES等加密算法加密密码 从客户端使用密钥(只有客户端和服务器知道) 使用 sha256 等哈希算法进行哈希(用户名 + 客户端时间 + 其他 密钥)。客户端将客户端时间和哈希字符串发送到 服务器。如果客户端时间相差太大,服务器将拒绝请求 来自服务器或哈希字符串不正确。

例如:

api/login?user=user1&password=AES('password',$secret_key1)&time=1449570208&hash=sha256('user1'+'|'+'1449570208'+'|'+$secret_key2)

注意:无论如何,服务器都应该使用验证码来避免暴力攻击,不要相信任何其他过滤器

关于 REST API 的验证码,我们可以基于令牌创建验证码。 例如。

对于注册操作:您必须调用 2 api

    /getSignupToken : 获取图片验证码 url 和注册令牌 分别。 /signup : 发布注册数据(包括注册令牌和 用户输入的验证码)

对于登录操作:我们可以通过基于用户名的失败登录次数来要求验证码

【讨论】:

验证码在您填写表格时起作用。当您可以直接访问 api 端点时,它们不起作用。您的客户端时间方法也可能会失败,您知道,android app apk 可以轻松转换为 java 代码,您可以轻松地从代码中找到密钥,并知道创建哈希的逻辑是添加时间,并发送相同的时间服务。一旦有人知道了这个逻辑,burte force 就是小菜一碟。 @EricB。 OAuth 2.0 使用登录页面和注册页面是 2 个普通的 html 表单,它们是在浏览器上打开的,验证码基于用户会话。关于 REST API 的验证码,我们可以根据令牌创建验证码。 当然有人可以解码APK文件,Encript解决方案只是限制性的。 根据您的编辑,如果有人发现了getSignupToken 服务,在调用注册服务之前,您不认为他们可以,只需点击它以获取注册令牌和验证码 url,然后使用这些参数点击注册服务? 我的意思是像验证码这样的东西不适用于移动 API。我需要一种独立于 Web 组件的方法,一种通用的方法,可用于移动设备和 Web。【参考方案4】:

在此处关注我的 api 模块以供参考。我通过访问令牌管理用户身份验证。登录时,我生成令牌,然后再次访问,客户端需要发送令牌,服务器会检查。

Yii2 Starter Kit lite

【讨论】:

以上是关于保护未经身份验证的 REST API的主要内容,如果未能解决你的问题,请参考以下文章

如何通过查询身份验证保护 REST API

Phonegap错误:401未经授权 - 在Phonegap中使用基本身份验证的Rest API

无需对移动应用进行用户身份验证即可保护私有 REST API 的最佳方法

JWT 在未经身份验证的端点上进行 CSRF 保护?

如何通过 Wordpress REST API 对 LearnDash 中受保护数据的远程访问进行身份验证?

Firestore 模拟器 REST API 身份验证