DRF中一些安全小知识

admin 2022年4月1日23:29:24评论178 views字数 4399阅读14分39秒阅读模式

DRF(Django REST Framework)是基于一个Django遵循REST的一个强大灵活的用于构建Web API的工具集。作为一个基础坚实,使用广泛的Web框架,其在安全方面的措施也是棒棒哒!

废话不多说,开门见山,跳过安装初始化步骤, 直接上接口:

  • 构建一个简单列表接口

视图(View)

from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from apple.one.serializers import UserSerializer, GroupSerializer
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

序列化(Serializer)


from django.contrib.auth.models import User, Group
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')

路由(urls)


from django.conf.urls import url, include
from rest_framework import routers
from tutorial.quickstart import views
router = routers.DefaultRouter()
router.register(r’users’, views.UserViewSet)
router.register(r’groups’, views.GroupViewSet)


urlpatterns = [
    url(r’^’, include(router.urls)),
    url(r’^api-auth/‘, include(‘rest_framework.urls’, namespace=‘rest_framework’))
]

浏览器访问http://127.0.0.1:8000/users/

DRF中一些安全小知识

  • 序列化(Serializer)

    内置的Serializer,可以很方便地控制Model中“我想让用户看到的属性”和“用户可以控制的属性”。Serializer的角色,虽然它有这样一个容易被人误解的名字,但Serializer实际作用和原生Django中的Form类似,主要作用是控制用户输入的内容,并进行校验。但有一个不同点是,Serializer还能控制输出信息的范围。

DRF中一些安全小知识

    我们可以把Serializer理解为一个Model和View之间的媒介,View将用户输入的信息发送给Serializer,Serializer进行筛选和校验,成功后发送给Model,保存进数据库;Model从数据库中取出信息交给Serializer,Serializer进行筛选,只显示开发者允许显示的内容,并交给View,Views显示出来。

在代码中,我们通过在Serializer里定义fields,来限制允许显示或修改的属性:


class UserSerializer(ModelSerializer):
class Meta:
    model = User
    fields = [
        'id',
        'username',
        'email',
        'password',
        'date_joined'
    ]
    read_only_fields = [
        'id',
        'username',
        'email',
        'date_joined'
    ]

    上述代码是一个简单的用户Model对应的Serializer,可见,我通过定义fields,列出程序需要的有哪些字段;再通过定义read_only_fields,来限制哪些是只读字段。

    但实际上有些字段是不太适合显示的,比如password,这个字段应该定义为“只可写而不允许读”:


extra_kwargs = {
  'password': {'write_only': True}
}


  • 权限控制

    DRF内置了三种授权(authentication)方法:HTTP基础认证、Session、Token。HTTP基础认证适合于纯浏览器的前端环境,Session适合于浏览器或基于浏览器内核的应用程序,Token适合无浏览器环境的应用程序。

    通过授权方法,DRF给每个请求标记上一个用户(未登录的用户被称为匿名用户AnonymousUser),但该用户是否有权限访问某个API,这就得问“许可模块”(Permission)了。也就是说,Authentication模块只负责给请求“发通行证”,Permission模块负责检查这个“通行证”是否有权限访问某个地点。

DRF中一些安全小知识


    不同的API View可以选择使用不同的Authentication和Permission,根据自己需要的访问权限任意搭配,也可以使用全局默认值。

    另外,权限方面DRF还提供了一个更高级的模块:Throttling。使用这个模块,即可定义某个“用户”访问某个API的频度。举个例子,某视频网站允许每个免费用户每天观看5个视频,就需要经过如下步骤:


Authentication:Session认证 --> Permission:是否是已登录用户 --> Permission:是否是免费用户 --> Throttling:是否已观看5个视频 --> View:返回视频地址


  • 模型(Modles)

    由于Python运行模式的特殊性(由某一入口点统一进入),上传文件后缀通常也不会卡的太死,只要不覆盖到程序本身的py文件,都不会有太大问题。所以,Django本身很多操作默认是不检查后缀的,比如我们定义一个model,其中包含一个ImageField():

class Attachment(models.Model):
    name = models.CharField('名称', blank=True, null=True, max_length=256)
    photo = models.ImageField('图片', blank=True)
    link = models.CharField('参考链接', blank=True, null=True, max_length=512)
    description = models.CharField('描述', blank=True, null=True, max_length=512)

    正常来说,ImageFieldDjango提供的图片字段,按理说Django自己应该已经做了细致的检查。但实际上Django只检查用户上传的文件内容是否是图片,而不会检查文件后缀是否是图片后缀。

所以,只需要上传一个文件内容符合GIF格式,而后缀.html的文件,即可构造一个XSS漏洞。

DRF中一些安全小知识

DRF中一些安全小知识

    解决这个问题的方法是,在ImageField字段上增加validators,如photo = models.ImageField('图片',validators=[check_image_extension], null=True, blank=True)check_image_extension函数里对文件后缀进行检查即可。

  • Django部署

    Django考虑的非常周到,在项目上线前,我们可以通过执行./manage.py check --deploy命令来查看可能存在的安全问题:

DRF中一些安全小知识

问题解释:

    另外,上线前,最好修改后台地址,如果你不需要使用Django自带的后台,可以在INSTALLED_APPS里将其移除。SECRET_KEY重新进行生成,不要和开发、测试环境相同:openssl rand 50

    1. SECURE_HSTS_SECONDS是否开启HSTS头,强制HTTPS访问

    2. SECURE_CONTENT_TYPE_NOSNIFF是否输出nosniff头,以防止类型混淆类漏洞

    3. SECURE_BROWSER_XSS_FILTER是否输出x-xss-protection头,让浏览器强制开启XSS过滤

    4. SECURE_SSL_REDIRECT是否让HTTP的请求强制跳转到HTTPS

    5. SESSION_COOKIE_SECURE是否将Cookie设置为Secure(不允许在HTTP中传输)

    6. CSRF_COOKIE_SECURE是否将CSRF Token Cookie设置为Secure(不允许在HTTP中传输)

    7. CSRF_COOKIE_HTTPONLY是否将CSRF Token Cookie设置为HTTP ONLY

    8. X_FRAME_OPTIONS是否返回X-FRAME-OPTIONS: DENY头,以防止被其他页面作为框架加载

    9. DEBUG是否开启调试模式

  • Django Rest Framework框架安全部署

    开发环境中DRF通常使用BrowsableAPIRenderer,但在部署到生产环境后,最好将这个Renderer移除,只保留我们需要用到的JSONRenderer

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
      #'rest_framework.renderers.BrowsableAPIRenderer',
    ),
    ...
}

    因为攻击者可以利用BrowsableAPIRenderer输出的表单和返回结果,很容易地进行测试和攻击,也可能是DRF本身出现的前端安全漏洞(如XSS),会因此受到影响。

  • 总结

    啰嗦这么多其实就是一句话,使用DRF写的接口一般情况下会存在哪些安全问题,在充分考虑安全的情况下我们可以如何避免这些问题,仅此而已,但不限于此。

原文始发于微信公众号(A9 Team):DRF中一些安全小知识

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月1日23:29:24
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DRF中一些安全小知识https://cn-sec.com/archives/863270.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息