我正在用 web.py 构建一个应用程序,但在MySQL中存储加密数据时遇到了一些麻烦。
PyCrypto创建密码文本,看起来像:"x06x7fx81xa0xf4dx00Hxefxd0x18[cx18Zxf8
",打印时显示为" ôdHïÐ[cZø
但是,MySQL将其存储为:???d H??[cZ?
我以下列方式存储它:
query_string = "INSERT INTO %s (%s) VALUES ("%s")" % (table, column, value)
连接到数据库后,我尝试使用" SET character_set_connection=utf8
",但它没有对结果产生任何变化。
我显然错过了一些非常重要的东西。有什么想法吗?
MySQL正在尝试将您的字节字符串存储在字符列中。由于连接字符集为 UTF-8,但字节字符串不表示有效的 UTF-8 序列,因此它会被破坏。
要将原始字节正确导入数据库,您需要:
-
使列成为二进制类型(或通常具有二进制排序规则的字符类型(,以及
-
使用参数化查询将数据导入数据库,而不是将它们内插到查询字符串中,在那里它们可能会与非二进制 (Unicode( 内容混合。
都应该使用参数化查询,因为您现在使用的字符串插值(没有转义(容易受到 SQL 注入的影响。在 web.py 中,这可能看起来像:
query_string= 'INSERT INTO %s (%s) VALUES ($value)' % (table, column)
db.query(query_string, vars= {'value': value})
(假设table
值和column
值已知良好。
这样做也意味着您不必担心美元符号。
另一种方法是使用普通字符串,编码掉非 ASCII 字节。您在当前的解决方法中使用uucode执行此操作,但是base64将是一种更常见的替代方案,在Python(ciphertext.encode('base64')
(中更容易获得。十六进制编码(.encode('hex')
(在哈希的情况下最常见。
我已经想出了一个解决方案。我不确定它有多优雅,但它是我能弄清楚的最好的。
编码:
1( import binascii
2( ciphertext = cipher.encrypt(plaintext)
3( asciitext = binascii.b2a_uu(ciphertext)
4( webpy_workaround = asciitext.replace('$', 'DOLLARSIGN') //if there are dollar signs in the text, webpy will try to use anything afterward, and will complain at you.
5(将webpy_workaround存储到SQL中。
译码:
1( 从 SQL 中检索值
2( asciitext = sql_value.replace('DOLLARSIGN', '$')
3( ciphertext = binascii.a2b_uu(asciitext)
4( plaintext = cipher.decrypt(ciphertext)