基于Python AST實(shí)現(xiàn)代碼安全檢測(cè)功能
在某些場(chǎng)景下(在線代碼執(zhí)行平臺(tái)、腳本上傳平臺(tái)、自動(dòng)任務(wù)系統(tǒng)等),我們必須限制用戶代碼中危險(xiǎn)模塊(如 os、sys、socket)以及危險(xiǎn)函數(shù)(如 eval、exec)的使用,否則會(huì)帶來(lái)安全風(fēng)險(xiǎn)。
本文介紹一種 基于 Python AST(抽象語(yǔ)法樹(shù)) 的代碼安全檢查方案,并給出完整示例代碼,適用于實(shí)際生產(chǎn)環(huán)境。
一、為什么使用 AST
常見(jiàn)的字符串匹配方式容易被繞過(guò),例如:
e = ev
b = al
(e + b)("print(123)")
而 AST 解析后,所有語(yǔ)句都會(huì)被解析成結(jié)構(gòu)化節(jié)點(diǎn),從根本上杜絕字符串拼接繞過(guò)的可能性。
二、完整檢測(cè)代碼
下面是完整的 AST 檢測(cè)類 CheckFun:
import ast
class CheckFun(ast.NodeVisitor):
def __init__(self):
super().__init__()
self.ban_moudel = [
"os",
"sys",
"socket",
"multiprocessing",
"requests",
]
self.ban_func = ["exec", "eval"]
self.allow = True
self.res = []
def visit_Import(self, node):
# 禁止導(dǎo)入模塊
for item in node.names:
if item.name in self.ban_moudel:
self.allow = False
self.res.append("不允許導(dǎo)入 %s 包" % item.name)
def visit_Assign(self, node):
# 禁止賦值后調(diào)用危險(xiǎn)函數(shù),如 b = eval
try:
if node.value.id in self.ban_func:
self.allow = False
self.res.append("賦值右側(cè)不允許出現(xiàn) %s" % node.value.id)
except:
pass
def visit_Call(self, node):
# 禁止直接調(diào)用 eval、exec
try:
if isinstance(node.func, ast.Name):
if node.func.id in self.ban_func:
self.allow = False
self.res.append("不允許調(diào)用 %s" % node.func.id)
except:
pass
def visit_ImportFrom(self, node):
# 禁止 from xxx import xx
if node.module in self.ban_moudel:
self.allow = False
self.res.append("不允許導(dǎo)入 %s 包" % node.module)
def test_function(fn_str):
root_node = ast.parse(fn_str)
ckf = CheckFun()
ckf.visit(root_node)
if ckf.allow:
print("allow")
else:
print("unallow")
for item in ckf.res:
print(item)
三、測(cè)試示例
示例一:包含危險(xiǎn)模塊和危險(xiǎn)函數(shù)的代碼
func2 = """
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
b=eval
b(123)
eval(321)
def aaaaaa(text):
import sx
import sys
print(1)
return re.search(r"\d+", text).group(0)
"""
檢測(cè)執(zhí)行:
test_function(func2)
輸出示例:
e = ev
b = al
(e + b)("print(123)")
四、從文件讀取并檢測(cè)
如果需要從外部文件讀取用戶代碼并檢測(cè),可以這樣寫:
with open('./tmp/' + args[1], 'r') as f:
root_node = ast.parse(f.read())
ckf = CheckFun()
ckf.visit(root_node)
if ckf.allow:
print("allow")
else:
print("unallow")
五、實(shí)際應(yīng)用場(chǎng)景
該方式非常適合:
- 在線代碼執(zhí)行平臺(tái)
- WebIDE / 教程平臺(tái)
- 自動(dòng) Python 任務(wù)系統(tǒng)
- 安全沙箱
- 禁止用戶訪問(wèn)系統(tǒng)資源的場(chǎng)景
因?yàn)?AST 是結(jié)構(gòu)化的,無(wú)法通過(guò)字符串拼接繞過(guò),是目前最可靠的靜態(tài)檢測(cè)方式之一。
到此這篇關(guān)于基于Python AST實(shí)現(xiàn)代碼安全檢測(cè)功能的文章就介紹到這了,更多相關(guān)Python代碼檢測(cè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python自動(dòng)調(diào)整PPT文本框內(nèi)容防止溢出的代碼實(shí)現(xiàn)
在自動(dòng)化處理PPT時(shí),文本框內(nèi)容溢出是一個(gè)常見(jiàn)問(wèn)題,本文將分享一個(gè)Python腳本,通過(guò)計(jì)算文本框容量自動(dòng)截?cái)辔谋静⑻砑邮÷蕴?hào),確保內(nèi)容適配文本框尺寸,代碼基于python-pptx庫(kù),適用于批量處理PPT模板,需要的朋友可以參考下2025-04-04
實(shí)例講解Python中浮點(diǎn)型的基本內(nèi)容
在本文里小編給大家整理了關(guān)于Python中浮點(diǎn)型的基本知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們學(xué)習(xí)下。2019-02-02
Python實(shí)現(xiàn)EM算法實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Python實(shí)現(xiàn)EM算法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
詳解python 破解網(wǎng)站反爬蟲(chóng)的兩種簡(jiǎn)單方法
這篇文章主要介紹了詳解python 破解網(wǎng)站反爬蟲(chóng)的兩種簡(jiǎn)單方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Python對(duì)列表中的各項(xiàng)進(jìn)行關(guān)聯(lián)詳解
這篇文章主要給大家介紹了關(guān)于Python對(duì)列表中各項(xiàng)進(jìn)行關(guān)聯(lián)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08
Python的type()函數(shù)用法小結(jié)(最新推薦)
在本文中,深入探討了type()函數(shù)的用法,提供了詳細(xì)的示例代碼,并討論了其在Python編程中的實(shí)際應(yīng)用,通過(guò)學(xué)習(xí)如何正確使用type()函數(shù),可以更好地掌握Python編程,并寫出更可靠的代碼,需要的朋友可以參考下2024-07-07

