Python 全栈安全(二)(4)

简介: Python 全栈安全(二)

Python 全栈安全(二)(3)https://developer.aliyun.com/article/1508739

第十章:授权

本章内容包括

  • 创建超级用户和权限
  • 管理组成员
  • 使用 Django 强制应用程序级别的授权
  • 测试授权逻辑

认证和授权往往容易混淆。认证 关系到用户是谁;授权 关系到用户可以做什么。认证和授权通常分别称为 authnauthz。认证是授权的先决条件。在本章中,我涵盖了与应用程序开发相关的授权,也称为 访问控制。在下一章中,我将继续介绍 OAuth 2,一种标准化的授权协议。

注:在撰写本文时,破坏授权是 OWASP 十大关键安全风险清单上的第五项(owasp.org/www-project-top-ten/)。

你将从应用程序级别的权限授权开始本章。权限 是授权的最原子形式。它授权一个人或一组人只能执行一件事情。接下来,你将为 Alice 创建一个超级用户帐户。然后你将以 Alice 的身份登录 Django 管理控制台,在那里你将管理用户和组权限。之后,我将向你展示几种应用权限和组来控制谁可以访问受保护的资源。

10.1 应用程序级授权

在这一部分,你将创建一个名为messaging的新 Django 应用程序。该应用程序使你接触到 Django 授权、权限的最基本元素。要创建新的消息应用程序,请在项目根目录中运行以下命令。此命令将在一个名为 messaging 的新目录中生成一个 Django 应用程序:

$ python manage.py startapp messaging

生成的应用程序的目录结构如图 10.1 所示。在这个练习中,你将在models模块中添加一个类,并通过对migrations包进行一些添加来多次修改数据库。


图 10.1 新 Django 应用程序 messaging 的目录结构

现在你需要在 Django 项目中注册你的 Django 应用程序。打开settings模块,找到INSTALLED_APPS列表。添加你在这里看到的加粗字体的行。确保不要改变之前安装的所有其他应用程序:

INSTALLED_APPS = [
    ...
 'messaging',
]

接下来,打开 models.py 并将以下模型类定义放入其中。AuthenticatedMessage表示一个消息和一个具有两个属性的哈希值。在第十四章中,Alice 和 Bob 将使用此类进行安全通信:

from django.db.models import Model, CharField
class AuthenticatedMessage(Model):
    message = CharField(max_length=100)
    hash_value = CharField(max_length=64)

正如所有模型一样,AuthenticatedMessage必须映射到一个数据库表。表是通过 Django 迁移创建的。(你在上一章学习过迁移。)映射由 Django 内置的 ORM 框架在运行时处理。

运行以下命令为你的模型类生成一个迁移脚本。此命令将自动检测新模型类并在迁移目录下创建一个新的迁移脚本,显示为粗体字体:

$ python manage.py makemigrations messaging
Migrations for 'messaging':
 messaging/migrations/0001_initial.py      # ❶
    - Create model AuthenticatedMessage

❶ 新的迁移脚本

最后,通过运行以下命令执行你的迁移脚本,显示为粗体:

$ python manage.py migrate
Running migrations:
  Applying messaging.0001_initial... OK

运行你的迁移脚本不仅会创建一个新的数据库表,还会在后台创建四个新的权限。下一节将解释这些权限存在的方式和原因。

10.1.1 权限

Django 使用内置模型 Permission 来表示权限。Permission 模型是 Django 授权的最基本元素。每个用户可以关联零到多个权限。权限分为两类:

  • 由 Django 自动创建的默认权限
  • 由你创建的自定义权限

Django 会自动为每个新模型创建四个默认权限。当运行迁移时,这些权限在后台创建。这些权限允许用户创建、读取、更新和删除模型。在 Django shell 中执行以下代码,观察AuthenticatedMessage模型的所有四个默认权限,显示为粗体:

