我有多個腳本正在導出相同的界面,並且它們在絕緣範圍內使用execfile()執行。使用已實現的權限規則共享插件資源
事情是,我希望他們共享一些資源,以便每個新腳本不必從頭開始重新加載它們,從而失去啓動速度並使用不必要的RAM數量。
腳本實際上比下面的例子更好地封裝和防止惡意插件,這是我開始遇到的問題。
問題是,我想創建一個資源的腳本能夠用數據填充它,刪除數據或刪除資源,並且當然可以訪問它的數據。
但是其他腳本不應該能夠改變他人的腳本資源,只需要閱讀它。我想確保新安裝的插件不會通過濫用共享資源干擾已加載和正在運行的插件。
例子:
class SharedResources:
# Here should be a shared resource manager that I tried to write
# but got stuck. That's why I ask this long and convoluted question!
# Some beginning:
def __init__ (self, owner):
self.owner = owner
def __call__ (self):
# Here we should return some object that will do
# required stuff. Read more for details.
pass
class plugin (dict):
def __init__ (self, filename):
dict.__init__(self)
# Here some checks and filling with secure versions of __builtins__ etc.
# ...
self["__name__"] = "__main__"
self["__file__"] = filename
# Add a shared resources manager to this plugin
self["SharedResources"] = SharedResources(filename)
# And then:
execfile(filename, self, self)
# Expose the plug-in interface to outside world:
def __getattr__ (self, a):
return self[a]
def __setattr__ (self, a, v):
self[a] = v
def __delattr__ (self, a):
del self[a]
# Note: I didn't use self.__dict__ because this makes encapsulation easier.
# In future I won't use object itself at all but separate dict to do it. For now let it be
----------------------------------------
# An example of two scripts that would use shared resource and be run with plugins["name"] = plugin("<filename>"):
# Presented code is same in both scripts, what comes after will be different.
def loadSomeResource():
# Do it here...
return loadedresource
# Then Load this resource if it's not already loaded in shared resources, if it isn't then add loaded resource to shared resources:
shr = SharedResources() # This would be an instance allowing access to shared resources
if not shr.has_key("Default Resources"):
shr.create("Default Resources")
if not shr["Default Resources"].has_key("SomeResource"):
shr["Default Resources"].add("SomeResource", loadSomeResource())
resource = shr["Default Resources"]["SomeResource"]
# And then we use normally resource variable that can be any object.
# Here I Used category "Default Resources" to add and/or retrieve a resource named "SomeResource".
# I want more categories so that plugins that deal with audio aren't mixed with plug-ins that deal with video for instance. But this is not strictly needed.
# Here comes code specific for each plug-in that will use shared resource named "SomeResource" from category "Default Resources".
...
# And end of plugin script!
----------------------------------------
# And then, in main program we load plug-ins:
import os
plugins = {} # Here we store all loaded plugins
for x in os.listdir("plugins"):
plugins[x] = plugin(x)
讓我們說,我們的兩個腳本存儲在plugins目錄下,並且使用加載到內存中的一些WAVE文件兩者。 首先加載的插件將加載WAVE並將其放入RAM中。 另一個插件將能夠訪問已經加載的WAVE,但不能替換或刪除它,從而搞亂了其他插件。
現在,我希望每個資源都擁有所有者,插件腳本的某個ID或文件名,並且該資源只能由其所有者寫入。
沒有調整或解決方法應該使其他插件訪問第一個。
我幾乎做到了,然後被卡住了,我的腦袋裏扎滿了實施時做的事情,但只是部分的概念。 這吃了我,所以我不能再集中精力了。任何建議都比歡迎!
添加:
這是我現在使用沒有任何安全包括:
# Dict that will hold a category of resources (should implement some security):
class ResourceCategory (dict):
def __getattr__ (self, i): return self[i]
def __setattr__ (self, i, v): self[i] = v
def __delattr__ (self, i): del self[i]
SharedResources = {} # Resource pool
class ResourceManager:
def __init__ (self, owner):
self.owner = owner
def add (self, category, name, value):
if not SharedResources.has_key(category):
SharedResources[category] = ResourceCategory()
SharedResources[category][name] = value
def get (self, category, name):
return SharedResources[category][name]
def rem (self, category, name=None):
if name==None: del SharedResources[category]
else: del SharedResources[category][name]
def __call__ (self, category):
if not SharedResources.has_key(category):
SharedResources[category] = ResourceCategory()
return SharedResources[category]
__getattr__ = __getitem__ = __call__
# When securing, this must not be left as this, it is unsecure, can provide a way back to SharedResources pool:
has_category = has_key = SharedResources.has_key
現在插件膠囊:
#-----------------------------------
# Get a category we want. (Using __call__()) Note: If a category doesn't exist, it is created automatically.
AudioResource = SharedResources("Audio")
# Use an MP3 resource (let say a bytestring):
if not AudioResource.has_key("Beep"):
f = open("./sounds/beep.mp3", "rb")
Audio.Beep = f.read()
f.close()
# Take a reference out for fast access and nicer look:
beep = Audio.Beep # BTW, immutables doesn't propagate as references by themselves, doesn't they? A copy will be returned, so the RAM space usage will increase instead. Immutables shall be wrapped in a composed data type.
:插件腳本的
class plugin(dict):
def __init__ (self, path, owner):
dict.__init__()
self["__name__"] = "__main__"
# etc. etc.
# And when adding resource manager to the plugin, register it with this plugin as an owner
self["SharedResources"] = ResourceManager(owner)
# ...
execfile(path, self, self)
# ...
例
這很好,但正如我所說的,在這裏搞亂資源太容易了。
我想要一個ResourceManager()的實例來負責誰返回什麼版本的存儲數據。
你相信插件的作者不是惡意的嗎?如果你不能相信作者,那麼已經證明,對eval/exec/execfile進行安全處理是不可能的。看到這裏:http://programmers.stackexchange.com/a/191628和/或谷歌「python exec untrusted」。如果您相信插件作者不想嘗試繞過沙箱,那麼您可能會想出一個系統,以防止人們意外地破壞共享資源和/或執行任意操作。 –
我不信任他們,但我可以忽略人們對自己的計算機做什麼。至於共享,我會在將所有新插件提供給插件管理器從服務器安裝之前檢查它們。而且,不,不可能製造完全安全的沙箱。已經存在rexec模塊,儘可能安全,但它不再被開發,現在被認爲是不安全的。但是概念是可以的,並且可以改進以確保完全安全。 – Dalen
在禁止插件編寫者訪問可能影響用戶數據等的模塊並給予他/她的受限制版本之後,您可以監視執行是否存在任何內存或CPU濫用,並且您可以檢查源代碼以查看是否存在是任何後向調用來訪問主要作用域,你不能通過限制來控制。例如,你可以簡單地禁止課堂創作。但是,不,現在這不是必要的。這取決於應用程序的普及程度。但是,由於某些人需要它,我相信它會被使用。 – Dalen