gmf*_*eak 6 python django primary-key django-urls
我环顾四周,但仍然对如何安全地加密 django 应用程序的 url 中的主 ID 感到不舒服。
我的网址如下:
http://www.example.com/primary1_id/primary2_id/testing/
Run Code Online (Sandbox Code Playgroud)
例如:
http://www.example.com/3/7/testing/
Run Code Online (Sandbox Code Playgroud)
我想向用户显示上述网址,如下所示:
http://www.example.com/623477897ghfjs23879/7829yfgweh/testing/ #encrypted key instead of primary id
Run Code Online (Sandbox Code Playgroud)
在我看来,我应该能够从加密密钥中解码回primary1_id和primary2_id
请我需要一些关于如何以最佳方式处理它的指导
提前致谢!
我编写了一个可以帮助您执行此操作的库:django-encrypted-id。这是一个示例模型:
from django.db import models
from encrypted_id.models import EncryptedIDModel
class Foo(EncryptedIDModel):
text = models.TextField()
Run Code Online (Sandbox Code Playgroud)
通过从 EncryptedIDModel 继承,您可以将 .ekey 作为模型实例的属性。它们看起来是这样的:
In [1]: from tapp.models import Foo
In [2]: f = Foo.objects.create(text="asd")
In [3]: f.id
Out[3]: 1
In [4]: f.ekey
Out[4]: 'bxuZXwM4NdgGauVWR-ueUA..'
Run Code Online (Sandbox Code Playgroud)
您可以进行反向查找:
In [5]: from encrypted_id import decode
In [6]: decode(f.ekey)
Out[6]: 1
Run Code Online (Sandbox Code Playgroud)
如果您不能从辅助基类继承,没问题,您可以使用 crypto_id 包中的 ekey() 函数:
In [7]: from encrypted_id import ekey
In [8]: from django.contrib.auth.models import User
In [9]: ekey(User.objects.get(pk=1))
Out[9]: 'bxuZXwM4NdgGauVWR-ueUA..'
Run Code Online (Sandbox Code Playgroud)
要进行反向查找,您有两个可用的助手。第一个是由 EncryptedIDManager 提供的,如果您继承自 EncryptedIDModel 并且没有覆盖 .objects,则默认使用它:
In [10]: Foo.objects.get_by_ekey(f.ekey)
Out[10]: <Foo: Foo object>
Run Code Online (Sandbox Code Playgroud)
但有时您会更喜欢以下形式:
In [11]: Foo.objects.get_by_ekey_or_404(f.ekey)
Out[11]: <Foo: Foo object>
Run Code Online (Sandbox Code Playgroud)
其工作原理相同,但它不是引发DoesNotExist,而是引发Http404,因此它可以在视图中使用。
您的经理不是继承自 EncryptedIDManager,您可以使用:
In [12]: e = ekey(User.objects.first())
In [13]: e
Out[13]: 'bxuZXwM4NdgGauVWR-ueUA..'
In [14]: get_object_or_404(User, e)
Out[14]: <User: amitu>
Run Code Online (Sandbox Code Playgroud)
cryptod_id.get_object_or_404 以及 EncryptedIDManager.get_by_ekey 和 EncryptedIDManager.get_by_ekey_or_404 采用额外的关键字参数,如果需要,可用于过滤。
如果您好奇的话,用于匹配生成的 id 的正则表达式是:
"[0-9a-zA-Z-_]+.{0,2}"
Run Code Online (Sandbox Code Playgroud)
如果您使用smarturls,您可以使用 URL 模式,例如:
"/<ekey:foo>/"
Run Code Online (Sandbox Code Playgroud)
我建议使用加密 ID 而不是 UUID,因为 UUID 有一些需要考虑的重大问题(tldr:它们在磁盘和 RAM 上占用更多空间,并且索引比整数 ID 差),并且如果您的目标只是创建 URL不可猜测的加密 ID 是一种更好的方法。
如果您对所使用的加密感到好奇:我正在使用 pycrypto 库中的 AES,并在 AES.CBC 模式下使用 SECRET_KEY 作为密码 (SECRET_KEY[:24]) 和 IV (SECRET_KEY[-16:])。一般来说,建议不要使用静态 IV,但 CBC 弥补了静态 IV 带来的一些问题。您问的静态 IV 有什么问题:如果纯文本“abc”和“abe”被加密,则前两个字节将是相同的。现在这对我们来说并不是一个严重的问题,因为我加密的纯文本在有效负载的开头使用 CRC32,所以即使你有 ids、1、11,攻击者也不能说它们都以相同的第一个字符开头。
该库还支持由于某种原因必须循环使用 SECRET_KEY 的情况,因此使用旧 SECRET_KEY 加密的 URL 在更改后仍然可以解码(只要您在 SECRET_KEYS 设置中存储旧版本)。为了解密,库会尝试每个秘密密钥,并比较数据的 CRC32,以确保我们已正确解密(就像事物中的情况一样)。
请随时在crypto-id github repo中提出问题,如果您遇到任何问题,我很乐意提供帮助。该库支持 python 2.7 和 3.5,以及 django 团队支持的所有 django 版本。
| 归档时间: |
|
| 查看次数: |
7707 次 |
| 最近记录: |