«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» есть не только в Перле, насколько я знаю, этот же механизм используется в Руби и одно время был реализован в ДжаваСкрипте.
10 января 2014 12:44

Томин Алексей (alxt.moikrug.ru)
10 января 2014, 13:17

Забавно. Но как-то не очень красиво (не расширяемо, точнее не видно как расширить на свои функции).

Для подобных вещей, кстати, когда-то была придумана "венгерская нотация".
У всех "грязных" переменных используется спецпрефикс. Присвоение грязной к чистой видно на кодревью.

PS: а устранять SQL-инъекции надо биндами. Всё остальное- изврат. Про html не знаю- вебом мало занимаюсь, а форумами- так вообще никогда

PPS: ctrl+enter не работает ;)

Roman Ryaboy (roman.yankovsky.me)
10 января 2014, 13:20

Вот ведь как люди без нормальной статической типизации мучаются :)

Евгений Степанищев (bolknote.ru)
10 января 2014, 13:28, ответ предназначен Томин Алексей (alxt.moikrug.ru):

Забавно. Но как-то не очень красиво (не расширяемо, точнее не видно как расширить на свои функции).
Можно «запачкать» расширяемые значения специальным вызовом, если это необходимо (вообще, данные должны автоматически «пачкаться»).
Для подобных вещей, кстати, когда-то была придумана «венгерская нотация».
У всех «грязных» переменных используется спецпрефикс. Присвоение грязной к чистой видно на кодревью.
Разве она для этого была придумана? Вот уж вряд ли :) Спецпрефикс — это такой же «ручной» способ, как и всё остальное.
а устранять SQL-инъекции надо биндами. Всё остальное — изврат
Не спорю.
PPS: ctrl+enter не работает ;)
Я знаю, лениво чинить :)

Евгений Степанищев (bolknote.ru)
10 января 2014, 13:28, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

Вот ведь как люди без нормальной статической типизации мучаются :)
А чем она тут поможет?

Roman Ryaboy (roman.yankovsky.me)
10 января 2014, 13:33, ответ предназначен Евгений Степанищев (bolknote.ru):

А чем она тут поможет?
Ну как это чем? Сделайте "грязные" данные отдельным типом и компилятор не позволит передать "грязные" данные в методы, которым нужны данные "чистые". Напишите функцию (любую, а не только регэксп), преобразующую "грязный" тип в "чистый". А перегрузка операторов позволит вам взять в свои руки полный контроль над взаимодействием "грязных" данных с "чистыми".

Олег Волчков (http://unhandled-exception… (инкогнито)
10 января 2014, 13:36

В языке «Парсер 3» таинтинг вшит прямо в язык и  является развитием Перловской идеи — http://www.parser.ru/docs/lang/tainting.htm. «Грязные» куски могут быть частью чистых данных (язык сохраняется при конкатенациях строк), а сами преобразования данных происходят в тот момент, когда результат вываливается во внешний мир (браузер, sql-сервер, фалы и т.п.) прозрачно для программиста.

Естественно, есть поддержка ручной работы с загрязнением/очисткой данных — http://www.parser.ru/docs/lang/opuntainttaint.htm

Евгений Степанищев (bolknote.ru)
10 января 2014, 13:47, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

Ну как это чем? Сделайте «грязные» данные отдельным типом и компилятор не позволит передать «грязные» данные в методы, которым нужны данные «чистые».
Это просто чуть больше автоматизации, чем «ручной» способ и всё. Данные не «загрязняться» автоматически, если к чистым присоединить «грязные», для разных типов данных (числа, строки) нужны разные «грязные» типы. В общем, не изящно и не спасает от ошибок.

Евгений Степанищев (bolknote.ru)
10 января 2014, 13:48, ответ предназначен Олегу Волчкову (http://unhandled-exception…

В языке «Парсер 3» таинтинг вшит прямо в язык и является развитием Перловской идеи
Ах да, совсем забыл про него. Язык настолько ужасен своим синтаксисом, что из памяти совершенно пропал.

Roman Ryaboy (roman.yankovsky.me)
10 января 2014, 13:57, ответ предназначен Евгений Степанищев (bolknote.ru):

Это просто чуть больше автоматизации, чем «ручной» способ и всё.
Это просто частная не расширяемая попытка реализовать в языке с динамической типизацией то, что статическая типизация позволяет "из коробки" :)
Данные не «загрязняться» автоматически, если к чистым присоединить «грязные», для разных типов данных (числа, строки) нужны разные «грязные» типы.
Это было так до изобретения дженериков. Если говорить о современных мейнстримных языках, то тип нужен ровно один. Что-то вроде "class Taint<T>", в котором будет спрятана вся логика и который можно будет использовать и с числами, и со строками, и с чем угодно.

Евгений Степанищев (bolknote.ru)
10 января 2014, 14:09, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

Это просто частная не расширяемая попытка реализовать в языке с динамической типизацией то, что статическая типизация позволяет "из коробки" :)
Статическая типизация это не позволяет сделать, ни «из коробки», ни ещё как-то. Заводить отдельные типы для «грязных» данных — совсем не выход. Это позволяет только пометить данные, но не позволяет автоматически «загрязнять» чистые типы.

