На западе, откуда пришла к нам теория и лучшие практики тестирования, существует список наиболее распространенных ошибок в программном обеспечении. Этот список является результатом сотрудничества двух организаций, SANS Institute и MITRE, а так же 40 экспертов в области безопасности программного обеспечения. В общем списке было выбрано 25 наиболее распространенных и опасных ошибок. Довольно вольным переводом этих 25 ошибок я и хочу поделиться.
Ошибка #1: Неправильная проверка ввода
Характеристики ошибки:
Степень распространенности: Высокая
Стоимость исправления: Низкая
Частота использования: Высокая
Последствия:
Выполнение кода
DoS-атака
Потеря данных
Сложность обнаружения: Чаще легко обнаружима
Осведомленность атакующего: Высокая
Описание:
Эта ошибка – убийца номер один в программном обеспечении, так что вы просто нарываетесь на проблемы, если не проверяете входные данные на соответствие ожиданиям. Например, в идентификатор, в котором вы ожидаете увидеть число, ни в коем случае не должны попасть буквы. Так же имеет смысл ввести верхнюю границу для высоты или ширины картинки в графическом редакторе. Обычно, приложения имеют более сложные требования к входным данным, чем эти просты примеры. Неверная валидация входных данных может привести к уязвимостям, когда атакующий сможет использовать совершенно неожиданный вами ввод. Многие распространенные сегодня уязвимости могли бы быть устранены благодаря корректной проверке входных данных.
Как это делают:
Следующий код на Java получает на вход целое число и создает массив заданного размера. Так как мы не знаем, что за число мы получим, то мы должны выполнить проверку и убедиться, что мы получили положительное число, что вполне логично, ведь нельзя создать массив отрицательной длины.
private void buildList ( int untrustedListSize ){ if ( 0 > untrustedListSize ){ die(«Negative value supplied for list size, die evil hacker!»); } Widget[] list = new Widget [ untrustedListSize ]; list[0] = newWidget(); }
В чем же проблема? Проблема во второй строке. Если ввести 0, будет создан массив нулевой длины, после этого в массив попытаются записать первый элемент и будет вызвано не перехваченное исключение.
Кстати, наглядно посмотреть на такую ошибку можно здесь:
Что делать:
Чтобы попасть в Production, часто такой ошибке нужно пройти довольно долгий путь, поэтому поймать ее можно на трех фазах разработки:
Фаза дизайна и проектирования:
Существуют различные фреймворки, которые предоставляют свои API для проверки ввода, попытайтесь использовать их;
Изучите все потенциальные области проникновения непроверенных данных в ваше приложение. Вот некоторые из них: параметры, куки, переменные окружения, заголовки запросов и их содержимое, компоненты URL, файлы, письма, данные из баз, в общем, все, что получено из внешних приложений;
Предположите, что весь ввод опасен. Используйте стратегию “принять, только то, что распознается”, своего рода «белый лист». Отклоните любой ввод, которой не соответствует строго спецификации или преобразуйте в такой, который соответствует;
Дублируйте все клиентские проверки на серверной стороне. Атакующий может обойти проверку на клиентской стороне, изменяя значения уже после проверки. В конце концов, он может отравить запрос любым клиентом, а не только браузером. И данные этого запроса попадут на исполнение, если вы не проверите их на серверной стороне;
Не полагайтесь только на проверку методом «черный список». Обычно существует довольно много вариантов кодирования одного и того же символа, вероятно вы упустите какой-нибудь из них;
Фаза имплементации:
Если ваше приложение объединяет данные из нескольких источников, выполните валидацию после объединения. Возможно, по отдельности элементы данных пройдут ваши проверки, но объединенные, они нарушат ограничения на ввод;
Будьте особенно аккуратны, когда ввод является результатом работы кода, написанного на другом языке. Убедитесь, что он не нарушает любые ожидания вашего языка программирования;
Прямо указывайте компилятору\интерпретатору тип данных для ввода, используя функции конвертации. После конвертации в желаемый тип данных убедитесь, что значение попало в диапазон допустимых значений;
Ввод должен быть декодирован и канониканизирован(это процесс перевода данных, которые имеют более одного возможного представления в стандартное представление) до его передачи во внутренний код вашего приложения. Убедитесь, что вы случайно не декодируете один и тот же ввод дважды;
Убедитесь, что вы используете одну и ту же кодировку когда обмениваетесь данными между компонентами системы. Кодировка должна применяться к любому интерфейсу с которым вы взаимодействуете. Явно установите кодировку, если это позволяет протокол;
Фаза тестирования:
Используйте инструменты статического анализа, которые нацелены на этот тип уязвимости. Многие современные методы используют анализ потоков данных, хотя это решение не совершенно и не может дать 100% точности и хорошего покрытия кода;
Используйте динамические инструменты и техники, которые взаимодействуют с приложением, используя большие объемы различных данных, такие как fuzz testing, robustness testing и fault injection. Во время такого тестирования ваше приложения может начать тормозить, но не должно стать нестабильным, упасть или сгенерировать некорректные результаты.
Почитать про эти виды тестирования можно здесь:
Fuzz testing:
Robustness testing:
Fault injection:
Если я правильно понял, это хоть и вольный, но перевод? В этом случае хорошо бы ссылку на оригинал привести, из уважения к автору. И не мешало бы на всякий случай спросить у автора разрешения на публикацию перевода, автору от этого будет ещё приятнее :)
Многие современные методы используют анализ потоков данных, хотя это решение не совершенно и не может дать 100% точности и хорошего покрытия кода
Я буквально только что на онлайн-семинаре в прошедший четверг про инструменты статического анализа рассказывал, и отметил, что как раз анализ потоков данных — это большая редкость. Мне известен только один «работающий» инструмент, который использует анализ потоков данных для поиска уязвимостей — . Ну и ещё , который позволяет полуавтоматически увеличивать покрытие кода.
Если Вы знаете ещё инструменты, которые умеют анализировать потоки данных — поделитесь ссылками, плиз!
полностью согласен с постом, вот только расписано он «многа букаф»
+ добавлю ещё одно
всегда игнорируют ограничения на ввод.
Допустим в базе есть некоторое поле varchar(64) на клиенте это поле Name и оно не имеет ограничений т.е можно вбивать и вбивать символы… А при сохранении возможны 2 ситуации
1. Вывалиться error
2. Имя «обрежут» до первых 64 символов
Комментарии (10)
RSS свернуть / развернутьbarancev
noonelf
Но какой ресурс этот CWE! Я раньше даже не подозревал о его существовании. Вот спасибо так спасибо!!!
barancev
Я буквально только что на онлайн-семинаре в прошедший четверг про инструменты статического анализа рассказывал, и отметил, что как раз анализ потоков данных — это большая редкость. Мне известен только один «работающий» инструмент, который использует анализ потоков данных для поиска уязвимостей — . Ну и ещё , который позволяет полуавтоматически увеличивать покрытие кода.
Если Вы знаете ещё инструменты, которые умеют анализировать потоки данных — поделитесь ссылками, плиз!
barancev
Наверное, стоило начать со списка этих 25 ошибок, без пояснений, с краткими аннотациями.
astenix
Ценность представляют разобранный пример и рекомендации для принятия превентивных мер и поиска ошибки на фазе тестирования.
noonelf
astenix
+ добавлю ещё одно
всегда игнорируют ограничения на ввод.
Допустим в базе есть некоторое поле varchar(64) на клиенте это поле Name и оно не имеет ограничений т.е можно вбивать и вбивать символы… А при сохранении возможны 2 ситуации
1. Вывалиться error
2. Имя «обрежут» до первых 64 символов
Maddi
Undo
korziner
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.