V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
whoami9894
V2EX  ›  Python

Python2/3 的 base64 对不可见字符编码结果不同

  •  
  •   whoami9894 · 2018-12-12 18:42:21 +08:00 · 3183 次点击
    这是一个创建于 2191 天前的主题,其中的信息可能已经有所发展或是发生改变。

    两个完全相同的.py,分别是 2 和 3:

    
    # py2
    import base64
    
    c = base64.b64decode('U/osUbnY8nSrWz4WPwKSwWPzKq9tOIQ9eCWnN5E+')
    plain = '{"name":"guest","admin":false}'
    res = ''
    for i in range(len(c)):
        res += chr(ord(c[i]) ^ ord(plain[i]))
    need = '{"name":"guest","admin":true}'
    payload = ''
    for i in range(len(need)):
        print ord(need[i]) ^ ord(res[i])
        payload += chr(ord(need[i]) ^ ord(res[i]))
    print payload, len(payload)
    payload = base64.b64encode(payload)
    print payload
    
    
    
    # py3
    import base64
    
    c = base64.b64decode('U/osUbnY8nSrWz4WPwKSwWPzKq9tOIQ9eCWnN5E+')
    plain = '{"name":"guest","admin":false}'
    res = ""
    for i in range(len(c)):
        res += chr(c[i] ^ ord(plain[i]))
    need = '{"name":"guest","admin":true}'
    payload = ""
    for i in range(len(need)):
        print(ord(need[i]) ^ ord(res[i]))
        payload += chr(ord(need[i]) ^ ord(res[i]))
    print(payload, len(payload))
    payload = base64.b64encode(payload.encode("utf-8"))
    print(payload)
    
    

    输出结果,逐字节打印 ascii 码,payload 变量是完全相同的,但编码结果不同

    # py2
    83
    250
    44
    81
    185
    216
    242
    116
    171
    91
    62
    22
    63
    2
    146
    193
    99
    243
    42
    175
    109
    56
    132
    61
    106
    54
    190
    33
    137
    S?Q 关玔 c?痬
    U/osUbnY8nSrWz4WPwKSwWPzKq9tOIQ9aja+IYk=
    
    
    # py3
    83
    250
    44
    81
    185
    216
    242
    116
    171
    91
    62
    22
    63
    2
    146
    193
    99
    243
    42
    175
    109
    56
    132
    61
    106
    54
    190
    33
    137
    Sú,Q¹Øòt«[>■?☻’=j6¾!‰
    b'U8O6LFHCucOYw7J0wqtbPhY/AsKSw4Fjw7Mqwq9tOMKEPWo2wr4hwok='
    

    将两个 base64 字串放到 Python3 中解码:

    >>> b64decode("U/osUbnY8nSrWz4WPwKSwWPzKq9tOIQ9aja+IYk=")
    b'S\xfa,Q\xb9\xd8\xf2t\xab[>\x16?\x02\x92\xc1c\xf3*\xafm8\x84=j6\xbe!\x89'
    
    >>> b64decode("U8O6LFHCucOYw7J0wqtbPhY/AsKSw4Fjw7Mqwq9tOMKEPWo2wr4hwok=")
    b'S\xc3\xba,Q\xc2\xb9\xc3\x98\xc3\xb2t\xc2\xab[>\x16?\x02\xc2\x92\xc3\x81c\xc3\xb3*\xc2\xafm8\xc2\x84=j6\xc2\xbe!\xc2\x89'
    

    对于这种情况应该如何避免

    7 条回复    2018-12-13 03:23:16 +08:00
    chenstack
        1
    chenstack  
       2018-12-12 18:54:14 +08:00   ❤️ 1
    python3 的那部分倒数第二行
    payload = base64.b64encode(payload.encode("utf-8"))
    改成
    payload = base64.b64encode(payload.encode("latin-1"))
    结果就和 python2 的一致了
    jingniao
        2
    jingniao  
       2018-12-12 18:56:53 +08:00 via Android   ❤️ 1
    默认编码?
    whoami9894
        3
    whoami9894  
    OP
       2018-12-12 19:32:37 +08:00
    @chenstack
    确实!是因为 Python2 默认 Latin-1 的缘故吧

    这是一道 PHP 生成流密码题目,我查了一下因为 PHP 默认也是 Latin-1,所以就解释通了,感谢
    atuocn
        4
    atuocn  
       2018-12-12 19:37:32 +08:00   ❤️ 1
    utf8 编码只会在全部字符都在 ascii 码范围内,才和字节码能对上。
    字符串也不能认为用 latin-1 编码就会变成 ascii 字节码。你试试

    '中文'.decode('latin-1')

    如果是新开发,要同时支持 py2, py3,建议统一用 utf8。如果是 py2 升级 py3,要保持旧接口的兼容性,改不了。那用楼主的主要语言环境的语言编码比如 gb2312,或者取系统的编码.
    CharAct3
        5
    CharAct3  
       2018-12-12 20:04:06 +08:00   ❤️ 3
    @whoami9894
    不是的,Python2 中所谓的字符串其实就是 bytes。

    在两段代码中 base64 编码 payload 的时候,传入的 bytes 是不一样的,所以结果不同。

    举个例子,虽然在 Python2 和 Python3 中 '\xef' 看起来是一样的,但是在 Python2 中这就是一个 0xef 的 byte,而在 Python3 中则代表 U+00ef 这个 Unicode 字符,使用 utf-8 编码后就是 b'\xc3\xaf' 这个 bytes。
    可以在 Python3 中试一试:
    '\xef' == '\u00ef'

    想把 U+0080 到 U+00ff 的 Unicode 字符编码为对应的 0x80 到 0xff 的 byte,就要使用 latin-1 编码,这个不受语言的影响。
    whoami9894
        6
    whoami9894  
    OP
       2018-12-12 20:13:36 +08:00
    @atuocn
    @CharAct3

    学到了,感谢!
    hacker
        7
    hacker  
       2018-12-13 03:23:16 +08:00 via iPhone
    建议不要再用 Python 2.x
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3042 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:49 · PVG 18:49 · LAX 02:49 · JFK 05:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.