19 смертных грехов, угрожающих безопасности программ - [4]

Шрифт
Интервал

прочесть о грехах 1, 2 и З.

□ Если вы программируете для Web с использованием таких технологий, как JSP, ASP, ASP.NET, PHP, CGI или Perl, то познакомьтесь с грехами 7 и 9.

□ Если вы создаете приложения для работы с базами данных, например Oracle, MySQL, DB2 или SQL Server, прочтите о грехе 4.

□ Если вы разрабатываете сетевые системы (клиент–серверные, через Web и прочие), не проходите мимо грехов 5, 8, 10, 14 и 15.

□ Если в вашем приложении каким–то образом используется криптография или пароли, обратите внимание на грехи 8, 10, 11, 17 и 18.

□ Если ваша программа работает в ОС Linux, Mac OS X или UNIX, следует прочесть о грехе 16.

□ Если с вашим приложением будут работать неопытные пользователи, взгляните на описание греха 19.

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

Майкл Ховард, Дэвид Лебланк, Джон Виега, июль 2005 г.

Грех 1. Переполнение буфера

В чем состоит грех

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

Строго говоря, переполнение возникает, когда программа пытается писать в память, не принадлежащую выделенному буферу, но есть и ряд других ошибок, приводящих к тому же эффекту. Одна из наиболее интересных связана с форматной строкой, мы рассмотрим ее в описании греха 2. Еще одно проявление той же проблемы встречается, когда противнику разрешено писать в произвольную область памяти за пределами некоторого массива. И хотя формально это не есть классическое переполнение буфера, мы рассмотрим здесь и этот случай.

Результатом переполнения буфера может стать что угодно – от краха программы до получения противником полного контроля над приложением, а если приложение запущено от имени пользователя с высоким уровнем доступа (root, Administrator или System), то и над всей операционной системой и другими пользователями. Если рассматриваемое приложение – это сетевая служба, то ошибка может привести к распространению червя. Первый получивший широкую известность Интернет–червь эксплуатировал ошибку в сервере finger, он так и назывался – «finger–червь Роберта Т. Морриса» (или просто «червь Морриса»). Казалось бы, что после того как в 1988 году Интернет был поставлен на колени, мы уже должны научиться избегать переполнения буфера, но и сейчас нередко появляются сообщения о такого рода ошибках в самых разных программах.

Быть может, кто–то думает, что такие ошибки свойственны лишь небрежным и беззаботным программистам. Однако на самом деле эта проблема сложна, решения не всегда тривиальны, и всякий, кто достаточно часто программировал на С или С++, почти наверняка хоть раз да допускал нечто подобное. Автор этой главы, который учит других разработчиков, как писать безопасный код, сам однажды передал заказчику программу, в которой было переполнение на одну позицию (off–by–one overflow). Даже самые лучшие, самые внимательные программисты допускают ошибки, но при этом они знают, насколько важно тщательно тестировать программу, чтобы эти ошибки не остались незамеченными.

Подверженные греху языки

Чаще всего переполнение буфера встречается в программах, написанных на С, недалеко от него отстает и С++. Совсем просто переполнить буфер в ассемблерной программе, поскольку тут нет вообще никаких предохранительных механизмов. По существу, С++ так же небезопасен, как и С, поскольку основан на этом языке. Но использование стандартной библиотеки шаблонов STL позволяет свести риск некорректной работы со строками к минимуму, а более строгий компилятор С++ помогает программисту избегать некоторых ошибок. Даже если ваша программа составлена на чистом С, мы все же рекомендуем использовать компилятор С++, чтобы выловить как можно больше ошибок.

В языках более высокого уровня, появившихся позже, программист уже не имеет прямого доступа к памяти, хотя за это и приходится расплачиваться производительностью. В такие языки, как Java, С# и Visual Basic, уже встроены строковый тип, массивы с контролем выхода за границы и запрет на прямой доступ к памяти (в стандартном режиме). Кто–то может сказать, что в таких языках переполнение буфера невозможно, но правильнее было бы считать, что оно лишь гораздо менее вероятно. Ведь в большинстве своем эти языки реализованы на С или С++, а ошибка в реализации может стать причиной переполнения буфера. Еще один потенциальный источник проблемы заключается в том, что на какой–то стадии все эти высокоуровневые языки должны обращаться к операционной системе, а уж она–то почти наверняка написана на С или С++. Язык С# позволяет обойти стандартные механизмы .NET, объявив небезопасный участок с помощью ключевого слова unsafe. Да, это упрощает взаимодействие с операционной системой и библиотеками, написанными на C/C++, но одновременно открывает возможность допустить обычные для C/C++ ошибки. Даже если вы программируете преимущественно на языках высокого уровня, не отказывайтесь от тщательного контроля данных, передаваемых внешним библиотекам, если не хотите пасть жертвой содержащихся в них ошибок.


Рекомендуем почитать
Графика DirectX в Delphi

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


Вторая жизнь старых компьютеров

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


DirectX 8. Начинаем работу с DirectX Graphics

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.