我希望创建一个函数装饰器,在执行实际函数之前,可以对其变量执行某些操作。我想提供这些操作作为eval()
字符串。变量是函数的参数。让我举个例子:
from functools import wraps
from inspect import getcallargs
def safeornot(*keys):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# get dict of arguments passed to the function
func_args = getcallargs(func, *args, **kwargs)
# now these are made locally visible as normal variables inside the eval function
_keys = []
for key in keys:
_key = eval(key, globals(), func_args)
_keys.append(_key)
print(_keys)
return func(*args, **kwargs)
return wrapper
return decorator
@safeornot('you + " " + __name__', 'you + " " + me')
def you_and_me(you, me):
print("you and me")
you_and_me("1", "2")
将会显然地打印出:
['1 __main__', '1 2']
you and me
我瞄准的目标是IT技术相关内容。
但是这个函数将用于一个不安全的环境:它将成为Web应用程序内部函数的速率限制装饰器,因此you
和me
变量就像它们所代表的一样不安全。
eval()
函数是否可以被攻击,例如格式化服务器?我不太能看到它被黑客攻击了,因为locals()
没有被调用且被视为不可调用对象(在此例中为str
)。
有任何黑客想法吗?
更新:
- 任何人都可以调用装饰过的函数。
- 装饰过的函数参数可以是任何内容。
*keys
参数只能由代码作者填写。
它的预期用途如下:
@ratelimit('some_custom_id_func(["by-username", username])').at('5/15s')
def login(username, password):
...
更新[2]:
如果:
# get dict of arguments passed to the function
func_args = getcallargs(func, *args, **kwargs)
# THE CHANGE IS HERE!
for func_arg_key in func_args.keys():
func_args[func_arg_key] = str(func_args[func_arg_key])
# NOW INPUT IS SANITIZED (KINDA)?
# now these are made locally visible as normal variables inside the eval function
_keys = []
for key in keys:
_key = eval(key, globals(), func_args)
_keys.append(_key)
print(_keys)
输入进行了净化处理吗?
更新 [3]
想象一下,我们摆脱了eval()
。这会让它更安全吗?如果是这样,为什么?
def ratelimit(*keys):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
# get dict of arguments passed to the function
func_args = getcallargs(func, *args, **kwargs)
for key in keys:
print(key(func_args))
return func(*args, **kwargs)
return wrapper
return decorator
@ratelimit(lambda d: d['you'] + " and " + d['me'], lambda d: d['me'] + " or " + d['you'])
def you_and_me(you, me):
print("you and me")
you_and_me("1", "2")
globals()
吗?使eval
更安全的一件事是不提供任何全局变量:https://www.programiz.com/python-programming/methods/built-in/eval - cadolphsglobals()
。虽然我没有尝试过,但没有理由不相信。不过我已经将其设置为可选项,并默认传入一个空字典。 - winwinstr.format()
或string.Template.substitute
。 - VPfB