Разработка приложений в среде Linux. Второе издание
Шрифт:
В каждом атрибутном байте отдельные биты интерпретируются так, как описано в табл. 21.12. Это VGA представление; некоторые цветовые устройства заменяют мерцание ярким задним фоном. Монохромное изображение использует нулевой бит цвета переднего плана для указания подчеркивания.
Таблица 21.12. Атрибуты
Бит (биты) | Результат |
---|---|
7 | Мерцание |
6-4 | Фон |
3 | Полужирный шрифт |
2-0 | Передний план |
Глава 22
Написание
Подавляющее большинство компьютеров, на которых работает система Linux, подключены к Internet, и многие из них используются большим количеством людей. Для того чтобы сохранить компьютер и его программное обеспечение в безопасности, предотвратить анонимные угрозы, поступающие через сетевое соединение, а также от локальных пользователей, которые пытаются проникнуть на несанкционированные уровни доступа, требуется тщательное программирование как основной операционной системы, так и множества приложений.
В данной главе предлагается краткий обзор тех важных моментов, которые необходимо учитывать при создании защищенных программ на языке С. Мы выясним, какие типы программ нуждаются в особом уровне надежности и защищенности, а также как минимизировать риски. Мы обратим внимание на самые общие ошибки в вопросе обеспечения безопасности. Все это может послужить введением в написание безопасных программ. Если вам необходима более глубокая информация, обратитесь к книге Давида Вилера (David A. Wheeler) Secure Programming for Linux and UNIX HOW TO. В нее входит также замечательная биография автора, а найти эту книгу можно по адресу http://www.dwheeler.com/secure-programs.
22.1. Когда безопасность имеет значение?
Компьютерные программы — это очень сложные вещи. Даже самая простая программа "Hello World" является на удивление запутанной. Игнорируя все, что происходит в ядре, библиотека С должна отыскать соответствующие совместно используемые библиотеки, загрузить их в систему, инициализировать стандартные методы ввода-вывода. На компьютере, с помощью которого готовилась данная глава, полная программа состояла из 25 системных вызовов. Только один из них оказался вызовом функции
С увеличением функциональности программ очень быстро возрастает их сложность. Большинство реально работающих программ принимают входные данные из нескольких источников (например, из командной строки, файлов конфигурации, терминала) и обрабатывают полученные данные сложными способами. Любая ошибка в процессе может вызвать непредсказуемое поведение, однако опытный программист чаще всего обрабатывает такие сюрпризы без появления нежелательных последствий. Если в эту "адскую смесь" добавить еще несколько сложных библиотек, то любому программисту (не говоря о команде программистов) будет очень трудно полностью представить себе реакцию программы на определенный набор входных данных.
Большинство программ очень внимательно тестируются, для гарантии того, что они дают соответствующие результаты для корректных наборов входных данных. При этом работа большинства программ с неожиданными входными данными проверяется недостаточно [156] . Несмотря на то что при проектировании ядра тщательно учитывается необходимость предотвращения риска для системы из-за неисправностей в пользовательских программах, все же ошибки в некоторых типах программ могут отразиться на целостности системы.
156
Популярным способом проверки в ранних ядрах Linux было создание последовательности абсолютно случайных байтов и запуск их на выполнение как программы. Кроме того, что таким методом невозможно сделать что-либо полезное, он довольно часто вызывает полную блокировку ядра. Поскольку попытки выполнения совершенно случайных последовательностей кодов не входят в "должностные инструкции" ядра, пользовательские программы не должны вызывать остановку корректной работы ядра. Таким образом, этот прием помогает находить большое число дефектов, которые необходимо устранить.
Существуют три типа программ, при создании которых программисты должны постоянно помнить о безопасности.
• Программы, обрабатывающие данные, которые могут поступать из ненадежных источников, очень уязвимы. Такие данные могут содержать скрытые атаки, использующие программные ошибки и вызывающие непредсказуемое поведение программ. Нередко целью таких атак является получение полного доступа к компьютеру для анонимных пользователей. Любая программа, имеющая доступ к данным через сеть (как клиентская, так и серверная) становится потенциальным мишенью для атак. Но даже безобидные программы вроде текстовых процессоров, могут быть поражены через поврежденные файлы данных [157] .
157
Атака на программное обеспечение приложений сейчас является основным способом распространения вирусов.
• Программы, которые во время запуска могут переключаться между пользовательскими или групповыми контекстами (через биты setuid и setgid в исполняемом файле), несут потенциальную опасность передачи прав и информации привилегированного пользователя другому (непривилегированному) пользователю.
• Любая программа, работающая как системный демон, может вызвать проблему безопасности. Подобные программы работают в системе как привилегированные пользователи (довольно часто они выступают в качестве root), поэтому любое взаимодействие с обычными пользователями подвергает систему опасности.
22.1.1. Когда выходит из строя система безопасности?
Дефекты в системе безопасности программ являются причиной четырех обширных категорий атак: удаленная эксплуатация, локальная эксплуатация, удаленные атаки отказа в обслуживании и локальные атаки отказа в обслуживании. Удаленные эксплуатации позволяют пользователям, имеющим доступ к сетевым службам компьютера, запустить на этом компьютере произвольный код. Для того чтобы удаленная атака могла иметь место, в программе, обращающейся к сети, должна быть некоторая неисправность. Обычно такие ошибки встречаются в сетевых серверах, что позволяет удаленному взломщику ввести сервер в заблуждение и получить доступ в систему. С недавних пор начали эксплуатироваться и ошибки в сетевых клиентах. Например, если Web-браузер имеет изъян в способе анализа HTML-данных, то Web-страница, загружаемая этим браузером, может побудить браузер активизировать произвольную последовательность кодов.
Локальная эксплуатация дает пользователям возможность выполнять такие действия, на которые у них обычно нет полномочий (на них часто ссылаются как на разрешение превышения локальных полномочий), например, нелегально проникать в систему под видом другого пользователя. Такой тип эксплуатации, как правило, направлен на локальных демонов (таких как серверы
Атаки отказа в обслуживании не позволяют взломщику получить контроль над системой, однако они могут помешать законному использованию данной системы. Это наиболее хитрые помехи, многие из них очень трудно ликвидировать. Например, многие программы, использующие файлы блокировок, подвергаются опасности таких атак. Хакер может просто вручную создать файл блокировки и ни одна программа никогда не удалит его. Одна из простейших атак отказа в обслуживании для пользователей заключается в заполнении их домашних каталогов ненужными файлами, тем самым исключая возможность создания новых файлов другими пользователями в той же файловой системе [158] . В общем случае для локальных атак рассматриваемого типа существует гораздо больше удобных случаев, чем для удаленных атак. Мы не будем здесь изучать атаки отказа в обслуживании подробно, поскольку они часто являются следствием всей программной архитектуры, а не одного дефекта.
158
Системные квоты предотвращают возможность успешности такой атаки.