Как тут дженерики помогут-то? Мне было бы интересно, если бы вы рассказали.

Пусть даже как-то помогут (у меня маленький опыт их использования), я правда не вижу, почему способ с дженериками лучше, чем способ с taint. И уж тем более не понимаю о каких «мучениях» идёт речь. Способ Перла в разы проще и к ошибкам не ведёт, не говоря уже о том, что ему не меньше десятка лет и у него большая практика использования.

Roman Ryaboy (roman.yankovsky.me)
10 января 2014, 14:23, ответ предназначен Евгений Степанищев (bolknote.ru):

Это позволяет только пометить данные, но не позволяет автоматически «загрязнять» чистые типы.
А не надо их автоматически "загрязнять". Это вы в коде должны указать, где "чистые" данные, а где "грязные". Статическая типизация хороша как раз тем, что позволяет убедиться в корректности работы с типами на этапе компиляции, а не когда у вас на продакшене unlink упадет.
Пусть даже как-то помогут (у меня маленький опыт их использования), я правда не вижу, почему способ с дженериками лучше, чем способ с taint. И уж тем более не понимаю о каких «мучениях» идёт речь.
Я говорю лишь о том, что ради частного случая обработки данных пришлось добавлять в язык новую сущность. Что будем делать, если регэкспа не достаточно для контроля "чистоты"? Внутри такого дженерика можно держать совершенно произвольную процедуру валидации. А вот что мне сможет предложить перловый taint? Вызывать дополнительную проверку для уже "очищенных" данных?

Евгений Степанищев (bolknote.ru)
10 января 2014, 14:33, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

А не надо их автоматически «загрязнять». Это вы в коде должны указать, где «чистые» данные, а где «грязные».
Как это, интересно? Предположим, у меня есть путь, я его присваиваю переменной, это чистые данных, я в них уверен, к пути надо что-то добавить (конкатенировать две строки), что чистыми данными не является. Результат должен быть грязным.
Я говорю лишь о том, что ради частного случая обработки данных пришлось добавлять в язык новую сущность.
Как будто в этом есть что-то новое. В Си# есть Nullable, например.
Что будем делать, если регэкспа не достаточно для контроля «чистоты»? Внутри такого дженерика можно держать совершенно произвольную процедуру валидации. А вот что мне сможет предложить перловый taint? Вызывать дополнительную проверку для уже «очищенных» данных?
Нет. Проверять данные как вздумается, если мы считаем, что отчистили их добела, помечать их как чистые. Всё как обычно.

Евгений Степанищев (bolknote.ru)
10 января 2014, 14:35, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

Применение регулярки к данным само по себе их не очищает. Вот пример из документации:

Александр Макаров (инкогнито)
10 января 2014, 15:06

Интересная штука. Для PHP можно вот этим пользоваться http://php.net/manual/en/intro.taint.php. Иногда показывает косяки.

Евгений Степанищев (bolknote.ru)
10 января 2014, 15:27, ответ предназначен Александру Макарову

К сожалению, очень слабое подобие :(

Roman Ryaboy (roman.yankovsky.me)
10 января 2014, 16:18, ответ предназначен Евгений Степанищев (bolknote.ru):

Давайте, чтоб тут много слов не разводить, попробуем сделать так. Вы мне дадите какой-то простой пример кода на перле (предельно простой, чтоб много времени не тратить), а я попробую то же самое сделать на языке со статической типизацией. Тогда без лишних слов моя идея станет понятна.

Евгений Степанищев (bolknote.ru)
10 января 2014, 16:38, ответ предназначен Roman Ryaboy (roman.yankovsky.me):

Так давайте с малого начнём. Пример в статье:

Denis Ibaev (dionys.moikrug.ru)
10 января 2014, 23:20

Вот ведь как люди без нормальной статической типизации мучаются :)
Диагностирую статическую типизацию головного мозга. Это просто классика: человек, привыкший к статической типизации, любую методологию из динамической воспринимает как некое извращение, потому что в статической делается иначе. И тут бесполезно что-либо доказывать — стена непонимания и неприятия.

