25 наболее частых ошибок в программировании: ошибка #1

На западе, откуда пришла к нам теория и лучшие практики тестирования, существует список наиболее распространенных ошибок в программном обеспечении. Этот список является результатом сотрудничества двух организаций, 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, будет создан массив нулевой длины, после этого в массив попытаются записать первый элемент и будет вызвано не перехваченное исключение.
 
Кстати, наглядно посмотреть на такую ошибку можно здесь:
http://community.software-testing.ru/blog/panbugon/17.html
 
Что делать:
Чтобы попасть в Production, часто такой ошибке нужно пройти довольно долгий путь, поэтому поймать ее можно на трех фазах разработки:
 
Фаза дизайна и проектирования:
 

  • Существуют различные фреймворки, которые предоставляют свои API для проверки ввода, попытайтесь использовать их;

  • Изучите все потенциальные области проникновения непроверенных данных в ваше приложение. Вот некоторые из них: параметры, куки, переменные окружения, заголовки запросов и их содержимое, компоненты URL, файлы, письма, данные из баз, в общем, все, что получено из внешних приложений;

  • Предположите, что весь ввод опасен. Используйте стратегию “принять, только то, что распознается”, своего рода «белый лист». Отклоните любой ввод, которой не соответствует строго спецификации или преобразуйте в такой, который соответствует;

  • Дублируйте все клиентские проверки на серверной стороне. Атакующий может обойти проверку на клиентской стороне, изменяя значения уже после проверки. В конце концов, он может отравить запрос любым клиентом, а не только браузером. И данные этого запроса попадут на исполнение, если вы не проверите их на серверной стороне;

  • Не полагайтесь только на проверку методом «черный список». Обычно существует довольно много вариантов кодирования одного и того же символа, вероятно вы упустите какой-нибудь из них;


 Фаза имплементации:


  • Если ваше приложение объединяет данные из нескольких источников, выполните валидацию после объединения. Возможно, по отдельности элементы данных пройдут ваши проверки, но объединенные, они нарушат ограничения на ввод;

  • Будьте особенно аккуратны, когда ввод является результатом работы кода, написанного на другом языке. Убедитесь, что он не нарушает любые ожидания вашего языка программирования;

  • Прямо указывайте компилятору\интерпретатору тип данных для ввода, используя функции конвертации. После конвертации в желаемый тип данных убедитесь, что значение попало в диапазон допустимых значений;

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

  • Убедитесь, что вы используете одну и ту же кодировку когда обмениваетесь данными между компонентами системы. Кодировка должна применяться к любому интерфейсу с которым вы взаимодействуете. Явно установите кодировку, если это позволяет протокол;


Фаза тестирования:
 

  • Используйте инструменты статического анализа, которые нацелены на этот тип уязвимости. Многие современные методы используют анализ потоков данных, хотя это решение не совершенно и не может дать 100% точности и хорошего покрытия кода;

  • Используйте динамические инструменты и техники, которые взаимодействуют с приложением, используя большие объемы различных данных, такие как fuzz testing, robustness testing и fault injection. Во время такого тестирования ваше приложения может начать тормозить, но не должно стать нестабильным, упасть или сгенерировать некорректные результаты.


Почитать про эти виды тестирования можно здесь:
Fuzz testing: en.wikipedia.org/wiki/Fuzz_testing
Robustness testing: www.sei.cmu.edu/pub/documents/05.reports/pdf/05tn015.pdf
Fault injection: en.wikipedia.org/wiki/Fault_injection
 
Так же про эту ошибку можно почитать в оригинале: cwe.mitre.org/data/definitions/20.html


Комментарии (10)

RSS свернуть / развернуть
+
0
Если я правильно понял, это хоть и вольный, но перевод? В этом случае хорошо бы ссылку на оригинал привести, из уважения к автору. И не мешало бы на всякий случай спросить у автора разрешения на публикацию перевода, автору от этого будет ещё приятнее :)
avatar

barancev

  • 24 августа 2009, 11:20
+
+2
Ссылка есть в конце статьи. Разрешение тоже есть.
avatar

noonelf

  • 24 августа 2009, 11:31
+
0
OK, я просто сначала не соотнёс, перевод действительно достаточно вольный :)

Но какой ресурс этот CWE! Я раньше даже не подозревал о его существовании. Вот спасибо так спасибо!!!
avatar

barancev

  • 24 августа 2009, 11:43
+
0
Многие современные методы используют анализ потоков данных, хотя это решение не совершенно и не может дать 100% точности и хорошего покрытия кода

Я буквально только что на онлайн-семинаре в прошедший четверг про инструменты статического анализа рассказывал, и отметил, что как раз анализ потоков данных — это большая редкость. Мне известен только один «работающий» инструмент, который использует анализ потоков данных для поиска уязвимостей — Pixy. Ну и ещё Pex, который позволяет полуавтоматически увеличивать покрытие кода.

Если Вы знаете ещё инструменты, которые умеют анализировать потоки данных — поделитесь ссылками, плиз!
avatar

barancev

  • 24 августа 2009, 11:48
+
+1
Так вам очень долго придется переводить.

Наверное, стоило начать со списка этих 25 ошибок, без пояснений, с краткими аннотациями.
avatar

astenix

  • 25 августа 2009, 16:41
+
+1
С моей точки зрения такой список будет бесполезен. Описание ошибки довольно водянисто, а характеристики ошибки довольно бесполезны.

Ценность представляют разобранный пример и рекомендации для принятия превентивных мер и поиска ошибки на фазе тестирования.
avatar

noonelf

  • 25 августа 2009, 22:50
+
0
Оффтоп от удивления: полный размер страницы "Comprehensive CWE Dictionary (ver. 1.5)" = 9,094.41 KB…
avatar

astenix

  • 25 августа 2009, 17:17
+
0
полностью согласен с постом, вот только расписано он «многа букаф»
+ добавлю ещё одно

всегда игнорируют ограничения на ввод.

Допустим в базе есть некоторое поле varchar(64) на клиенте это поле Name и оно не имеет ограничений т.е можно вбивать и вбивать символы… А при сохранении возможны 2 ситуации

1. Вывалиться error
2. Имя «обрежут» до первых 64 символов

avatar

Maddi

  • 26 августа 2009, 14:27
+
0
ждём продолжения, хорошая тема поднята.
avatar

Undo

  • 26 августа 2009, 15:07
+
0
Какие в первую очередь стоит перевести?
avatar

korziner

  • 30 января 2010, 16:23

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.