$ python manage.py shell
>>> from django.contrib.auth.models import Permission
>>> 
>>> permissions = Permission.objects.filter(
...     content_type__app_label='messaging',
...     content_type__model='authenticatedmessage')
>>> [p.codename for p in permissions]
['add_authenticatedmessage', 'change_authenticatedmessage', 
'delete_authenticatedmessage', 'view_authenticatedmessage']

随着项目的发展,通常会需要自定义权限。通过将一个内部Meta类添加到你的模型中来声明这些权限。打开你的models模块,并向AuthenticatedMessage添加以下Meta类,显示为粗体,Meta类的permissions属性定义了两个自定义权限。这些权限指定了哪些用户可以发送和接收消息:

class AuthenticatedMessage(Model):       # ❶
    message = CharField(max_length=100)
    mac = CharField(max_length=64)
 class Meta:                          # ❷
 permissions = [
 ('send_authenticatedmessage', 'Can send msgs'),
 ('receive_authenticatedmessage', 'Can receive msgs'),
 ]

❶ 你的模型类

❷ 你的模型 Meta 类

与默认权限类似,自定义权限在迁移期间会自动创建。使用以下命令生成一个新的迁移脚本。如粗体字体的输出所示,此命令会在迁移目录下生成一个新的脚本:

$ python manage.py makemigrations messaging --name=add_permissions
Migrations for 'messaging':
 messaging/migrations/0002_add_permissions.py      # ❶
    - Change Meta options on authenticatedmessage

❶ 新的迁移脚本

接下来,使用以下命令执行你的迁移脚本:

$ python manage.py migrate
Running migrations:
  Applying messaging.0002_add_permissions... OK

现在,你已经向你的项目添加了一个应用、一个模型、一个数据库表和六个权限。在下一节中,你将为 Alice 创建一个账户,以她的身份登录,并将这些新权限授予 Bob。

10.1.2 用户和组管理

在本节中,你将创建一个超级用户 Alice。超级用户是具有执行所有操作权限的特殊管理用户;这些用户拥有所有权限。作为 Alice,你将访问 Django 内置的管理控制台。默认情况下,该控制台在每个生成的 Django 项目中都是启用的。管理控制台的简要介绍将向你介绍 Django 如何实现应用级授权。

如果您的 Django 项目能够提供静态内容,则管理控制台更易于使用且更好看。Django 可以自行通过 HTTP 完成此操作,但 Gunicorn 不设计通过 HTTPS 完成此操作。这个问题很容易通过 WhiteNoise 解决,它是一个专门设计用于有效地提供静态内容并最小化设置复杂性的软件包(如图 10.2 所示)。管理控制台(以及项目的其余部分)将使用 WhiteNoise 正确地向您的浏览器提供 JavaScript、样式表和图像。


图 10.2 一个 Django 应用服务器使用 WhiteNoise 提供静态资源。

在虚拟环境中运行以下 pipenv 命令来安装 WhiteNoise:

$ pipenv install whitenoise

现在,您需要通过中间件在 Django 中激活 WhiteNoise。什么是中间件?中间件是 Django 中的一个轻量级子系统,位于每个入站请求和您的视图之间的中间,以及您的视图和每个出站响应之间的中间。从这个位置上,中间件应用前后处理逻辑。

中间件逻辑由一组中间件组件实现。每个组件都是一个独特的小型处理挂钩,负责执行特定任务。例如,内置的 AuthenticationMiddleware 类负责将入站 HTTP 会话 ID 映射到用户。我在后面的章节中介绍的一些中间件组件负责管理与安全相关的响应头。在本节中添加的组件 WhiteNoiseMiddleware 负责提供静态资源。

与 Django 的每个其他子系统一样,中间件在 settings 模块中进行配置。打开您的 settings 模块并找到 MIDDLEWARE 设置。该设置是一个中间件组件类名称列表。如下代码中加粗显示的那样,将 WhiteNoiseMiddleware 添加到 MIDDLEWARE 中。确保此组件紧随 SecurityMiddleware 之后,并位于所有其他内容之前。不要移除任何现有的中间件组件:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',   # ❶
    'whitenoise.middleware.WhiteNoiseMiddleware',      # ❷
    ...
]

