保护非认证的REST API

27

我一直在阅读关于保护REST API的内容,了解到oAuth和JWTs这两种方法。它们都非常优秀,但据我所知,它们都是在用户经过身份验证或者说“登录”之后才能发挥作用。基于用户凭证产生oAuth和JWTs,一旦获得了oAuth令牌或JWT,用户就可以执行其被授权的所有操作。

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

我正在使用yii2编写我的API。


即使您对JS文件进行了缩小,某人是否可以从JavaScript中读取您的API端点? - Saurabh Chaturvedi
2
缩小代码并不能解决问题。您可以轻松地将整个代码复制粘贴到IDE中,自动格式化代码将格式化所有代码。 - Eric B.
“Secures them”是什么意思?你想要防止谁进入?还是只是防止拒绝服务攻击等? - jwilleke
是的,DDOS攻击和垃圾邮件,正如您在问题中提到的那样,如果有人知道我的注册API,他们可以轻松地向我的数据库发送垃圾信息。同样,如果他们知道登录API,他们可以进行暴力破解。 - Eric B.
你永远不应该将任何机密信息存储在客户端可访问的文件中。对于oAuth,如果您使用密码授权类型,则除了凭据之外,您只会传递公共客户端ID。对于JWT也是如此,您将保留您的秘密服务器端,并且仅使用它生成的令牌才能通过身份验证检查。至于您其他的问题,下面关于速率限制的答案看起来很好。 - mickadoo
显示剩余2条评论
4个回答

10
The Yii 2.0框架有一个内置的过滤器叫做yii\filters\RateLimiter,它实现了基于漏桶算法的速率限制算法。它将允许您在一定时间间隔内限制接受的最大请求数。例如,您可以将登录和注册端点限制为在10分钟时间间隔内最多接受100个API调用。当超过该限制时,将抛出yii\web\TooManyRequestsHttpException异常(429 状态码)。
您可以在Yii2 RESTful API 相关文档或这个SO帖子中了解更多信息。

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

请注意,RateLimiter 需要 $user 实现 yii\filters\RateLimitInterface。如果 $user 未设置或未实现 yii\filters\RateLimitInterface,则 RateLimiter 将不起作用。

我猜它被设计成只与已登录的用户一起使用,可能是通过使用与高级模板中引入的默认用户相关的数据库表。我不确定,但我知道它需要将允许的请求数量和相关时间戳存储到某个持久存储器中,在您需要在用户类中定义的saveAllowance方法中。因此,我认为您将不得不通过IP地址跟踪您的访客用户,就像@LajosArpad建议的那样,然后重新设计您的用户类以保存他们的身份,以便您可以启用它。
快速谷歌搜索让我找到了这个扩展:yii2-ip-ratelimiter,您也可以看一下。

我了解到RateLimiter,正如你所指出的,它需要一个用户,并基于此应用限制。此外,我猜RateLimiter是针对整个应用程序而不仅仅是一些API。因此,我想到了一个更好的解决方案,即创建两个由同一数据库支持的Yii应用程序。其中一个仅用于这些未受保护的服务,访问不包含用户名密码的用户表,而是包含IP地址;另一个Yii应用程序包含我的正常应用程序逻辑用户。 - Eric B.
我建议使用两个模块:apiauth,每个模块都有自己的用户类,就像我之前在这个示例中所做的那样。第一个模块提供资源,而auth模块提供令牌,并且有两个控制器:第一个控制器包含不需要身份验证的操作,而第二个控制器则需要身份验证,例如注销或撤销操作(在此处查看)。 - Salem Ouerdani
使用REDIS数据库对于这个工作来说是一个绝佳的选择。实际上,我可能会自己进行这种架构变更。@Salem,你在Yii方面有很深入的了解。我刚刚开始接触它,所以不太了解它的工作原理。 - Eric B.
谢谢,我希望这个代码库能够帮助你得到一些想法。我会在某一天更新它,因为我学到了更多的东西。REST 是广泛的,每个人都有自己的架构,我仍在阅读和学习它。祝你设计成功。 - Salem Ouerdani
祝你好运。 - Eric B.
显示剩余2条评论

