Почему нет функции, аналога для f-string?
На самом деле, f-string можно представить в виде простой функции format() в которую вместе со стркой-шаблоном передаются словари locals() и globals(). Но так делать точно не стОит! И прежде всего, в целях безопасности.
О чём это я?
Допустим, у нас есть шаблон:
template = 'Hello {username}!'
И потом мы просто форматируем строку по этому шаблону псевдо-функцией fstring() (представим, что она существует)
username = user.get_name()
greeting = fstring(template)
Выглядит всё логично, но тут есть скрытая угроза безопасности!
Допустим, у нас некий веб сервис и мы предоставляем юзеру возможность сформировать себе любой шаблон какой ему нравится, после чего форматируем строку по аналогии с f-string.
В чем же тут может быть опасность? А в том, что в отличие от простого метода строки format() этот способ имеет возможность вшить в шаблон любой экспрешн! То есть, мы позволяем юзеру написать любой код и самолично его выполняем на сервере!
Если юзер действует по правилам, то напишет что-то вроде:
"Hey what's up, {username}?)))"
А если попадётся слишком догадливый, знающий о некомпетентности программиста и, допустим, что логика на Django+Python, то он может написать что-то такое:
"{__import__('django.conf', fromlist=['conf']).settings.SECRET_KEY}"
И алгоритм выдаст ему секретный ключ сайта!
Можно и более кардинально:
"{__import__('django.contrib.auth', fromlist=['auth']).get_user_model().objects.filter(email='[email protected]').update(is_superuser=True)}"
Этот однострочный экспрешн делает юзера суперадмином!
Теперь можно заходить на сайт как админ и делать там что хочешь)))
Поэтому, только программист может формировать подобные строки. То есть нельзя в f-sting передать неизвестно что из переменной.
Никогда не давайте юзерам слишком много свободы.
Если требуется подобный функционал, лучше использовать простой метод format() или класс 'string.Template'. А ещё лучше, выдавать список готовых вариантов 🤓
PS. Для тех кто хочет поэкспериментировать с f-string функцией, можете попробовать этот вариант
def fstring(fstring_text):
return eval(f'f"{fstring_text}"', locals(), globals())
Пример:
>>> template = 'Hello, {username}!'
>>> username = 'Max'
>>> fstring(template)
Hello, Max!
Теперь попробуйте придумать хитрые способы взлома)
#tricks