❶ 确保 SecurityMiddleware 保持在第一位。

❷ 将 WhiteNoise 添加到您的项目中

警告:每个生成的 Django 项目都使用 SecurityMiddleware 作为第一个 MIDDLEWARE 组件进行初始化。SecurityMiddleware 实现了一些先前介绍过的安全特性,如 Strict-Transport-Security 响应头和 HTTPS 重定向。如果将其他中间件组件放在 SecurityMiddleware 前面,这些安全特性就会受到影响。

重新启动您的服务器,并将浏览器指向 https:/./localhost:8000/admin/ 的管理控制台登录页面。登录页面应该会显示如图 10.3. 所示。如果您的浏览器以没有样式的相同表单呈现,则表示 WhiteNoise 尚未安装。如果 MIDDLEWARE 配置错误或服务器未重新启动,则会发生这种情况。管理控制台仍将在没有 WhiteNoise 的情况下工作;它只是看起来不太好而已。


图 10.3 Django 的管理登录页面

管理控制台登录页面需要具有超级用户或工作人员身份的用户的身份验证凭据;Django 不允许常规最终用户登录管理控制台。

从项目根目录运行以下命令以创建超级用户。此命令在您的数据库中创建一个超级用户;它将提示您输入新超级用户的密码:

$ python manage.py createsuperuser \
         --username=alice --email=alice@alice.com

作为 Alice 登录管理控制台。作为超级用户,您可以从管理登录页面管理组和用户。单击组旁边的添加,导航到新的组输入表单。

小组

提供了一种将一组权限与一组用户关联起来的方法。一个组可以与零到多个权限以及零到多个用户关联。与组关联的每个权限都隐式授予该组的每个用户。

新的组输入表单,如图 10.4 所示,需要组名称和可选权限。请花一分钟观察可用权限。注意它们分成了四组。每个批次代表数据库表的默认权限,控制谁可以创建、读取、更新和删除行。


图 10.4 新的组输入表单接受组名称和多个组权限。

浏览可用权限选择器,并找到您为消息应用程序创建的权限。与其他批次不同,这个批次有六个元素:四个默认权限和两个自定义权限。

在名称字段中输入observersobservers组旨在对每个表具有只读访问权限。选择包含文本“Can view”的每个可用权限。通过单击保存提交表单。

提交表单后,您将被带到列出所有组的页面。通过单击左侧边栏中的“用户”导航到列出所有用户的类似页面。当前,此页面仅列出 Alice 和 Bob。通过单击其名称,导航到 Bob 的用户详细信息页面。向下滚动用户详细信息页面,直到找到两个相邻的组和权限部分。在此部分中,如图 10.5 所示,将 Bob 分配到observers组,并为他赋予消息应用程序的所有六个权限。滚动到底部,然后单击保存。


图 10.5 作为管理员分配组和权限

小组成员资格和权限不需要手动管理;相反,您可以通过编程方式进行管理。列表 10.1 展示了如何通过User模型的两个属性授予和撤销权限。小组成员资格通过groups属性授予和撤销。user_permissions属性允许向用户添加或删除权限。

列表 10.1 编程方式管理组和权限

from django.contrib.auth.models import User
from django.contrib.auth.models import Group, Permission
bob = User.objects.get(username='bob')                                  # ❶
observers = Group.objects.get(name='observers')                         # ❶
can_send = Permission.objects.get(codename='send_authenticatedmessage') # ❶
bob.groups.add(observers)                                               # ❷
bob.user_permissions.add(can_send)                                      # ❸
bob.groups.remove(observers)                                            # ❹
bob.user_permissions.remove(can_send)                                   # ❺

❶ 检索模型实体

❷ 将 Bob 添加到一个组

❸ 为 Bob 添加权限

❹ 将 Bob 从一个组中移除

❺ 从 Bob 中移除一个权限

