«Taint» в Перле
Спасибо провидению, в своё время мне удалось несколько лет попрограммировать на Перле. Язык (заслуженно) ругают, но там есть много интересных вещей, которые не грех бы перенести и в другие языки.
Например, хорошей вещью, на мой взгляд, является «taint» («загрязнение») — это специальная метка на переменной, что в ней лежат недоверенные данные, смешивание доверенных и недоверенных данных приводит к «загрязнению» результата. Недоверенными данными является весь ввод — то, что пришло со входного потока, прочитано из файлов и так далее, доверенными — то, что произвела сама программа. Например:
my $a = "hello"; # доверенные данные
my $b = <>; # «загрязённые» (строка, прочитанная из входного потока)
$a .= $b; # данные в переменной $a стали «грязными»
«Грязные» данные (если включен соответствующий режим), при попадании в операции, где они могут представлять угрозу для безопасности (например, пользовательский ввод напрямую попадает в функцию языка для удаления файла), генерируют специальное сообщение.
Вот, например, что будет если я добавлю в конец предыдущего кода вызов unlink (эта функция удаляет файл в Перле) с переменной «a», в качестве аргумента:
Insecure dependency in unlink while running with -T switch at sample.pl line 6, <> line 1
Причём выполнение программы прервётся в этом месте.
«Грязные» данные можно отчистить, например, пропустив их через регулярное выражение (предполагается, что в этом случае вы проверяете их на корректность и выбираете только то, что безопасно для вашей программы), за подробностями отсылаю в документацию, она простая и понятная, даже если вы плохо знаете английский.
Было бы полезно иметь такой же механизм в ПХП — это помогло бы свести многие уязвимости к нулю, например, внедрение скриптов в код ХТМЛ или СКуЭл-уязвимости.
Справедливости ради, «taint» есть не только в Перле, насколько я знаю, этот же механизм используется в Руби и одно время был реализован в ДжаваСкрипте.
Забавно. Но как-то не очень красиво (не расширяемо, точнее не видно как расширить на свои функции).
Для подобных вещей, кстати, когда-то была придумана «венгерская нотация».
У всех «грязных» переменных используется спецпрефикс. Присвоение грязной к чистой видно на кодревью.
PS: а устранять SQL-инъекции надо биндами. Всё остальное- изврат. Про html не знаю- вебом мало занимаюсь, а форумами- так вообще никогда
PPS: ctrl+enter не работает ;)
Вот ведь как люди без нормальной статической типизации мучаются :)
Комментарий для alxt.moikrug.ru:
Можно «запачкать» расширяемые значения специальным вызовом, если это необходимо (вообще, данные должны автоматически «пачкаться»).
Разве она для этого была придумана? Вот уж вряд ли :) Спецпрефикс — это такой же «ручной» способ, как и всё остальное.
Не спорю.
Я знаю, лениво чинить :)
Комментарий для roman.yankovsky.me:
А чем она тут поможет?
Комментарий для Евгения Степанищева:
Ну как это чем? Сделайте «грязные» данные отдельным типом и компилятор не позволит передать «грязные» данные в методы, которым нужны данные «чистые». Напишите функцию (любую, а не только регэксп), преобразующую «грязный» тип в «чистый». А перегрузка операторов позволит вам взять в свои руки полный контроль над взаимодействием «грязных» данных с «чистыми».
В языке «Парсер 3» таинтинг вшит прямо в язык и является развитием Перловской идеи — http://www.parser.ru/docs/lang/tainting.htm. «Грязные» куски могут быть частью чистых данных (язык сохраняется при конкатенациях строк), а сами преобразования данных происходят в тот момент, когда результат вываливается во внешний мир (браузер, sql-сервер, фалы и т. п.) прозрачно для программиста.
Естественно, есть поддержка ручной работы с загрязнением/очисткой данных — http://www.parser.ru/docs/lang/opuntainttaint.htm
Комментарий для roman.yankovsky.me:
Это просто чуть больше автоматизации, чем «ручной» способ и всё. Данные не «загрязняться» автоматически, если к чистым присоединить «грязные», для разных типов данных (числа, строки) нужны разные «грязные» типы. В общем, не изящно и не спасает от ошибок.
Комментарий для Олег Волчков (http://unhandled-exception…:
Ах да, совсем забыл про него. Язык настолько ужасен своим синтаксисом, что из памяти совершенно пропал.
Комментарий для Евгения Степанищева:
Это просто частная не расширяемая попытка реализовать в языке с динамической типизацией то, что статическая типизация позволяет «из коробки» :)
Это было так до изобретения дженериков. Если говорить о современных мейнстримных языках, то тип нужен ровно один. Что-то вроде «class Taint<T>», в котором будет спрятана вся логика и который можно будет использовать и с числами, и со строками, и с чем угодно.
Комментарий для roman.yankovsky.me:
Статическая типизация это не позволяет сделать, ни «из коробки», ни ещё как-то. Заводить отдельные типы для «грязных» данных — совсем не выход. Это позволяет только пометить данные, но не позволяет автоматически «загрязнять» чистые типы.
Как тут дженерики помогут-то? Мне было бы интересно, если бы вы рассказали.
Пусть даже как-то помогут (у меня маленький опыт их использования), я правда не вижу, почему способ с дженериками лучше, чем способ с taint. И уж тем более не понимаю о каких «мучениях» идёт речь. Способ Перла в разы проще и к ошибкам не ведёт, не говоря уже о том, что ему не меньше десятка лет и у него большая практика использования.
Комментарий для Евгения Степанищева:
А не надо их автоматически «загрязнять». Это вы в коде должны указать, где «чистые» данные, а где «грязные». Статическая типизация хороша как раз тем, что позволяет убедиться в корректности работы с типами на этапе компиляции, а не когда у вас на продакшене unlink упадет.
Я говорю лишь о том, что ради частного случая обработки данных пришлось добавлять в язык новую сущность. Что будем делать, если регэкспа не достаточно для контроля «чистоты»? Внутри такого дженерика можно держать совершенно произвольную процедуру валидации. А вот что мне сможет предложить перловый taint? Вызывать дополнительную проверку для уже «очищенных» данных?
Комментарий для roman.yankovsky.me:
Как это, интересно? Предположим, у меня есть путь, я его присваиваю переменной, это чистые данных, я в них уверен, к пути надо что-то добавить (конкатенировать две строки), что чистыми данными не является. Результат должен быть грязным.
Как будто в этом есть что-то новое. В Си# есть Nullable, например.
Нет. Проверять данные как вздумается, если мы считаем, что отчистили их добела, помечать их как чистые. Всё как обычно.
Комментарий для roman.yankovsky.me:
Применение регулярки к данным само по себе их не очищает. Вот пример из документации:
http://pastebin.com/jWws7mHj
Интересная штука. Для PHP можно вот этим пользоваться http://php.net/manual/en/intro.taint.php. Иногда показывает косяки.
Комментарий для Александр Макаров:
К сожалению, очень слабое подобие :(
Комментарий для Евгения Степанищева:
Давайте, чтоб тут много слов не разводить, попробуем сделать так. Вы мне дадите какой-то простой пример кода на перле (предельно простой, чтоб много времени не тратить), а я попробую то же самое сделать на языке со статической типизацией. Тогда без лишних слов моя идея станет понятна.
Комментарий для roman.yankovsky.me:
Так давайте с малого начнём. Пример в статье:
http://pastebin.com/Mii3hNks
Диагностирую статическую типизацию головного мозга. Это просто классика: человек, привыкший к статической типизации, любую методологию из динамической воспринимает как некое извращение, потому что в статической делается иначе. И тут бесполезно что-либо доказывать — стена непонимания и неприятия.
Комментарий для Евгения Степанищева:
Шрифты выглядят плохо. Но возможно у меня под Windows неправильный DjVu Sans.
А почему вы пишете «СКуЭл», а не «ЭсКуЭл»?
В руби ничего подобного нет, если что :)
Комментарий для Андрей:
Вы заблуждаетесь: http://ruby-doc.com/docs/ProgrammingRuby/html/taint.html#S2
Ой, спасибо. Ни разу не встречал практического использования.
Комментарий для dionys.moikrug.ru:
А откуда он у тебя под виндой и зачем?
Комментарий для Леша:
Потому что буква «С» так и читается — «Эс», зачем повторяться?
Комментарий для Евгения Степанищева:
У меня есть софт, портированный с Linux. Вероятно, какой-нибудь дистрибутив притащил шрифт с собой.
Комментарий для Евгения Степанищева:
А буква «К» читается «Ка». Иными словами, слово либо является аббревиатурой с начала и до конца, либо с начала и до конца не является.
Должно быть, надо думать так: «Текст вашего комментария, не ЭйчТиМЭл.» Это вполне безумно, по-моему.
Комментарий для Леша:
Ой, это уже 300 раз обсудили и обсосали у меня в комментариях. Ещё раз не интересно.
Комментарий для dionys.moikrug.ru:
Ну блин, не знаю что и делать. На винде уродский дежавю, на линуксе — Требушет. Винды, конечно, больше, чем Линуксов, придётся пожертвовать, по всей видимости.
Комментарий для dionys.moikrug.ru:
А Segoe UI есть?
Комментарий для Евгения Степанищева:
У меня Vista, в ней Segoe UI предустановлен. А почему не указать первым Segoe UI, а потом уже DejaVu?
Комментарий для Евгения Степанищева:
Это выглядит дико, поэтому вопрос возникнет еще триста раз, гарантия 100%.
Комментарий для dionys.moikrug.ru:
Потому и спросил — есть или нету. Поставил Сегое первым.
Комментарий для Леша:
Да пусть возникает, это ещё не значит что я должен каждый раз на него отвечать.
«ПХП, ХТМЛ, СКуЭл» — это конечно все неофициальный жаргон. Кому как удобнее, пускай так и пишет. Главное, чтобы было понятно.
Другое дело — документация. Там нельзя ничего русифицировать.
Комментарий для 100grammist:
Почему это, скажите на милость? Можно и нужно. Устоявшиеся термины нужно писать на русском, новые — вводить стандартно (на русском, в скобках — значение).
Комментарий для Евгения Степанищева:
Ну даже потому, что ХТМЛ выглядит как XTML. Если читать бегло, то уже возможна ошибка в понимании.
ЭсКуЭл, ЭсКуЭль, СКуЭл, СКуЛ, Сиквэл. А потом попробуй найти поиском по тексту упоминания.
А навязывать только один правильный? Ради чего? Чтобы не переключать кодировку?
Все это вносит неразбериху.
Комментарий для 100grammist:
Сто раз это уже обсуждалось. Я не хочу повторяться. Но вкратце напишу.
На русском надо писать по-русски. Каком смысл мешать языки и думать читается ли PHP как «эр-эн-эр» или как «пи-эйч-пи» — непонятно.
Надо убирать из сознания ту херню, которая нам навязал поток нерусифицированной жратвы и шмоток, хлынувшей из-за рубежа в перестройку. До этого всё писали по-русски и никто проблемы в этом не видел.
Комментарий для Евгения Степанищева:
Извините, что отнял время. Наверное я пропустил эти обсуждения.
Вашу позицию понимаю, но у каждого своя правда.
Уже 15 января, а где тут статически типизированная реализация taint ?
Жду же с нетерпением!
(саргазм)
Комментарий для jankkhvej.tumblr.com:
Я думаю, там кода будет на несколько экранов, да и то, только частный случай :)
Комментарий для Евгения Степанищева:
И ведь понимаешь, что так и будет, но всё равно надеешься на чудо. А вдруг?
Комментарий для Евгения Степанищева:
В Django есть auto-escaping, который, судя по описанию, похож на taint в Parser3 (там тоже, насколько я понял, результат taint заключается в авто-эскейпе).
https://code.djangoproject.com/wiki/AutoEscaping
Комментарий для gladilin.livejournal.com:
Так он во всех движках шаблонов есть.
Комментарий для Евгения Степанищева:
По ссылке, которую я дал, описана реализация маркировки «загрязненности» данных с помощью множественного наследования в python. Я не специалист по движкам шаблонов, но мне такое не попадалось...
class escaped:
pass
class escapedstr(str, escaped):
pass
class escapedunicode(unicode, escaped):
pass
def markescaped(s):
if isinstance(s, escaped):
return s
if isinstance(s, str):
return escapedstr(s)
if isinstance(s, unicode):
return escapedunicode(s)
raise ValueError, «’s’ must be str or unicode»
Комментарий для gladilin.livejournal.com:
А, вон оно что. В «Твиге» (пхпешный движок) всё попроще: всё считается «грязным», чтобы вывести «как есть», надо использовать фильтр «raw».
Комментарий для Евгения Степанищева:
Как написано в том же тексте про Django, проблема с «все считается грязным» заключается в том, что есть шанс за-эскейпить дважды — и какая-то отметка, что строку уже эскепили, полезна. Еще одна проблема — если надо решать, что эскепить, а что нет, в контроллере, а не во view. Опять же, хочется возможности еще в контроллере отметить, что вот эта строка (например, содержащая html) — это строка, которую эскепить не надо — и чтобы view эту метку получил.