网址中的Django Encrypt主键 [英] Django Encrypt primary key in a url

查看:43
本文介绍了网址中的Django Encrypt主键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我环顾四周,但仍然对如何安全地加密django应用程序的URL中的主ID感到不满意.

I looked around a lot but still not comfortable with how to securely encrypt primary ids in the urls of my django app.

我的网址如下:

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

例如:

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

我想向用户显示以上网址,如下所示:

I want to show the above url to users as follows:

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

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

In my views, I should be able to decode back the primary1_id and primary2_id from the encrypted keys

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

Please I need some guidance over how to deal with it in the best possible way

提前谢谢!

推荐答案

我编写了一个库来帮助您执行此操作: django-encrypted-id .这是一个示例模型:

I have written a library that helps you do this: django-encrypted-id. Here is an example model:

from django.db import models

from encrypted_id.models import EncryptedIDModel


class Foo(EncryptedIDModel):
    text = models.TextField()

通过从EncryptedIDModel继承,您可以将.ekey作为模型实例上的属性.这是它们的外观:

By inheriting from EncryptedIDModel, you get .ekey as a property on your model instances. This is how they will look like:

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

如果您不能从helper基类继承,那么没问题,您可以只使用cryptod_id包中的ekey()函数:

If you can not inherit from the helper base class, no problem, you can just use the ekey() function from encrypted_id package:

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,则默认使用它:

To do the reverse lookup, you have two helpers available. First is provided by EncryptedIDManager, which is used by default if you inherit from EncryptedIDModel, and have not overwritten the .objects:

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

但是有时候您会更喜欢以下形式:

But sometimes you will prefer the form:

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

其工作原理相同,但是它不是引发DoesNotExist,而是引发Http404,因此可以在视图中使用.

Which works the same, but instead of raising DoesNotExist, it raises Http404, so it can be used in views.

您的管理员不是从EncryptedIDManager继承的,可以使用:

You your manager is not inheriting from EncryptedIDManager, you can use:

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带有额外的关键字参数,可以根据需要进行过滤.

encrypted_id.get_object_or_404, as well as EncryptedIDManager.get_by_ekey and EncryptedIDManager.get_by_ekey_or_404 take extra keyword argument, that can be used to filter if you want.

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

If you are curios, the regex used to match the generated ids is:

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

如果您使用的是 smarturls ,则可以使用以下网址格式:

If you are using smarturls, you can use URL pattern like:

"/<ekey:foo>/"

我建议在UUID上使用加密ID,作为UUID有很多值得考虑的问题(tldr:它们在磁盘和RAM上占用的空间更多,并且索引比整数id差),如果您的目标只是使URL不可猜测,那么加密id是一种更好的方法

I recommend this usage of encrypted-id over UUID, as UUIDs have significant issues that should be considered (tldr: they take more space on disk and RAM, and have inferior indexing than integer ids), and if your goal is simply to make URLs non guessable, encrypted id is a superior approach.

如果您对使用的加密感到好奇:我正在使用pycrypto库中的AES,并正在使用AES.CBC中的SECRET_KEY作为密码(SECRET_KEY [:24])和IV(SECRET_KEY [-16:]).模式.通常,建议不要使用静态IV,但是CBC可以弥补使用静态IV带来的一些问题.您问的静态IV的问题是什么:如果对纯文本"abc"和"abe"进行了加密,则前两个字节将是相同的.现在这对我们来说并不构成严重问题,因为我加密的纯文本在有效负载的开头使用了CRC32,因此即使您具有ID(11、11),攻击者也不能说它们都以相同的第一个字符开头

If you are curious about the encryption used: I am using AES, from pycrypto library, and am using SECRET_KEY for password (SECRET_KEY[:24]) and IV (SECRET_KEY[-16:]), in the AES.CBC mode. In general it is recommended not to have static IV, but CBC offsets some of the problems with having static IV. What is the the issue with static IV you ask: if plain text "abc" and "abe" are encrypted, the first two bytes would be same. Now this does not present a serious problem for us, as the plain text that I am encrypting uses CRC32 in the beginning of payload, so even if you have ids, 1, 11, an attacker can not say they both start with same first character.

该库还支持由于某种原因而必须循环SECRET_KEY的情况,因此,使用较旧的SECRET_KEY加密的URL仍可以在更改后解码(只要您将旧版本存储在SECRET_KEYS设置中).为了解密该库,将尝试每个秘密密钥,并比较数据的CRC32以确保(肯定是这样),我们已经正确解密了.

The library also supports the scenario that you have to cycle SECRET_KEY due to some reason, so URLs encrypted with older SECRET_KEY can still be decoded after you have changed it (as long as you store old versions in SECRET_KEYS setting). In order to decrypt the library tries each secret key, and compares the CRC32 of data to know for sure (as sure as things get in such things), that we have decrypted properly.

请随时在 encrypted-id github repo 中提出问题您遇到任何问题,我们将竭诚为您服务.该库支持python 2.7和3.5,以及django团队支持的所有django版本.

Do feel free to raise an issue in encrypted-id github repo, if you face any issues, I would be happy to help. The library supports both python 2.7 and 3.5, as well as it all versions of django that django team supports.

这篇关于网址中的Django Encrypt主键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