到目前为止,你已经了解了组和权限是如何工作的。你知道它们是什么,如何创建它们,以及如何将它们应用到用户身上。但它们在实际应用中是什么样子呢?在接下来的部分,你将开始使用组和权限来解决问题。

10.2 强制授权

授权的整个目的是防止用户做他们不应该做的事情。这适用于系统内的操作,比如阅读敏感信息,以及系统外的操作,比如指挥飞行交通。在 Django 中有两种实施授权的方式:低级的困难方式和高级的简单方式。在本节中,我将先展示困难的方式。之后,我将向你展示如何测试你的系统是否正确地执行了授权。

10.2.1 低级的困难方式

User 模型提供了几种设计用于程序化权限检查的低级方法。下面的代码展示了 has_perm 方法,它允许你访问默认权限和自定义权限。在这个例子中,Bob 不被允许创建其他用户,但允许接收消息:

>>> from django.contrib.auth.models import User
>>> bob = User.objects.get(username='bob')
>>> bob.has_perm('auth.add_user')                            # ❶
False                                                        # ❶
>>> bob.has_perm('messaging.receive_authenticatedmessage')   # ❷
True

❶ Bob 无法添加用户。

❷ Bob 可以接收消息。

对于超级用户,has_perm 方法将始终返回 True

>>> alice = User.objects.get(username='alice')
>>> alice.is_superuser                         # ❶
True                                           # ❶
>>> alice.has_perm('auth.add_user')
True

❶ Alice 可以做任何事情。

has_perms 方法提供了一种方便的方式来一次检查多个权限:

>>> bob.has_perms(['auth.add_user',                              # ❶
...                'messaging.receive_authenticatedmessage'])    # ❶
False                                                            # ❶
>>> 
>>> bob.has_perms(['messaging.send_authenticatedmessage',        # ❷
...                'messaging.receive_authenticatedmessage'])    # ❷
True 

❶ Bob 无法添加用户和接收消息。

❷ Bob 可以发送和接收消息。

低级 API 并没有错,但你应该尽量避免使用它,原因有两个:

  • 低级权限检查需要比我后面介绍的方法更多的代码行。
  • 更重要的是,以这种方式检查权限容易出错。例如,如果你查询这个 API 关于一个不存在的权限,它将简单地返回 False
>>> bob.has_perm('banana')
False

这是另一个陷阱。权限是一次从数据库中批量获取并缓存的。这带来了一个危险的折衷。一方面,has_permhas_perms 在每次调用时不会触发数据库查询。另一方面,当你在将权限应用到用户之后立即检查权限时,你必须小心。下面的代码片段演示了为什么。在这个例子中,一个权限被从 Bob 那里拿走了。不幸的是,本地权限状态没有被更新:

>>> perm = 'messaging.send_authenticatedmessage'    # ❶
>>> bob.has_perm(perm)                              # ❶
True                                                # ❶
>>> 
>>> can_send = Permission.objects.get(              # ❷
...     codename='send_authenticatedmessage')       # ❷
>>> bob.user_permissions.remove(can_send)           # ❷
>>> 
>>> bob.has_perm(perm)                              # ❸
True 

❶ Bob 从权限开始。

❷ Bob 失去了权限。

❸ 本地副本无效。

继续使用同一个例子,当在 User 对象上调用 refresh_from_db 方法时会发生什么?本地权限状态仍然没有被更新。为了获取最新状态的副本,必须重新从数据库加载一个新的 User 模型:

>>> bob.refresh_from_db()                     # ❶
>>> bob.has_perm(perm)                        # ❶
True                                          # ❶
>>> 
>>> reloaded = User.objects.get(id=bob.id)    # ❷
>>> reloaded.has_perm(perm)                   # ❷
False                                         # ❷

❶ 本地副本仍然无效。

❷ 重新加载的模型对象有效。

这是第三个陷阱。列表 10.2 定义了一个视图。这个视图在渲染敏感信息之前执行授权检查。它有两个错误。你能发现其中任何一个吗?