Denis Ibaev (dionys.moikrug.ru)
11 января 2014, 00:00, ответ предназначен Евгений Степанищев (bolknote.ru):

Шрифты выглядят плохо. Но возможно у меня под Windows неправильный DjVu Sans.

Леша (инкогнито)
11 января 2014, 05:08

А почему вы пишете "СКуЭл", а не "ЭсКуЭл"?

Андрей (инкогнито)
11 января 2014, 07:20

В руби ничего подобного нет, если что :)

Леша (инкогнито)
11 января 2014, 07:30, ответ предназначен Андрею

Вы заблуждаетесь: http://ruby-doc.com/docs/ProgrammingRuby/html/taint.html#S2

Андрей (инкогнито)
11 января 2014, 07:41

Ой, спасибо. Ни разу не встречал практического использования.

Евгений Степанищев (bolknote.ru)
11 января 2014, 09:09, ответ предназначен Denis Ibaev (dionys.moikrug.ru):

Шрифты выглядят плохо. Но возможно у меня под Windows неправильный DjVu Sans.
А откуда он у тебя под виндой и зачем?

Евгений Степанищев (bolknote.ru)
11 января 2014, 09:10, ответ предназначен Леше

А почему вы пишете "СКуЭл", а не "ЭсКуЭл"?
Потому что буква «С» так и читается — «Эс», зачем повторяться?

Denis Ibaev (dionys.moikrug.ru)
11 января 2014, 12:42, ответ предназначен Евгений Степанищев (bolknote.ru):

А откуда он у тебя под виндой и зачем?
У меня есть софт, портированный с Linux. Вероятно, какой-нибудь дистрибутив притащил шрифт с собой.

Леша (инкогнито)
11 января 2014, 13:03, ответ предназначен Евгений Степанищев (bolknote.ru):

Потому что буква «С» так и читается — «Эс», зачем повторяться?
А буква "К" читается "Ка". Иными словами, слово либо является аббревиатурой с начала и до конца, либо с начала и до конца не является.
Текст вашего комментария, не HTML:
Должно быть, надо думать так: "Текст вашего комментария, не ЭйчТиМЭл." Это вполне безумно, по-моему.

Евгений Степанищев (bolknote.ru)
11 января 2014, 14:56, ответ предназначен Леше

Ой, это уже 300 раз обсудили и обсосали у меня в комментариях. Ещё раз не интересно.

Евгений Степанищев (bolknote.ru)
11 января 2014, 14:57, ответ предназначен Denis Ibaev (dionys.moikrug.ru):

У меня есть софт, портированный с Linux. Вероятно, какой-нибудь дистрибутив притащил шрифт с собой.
Ну блин, не знаю что и делать. На винде уродский дежавю, на линуксе — Требушет. Винды, конечно, больше, чем Линуксов, придётся пожертвовать, по всей видимости.

Евгений Степанищев (bolknote.ru)
11 января 2014, 15:10, ответ предназначен Denis Ibaev (dionys.moikrug.ru):

А Segoe UI есть?

Denis Ibaev (dionys.moikrug.ru)
12 января 2014, 02:24, ответ предназначен Евгений Степанищев (bolknote.ru):

У меня Vista, в ней Segoe UI предустановлен. А почему не указать первым Segoe UI, а потом уже DejaVu?

Леша (инкогнито)
12 января 2014, 08:03, ответ предназначен Евгений Степанищев (bolknote.ru):

Это выглядит дико, поэтому вопрос возникнет еще триста раз, гарантия 100%.

Евгений Степанищев (bolknote.ru)
12 января 2014, 09:39, ответ предназначен Denis Ibaev (dionys.moikrug.ru):

Потому и спросил — есть или нету. Поставил Сегое первым.

Евгений Степанищев (bolknote.ru)
12 января 2014, 09:40, ответ предназначен Леше

Это выглядит дико, поэтому вопрос возникнет еще триста раз, гарантия 100%.
Да пусть возникает, это ещё не значит что я должен каждый раз на него отвечать.

