Django urlsafe base64 解码与解密

发布于 2024-08-20 14:40:42 字数 1042 浏览 5 评论 0原文

我正在编写自己的验证码系统用于用户注册。所以我需要创建一个合适的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 内部深处的解码错误),如果我使用 key.repr 它可以工作,但解密器不能工作,并出现错误“输入字符串必须是多个长度为16”。 在测试文件中,所有这些构造都完美地工作,我不明白,出了什么问题?

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:

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

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.repr it 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

死开点丶别碍眼 2024-08-27 14:40:42

问题是 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"

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

>>> base64.urlsafe_b64decode(uenc.encode("ascii"))
"Hi, I'm a string"
落花随流水 2024-08-27 14:40:42

我解决了问题!

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文