Skip to main content
 首页 » 编程设计

python之Django 在 url 中加密主键

2024年11月01日24zfyouxi

我环顾四周,但仍然不了解如何在我的 Django 应用程序的 URL 中安全地加密主要 ID。

我的网址如下:

http://www.example.com/primary1_id/primary2_id/testing/ 

例如:

http://www.example.com/3/7/testing/ 

我想向用户显示上面的 url,如下所示:

http://www.example.com/623477897ghfjs23879/7829yfgweh/testing/ #encrypted key instead of primary id 

在我看来,我应该能够从加密 key 中解码回 primary1_id 和 primary2_id

我需要一些关于如何以最好的方式处理它的指导

提前致谢!

请您参考如下方法:

我写了一个库来帮助你做到这一点:django-encrypted-id .这是一个示例模型:

from django.db import models 
 
from encrypted_id.models import EncryptedIDModel 
 
 
class Foo(EncryptedIDModel): 
    text = models.TextField() 

通过从 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..' 

你可以做反向查找:

In [5]: from encrypted_id import decode 
 
In [6]: decode(f.ekey) 
Out[6]: 1 

如果你不能从辅助基类继承,没问题,你可以使用 encrypted_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..' 

要进行反向查找,您可以使用两个助手。第一个由 EncryptedIDManager 提供,如果您从 EncryptedIDModel 继承并且没有覆盖 .objects,则默认使用它:

In [10]: Foo.objects.get_by_ekey(f.ekey) 
Out[10]: <Foo: Foo object> 

但有时你会更喜欢这种形式:

In [11]: Foo.objects.get_by_ekey_or_404(f.ekey) 
Out[11]: <Foo: Foo object> 

它的工作原理相同,但不是引发 DoesNotExist,而是引发 Http404,因此它可以在 View 中使用。

您的管理器没有继承自 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> 

encrypted_id.get_object_or_404,以及 EncryptedIDManager.get_by_ekey 和 EncryptedIDManager.get_by_ekey_or_404 采用额外的关键字参数,如果需要可用于过滤。

如果你很好奇,用于匹配生成的 ID 的正则表达式是:

"[0-9a-zA-Z-_]+.{0,2}" 

如果您使用 smarturls ,您可以使用 URL 模式,例如:

"/<ekey:foo>/" 

我推荐使用 encrypted-id 而不是 UUID,as UUIDs have significant issues that should be considered (tldr:它们在磁盘和 RAM 上占用更多空间,并且索引比整数 ID 差),如果您的目标只是使 URL 不可猜测,加密 ID 是一种更好的方法。

如果您对使用的加密感到好奇:我正在使用 AES,来自 pycrypto 库,并且在 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 设置中)。为了解密库,会尝试每个 secret key ,并比较数据的 CRC32 以确保(确定事情进入此类事情),我们已经正确解密。

请随时在 encrypted-id github repo 中提出问题,如果您遇到任何问题,我很乐意提供帮助。该库支持 python 2.7 和 3.5,以及 django 团队支持的所有 django 版本。