如何保护 Django Rest Framework 中注册和登录的 API?

Posted

技术标签:

【中文标题】如何保护 Django Rest Framework 中注册和登录的 API?【英文标题】:How to secure APIs for Registration and Login in Django Rest Framework? 【发布时间】:2017-02-02 01:59:17 【问题描述】:

我曾经和现在可能是几乎所有使用 Django Rest Framework 来创建 REST API 的 Django Framework 用户。我使用django-rest-framework-jwt 将它与令牌身份验证一起使用,当用户通过我们的rest API 登录时它会返回令牌。

所以问题是如何保护我们的 API 端点的任何注册或登录视图。任何高级 XSS 脚本都可能有恶意循环来创建注册。我们如何在 Django Rest Framework 中保护它?

【问题讨论】:

在应用程序级别执行此操作不是最佳解决方案。理想情况下,您应该使用类似 fail2ban 的东西来检测已知的攻击模式并在防火墙级别阻止它们。这样一来,蛮力尝试就不会达到应用程序一旦检测到的程度。 @MatthewDaly 是的,我在寻找fail2ban。但是目前的解决方案我发现移动和后端开发人员可以共享一个密钥。所以在这些 API 中,移动应用会根据一些文本发送一些加密密钥,后端开发人员可以使用相同的文本解密文本。 @Aniket 我说的是 JWT 实现。如果有人试图暴力破解注册或身份验证端点,您希望阻止他们到达应用程序,因为即使他们未能通过身份验证,来自多个请求的开销也会杀死应用程序。当日志条目与已知模式匹配时,Fail2ban 将阻止 IP 地址,因此它们甚至无法发出请求。 【参考方案1】:

正如您所说,您不能让 JWT 之类的身份验证系统保护您的页面,例如登录和注册。 但是,您还可以做许多其他事情。下面我简单提到了其中的两个,让你入门,休息一下,你可以详细研究。

首先解决 XSS 问题 -

某些浏览器能够阻止看似 XSS 攻击的内容。它们通过在页面的 GET 或 POST 参数中查找 javascript 内容来工作。如果在服务器的响应中重放 JavaScript,则页面将被阻止呈现并显示错误页面。 X-XSS-Protection 标头用于控制 XSS 过滤器的操作。

实施

django提供中间件和settings>base.py中添加的设置 中间件:

django.middleware.security.SecurityMiddleware

设置:

SECURE_BROWSER_XSS_FILTER = True
This sets header to X-XSS-Protection: 1; mode=block

您可以采取的其他措施来防止某些脚本重复访问您的登录或注册页面 -

蛮力攻击

安全问题

自动化程序可能会攻击以破解用户的用户名和密码或降低服务器速度。

这些攻击通常采用以下几种形式之一: 1.一个IP地址尝试一个用户名和多个密码。 2.多个IP地址尝试一个用户名和多个密码。 3. 一个 IP 地址尝试使用几个常用密码的多个用户名。 4. 许多 IP 地址尝试使用一个或几个通用密码的多个用户名。 5. 对域中任意随机url进行攻击,以减慢服务器响应。

实施

Django Rest Framework 提供了用于节流的内置设置

REST_FRAMEWORK = 
    ...
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle',
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': 
        'anon': '60/minute',
        'app1': '10000/day',
        'app2': '10000/day',
    ,
    ...

另一种解决方案是 django-defender 或 django-ratelimit 仅用于防止登录尝试失败。

希望对你有帮助。

【讨论】:

【参考方案2】:

我在自定义Django REST Throttling 后找到了解决方案,

在 3 次登录尝试后阻止特定用户(阻止我的应用程序中出现的 user_id)。匿名用户 6 次登录尝试后阻止 IP 地址。

prevent.py:-

#!/usr/bin/python

from collections import Counter

from rest_framework.throttling import SimpleRateThrottle
from django.contrib.auth.models import User


class UserLoginRateThrottle(SimpleRateThrottle):
    scope = 'loginAttempts'

    def get_cache_key(self, request, view):
        user = User.objects.filter(username=request.data.get('username'))
        ident = user[0].pk if user else self.get_ident(request)

        return self.cache_format % 
            'scope': self.scope,
            'ident': ident
        

    def allow_request(self, request, view):
        """
        Implement the check to see if the request should be throttled.
        On success calls `throttle_success`.
        On failure calls `throttle_failure`.
        """
        if self.rate is None:
            return True

        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True

        self.history = self.cache.get(self.key, [])
        self.now = self.timer()

        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()

        if len(self.history) >= self.num_requests:
            return self.throttle_failure()

        if len(self.history) >= 3:
            data = Counter(self.history)
            for key, value in data.items():
                if value == 2:
                    return self.throttle_failure()
        return self.throttle_success(request)

    def throttle_success(self, request):
        """
        Inserts the current request's timestamp along with the key
        into the cache.
        """
        user = User.objects.filter(username=request.data.get('username'))
        if user:
            self.history.insert(0, user[0].id)
        self.history.insert(0, self.now)
        self.cache.set(self.key, self.history, self.duration)
        return True

view.py:-

from .prevent import UserLoginRateThrottle
   ....
   ....
   ....
   class ObtainAuthToken(auth_views.ObtainAuthToken):
       throttle_classes = (UserLoginRateThrottle,)/use this method here your login view

       def post(self, request, *args, **kwargs):
           ....
       ....

settings.py:-

# Django-rest-framework
REST_FRAMEWORK = 
    ...
    ...
    ...
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.UserRateThrottle',

    ),
    'DEFAULT_THROTTLE_RATES': 
        'loginAttempts': '6/hr',
        'user': '1000/min',
    

【讨论】:

以上是关于如何保护 Django Rest Framework 中注册和登录的 API?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用邮递员测试 Django REST 框架登录保护 API?

为啥 django-rest-framework 不显示 OneToOneField 数据 - django

django.test.client 上的 Django rest 框架导入错误

Django 和 Django 休息框架

无法使用 Django Rest 框架发送压缩的 gzip 数据

Django REST to React - 无需密码即可获取社交身份验证令牌