简体   繁体   English

Django urlsafe base64解密与解密

[英]Django urlsafe base64 decoding with decryption

I'm writing my own captcha system for user registration. 我正在为用户注册编写自己的验证码系统。 So I need to create a suitable URL for receiving generated captcha pictures. 所以我需要创建一个合适的URL来接收生成的验证码图片。 Generation looks like this: 一代看起来像这样:

_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)

But then I'm trying to receive this key via GET request in the view function, it fails on urlsafe_b64decode() with "character mapping must return integer, None or unicode" error: 但后来我试图通过视图函数中的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()

I found that on the output of urlsafe_b64encode there is an str, but GET request returns a unicode object (nevertheless it's a right string). 我发现在urlsafe_b64encode的输出上有一个str,但是GET请求返回一个unicode对象(不过它是一个正确的字符串)。 Str() didn't help (it returns decode error deep inside django), and if I use key. Str()没有帮助(它在django内部返回解码错误),如果我使用密钥。 repr it works, but decryptor doesn't work with an error "Input strings must be a multiple of 16 in length". repr它工作,但解密器不能使用错误“输入字符串必须是16的倍数”。 Inside a test file all this construction works perfectly, I can't understand, what's wrong? 在测试文件里面所有这些结构都很完美,我无法理解,有什么不对?

The problem is that b64decode quite explicitly can only take bytes (a string), not unicode. 问题是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

Since you know that your data only contains ASCII data (that's what base64encode will return), it should be safe to encode your unicode code points as ASCII or UTF-8 bytes, those bytes will be equivalent to the ASCII you expected. 由于您知道您的数据仅包含ASCII数据(这将是base64encode将返回的数据),因此将您的unicode代码点编码为ASCII或UTF-8字节应该是安全的,这些字节将等于您期望的ASCII。

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

I solved the problem! 我解决了这个问题!

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

But still I don't understand, why it didn't work first time. 但我仍然不明白,为什么它第一次没用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM