Django、Python 和链接加密

5 投票
2 回答
6417 浏览
提问于 2025-04-15 19:27

我需要设置一种加密方式,用来生成用户特定的链接。用户点击这个链接后,在另一个页面上,相关的链接会用加密的字符串解密,然后返回结果。

为此,我需要一个加密函数,这个函数需要输入一个数字(或者字符串),这个数字是我选择的项目的主键,和用户账户绑定。同时,它还需要一个种子(seed),然后生成一个加密代码,这个代码会在另一个页面解密。

所以大概是这样的:

my_items_pk = 36 #primary key of an item
seed = "rsdjk324j23423j4j2" #some string for crypting
encrypted_string = encrypt(my_items_pk,seed)
#generates some crypted string such as "dsaj2j213jasas452k41k"
and at another page:
decrypt_input = encrypt(decypt,seed)
print decrypt_input
#gives 36

我希望我的“种子”是某种主要变量(而不是某个类),可以是一个数字或者字符串。

我该如何在Python和Django中实现这个呢?

2 个回答

0

Django现在有一些功能可以做到这一点。你可以查看这个链接:https://docs.djangoproject.com/en/dev/topics/signing/

引用一下那页内容:

“Django提供了一个低级别的API来对值进行签名,还有一个高级别的API来设置和读取签名的cookie,这是在网络应用中最常见的签名用途之一。”

你可能还会发现签名在以下方面很有用:

  • 生成“找回我的账户”链接,发送给那些忘记密码的用户。
  • 确保存储在隐藏表单字段中的数据没有被篡改。
  • 生成一次性秘密链接,让用户临时访问受保护的资源,比如他们已经支付的可下载文件。
9

Python本身并没有内置的加密算法。不过,你可以看看Python加密工具包(PyCrypt)。我只是稍微试过一下,但在Python的文档中提到过加密服务。下面是一个使用PyCrypt通过AES加密字符串的例子:

from Crypto.Cipher import AES
from urllib import quote

# Note that for AES the key length must be either 16, 24, or 32 bytes
encryption_obj = AES.new('abcdefghijklmnop')
plain = "Testing"

# The plaintext must be a multiple of 16 bytes (for AES), so here we pad it
# with spaces if necessary.
mismatch = len(plain) % 16
if mismatch != 0:
  padding = (16 - mismatch) * ' '
  plain += padding

ciph = encryption_obj.encrypt(plain)

# Finally, to make the encrypted string safe to use in a URL we quote it
quoted_ciph = quote(ciph)

然后你可以把这个加密后的部分放到你的URL里,可能作为GET请求的一部分。

要解密,只需反向操作;假设encryption_obj是像上面那样创建的,并且你已经获取了URL中相关的部分,下面的代码可以做到:

from urllib import unquote

# We've already created encryption_object as shown above

ciph = unquote(quoted_ciph)
plain = encryption_obj.decrypt(ciph)

你也可以考虑另一种方法:一个简单的办法是对主键进行哈希(如果你愿意,可以加点盐),然后把哈希值和主键存储在数据库里。给用户提供哈希值作为他们链接的一部分,当他们返回并提供哈希值时,查找对应的主键并返回相应的对象。(如果你想走这条路,可以看看内置库hashlib。)

举个例子,你可以在models.py中定义类似这样的内容:

class Pk_lookup(models.Model):
  # since we're using sha256, set the max_length of this field to 32
  hashed_pk = models.CharField(primary_key=True, max_length=32)
  key = models.IntegerField()

然后你可以在视图中生成哈希,使用类似下面的代码:

import hashlib
import Pk_lookup

hash = hashlib.sha256()
hash.update(str(pk)) # pk has been defined previously
pk_digest = hash.digest()

lookup = Pk_lookup(hashed_pk=pk_digest,key=pk)
lookup.save()

注意,你也需要对这个版本进行引用;如果你愿意,可以使用hexdigest()代替digest(这样生成的字符串就不需要引用了),但你需要把字段的长度调整为64。

撰写回答