1

我正在编写一个与流行的数据仓库 SaaS 交互的工具。他们的在线 sql 编辑器将 sql 工作表序列化为 JSON,但 SQL 工作表的主体是使用 pako.js 对 zlib 进行压缩的。我正在尝试从 python 读取和扩充这些 zlib 字符串,但我只能解码包含短的字节串

带有 sql 文本的示例是字母a

bytestring = b'x\xef\xbf\xbdK\x04\x00\x00b\x00b\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
>>> "a"

如果我包含分号a;,则无法解压缩:

bytestring = b'x\xef\xbf\xbdK\xef\xbf\xbd\x06\x00\x00\xef\xbf\xbd\x00\xef\xbf\xbd\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
*** UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 1: invalid start byte

注意:我还尝试使用 'punycode' 解码这些示例,我在 javascript 实现中找到了参考。

我对 zlib 的理解非常有限,但我发现 zlib 字符串的前两个和最后四个字节是页眉/页脚,如果我们使用幻数 -15 运行 zlib 可以修剪。完全有可能有 zlib 幻数可以解压缩这些字符串而无需剥离页眉和页脚,但是当从 -64 循环到 64 时,我无法让任何组合起作用。

我已经通过在线 sql 工作表编辑器的保存和加载功能设置了断点,发现它们正在使用 pako zlib 库pako.deflate(a, {to: 'string'})pako.inflate(b['body'], {to: 'string'}) 并且我可以使用该pako库在浏览器中对 sql 字符串进行充气/放气,但一直无法在 python 中重现相同的结果。

4

2 回答 2

3

我同意这是一个数据损坏问题。 zlib并且pako应该能够在没有任何剥离字段或添加幻数的情况下读取彼此的数据。

为了证明这一点,我放了几个演示脚本,一个pako用于压缩数据,一个zlib用于再次膨胀:

// deflate.js
var pako = require("./pako.js");
console.log(escape(pako.deflate(process.argv[2], {to: "string"})));
# inflate.py
import urllib.parse, zlib, sys
print(zlib.decompress(urllib.parse.unquote_to_bytes(sys.stdin.read())).decode("utf-8"))

使用 . 在命令行上运行它们node deflate.js "Here is some example text" | inflate.py。预期的输出是传递给的参数node deflate.js

值得指出的一件事是pako使用该to: "string"选项时的行为。此选项的文档如下:

to(String) - 如果等于 'string',则结果将是“二进制字符串”(每个字符代码 [0..255])

正是出于这个原因,我escape在上面的 JavaScript 函数中使用。Usingescape确保在 JavaScript 和 Python 之间传递的字符串不包含任何非 ASCII 字符。(请注意,这不起作用encodeURIComponent,因为字符串包含二进制数据。)然后我在 Python 中使用来撤消这种转义。urllib.parse.unquote_to_bytes

如果您可以escapepako浏览器中使用 -deflate 数据,您可能会将其传递给 Python 以再次对其进行充气。

于 2020-04-26T10:31:22.213 回答
2

每个序列\xef\xbf\xbd代表原始数据损坏的一个实例。

在您的第一个示例中,第一个也是唯一\xef\xbf\xbd应该是一个字节,这是 zlib 标头的第二个字节。在第二个示例中,第一个\xef\xbf\xbd应该是 zlib 标头的第二个字节,第二个实例应该是\b4,第三个实例应该是\ff,第四个实例应该是\9b

一路上的某个地方有一些不应该发生的 UTF-8 处理。每次遇到设置了高位的字节时,它都会失败。在这些情况下,它用那个三字节的 UTF-8 序列替换字节U+FFFD,这是用于表示未知字符的“替换”字符。

底线是您的数据已不可挽回地损坏。您需要从那里修复上游发生的任何事情。您是否尝试使用复制和粘贴来获取数据?如果您在黑色菱形中看到一个问号,那就是那个 UTF-8 字符。

于 2020-04-25T16:22:47.073 回答