Python 程序分析工具调研
1.Bandit:构建 AST 并使用插件检查安全问题,最初在 OpenStack 安全项目中开发,后来被重新定位到 PyCQA。主要用于扫描危险函数,支持自定义漏洞测试和扩展插件。
识别问题信息:
[main] INFO profile include tests: None
[main] INFO profile exclude tests: None
[main] INFO cli include tests: None
[main] INFO cli exclude tests: None
[main] INFO running on Python 3.11.3
Run started:2023-08-03 03:09:58.766531
Test results:
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/learn/http/http_request.py:14:11
13
14 response = requests.get('https://www.imooc.com')
15 content = str(response.content, encoding='utf-8') # ==> 打印具体内容
--------------------------------------------------
>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: '123456'
Severity: Low Confidence: Medium
CWE: CWE-259 (https://cwe.mitre.org/data/definitions/259.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b105_hardcoded_password_string.html
Location: ./HelloPython/src/com/python/learn/learn1_for_if.py:18:11
17 account = 'qiyue'
18 password = '123456'
19
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/__init__.py:25:13
24 upload_url = uri + "/put/ts/js/data/" + tenantId
25 result = request.post(upload_url, headers={"Content-Type": "application/json"}, json=data)
26 print(result.text)
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/__init__.py:31:11
30 def get_num(start_num, end_num):
31 return random.randrange(start_num, end_num) + random.randrange(0, 9) * 0.1
32
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/__init__.py:31:50
30 def get_num(start_num, end_num):
31 return random.randrange(start_num, end_num) + random.randrange(0, 9) * 0.1
32
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/__init__.py:38:13
37 paths = [browsePath]
38 result = request.post(query_url, headers={"Content-Type": "application/json"}, json=paths)
39 print(result.text)
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/__init__.py:55:38
54 ljdl_old_value = get_path_value(eq_uri + "/zljblz/ljydl")[0].get("v").__int__()
55 ljdl_end_value = ljdl_old_value + random.randrange(1, 9) * 10
56 ljydl = get_num(ljdl_old_value, ljdl_end_value) # 累计电量
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/data_demo.py:25:13
24 upload_url = uri + "/put/ts/js/data/" + tenantId
25 result = request.post(upload_url, headers={"Content-Type": "application/json"}, json=data)
26 print(result.text)
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/data_demo.py:31:11
30 def get_num(start_num, end_num):
31 return random.randrange(start_num, end_num) + round(random.randrange(0, 9) * 0.1,1)
32
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/data_demo.py:31:56
30 def get_num(start_num, end_num):
31 return random.randrange(start_num, end_num) + round(random.randrange(0, 9) * 0.1,1)
32
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/data_demo.py:38:13
37 paths = [browsePath]
38 result = request.post(query_url, headers={"Content-Type": "application/json"}, json=paths)
39 print(result.text)
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/write_data.py:24:13
23 upload_url = uri + "/put/ts/js/data/" + tenantId
24 result = request.post(upload_url, headers={"Content-Type": "application/json"}, json=data)
25 print(result.text)
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/write_data.py:30:11
29 def get_num(start_num, end_num):
30 return random.randrange(start_num, end_num) + round(random.randrange(0, 9) * 0.1,1)
31
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/write_data.py:30:56
29 def get_num(start_num, end_num):
30 return random.randrange(start_num, end_num) + round(random.randrange(0, 9) * 0.1,1)
31
--------------------------------------------------
>> Issue: [B113:request_without_timeout] Requests call without timeout
Severity: Medium Confidence: Low
CWE: CWE-400 (https://cwe.mitre.org/data/definitions/400.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/plugins/b113_request_without_timeout.html
Location: ./HelloPython/src/com/python/model/write_data.py:37:13
36 paths = [browsePath]
37 result = request.post(query_url, headers={"Content-Type": "application/json"}, json=paths)
38 print(result.text)
--------------------------------------------------
>> Issue: [B311:blacklist] Standard pseudo-random generators are not suitable for security/cryptographic purposes.
Severity: Low Confidence: High
CWE: CWE-330 (https://cwe.mitre.org/data/definitions/330.html)
More Info: https://bandit.readthedocs.io/en/1.7.5/blacklists/blacklist_calls.html#b311-random
Location: ./HelloPython/src/com/python/model/write_data.py:126:43
125 params = [dataInfo(id=eq_uri + "/zljblz/eer", s=0, t=now,
126 v=5 + round(random.randrange(3, 7) * 0.1,1), vtype="F")
127 ]
--------------------------------------------------
Code scanned:
Total lines of code: 392
Total lines skipped (#nosec): 0
Run metrics:
Total issues (by severity):
Undefined: 0
Low: 9
Medium: 7
High: 0
Total issues (by confidence):
Undefined: 0
Low: 7
Medium: 1
High: 8
Files skipped (0):
2.Vulture:同样利用了 ast 模块生成抽象语法树,在遍历时记录已定义和使用的对象名称,最后报告未使用的对象(死代码)。还通过查找 return、break、continue、raise、不满足条件的 if 条件、while 条件来检测不可达的代码。因为只考虑对象名称,没有考虑作用域,因此可能存在漏报,而且隐式调用可能会被误报。
可信度为函数执行的可信度
检测报告:
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/__init__.py:8: unused variable 'edzll_1' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/__init__.py:9: unused variable 'edzll_2' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/__init__.py:10: unused variable 'edzll_3' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/__init__.py:13: unused variable 'nhb' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/data_demo.py:8: unused variable 'edzll_1' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/data_demo.py:9: unused variable 'edzll_2' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/data_demo.py:10: unused variable 'edzll_3' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py:7: unused variable 'edzll_1' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py:8: unused variable 'edzll_2' (60% confidence, 1 line)
/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py:9: unused variable 'edzll_3' (60% confidence, 1 line)
3.Pysa:由 Facebook 开源的 Pyre 是兼容 PEP 484 的 Python 性能类型检查器,可以增量分析大型代码库,能够迅速处理百万级别的代码。Pyre 附带了 Pysa,一个关注安全性的静态分析工具,Pysa 是 Python Static Analyzer 的缩写,Pysa 支持追踪和分析 Python 程序中的数据流(污点分析)。
会递归检索,但程序及依赖需要配置到环境中
并在目录下配置相关的检索配置文件:.pyre_configuration
检测信息报告:
ƛ No cached overrides loaded, computing overrides...
ƛ `google.protobuf.message.Message.ClearField` has 57 overrides, this might slow down the analysis considerably.
ƛ `google.protobuf.message.Message.__init__` has 58 overrides, this might slow down the analysis considerably.
ƛ `object.__eq__` has 82 overrides, this might slow down the analysis considerably.
ƛ `object.__init__` has 754 overrides, this might slow down the analysis considerably.
ƛ `object.__ne__` has 60 overrides, this might slow down the analysis considerably.
ƛ `type.__call__` has 131 overrides, this might slow down the analysis considerably.
ƛ `type.__init__` has 448 overrides, this might slow down the analysis considerably.
ƛ `type.__new__` has 75 overrides, this might slow down the analysis considerably.
[
{
"line": 12,
"column": 18,
"stop_line": 12,
"stop_column": 35,
"path": "views.py",
"code": 5001,
"name": "Possible RCE:",
"description":
"Possible RCE: [5001]: User specified data may reach a code execution sink",
"long_description":
"Possible RCE: [5001]: User specified data may reach a code execution sink",
"concise_description":
"Possible RCE: [5001]: User specified data may reach a code execution sink",
"inference": null,
"define": "views.operate_on_twos"
}
]
4*.PyCG :PyCG 使用静态分析生成 Python 代码的调用图。它有效地支持
- 高阶函数
- 扭曲的类继承方案
- 自动发现导入的模块以进行进一步分析
- 嵌套定义
输出信息为类之间的依赖和嵌套关系:
{
"...src.com.python.model": [
"datetime.datetime.now",
"<builtin>.print",
"...src.com.python.model.set_eq_data",
"...src.com.python.model.get_eq_data_info",
"time.sleep"
],
"...src.com.python.model.dataInfo": [],
"...src.com.python.model.uplod_ts_data": [
"<builtin>.print",
"requests.post"
],
"requests.post": [],
".print": [],
"...src.com.python.model.get_num": [
"random.randrange"
],
"random.randrange": [],
"...src.com.python.model.get_path_value": [
"<builtin>.print",
"requests.post",
"requests.post.json.get",
"requests.post.json"
],
"requests.post.json": [],
"requests.post.json.get": [],
"...src.com.python.model.get_eq_data_info": [
"...src.com.python.model.get_path_value",
"<builtin>.round",
"<builtin>.print",
"random.randrange",
"...src.com.python.model.get_num"
],
".round": [],
"...src.com.python.model.set_eq_data": [
"<builtin>.print",
"...src.com.python.model.uplod_ts_data",
"...src.com.python.model.dataInfo",
"time.time"
],
"time.time": [],
"datetime.datetime.now": [],
"time.sleep": [],
"...src.com.python.model.data_demo": [
"datetime.datetime.now",
"<builtin>.print",
"...src.com.python.model.data_demo.get_eq_data_info",
"time.sleep",
"...src.com.python.model.data_demo.set_eq_data"
],
"...src.com.python.model.data_demo.dataInfo": [],
"...src.com.python.model.data_demo.uplod_ts_data": [
"<builtin>.print",
"requests.post"
],
"...src.com.python.model.data_demo.get_num": [
"<builtin>.round",
"random.randrange"
],
"...src.com.python.model.data_demo.get_path_value": [
"<builtin>.print",
"requests.post",
"requests.post.json.get",
"requests.post.json"
],
"...src.com.python.model.data_demo.get_eq_data_info": [
"<builtin>.round",
"<builtin>.print",
"...src.com.python.model.data_demo.get_path_value",
"...src.com.python.model.data_demo.get_num"
],
"...src.com.python.model.data_demo.set_eq_data": [
"time.time",
"...src.com.python.model.data_demo.uplod_ts_data",
"<builtin>.print",
"...src.com.python.model.data_demo.get_num",
"...src.com.python.model.data_demo.dataInfo"
],
"...src.com.python.model.write_data": [
"<builtin>.round",
"<builtin>.print",
"...src.com.python.model.write_data.dataInfo",
"random.randrange",
"...src.com.python.model.write_data.uplod_ts_data"
],
"...src.com.python.model.write_data.dataInfo": [],
"...src.com.python.model.write_data.uplod_ts_data": [
"<builtin>.print",
"requests.post"
],
"...src.com.python.model.write_data.get_num": [
"<builtin>.round",
"random.randrange"
],
"...src.com.python.model.write_data.get_path_value": [
"<builtin>.print",
"requests.post",
"requests.post.json.get",
"requests.post.json"
],
"...src.com.python.model.write_data.get_eq_data_info": [
"<builtin>.round",
"<builtin>.print",
"...src.com.python.model.write_data.get_path_value",
"...src.com.python.model.write_data.get_num"
],
"...src.com.python.model.write_data.set_eq_data": [
"time.time",
"<builtin>.print",
"...src.com.python.model.write_data.dataInfo",
"...src.com.python.model.write_data.get_num",
"...src.com.python.model.write_data.uplod_ts_data"
]
}
静态代码分析工具:
5.pytype
Pytype 检查并推断 Python 代码的类型 - 无需类型注释。Pytype 可以:
- Lint 纯 Python 代码,标记常见错误,例如拼写错误的属性名称、不正确的函数调用等等,甚至跨文件边界。
- 强制执行用户提供的类型注释。虽然注释对于 pytype 来说是可选的,但它会检查并应用它们。
- 在独立文件(“ pyi 文件”)中生成类型注释,可以使用提供的merge-pyi工具将其合并回 Python 源 。
Pytype是一个静态分析器;它不执行它所运行的代码。
Google 的数千个项目都依赖 pytype 来保持其 Python 代码类型正确且无错误。
Computing dependencies
Analyzing 1 sources with 0 local dependencies
ninja: Entering directory `.pytype'
[1/1] check com.python.model.write_data
FAILED: /Users/dingzhenying/project/pythonProject/HelloPython/.pytype/pyi/com/python/model/write_data.pyi
/Users/dingzhenying/project/pythonProject/HelloPython/myenv/bin/python3.8 -m pytype.single --imports_info /Users/dingzhenying/project/pythonProject/HelloPython/.pytype/imports/com.python.model.write_data.imports --module-name com.python.model.write_data --platform darwin -V 3.8 -o /Users/dingzhenying/project/pythonProject/HelloPython/.pytype/pyi/com/python/model/write_data.pyi --analyze-annotated --enable-cached-property --nofail --quick /Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py
File "/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py", line 22, in <module>: Invalid type annotation '<instance of Callable>' for data [invalid-annotation]
Not a type
File "/Users/dingzhenying/project/pythonProject/HelloPython/src/com/python/model/write_data.py", line 30, in get_num: Function random.randrange was called with the wrong arguments [wrong-arg-types]
Expected: (start: int, ...)
Actually passed: (start: float, ...)
Called from (traceback):
line 54, in get_eq_data_info
For more details, see https://google.github.io/pytype/errors.html
ninja: build stopped: subcommand failed.
Leaving directory '.pytype'
6、mypy
最早的官方推出的mypy是由Python之父Guido van Rossum亲自开发,被各种主流编辑器所集成(如PyCharm, Emacs, Sublime Text, VS Code等),用户基础和文档经验都很丰富。
(myenv) iMonster-PC:HelloPython dingzhenying$ mypy src/com/python/model/write_data.py
src/com/python/model/__init__.py:5: error: Library stubs not installed for "requests" [import]
src/com/python/model/__init__.py:23: error: Function "com.python.model.dataInfo" is not valid as a type [valid-type]
src/com/python/model/__init__.py:23: note: Perhaps you need "Callable[...]" or a callback protocol?
src/com/python/model/write_data.py:4: error: Library stubs not installed for "requests" [import]
src/com/python/model/write_data.py:4: note: Hint: "python3 -m pip install types-requests"
src/com/python/model/write_data.py:4: note: (or run "mypy --install-types" to install all missing stub packages)
src/com/python/model/write_data.py:4: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
src/com/python/model/write_data.py:22: error: Function "com.python.model.write_data.DataInfo" is not valid as a type [valid-type]
src/com/python/model/write_data.py:22: note: Perhaps you need "Callable[...]" or a callback protocol?
Found 4 errors in 2 files (checked 1 source file)