列表 10.2 如何不强制授权

from django.shortcuts import render
from django.views import View
class UserView(View):
    def get(self, request):
        assert request.user.has_perm('auth.view_user')   # ❶
        ...
        return render(request, 'sensitive_info.html')    # ❷

❶ 检查权限

❷ 渲染敏感信息

第一个错误在哪里?与许多编程语言一样,Python 有一个 assert 语句。该语句评估一个条件,如果条件为 False,则会引发一个 AssertionError。在这个例子中,条件是一个权限检查。在开发和测试环境中,assert 语句非常有用,但是当 Python 使用 -O 选项调用时,它们会产生一种虚假的安全感。(此选项代表 优化。)作为一种优化,Python 解释器会移除所有 assert 语句。在控制台中键入以下两个命令,自己看一下:

$ python -c 'assert 1 == 2'               # ❶
Traceback (most recent call last):        # ❶
  File "<string>", line 1, in <module>    # ❶
AssertionError                            # ❶
$ python -Oc 'assert 1 == 2'              # ❷

❶ 引发 AssertionError

❷ 不引发任何内容

警告 assert 语句是调试程序的一种好方法,但不应用于执行权限检查。除了权限检查之外,assert 语句也不应用于一般应用程序逻辑。这包括所有安全检查。-O 标志在开发或测试环境中很少使用;它经常在生产中使用。

第二个错误在哪里?假设断言实际上是在您的生产环境中执行的。与任何错误一样,服务器会将 AssertionError 转换为状态码 500. 根据 HTTP 规范的定义,此代码指定为内部服务器错误(tools.ietf.org/html/rfc7231)。您的服务器现在阻止未经授权的请求,但未生成有意义的 HTTP 状态码。一个出于善意的客户端现在收到这个代码,并错误地得出根本问题是服务器端的结论。

未经授权的请求的正确状态码是 403. 服务器发送状态码 403 以指定资源为禁止。此状态码在本章中出现了两次,从下一节开始。

10.2.2 高级简单方法

现在我将向您展示简单的方法。这种方法更清洁,您不必担心任何上述的陷阱。Django 预装了几个专为授权而设计的内置 mixin 和装饰器。使用以下高级工具比使用一堆 if 语句更清洁:

  • PermissionRequiredMixin
  • @permission_required

PermissionRequiredMixin 强制执行各个视图的授权。此类自动检查与每个传入请求关联的用户的权限。您可以使用 permission_required 属性指定要检查的权限。此属性可以是表示一个权限的字符串,也可以是表示多个权限的字符串可迭代对象。

在第 10.3 节的视图中继承自 PermissionRequiredMixin,如粗体字所示。permission_required 属性,也以粗体字显示,确保在处理请求之前用户必须具有查看经过身份验证的消息的权限。

在 PermissionRequiredMixin 中进行授权的第 10.3 节

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.http import JsonResponse
class AuthenticatedMessageView(PermissionRequiredMixin, View):     # ❶
 permission_required = 'messaging.view_authenticatedmessage'    # ❷
    def get(self, request):
         ...
         return JsonResponse(data)

❶ 确保权限已检查

❷ 声明要检查的权限

PermissionRequiredMixin 对匿名请求作出响应,将浏览器重定向到登录页面。如预期,对未经授权的请求作出状态码为 403 的响应。

@permission_required 装饰器是 PermissionRequiredMixin 的功能等效物。列表 10.4 演示了 @permission_ required 装饰器的授权,它显示在粗体中,对基于函数的视图进行了授权。与前一个示例类似,此代码确保用户必须具有权限查看已认证消息才能处理请求。

10.4 列表使用 @permission_required 进行授权

from django.contrib.auth.decorators import permission_required
from django.http import JsonResponse
@permission_required('messaging.view_authenticatedmessage', raise_exception=True)                      # ❶
def authenticated_message_view(request):        # ❷
    ...                                         # ❷
    return JsonResponse(data)                   # ❷

❶ 在处理请求之前检查权限

