返回 登录
3

Python编码二三事

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

前两天改一个自己刚入学的时候写的python小工具,发现编码解码真是一个头疼却有不得不面对的问题。

一个小工具如果是自己用,写的很粗犷能达到预期目的就行。但是如果给别人用甚至更多人用,就不得不考虑代码的健壮了,不仅仅要预想运行的不同环境,也要考虑不符合预期的输入应该怎么处理。

0x01

从文件或者数据库读取输入后,在对内容进行处理前(如正则匹配),要先对输入进行一次规范化。我发现这是我经常疏忽的问题,结果就是在我的机器上可以跑,而给别人用的时候总会出问题。

一个数据交互不大的程序,可以考虑直接读写文件txt/csv/xls等,再大一点SQLite也不错。
从文件读取的内容的编码和文件是一致的,这时候如果要取出来的字符串进行正则匹配或者去数据库匹配结果,编码就很重要了。

可以考虑使用chardet模块先对字符串编码格式化,再进行其他处理。ab是从两种不同的文件中读取到的字符串,cd是程序中定义的字符串,下图可以看到chardect对他们的编码的识别。

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

大多数资料中提到这种情况会随文件也就是第二行声明的utf8而编码(事实上确实如果在头部不申明编码,这样进行赋值程序将会报错)。然而测试发现即使文件申明用gbk编码,值为汉字的变量的编码格式仍然是utf8,这可能和操作系统有关,没有继续研究这个点,因为既然识别出来了,可以用chardet.detect()很方便的解出来。因此只要在操作字符串之前加上

1
data=data.decode(chardet.detect(data)[‘encoding’])
这时候字符串被转换成ascii格式,这种格式可以使用encode函数转换成想要的编码就行了。

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

1
MySQLdb.connect(host=”,user=”,passwd=”,db=’test’,charset=”utf8”)
这样设置一致读出来的数据直接处理一般没出什么问题,然而养成好习惯还是可以用chardet先格式化一次避免出现问题。

0x02

剩下聊一些其他不符合预期的输入或者操作导致的问题的解决吧。

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

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

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

The last,wish us to have a good job .

评论