Python中编码二三事

0x00

在审计的时候比较喜欢注意对字符串操作的编码、解码和截断这些操作,因为这里有可能导致对抗SQLi和XSS等安全函数失效。

前两天改一个自己刚入学的时候写的python小工具,发现编码解码真是一个头疼却有不得不面对的问题。一个小工具如果是自己用,写的很粗犷能达到预期目的就行。但是如果给别人用甚至更多人用,就不得不考虑代码的健壮性了,不仅仅要预想运行的不同环境,也要考虑不符合预期的输入应该怎么处理。

0x01

从文件或者数据库读取输入后,在对内容进行处理前(如正则匹配),要先对输入进行一次规范化。我发现这是我经常疏忽的问题,结果就是在我的机器上可以跑,而给别人用的时候总会出问题。
一个数据交互不大的程序,可以考虑直接读写文件txt/csv/xls等,再大一点SQLite也不错。

从文件读取出的内容的编码和文件是一致的,这时候如果要取出来的字符串进行正则匹配或者去数据库匹配结果,编码就很重要了。

这里可以使用chardet模块编码转换。文字比较小,ab是从两种不同的文件中读取到的字符串,cd是程序中定义的字符串,下图可以看到chardect对他们的编码的识别。

QQ截图20160901173434

从c和d的编码的区别我们可以发现,变量的值如果是一般字符,变量的编码格式是ascii;如果变量的值是汉字或者其他特殊文字,将随py文件的编码而编码。

QQ截图20160901173402

大多数资料中说是说会随文件也就是第二行声明的utf8而编码。然而测试发现即使文件申明用gbk编码,值为汉字的变量识别出来的编码仍然是utf8。也许和系统有关,这里也没深究,因为既然识别出来了,可以用chardet.detect()很方便的解出来。因此只要在操作字符串之前加上

data=data.decode(chardet.detect(data)['encoding'])

这时候字符串被转换成ascii格式,这种格式可以使用encode函数转换成想要的编码就行了。如下图的转换成GBK再输出。输出的内容用来正则匹配或者二次查询都OK。

QQ截图20160901174710

更多的时候我们会使用SQLite或者MySQL,比如做数据对比或者提取关键信息时,不编码肯定会出问题,MySQL数据存储的时候我一般设置成utf8-general-ci,所以设置数据库连接的时候使用一样的格式。

MySQLdb.connect(host='',user='',passwd='',db='test',charset="utf8")

这样设置一致读出来的数据直接处理一般没出什么问题,然而养成好习惯还是可以用chardet先格式化一次避免出现问题。上面的文本操作只是举一个例子,Py在做数据交互的时候都要注意编码问题。

0x02

剩下聊一些其他不符合预期的输入或者操作导致的问题的解决吧。感触就是方法不分贵贱,最合适的才是最好的。

使用try,然后pass掉出错的数据自然是一个很省力的方案。但常常不是最优的方案,因为这样本来能够处理的数据因为上面的原因而被抛弃掉,如果舍弃数量大或者刚好舍弃掉重要的数据对功能产生很大影响。所以最好还是要找到根源问题所在,上面改的心有些累就是因为有的地方会因为有少量数据会出错不好被直接pass掉而不得不重新选取方法而改大片的代码~

找到问题->查找资料->思考解决方案->解决问题这个链条中,我们常会比较在意的是找第一个和最后一个环节,现在感觉中间的反复资料查找和思考却是最难的。上文提到的程序修改的时候还遇到了很多各种各样的错误,git一些项目中的做法和stackoverflow上的讨论等等总能提供很多思路。

具体做法还是见人见智,找到适合自己的方式就好。Leader Ourren常让我们遇到问题要多自己思考,而不要去依赖别人给出的解决方案。事实上也切身感受到,如果在学习中自己多思考,最后常会发现解决问题的方法上得到的收获远大于问题本身。

The last,wish us to have a good job in the Sep’s hard winter.

Python中编码二三事》上有1条评论

  1. Pingback引用通告: Python中编码二三事-MottoIN

发表评论

电子邮件地址不会被公开。