这个 eval() 是可破解的吗?
Is this eval() hackable?
我想做一个函数装饰器,在执行实际函数之前,它会用它的变量做一些动作。我想以 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
我的目标。
但是这个函数将在不安全的环境中使用:它将成为 web 应用程序内部函数的速率限制装饰器,因此 you
和 me
变量与它们一样不安全来吧
这 eval()
是否可以被黑客入侵,例如格式化服务器?我有点不认为它被黑了,因为 locals()
本身不是 eval
,而是被视为不可调用的对象(在这种情况下为 str
)。
有什么黑客想法吗?
更新:
- 任何人都可以调用装饰函数。
- 装饰函数的参数可以是任何东西。
*keys
参数只能由代码作者填写
它的预期用途例如:
@ratelimit('some_custom_id_func(["by-username", username])').at('5/15s')
def login(username, password):
...
UPD[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)
输入已清理?
UPD[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")
我能给你的最佳答案是“我不知道”。我什么也想不出来,但有很多人在破坏东西方面比我聪明得多。我讨厌 eval
,并且认为每次出现的 eval 都是一个等待发生的安全漏洞。你应该不惜一切代价避免它。
如果是我,我会写:
def login_logger(x, y):
Do whatever you want here safely
@ratelimit(login_logger)
def login(x, y): ...
让您的 @ratelimit
调用一个日志函数,该函数采用与它包装的函数完全相同的参数。
我想做一个函数装饰器,在执行实际函数之前,它会用它的变量做一些动作。我想以 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
我的目标。
但是这个函数将在不安全的环境中使用:它将成为 web 应用程序内部函数的速率限制装饰器,因此 you
和 me
变量与它们一样不安全来吧
这 eval()
是否可以被黑客入侵,例如格式化服务器?我有点不认为它被黑了,因为 locals()
本身不是 eval
,而是被视为不可调用的对象(在这种情况下为 str
)。
有什么黑客想法吗?
更新:
- 任何人都可以调用装饰函数。
- 装饰函数的参数可以是任何东西。
*keys
参数只能由代码作者填写
它的预期用途例如:
@ratelimit('some_custom_id_func(["by-username", username])').at('5/15s')
def login(username, password):
...
UPD[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)
输入已清理?
UPD[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")
我能给你的最佳答案是“我不知道”。我什么也想不出来,但有很多人在破坏东西方面比我聪明得多。我讨厌 eval
,并且认为每次出现的 eval 都是一个等待发生的安全漏洞。你应该不惜一切代价避免它。
如果是我,我会写:
def login_logger(x, y):
Do whatever you want here safely
@ratelimit(login_logger)
def login(x, y): ...
让您的 @ratelimit
调用一个日志函数,该函数采用与它包装的函数完全相同的参数。