❷ 基于函数的视图

有时您需要使用比简单的权限检查更复杂的逻辑来保护资源。以下一对内置实用程序旨在使用任意 Python 强制授权;它们在其他方面的行为类似于 PermissionRequiredMixin@permission_required 装饰器:

  • UserPassesTestMixin
  • @user_passes_test

在粗体显示的列表 10.5 中,UserPassesTestMixin 保护了使用 Python 中任意逻辑的视图。此实用程序为每个请求调用 test_func 方法。此方法的返回值确定了是否允许该请求。在此示例中,用户必须具有新账户或为 Alice。

10.5 列表使用 UserPassesTestMixin 进行授权

from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import JsonResponse
class UserPassesTestView(UserPassesTestMixin, View):
    def test_func(self):                                                # ❶
        user = self.request.user                                        # ❶
        return user.date_joined.year > 2020 or user.username == 'alice' # ❶
    def get(self, request):
        ...
        return JsonResponse(data)

❶ 任意授权逻辑

在粗体显示的列表 10.6 中,@user_passes_test 装饰器是 UserPassesTestMixin 的功能等效物。与 UserPassesTestMixin 不同,@user _passes_test 装饰器对未经授权的请求作出将浏览器重定向到登录页面的响应。在此示例中,用户必须具有来自 alice.com 的电子邮件地址或名为 bob 的名字。

10.6 列表使用 @user_passes_test 进行授权

from django.contrib.auth.decorators import user_passes_test
from django.http import JsonResponse
def test_func(user):                                                     # ❶
    return user.email.endswith('@alice.com') or user.first_name == 'bob' # ❶
@user_passes_test(test_func)
def user_passes_test_view(request):                                      # ❷
    ...                                                                  # ❷
    return JsonResponse(data)                                            # ❷

❶ 任意授权逻辑

❷ 基于函数的视图

10.2.3 条件渲染

通常,向用户显示他们无权执行的操作是不可取的。例如,如果 Bob 没有权限删除其他用户,您希望避免用一个删除用户的链接或按钮误导他。解决方案是有条件地呈现控件:您将其从用户那里隐藏,或以禁用状态显示给他们。

基于授权的条件渲染内置于默认的 Django 模板引擎中。您通过 perms 变量访问当前用户的权限。以下模板代码说明了如何在当前用户被允许发送消息时有条件地呈现链接。perms 变量已用粗体标出:

{% if perms.messaging.send_authenticatedmessage %}
    <a href='/authenticated_message_form/'>Send Message</a>
{% endif %}

或者,您可以使用此技术将控件呈现为已禁用状态。以下控件对任何人都可见;仅对被允许创建新用户的人启用:

<input type='submit'
       {% if not perms.auth.add_user %} disabled {% endif %}
       value='Add User'/>

警告:永远不要让条件渲染成为一种虚假的安全感。它永远不会取代服务器端的授权检查。这适用于服务器端和客户端的条件渲染。

不要被这个功能所误导。条件渲染是改善用户体验的好方法,但它并不是执行授权的有效方法。控件是隐藏还是禁用都无关紧要;这两种情况都不能阻止用户向服务器发送恶意请求。授权必须在服务器端执行;其他任何事情都不重要。

10.2.4 测试授权

在第八章中,你了解到认证对于测试来说不是障碍;这也适用于授权。清单 10.7 展示了如何验证你的系统是否正确地保护了受保护的资源。

TestAuthorization 的设置方法创建并验证了一个名为 Charlie 的新用户。测试方法从断言 Charlie 被禁止查看消息开始,显示为粗体。(你之前学过服务器用状态码 403 来传达这一信息。)然后,测试方法验证了在授予 Charlie 权限后他可以查看消息;网络服务器用状态码 200 来传达这一信息,也显示为粗体。

清单 10.7 测试授权

