Даже пробел может считаться управляющим символом, поскольку разделяет семантически значимые аргументы или команды. И в таком качестве используются многие символы, помимо пробела, а именно: символ табуляции, перевода строки, возврата каретки, перевода страницы и вертикальной табуляции.
К тому же есть еще управляющие символы типа Ctrl–D или NULL, которые также могут приводить к нежелательным эффектам.
В общем, гораздо надежнее работать со списком «только эти». В случае списка «все кроме» вы должны быть абсолютно уверены, что рассмотрели все возможности. Но даже разрешительного подхода на основе списка «только эти» может оказаться недостаточно. Знать, как действует тот или иной символ, все равно необходимо, поскольку иначе вы можете включить в список разрешенных пробелы или тильду, не понимая, какие последствия это будет иметь для безопасности программы.
Другая проблема, свойственная разрешительному подходу, состоит в том, что пользователи могут быть недовольны, когда программа не дает вводить допустимые с их точки зрения символы. Например, вы можете запретить символ «+» в почтовых адресах, но найдутся люди, которые применяют этот символ, чтобы отличить тех, кому они сообщили свой адрес. И все же пропускание только разрешенных символов надежнее двух других подходов.
Рассмотрим случай, когда вы принимаете от пользователя значение, интерпретируемое как имя файла. Предположим, что проверка реализована так (код ниже написан на Python):
...
for char in filename:
if (not char in string.ascii_letters and not char in string.digits
and char <> \'.\'):
raise "InputValidationError"
Здесь разрешены точки, чтобы пользователь мог указывать имена файлов с расширением, но о символе подчеркивания мы забыли. При подходе «все кроме» вы могли бы не подумать о том, чтобы запретить косую черту, а это плохо – противник может с помощью символа косой черты и точек сформировать имя файла из другой части файловой системы, вне текущего каталога. Если бы вы применили «закавычивание», то функция проверка оказалась бы гораздо более сложной.
Для такого рода проверок часто применяют регулярные выражения. Однако в регулярном выражении, особенно сложном, легко допустить ошибку. Если вам нужны вложенные конструкции и другие подобные вещи, лучше о регулярных выражениях забыть.
Вообще говоря, с точки зрения безопасности лучше перестраховаться, чем потом кусать локти. Регулярные выражения проще, но не безопаснее, особенно когда для точного контроля нужно учитывать сложную семантику, а не просто сопоставлять с образцом.
Если проверка не проходит
Есть три основные стратегии обработки ошибок. Они не являются взаимоисключающими, и, по крайней мере, первые два способа лучше применять совместно.
□ Известить об ошибке (и, разумеется, не запускать команду, несмотря ни на что). Но думайте о том, как выглядит сообщение об ошибке. Если вы просто включите в него неверные данные, то можете нарваться на атаку с кросс–сайтовым сценарием. Не стоит также сообщать противнику слишком много информации (особенно если в ходе проверки используются данные из конфигурационного файла). Иногда лучше всего просто сказать «недопустимый символ» или что–нибудь, столь же туманное.
□ Протоколировать ошибку и все связанные с ней данные. Но следите, чтобы сам процесс протоколирования не оказался мишенью атаки; некоторые системы протоколирования принимают символы форматирования, а попытка бесхитростно записать в протокол некоторые данные (например, символ возврата каретки или перевода строки) может привести к порче протокола.
□ Модифицировать поступившие данные, заменив их значением по умолчанию или как–то преобразовав.
В общем случае мы не рекомендуем третий вариант. Вы можете ошибиться, но даже в том случае, когда правы вы, а ошибся пользователь, результат может оказаться неожиданным. Лучше совсем отказаться от операции, но сделать это безопасно.
Дополнительные защитные меры
В языке Perl есть средства, которые позволяют обнаружить такого рода ошибки во время выполнения. Это так называемый «осторожный режим» (taint mode). Идея в том, что Perl не позволит передать непроверенные данные любой из перечисленных выше функций. Однако проверка выполняется только в осторожном режиме, поэтому, не включив его, вы не получите никаких преимуществ. Кроме того, вы можете случайно отключить этот режим, предварительно ничего не проверив. Есть и другие мелкие ограничения, поэтому лучше не полагаться только на этот механизм. Тем не менее это прекрасный инструмент для тестирования, и обычно стоит задействовать его в качестве одного из средств защиты.
Читать дальше
Конец ознакомительного отрывка
Купить книгу