【问题标题】:Eval safety in python, string pulled from JSONpython中的评估安全性,从JSON中提取的字符串
【发布时间】:2012-10-28 17:52:13
【问题描述】:

我绞尽脑汁想找到一种方法来利用这个设置。我的概念是这样的:我的扭曲服务器接收消息(通过LineReceiver)。消息是 base64 JSON,应该包含一个字典。字典有一个"INSTRUCTION" 键,它指示服务器应该处理什么样的客户端操作。

在程序的这一部分,line 是通过网络接收的 base64 字符串。

def Decode(line):
    return json.loads(base64.b64decode(line))

以及解释(在扭曲的Protocol 对象内)

def lineReceived(self, line):
    instruction = Decode(line)  #dict
    if instruction and "INSTRUCTION" in instruction:
        if instruction["INSTRUCTION"] in ("register", "join", "create", 
         "list", "passturn", "impmove", "warpmove","laserattack",
         "torpattack", "mine", "data", "status"):
            cmdstring = instruction["INSTRUCTION"] + "(self)"
            eval(cmdstring)

为什么我认为它是安全的:

  • 只有当我得到一个纯字符串作为值时,eval 才会运行。
  • JSON 不能打包复杂的对象,只能打包 python 基础。攻击者不应该拥有__str__ 访问我收到的内容的权限,对吧?
  • 我正在使用 eval 来为十几行 if instruction["INSTRUCTION"] == "functionA": functionA(self) 行提供可读性较差但更紧凑的替代品。我只是在运行 eval 以从特定列表中选择一个函数。

这样安全吗?这被认为是可接受的风格或形式吗?由于客户端不可信,这个代码块对于多人游戏是否足够健壮? (验证指令遵循游戏规则是稍后,我想保护我的服务器免受破坏性修补。)

有没有更好的方法来做我正在尝试的事情(我想是远程执行函数)更标准/更安全?

【问题讨论】:

  • 为什么要对 JSON 进行 base64 编码?这只会扩大有效载荷的大小,而不会增加可转移性..
  • 不管怎样,这是一个糟糕的协议。这是您设计的东西还是您必须应对的东西?如果您对此有任何控制权,则应考虑使用 AMP amp-protocol.net 或类似的东西。

标签: python security networking eval twisted


【解决方案1】:

你最好使用getattr()

if instruction and "INSTRUCTION" in instruction:
    instr_callable = getattr(self, 'do_' + instruction['INSTRUCTION'], None)
    if instr_callable is not None:
        instr_callable()

其中do_是指令名的前缀,以确保通过该方法只调用允许的方法。

如果您的指令函数位于全局命名空间中,请改用globals(),并将其用作映射:

if instruction and "INSTRUCTION" in instruction:
    instr_callable = globals().get('do_' + instruction['INSTRUCTION'], None)
    if instr_callable is not None:
        instr_callable(self)

但是,您最好将这些可调用对象放在显式映射中:

instr_callables = dict(
    register=register,
    join=join,
    ...
)

if instruction and "INSTRUCTION" in instruction:
    instr_callable = instr_callables.get(instruction['INSTRUCTION'], None)
    if instr_callable is not None:
        instr_callable(self)

eval() 很少需要在 python 命名空间中查找任意对象。

【讨论】:

  • 呸,打败我。不过,我称我的为“instruction_name/instruction_fn”,以防止破坏callable(不是任何人都使用过它。)
  • @DSM:更好地保持 SO 众所周知的鼻子清洁,而不是阴影可调用。
  • 可以使用'do_' 之类的前缀:getattr(self, 'do_'+...)。如果函数是全局的;可以使用模块对象代替self,无需重复名称
猜你喜欢
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2018-04-12
  • 1970-01-01
相关资源
最近更新 更多