from django.contrib.auth.models import User, Permission
class TestAuthorization(TestCase):
    def setUp(self):
        passphrase = 'fraying unwary division crevice'     # ❶
        self.charlie = User.objects.create_user(           # ❶
            'charlie', password=passphrase)                # ❶
        self.client.login(
            username=self.charlie.username, password=passphrase)
    def test_authorize_by_permission(self):
        url = '/messaging/authenticated_message/'
        response = self.client.get(url, secure=True)       # ❷
 self.assertEqual(403, response.status_code)        # ❷
        permission = Permission.objects.get(               # ❸
            codename='view_authenticatedmessage')          # ❸
        self.charlie.user_permissions.add(permission)      # ❸
        response = self.client.get(url, secure=True)       # ❹
 self.assertEqual(200, response.status_code)        # ❹

❶ 为 Charlie 创建账户

❷ 断言无法访问

❸ 授予权限

❹ 断言可以访问

在前一节中,你学会了如何授予权限;在本节中,你学会了如何执行权限。我认为可以肯定地说,这个主题不像本书中的其他一些材料那么复杂。例如,TLS 握手和密钥派生函数要复杂得多。尽管授权看起来很简单,但令人惊讶的是,有相当高的组织都做错了。在下一节中,我会向你展示一个规则,以避免这种情况。

10.3 反模式和最佳实践

2020 年 7 月,一小群攻击者成功进入了 Twitter 的一个内部管理系统。攻击者通过这个系统重置了 130 个知名 Twitter 账户的密码。埃隆·马斯克、乔·拜登、比尔·盖茨等许多公众人物的账户受到了影响。其中一些被劫持的账户随后被用于针对数百万 Twitter 用户进行比特币诈骗,获得了约 12 万美元的收入。

根据两名前 Twitter 员工的说法,超过 1000 名员工和承包商可以访问受损的内部管理系统(mng.bz/9NDr)。尽管 Twitter 拒绝就此数字发表评论,但我可以肯定地说这并不会使他们比大多数组织更糟糕。大多数组织至少有一个糟糕的内部工具,允许太多权限被授予太多用户。

这种反模式,即每个人都可以做任何事情,源于组织未能应用最小权限原则。正如第一章所指出的,PLP 表明用户或系统只应被赋予执行其职责所需的最低权限。越少越好;要保守行事。

相反,一些组织有太多的权限和太多的群组。这些系统更安全,但行政和技术维护成本是高得令人难以承受的。一个组织如何平衡?一般来说,你应该偏爱以下两个经验法则:

  • 通过组成员资格授予权限。
  • 通过独立的独立权限强制执行授权。

这种方法可以减少技术成本,因为每次一个群体增加或减少用户或职责时,你的代码都不需要改变。行政成本保持低廉,但前提是每个群体都以有意义的方式定义。作为一个经验法则,创建模拟实际现实世界组织角色的群体。如果你的用户属于“销售代表”或“后端运营经理”这样的类别,你的系统可能只需要用一个组来模拟他们。在为群体命名时不要创造性;只需使用他们自己称呼的名字。

授权是任何安全系统的重要组成部分。你知道如何授予、强制执行和测试它。在本章中,你了解了在应用程序开发中应用的这个主题。在下一章中,我将继续讲述这个主题,介绍 OAuth 2,一个授权协议。这个协议允许用户授权第三方访问受保护的资源。

概要

  • 认证与你是谁有关;授权与你能做什么有关。
  • 用户、组和权限是授权的构建模块。
  • WhiteNoise 是一种简单而高效的静态资源服务方式。
  • Django 的管理控制台使超级用户能够管理用户。
  • 更倾向于使用高级授权 API 而不是低级 API。
  • 通常情况下,通过独立权限来强制执行授权;通过组成员资格授予权限。
