Когда пользователь передал в программу на Perl строку, в середине которой имеется нулевой байт, вся строка попадает в переменную как есть. То есть всё, что идёт до нулевого байта, сам нулевой байт и всё, что после, будет сохранено в строке. Как только вы попытаетесь открыть файл с именем, хранящемся в такой переменной, нулевой байт будет означать конец строки, потому что Perl написан на языке C, а для языка C нулевой байт это как раз символ окончания строки. Поэтому имя открываемого файла в конечном счёте будет воспринято внутренней сишной природой перла как строка до нулевого байта, остаток байт в перловой строке будет проигнорирован.
Представьте
себе, что вы написали защиту, которая опирается на проверку строки от пользователя с помощью регулярного выражения. Вы хотите, чтобы это был исключительно текстовый файл. Вы сравниваете строку с выражением /\.txt$/ и считаете, что на этом задача решена. Однако пользователь может передать вам строку config.pl\x00.txt. Такая строка пройдёт проверку, ведь у неё в конце по версии перлового представления строк есть фрагмент .txt, а какой файл откроется на самом деле, вы уже догадались? :)
Уязвимость чинится очень просто: как только вам передали имя файла, нулевой байт вырезается ($str =~ s/\0//g;) а лучше сразу фильтровать всё, кроме алфавитно-цифровых символов, точек, минусов, подчёркиваний, словом, всего того, из чего может состоять имя файла, который допустимо открыть.
Не доверять пользователю. Если вы попытаетесь использовать данные от пользователя напрямую (Cookie, переменные окружения, параметры, переданные по CGI, ввод с клавиатуры и т.п.), Perl выдаст предупреждение о том, что такие данные требуется отфильтровать. Например, с помощью регулярного выражения выполняется извлечение, и только использование результата такого извлечения пройдёт без предупреждения.
-w
Показывать предупреждения о проблемах, которые не фатальны, с которыми скрипт работать будет, но обратить внимание на которые стоит как с точки зрения аккуратного программирования, так и с точки зрения безопасности. Одно из самых полезных предупреждений, на мой взгляд, использование переменной, которой ничего не присвоено, то есть то же, что и undef. Проверить неопределённость переменной можно так: defined($var). Когда вы добьетесь чистого выполнения скрипта без предупреждений с ключом -w в самых разных условиях, которые только сумеете придумать, вы как минимум теоретически усилите безопасность скрипта.
-W
То же, что и -w, только Perl покажет больше предупреждений, часть из которых совсем уж незначительна. Например, часто можно видеть, как при -W Perl ругается даже на собственные модули из коробки! Это, безусловно, отвлекает. С этим особо нечего поделать. Тут придётся либо на время наведения железного порядка у себя в скрипте смириться и игнорировать их, либо принять участие в улучшении чужого модуля сообщество программистов будет вам признательно :) Только перед тем, как чинить чужое, убедитесь что у вас именно последняя версия модуля.
-X
Заткнуть Perl от любых предупреждений. Сообщения о фатальных ошибках при этом останутся. Этот ключ полезно использовать тогда, когда вы знаете о проблемах, отложили их починку, но хотите, чтобы в логах веб-сервера не было предупреждений. Не обязательно так делать, это всего лишь способ не засорять логии тем, о чём вы и так в курсе (представляете, что будет, если Warning выдаётся во фрагменте кода с большими циклами? Так что это ещё и экономия места на диске с логами, может быть важно для стартапов). Также это снизит нагрузку на диск при интенсивной ругани Perl-а предупреждениями.
Однако, это палка о двух концах. С одной стороны вы не видите известные проблемы (и это скорее хорошо, если исправить их запланировано), с другой не видите и те, о которых не знаете. Это опять же касается стартапов, где может не быть лёгкой возможности подставить сервер с отлаживаемой версией под реальную нагрузку. Вам придётся принять решение, что для вас важнее: производительность с -X или возможность зафиксировать максимум предупреждений в логах на боевой машине и некоторое падение производительности с -w или даже -W.
Варианты:
strict vars
Без этого вы используете переменную без объявления, считая, что Perl создаёт её автоматически. С этим вариантом вы должны объявить каждую переменную (массив, хеш абсолютно всё).
Полезно вот что: если вы вдруг опечатались, Perl вас обругает, такая переменная не объявлена (компиляция будет остановлена). В обычном режиме Perl заботливо создаст для вас новую переменную с новым именем, таким, как вы опечатались.
И внутри у неё будет, разумеется, undef, что в выражении приведётся к нулю или пустой строке. При присваивании будет ещё хуже. Вам покажется,
что всё хорошо (синтаксически-то всё безупречно), а на деле присваивание произойдёт мимо нужной переменной в новую.
strict subs
Perl обычно не ругается, если вы присвоите переменной имя процедуры как есть, голое название без кавычек. А когда вы включите strict subs, Perl не позволит вам так сделать, вы обязательно должны будете либо заключить название в кавычки, либо использовать особый синтаксис: