将来自不受信任来源的信息作为 python 异常消息放置是否安全?
Is it safe to put information from an untrusted source as python exception message?
有没有以下危险的方式?例如,如果有人将此异常打印到 stdout
?
,代码能否执行?
def somefunc(val_from_untrusted_source):
if val_from_untrusted_source == 'something_we_except':
# do something useful
pass
else:
raise RuntimeException('unknown input: {}'.format(val_from_untrusted_source))
据我所知,没有什么危险是不可能发生的。最不愉快的后果:
- (如果 Python 假定为 2)如果
val_from_untrusted_source
不是 ASCII,则 UnicodeEncodeError
将在尝试引发 RuntimeException
时出现
- 如果
val_from_untrusted_source
包含 '\r' 并且有人将此异常写入日志 - 当前日志行的开头可能会被覆盖
永远不要那样!
日志消息旨在通知有关处理的信息,应该安全地传送,以便在出现问题时找到发生的事情的证据。这里没有进行任何控制,所以这里有一些可能的问题:
str(val_from_untrusted_source)
本身可能引发异常,其中 UnicodeEncodeError
用于在 Python 2 中包含非 ASCII 字符的 unicode 字符串,或 UnicodeDecodeError
用于包含非 ASCII 的字节字符串Python 3 中的字符。这还包括特制对象,异常引发 __str__
方法
str(val_from_untrusted_source)
可能是一个很长的字符串。它包括长字节或 unicode 字符串,还包括特制的微小对象:
class DONT:
def __init__(self, size, pattern):
self.pattern = pattern
self.size = size
def __str__(self):
return self.pattern * self.size
它们可能导致日志文件耗尽到磁盘 space
- 可以使用永无止境的
__str__
方法或试图耗尽内存的方法特制对象。想象一下上面 DONT
... 的细微变化
所有这些都是在代码不受控制的更糟糕的用例中可能发生的情况。在更实际的使用场景中,val_from_untrusted_source
可能是一个字符串。在那种情况下,限制其大小并处理 UnicodeError
exception:
就足够了
if val_from_untrusted_source == 'something_we_except':
# do something useful
pass
else:
try:
txt = str(val_from_untrusted_source)
except UnicodeEncodeError: # unicode string on Python 2
txt = val_from_untrusted_source.encode(error = 'replace')
except UnicodeDecodeError: # byte string on Python 3
txt = val_from_untrusted_source.decode(error = 'replace')
except Exception: # quite weird but once we are there...
txt = "object non convertible to string"
if len(text) > 47): # limit length to 50
txt = txt[:47] + '...'
raise RuntimeException('unknown input: {}'.format(txt))
有没有以下危险的方式?例如,如果有人将此异常打印到 stdout
?
def somefunc(val_from_untrusted_source):
if val_from_untrusted_source == 'something_we_except':
# do something useful
pass
else:
raise RuntimeException('unknown input: {}'.format(val_from_untrusted_source))
据我所知,没有什么危险是不可能发生的。最不愉快的后果:
- (如果 Python 假定为 2)如果
val_from_untrusted_source
不是 ASCII,则UnicodeEncodeError
将在尝试引发RuntimeException
时出现
- 如果
val_from_untrusted_source
包含 '\r' 并且有人将此异常写入日志 - 当前日志行的开头可能会被覆盖
永远不要那样!
日志消息旨在通知有关处理的信息,应该安全地传送,以便在出现问题时找到发生的事情的证据。这里没有进行任何控制,所以这里有一些可能的问题:
str(val_from_untrusted_source)
本身可能引发异常,其中UnicodeEncodeError
用于在 Python 2 中包含非 ASCII 字符的 unicode 字符串,或UnicodeDecodeError
用于包含非 ASCII 的字节字符串Python 3 中的字符。这还包括特制对象,异常引发__str__
方法str(val_from_untrusted_source)
可能是一个很长的字符串。它包括长字节或 unicode 字符串,还包括特制的微小对象:class DONT: def __init__(self, size, pattern): self.pattern = pattern self.size = size def __str__(self): return self.pattern * self.size
它们可能导致日志文件耗尽到磁盘 space
- 可以使用永无止境的
__str__
方法或试图耗尽内存的方法特制对象。想象一下上面DONT
... 的细微变化
所有这些都是在代码不受控制的更糟糕的用例中可能发生的情况。在更实际的使用场景中,val_from_untrusted_source
可能是一个字符串。在那种情况下,限制其大小并处理 UnicodeError
exception:
if val_from_untrusted_source == 'something_we_except':
# do something useful
pass
else:
try:
txt = str(val_from_untrusted_source)
except UnicodeEncodeError: # unicode string on Python 2
txt = val_from_untrusted_source.encode(error = 'replace')
except UnicodeDecodeError: # byte string on Python 3
txt = val_from_untrusted_source.decode(error = 'replace')
except Exception: # quite weird but once we are there...
txt = "object non convertible to string"
if len(text) > 47): # limit length to 50
txt = txt[:47] + '...'
raise RuntimeException('unknown input: {}'.format(txt))