8

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

创建类似于此架构的数据库表:

ip_addresses(ip、is_suspicious、login_attempts、register_attempts)

其中is_suspicious表示已列入黑名单。login_attempts和register_attempts应为json值,显示该IP地址尝试登录/注册的历史记录。如果最近20次尝试没有成功且在一分钟内,则应将IP地址列入黑名单。列入黑名单的IP地址应该收到黑名单回复,无论请求类型如何。因此,如果他们拒绝您的服务或尝试入侵,您可以拒绝为他们提供服务。

使用sha1等算法来保护密码。该算法足够安全,并且比例如sha256之类的算法更快,而后者可能会过度消耗资源。如果您的API涉及银行账户或其他非常重要的事项,坏人可能使用服务器群来攻击它,则强制用户创建非常长的密码,包括数字、特殊字符、大写和小写字母。


1
这是一个很好的建议,对于登录和注册非常有效。我认为如果在过去的2分钟内进行了5次注册尝试,我将会把它们列入黑名单。同样地,如果在2分钟内进行了10次登录尝试并且全部失败,我也会将它们列入黑名单。但是@Lajos,如果黑客使用代理服务器进行攻击,我们该怎么办?你有什么建议吗? - Eric B.
@EricB.,代理服务器有IP地址。您可以最初黑名单一组大型代理服务器,每当出现可疑情况时,都可以检查请求来自哪个IP地址。此外,还有一种自动解除几个代理服务器的方法,请参见:https://dev59.com/pHRB5IYBdhLWcg3wNk53 - Lajos Arpad
感谢您的建议,@Lajos。它帮了我很多。我一定会尝试这个方法。此外,如果没有更好的答案,我会接受您的回答。 - Eric B.
@MvdD,我想友好地请教您,如果某人每个IP地址只有非常有限的尝试次数,他将如何解密sha1加密的密码? - Lajos Arpad
问题不在于在线尝试,而在于离线尝试。如果您被黑客攻击并且密码数据库被盗,使用彩虹表检索原始密码就是小菜一碟。请务必对密码进行盐处理并使用缓慢的哈希算法。 - MvdD
显示剩余2条评论

2
请参考我的API模块。我通过访问令牌管理用户身份验证。当登录时,我会生成令牌,然后再次访问,客户端需要发送令牌,服务器将进行检查。 Yii2 Starter Kit lite

2
对于javascript,您应该使用OAuth 2.0 Implicit Grant流程,例如Google或Facebook。
登录和注册使用两个基本网页。不要忘记为它们添加验证码。
对于某些特殊客户端,例如移动应用程序或Web服务器:
如果您确定您的二进制文件是安全的,则可以为其创建自定义登录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
1. /getSignupToken:获取图像验证码URL和注册令牌。 2. /signup:发布注册数据(包括注册令牌和用户输入的验证码)。
对于登录操作:我们可以根据用户名的失败登录次数要求验证码。

当您填写表单时,验证码可以正常工作。但是当您直接访问API端点时,它们无法正常工作。您的客户端时间方法也可能会失败,因为Android应用程序APK可以轻松转换为Java代码,您可以轻松从代码中找到密钥,并知道创建哈希的逻辑是添加时间并将相同的时间发送到服务中。一旦有人知道了这个逻辑,暴力破解就变得非常容易。 - Eric B.
根据您的编辑,如果有人找到了“getSignupToken”服务,他们不认为可以在调用注册服务之前,只需单击一下该服务以获取注册令牌和验证码URL,然后使用这些参数访问注册服务吗? - Eric B.
我的意思是像验证码这样的东西对于移动API来说不起作用。我需要一种独立于Web组件的方法,一种通用的方法,既可以用于移动端也可以用于Web端。 - Eric B.
当然,基于令牌的验证码适用于所有平台。 - Ngô Văn Thao
我进行了快速的谷歌搜索,并找到了这个 - Eric B.
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接