python Django urlsafe base64 解码和解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2229827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-04 00:07:23  来源:igfitidea点击:

Django urlsafe base64 decoding with decryption

pythondjangoencryptionencodingbase64

提问by Enchantner

I'm writing my own captcha system for user registration. So I need to create a suitable URL for receiving generated captcha pictures. Generation looks like this:

我正在为用户注册编写自己的验证码系统。所以我需要创建一个合适的 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)

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). Str() didn't help (it returns decode error deep inside django), and if I use key.reprit works, but decryptor doesn't work with an error "Input strings must be a multiple of 16 in length". Inside a test file all this construction works perfectly, I can't understand, what's wrong?

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

回答by Jeffrey Harris

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"

回答by Enchantner

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.

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