python安全tips

Input function

在python2中,通过input输入的内容将作为python代码执行。

1
2
3
4
5
6
7
$ python2
>>> input()
dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> input()
__import__('sys').exit()
$

安全的输入方式是使用raw_input()获取stdin内容,在python3中input已变得跟raw_input相等。

Assert

在python中使用assert语句使用断言,例如使用断言以判断程序是否可以继续执行。

1
2
3
4
def verify_credentials(username, password):
assert username and password, 'Credentials not supplied by caller'

... authenticate possibly null user with null password ...

这样使用并没有什么问题,但是当程序使用python -O 编译为优化的字节码时,会导致asser语句被忽略。

In Python 2.7, -O has the following effect:

  • the byte code extension changes to .pyo
  • sys.flags.optimize gets set to 1
  • debug is False
  • assert don’t get executed

可重复使用整数

1
2
3
4
>>> 999+1 is 1000
False
>>> 1+1 is 2
True

这两个结果看起来有点匪夷所思,但实际上是我们对is有错误的理解。is操作符是在两个对象的标识上工作的,并不能用于比较数值。在python中,万物皆对象,每个对象都有一个唯一标识,可以用id函数来读取。要找出两个变量或两个属性是否都指向同一个对象,可以使用is操作符。

浮点数比较

1
2
>>> 2.2 * 3.0 == 3.3 * 2.0
False

上面的结果是由于固有受限精度导致舍入错误:

1
2
3
4
>>> (2.2 * 3.0).hex()
'0x1.a666666666667p+2'
>>> (3.3 * 2.0).hex()
'0x1.a666666666666p+2'

float > 无穷

在python中,float类型支持无穷大的概念:float(‘infinity’)

1
2
>>> 10**1000000 > float('infinity')
False

因此我们有理由相信,一切都比无穷小,但是一不小心,又翻车了

任意type对象比无穷大

1
2
3
4
>>> float > float('infinity')
True
>>> int > float('infinity')
True

这一车祸现场在python3中被处理,type()不能与float()进行比较。

私有属性

python不支持对象隐藏属性,但是其提供一种使用双下划线__开头的属性隐藏方法。

1
2
3
4
5
6
7
8
9
10
11
12
class Foo:
__N=111111
N =222222
def __init__(self,name):
self.__Name=name

def __f1(self):
print self.__Name
def f2(self):
self.__f1()
def get_private(self):
... return self.__N

定义上面的class

1
2
3
4
5
6
7
8
9
>>> f = Foo('boogle')
>>> f.N
222222
>>> f.__N
AttributeError: Foo instance has no attribute '__N'
>>> f.__f1()
AttributeError: Foo instance has no attribute '__f1'
>>> f.f2()
boogle

从上面的测试来看,使用__开头貌似确实实现了隐藏,而且其也成功在 getattr()/hasattr()中隐藏

1
2
>>> f.has_private()
False

但这种隐藏只是一种语法上的变形,并没有达到真正意义上的隐藏

1
2
>>>print  Foo.__dict__
{'__module__': '__main__', '_Foo__f1': <function __f1 at 0x02D8D0B0>, 'f2': <function f2 at 0x02D8D070>, 'N': 222222, '_Foo__N': 111111, '__doc__': None, '__init__': <function __init__ at 0x02D8D130>}

得到Foo类的所有属性跟函数。
那么有没有办法直接查看这些属性的内容呢?答案是肯定的,我们可以用下划线_加类名加属性名的方法查看其内容(注意类名前是单下划线)

1
2
3
4
>>> f._Foo__N
111111
>>> f.__dict__
{'_Foo__Name': 'boogle'}

另外当对属性进行重新赋值时,这些隐藏的属性也会被显示出来

1
2
3
4
5
>>> f.__N = 333333
>>> f.__N
333333
>>> f.has_private()
True

模块注入

python的模块导入为python注入了活力,其功能强大而复杂,例如通过

os ```可以导入系统命令模块,从而执行系统系统命令。
1
2
3
4

python中模块和包可以通过定义在sys.path列表中的搜索路径找到的文件或目录名导入。搜索路径初始化是一个复杂的过程,它也依赖于Python版本,平台和本地配置。要想对其实施模块注入,就要知道其初始化的搜索路径,从来正确导入。

我们可以运行下面的脚本知道其实际的搜索路径

$ cat myapp.py

#!/usr/bin/python

import sys
import pprint

pprint.pprint(sys.path)

1
2
3
4
5
6
```
$ python -m myapp
['',
'/usr/lib/python3.3/site-packages/pip-7.1.2-py3.3.egg',
'/usr/lib/python3.3/site-packages/setuptools-20.1.1-py3.3.egg',
...]

从上面程序执行结果可以看到,其当前工作目录被自动插入到sys.path中。
那么便可以在sys.path中出现的任意一个我们具有操作权限的目录写入我们要导入的模块,从而进行导入。
两外在沙箱环境中,很有可能会删除
然会我们继续查看,会发现sys下面又一个modules。我们对sys.moudles做一些改动,看看会发生什么

1
2
3
4
5
>>> sys.modules['os']=None
>>> import os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named os

果然如我们所料,将os从 sys.modules 中删掉之后,就不能再引入了。
那么当一个沙箱环境通过这种方式将可能带来危险的模块删除时,我们便可以重新导入

1
2
3
4
>>> import sys
>>> sys.modules['os']='/usr/lib/python2.7/os.py'
>>> import os
>>>

另外如果sys也被禁止导入了呢?那么可以使用execfile()执行相应的代码

1
2
3
4
5
6
7
8
9
>>> execfile('/usr/lib/python2.7/os.py')
>>> system('cat /etc/passwd')
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
>>> getcwd()
'/usr/lib/python2.7'

subprocess shell注入

shell = True时

此时如果命令参数可控,即可进行shell注入

1
s=subprocess.Popen('ls;id', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

shell = False时

subprocess.call([]) 执行的是list拼接起来的命令,如果可控参数在拼接之后使得参数变成了参数选项,则存在命令注入风险

1
2
3
>>> from subprocess import call
>>>
>>> call(['/bin/ls', '/tmp'])

参考链接:
A bite of Python
Python 如何隐藏属性

本文标题:python安全tips

文章作者:boogle

发布时间:2018年11月16日 - 11:16

最后更新:2019年03月07日 - 11:37

原始链接:https://zhengbao.wang/python-安全-tips/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

感觉写的不错,给买个棒棒糖呗