100grammist (инкогнито)
12 января 2014, 18:35

"ПХП, ХТМЛ, СКуЭл" - это конечно все неофициальный жаргон. Кому как удобнее, пускай так и пишет. Главное, чтобы было понятно.
Другое дело - документация. Там нельзя ничего русифицировать.

Евгений Степанищев (bolknote.ru)
12 января 2014, 20:00, ответ предназначен 100grammist

Почему это, скажите на милость? Можно и нужно. Устоявшиеся термины нужно писать на русском, новые — вводить стандартно (на русском, в скобках — значение).

100grammist (инкогнито)
12 января 2014, 21:04, ответ предназначен Евгений Степанищев (bolknote.ru):

Ну даже потому, что ХТМЛ выглядит как XTML. Если читать бегло, то уже возможна ошибка в понимании.
ЭсКуЭл, ЭсКуЭль, СКуЭл, СКуЛ, Сиквэл. А потом попробуй найти поиском по тексту упоминания.
А навязывать только один правильный? Ради чего? Чтобы не переключать кодировку?
Все это вносит неразбериху.

Евгений Степанищев (bolknote.ru)
12 января 2014, 21:52, ответ предназначен 100grammist

Сто раз это уже обсуждалось. Я не хочу повторяться. Но вкратце напишу.

На русском надо писать по-русски. Каком смысл мешать языки и думать читается ли PHP как «эр-эн-эр» или как «пи-эйч-пи» — непонятно.

Надо убирать из сознания ту херню, которая нам навязал поток нерусифицированной жратвы и шмоток, хлынувшей из-за рубежа в перестройку. До этого всё писали по-русски и никто проблемы в этом не видел.

100grammist (инкогнито)
12 января 2014, 23:41, ответ предназначен Евгений Степанищев (bolknote.ru):

Извините, что отнял время. Наверное я пропустил эти обсуждения.
Вашу позицию понимаю, но у каждого своя правда.

jankkhvej.tumblr.com (инкогнито)
15 января 2014, 19:43

Уже 15 января, а где тут статически типизированная реализация taint ?
Жду же с нетерпением!
(саргазм)

Евгений Степанищев (bolknote.ru)
15 января 2014, 21:19, ответ предназначен jankkhvej.tumblr.com

Я думаю, там кода будет на несколько экранов, да и то, только частный случай :)

jankkhvej.tumblr.com (инкогнито)
16 января 2014, 10:20, ответ предназначен Евгений Степанищев (bolknote.ru):

И ведь понимаешь, что так и будет, но всё равно надеешься на чудо. А вдруг?

Sergey Gladilin (gladilin.livejournal.com)
31 января 2014, 14:06, ответ предназначен Евгений Степанищев (bolknote.ru):

В Django есть auto-escaping, который, судя по описанию, похож на taint в Parser3 (там тоже, насколько я понял, результат taint заключается в авто-эскейпе).
https://code.djangoproject.com/wiki/AutoEscaping

Евгений Степанищев (bolknote.ru)
31 января 2014, 18:17, ответ предназначен Sergey Gladilin (gladilin.livejournal.com):

Так он во всех движках шаблонов есть.

Sergey Gladilin (gladilin.livejournal.com)
1 февраля 2014, 13:17, ответ предназначен Евгений Степанищев (bolknote.ru):

По ссылке, которую я дал, описана реализация маркировки "загрязненности" данных с помощью множественного наследования в 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"

Евгений Степанищев (bolknote.ru)
1 февраля 2014, 18:27, ответ предназначен Sergey Gladilin (gladilin.livejournal.com):

А, вон оно что. В «Твиге» (пхпешный движок) всё попроще: всё считается «грязным», чтобы вывести «как есть», надо использовать фильтр «raw».

Sergey Gladilin (gladilin.livejournal.com)
1 февраля 2014, 23:03, ответ предназначен Евгений Степанищев (bolknote.ru):

Как написано в том же тексте про Django, проблема с "все считается грязным" заключается в том, что есть шанс за-эскейпить дважды - и какая-то отметка, что строку уже эскепили, полезна. Еще одна проблема - если надо решать, что эскепить, а что нет, в контроллере, а не во view. Опять же, хочется возможности еще в контроллере отметить, что вот эта строка (например, содержащая html) - это строка, которую эскепить не надо - и чтобы view эту метку получил.

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)