我该如何避免格式化字符串漏洞?

8

是否可以使用Python的str.format(key=value)语法仅替换特定的键。

考虑以下示例:

my_string = 'Hello {name}, my name is {my_name}!'

my_string = my_string.format(name='minerz029')

该函数返回

KeyError: 'my_name'

有没有办法实现这个?
3个回答

17

你可以使用双花括号来转义my_name,就像这样:

>>> my_string = 'Hello {name}, my name is {{my_name}}!'
>>> my_string.format(name='minerz029')
'Hello minerz029, my name is {my_name}!'

如您所见,格式化一次后,外部的{}将被删除,{{my_name}}变成了{my_name}。如果您之后想要再次格式化my_name,只需像这样再次进行格式化即可。

>>> my_string = 'Hello {name}, my name is {{my_name}}!'
>>> my_string = my_string.format(name='minerz029')
>>> my_string
'Hello minerz029, my name is {my_name}!'
>>> my_string.format(my_name='minerz029')
'Hello minerz029, my name is minerz029!'

8
Python3.2+有format_map函数,可以帮助您实现此功能。
>>> class D(dict):
...     def __missing__(self, k):return '{'+k+'}'
... 
>>> my_string = 'Hello {name}, my name is {my_name}!'
>>> my_string.format_map(D(name='minerz029'))
'Hello minerz029, my name is {my_name}!'
>>> _.format_map(D(my_name='minerz029'))
'Hello minerz029, my name is minerz029!'

现在不需要额外添加{},只有您提供给D的键将被替换。

正如@steveha指出的那样,如果您使用较旧版本的Python3,仍然可以使用以下方式:

my_string.format(**D(name='minerz029'))

我刚刚测试了一下,你不需要使用 str.format_map(d);你可以使用 str.format(**d),它也能正常工作。然而,.format_map() 更高效,因为它不需要复制字典。 - steveha
@steveha,在Python2中仍会将其转换为“dict”,但对于Python3来说,它可以正常工作。 - John La Rooy
没错...我在Python3中测试过了。Python2没有.format_map()。我只是想说,在有.format_map()的Python版本中,你实际上可以使用str.format(**d),它也能正常工作。抱歉没有详细说明。 - steveha
在这里使用定义了__missing__dict子类是一种非常优雅的解决方案。 - kindall

0
我使用的一个比较简单的解决方法是:
my_string = 'Hello {name}, my name is {my_name}!'

to_replace = {
    "search_for" : "replace_with",
    "name" : "minerz029",
}

for search_str in to_replace:
    my_string = my_string.replace('{' + search_str + '}', to_replace[search_str])

print(my_string)

这个可以很容易地通过在to_replace字典中添加更多的键来扩展,即使搜索字符串不存在也不会报错。它可能可以改进以提供更多.format()的功能,但对我来说已经足够了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接