相关文章
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
159 45
|
4月前
|
存储 安全 数据安全/隐私保护
解锁Python安全新姿势!AES加密:让你的数据穿上防弹衣,无惧黑客窥探?
【8月更文挑战第1天】在数字化时代,确保数据安全至关重要。AES(高级加密标准)作为一种强大的对称密钥加密算法,能有效保护数据免遭非法获取。AES支持128/192/256位密钥,通过多轮复杂的加密过程提高安全性。在Python中,利用`pycryptodome`库可轻松实现AES加密:生成密钥、定义IV,使用CBC模式进行加密与解密。需要注意的是,要妥善管理密钥并确保每次加密使用不同的IV。掌握AES加密技术,为数据安全提供坚实保障。
209 2
|
1月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
54 2
|
3月前
|
存储 安全 数据安全/隐私保护
安全升级!Python AES加密实战,为你的代码加上一层神秘保护罩
【9月更文挑战第12天】在软件开发中,数据安全至关重要。本文将深入探讨如何使用Python中的AES加密技术保护代码免受非法访问和篡改。AES(高级加密标准)因其高效性和灵活性,已成为全球最广泛使用的对称加密算法之一。通过实战演练,我们将展示如何利用pycryptodome库实现AES加密,包括生成密钥、初始化向量(IV)、加密和解密文本数据等步骤。此外,还将介绍密钥管理和IV随机性等安全注意事项。通过本文的学习,你将掌握使用AES加密保护敏感数据的方法,为代码增添坚实的安全屏障。
153 8
|
3月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
140 5
|
3月前
|
存储 安全 算法
显微镜下的安全战!Python加密解密技术,透视数字世界的每一个安全细节
【9月更文挑战第7天】在数字世界中,数据安全至关重要。Python加密解密技术如同显微镜下的精密工具,确保信息的私密性和完整性。以大型医疗机构为例,通过AES和RSA算法的结合,既能高效加密大量医疗数据,又能安全传输密钥,防止数据泄露。以下是使用Python的`pycryptodome`库实现AES加密和RSA密钥交换的简化示例。此方案不仅提高了数据安全性,还为数字世界的每个细节提供了坚实保障,引领我们迈向更安全的未来。
42 1
|
4月前
|
存储 安全 算法
显微镜下的安全战!Python加密解密技术,透视数字世界的每一个安全细节
【8月更文挑战第3天】在数字世界中,数据安全至关重要。以一家处理大量敏感医疗信息的医疗机构为例,采用Python实现的AES和RSA加密技术成为了守护数据安全的强大工具。AES因其高效性和安全性被用于加密大量数据,而RSA则保证了AES密钥的安全传输。通过使用Python的`pycryptodome`库,可以轻松实现这一加密流程。此案例不仅展示了如何有效保护敏感信息,还强调了在数据加密和密钥管理过程中需要注意的关键点,为构建更安全的数字环境提供了参考。
45 10
|
4月前
|
JSON 安全 数据安全/隐私保护
Python安全新篇章:OAuth与JWT携手,开启认证与授权的新时代
【8月更文挑战第6天】随着互联网应用的发展,安全认证与授权变得至关重要。本文介绍OAuth与JWT两种关键技术,并展示如何结合它们构建安全系统。OAuth允许用户授权第三方应用访问特定信息,无需分享登录凭证。JWT是一种自包含的信息传输格式,用于安全地传递信息。通过OAuth认证用户并获取JWT,可以验证用户身份并保护数据安全,为用户提供可靠的身份验证体验。
54 6
|
4月前
|
存储 安全 Python
[python]使用标准库logging实现多进程安全的日志模块
[python]使用标准库logging实现多进程安全的日志模块
|
4月前
|
存储 安全 数据安全/隐私保护
安全升级!Python AES加密实战,为你的代码加上一层神秘保护罩
【8月更文挑战第2天】数据安全至关重要,AES加密作为对称加密的标准之一,因其高效性与灵活性被广泛采用。本文通过实战演示Python中AES的应用,使用pycryptodome库进行安装及加密操作。示例代码展示了生成随机密钥与初始化向量(IV)、对数据进行加密及解密的过程。注意事项包括密钥管理和IV的随机性,以及加密模式的选择。掌握AES加密能有效保护敏感数据,确保信息安全无虞。
142 6