from string import Formatter
from collections import Mapping
class MagicFormatMapping(Mapping):
"""This class implements a dummy wrapper to fix a bug in the Python
standard library for string formatting.
See http://bugs.python.org/issue13598 for information about why
this is necessary.
"""
def __init__(self, args, kwargs):
self._args = args
self._kwargs = kwargs
self._last_index = 0
def __getitem__(self, key):
if key == '':
idx = self._last_index
self._last_index += 1
try:
return self._args[idx]
except LookupError:
pass
key = str(idx)
return self._kwargs[key]
def __iter__(self):
return iter(self._kwargs)
def __len__(self):
return len(self._kwargs)
# This is a necessary API but it's undocumented and moved around
# between Python releases
try:
from _string import formatter_field_name_split
except ImportError:
formatter_field_name_split = lambda \
x: x._formatter_field_name_split()
class SafeFormatter(Formatter):
def get_field(self, field_name, args, kwargs):
first, rest = formatter_field_name_split(field_name)
obj = self.get_value(first, args, kwargs)
for is_attr, i in rest:
if is_attr:
obj = safe_getattr(obj, i)
else:
obj = obj[i]
return obj, first
def safe_getattr(obj, attr):
# Expand the logic here. For instance on 2.x you will also need
# to disallow func_globals, on 3.x you will also need to hide
# things like cr_frame and others. So ideally have a list of
# objects that are entirely unsafe to access.
if attr[:1] == '_':
raise AttributeError(attr)
return getattr(obj, attr)
def safe_format(_string, *args, **kwargs):
formatter = SafeFormatter()
kwargs = MagicFormatMapping(args, kwargs)
return formatter.vformat(_string, args, kwargs)
现在,我们就可以使用safe_format方法来替代str.format了:
>>> '{0.__class__}'.format(42)
""
>>> safe_format('{0.__class__}', 42)
Traceback (most recent call last):
File "", line 1, in
AttributeError: __class__
小结:
在本文中,我们对Python引入的一种格式化字符串的新型语法的安全漏洞进行了深入的分析,并提供了相应的安全解决方案,希望对读者能够有所帮助。
分页阅读: 1 2
发表评论