Django urlsafe base64解密与解密

时间:2010-02-09 14:39:17

标签: python django encryption encoding base64

我正在为用户注册编写自己的验证码系统。所以我需要创建一个合适的URL来接收生成的验证码图片。一代看起来像这样:

_cipher = cipher.new(settings.CAPTCHA_SECRET_KEY, cipher.MODE_ECB)
_encrypt_block = lambda block: _cipher.encrypt(block + ' ' * (_cipher.block_size - len(block) % _cipher.block_size)) 
#...
a = (self.rightnum, self.animal_type[1])
serialized = pickle.dumps(a)
encrypted = _encrypt_block(serialized)
safe_url = urlsafe_b64encode(encrypted)

但是后来我试图通过视图函数中的GET请求接收此密钥,它在urlsafe_b64decode()上失败,“字符映射必须返回整数,无或unicode”错误:

def captcha(request):
  try:
    key = request.REQUEST['key']
    decoded = urlsafe_b64decode(key)
    decrypted = _decrypt_block(decoded)
    deserialized = pickle.loads(decrypted)
    return HttpResponse(deserialized)
  except KeyError: 
    return HttpResponseBadRequest()

我发现在urlsafe_b64encode的输出上有一个str,但是GET请求返回一个unicode对象(不过它是一个正确的字符串)。 Str()没有帮助(它在django内部返回解码错误),如果我使用密钥。 repr 它可以工作,但解密器不能处理错误“输入字符串必须是多个16个长度“。 在测试文件中,所有这些构造都完美无缺,我无法理解,出了什么问题?

2 个答案:

答案 0 :(得分:36)

问题是b64decode非常明确地只能占用字节(字符串),而不是unicode。

>>> import base64
>>> test = "Hi, I'm a string"
>>> enc = base64.urlsafe_b64encode(test)
>>> enc
'SGksIEknbSBhIHN0cmluZw=='
>>> uenc = unicode(enc)
>>> base64.urlsafe_b64decode(enc)
"Hi, I'm a string"
>>> base64.urlsafe_b64decode(uenc)
Traceback (most recent call last):
...
TypeError: character mapping must return integer, None or unicode

由于您知道您的数据仅包含ASCII数据(这将是base64encode将返回的数据),因此将您的unicode代码点编码为ASCII或UTF-8字节应该是安全的,这些字节将等于您期望的ASCII。

>>> base64.urlsafe_b64decode(uenc.encode("ascii"))
"Hi, I'm a string"

答案 1 :(得分:3)

我解决了这个问题!

deserialized = pickle.loads(captcha_decrypt(urlsafe_b64decode(key.encode('ascii'))))
return HttpResponse(str(deserialized))

但我仍然不明白,为什么它第一次不起作用。