Написание защищённого кода
- Подробности
- Категория: Сетевая безопасность
- Дата публикации: 05.08.2013 17:30
Задача защиты программного кода от различных уязвимостей - очень важная проблема в современной быстро растущей индустрии IT. XSS, SQL-инъекции, переполнение буффера с последующими получением привилегий - всё это и многое другое следствия ошибок разработчиков, которые, к сожалению, совершают их с каждым днём всё больше и больше. Объясняется это просто: технологии движутся вперёд, объёмы кода сильно растут, а качество мозга людей и соответственно, написанного ими программного кода - не растёт. Или растёт, но не так быстро.
В нынешнее время очень хорошим результатом для гуру-программиста считается 1 серьёзная ошибка на 1000 строк кода. Для примера, в новомодной Windows 8 содержится 7 миллионов строк. Число критических ошибок подсчитать может 9-летний выпускник начальной школы.
Почему же ситуация столь плоха? Что надо делать, чтобы писать защищённый код и ограждаться от множества уязвимостей в собственном ПО? Об этом в сегодняшней статье, основанной на трудах ведущих разработчиков Microsoft М. Ховарда и Дж. ЛеБланка.
Прежде чем писать о защищённости программ и принципах написания защищённого кода, отметим ещё один важный фактор, сильно влияющий на конечный результат. Приложения пишутся людьми, люди склонны к лени, невнимательности и как следствие, - множеству ошибок. Также, люди склонны к личной выгоде, универсалом которой являются деньги. Соответственно, первый и главный аспект написания защищённых приложений - это мотивирование персонала: разработчиков и тестировщиков. О том, как это сделать сказано в замечательной статье о плате за взлом или защите от уязвимостей.
Безопасность приложений
Основная задача написания защищённого кода – создание защищённых программ, т.е. программ, которые обеспечивают конфиденциальность, целостность и доступность информации клиента вашей IT-компании, а также целостность и доступность вычислительных ресурсов, управляемых владельцем системы или системным администратором. Здесь и далее будет идти речь об организациях, занимающихся разработкой ПО. Обеспечить исполнение определённых правил конкретно написания кода мало – прежде всего, надо корректно организовать весь итеративно-инкрементный процесс разработки ПО, а также обеспечить корректное управление безопасностью приложений.
Перечислим общие принципы, которые должны быть включены в политику безопасности, при работе с приложениями и при их написании. Одним из основных девизов компании должен стать девиз «безопасность (безопасность ПО в вышеуказанном смысле) – превыше всего».
Действие №1. Пропаганда идей безопасности на предприятии, пока идея их обеспечения не станет статьёй в бизнес-плане компании. Для этого, естественно, нужно предъявить начальству весомую аргументацию, прямо касающуюся прибыли компании, после чего убедить начальство в том, чтобы оно само обратилось к сотрудникам с выработанным регламентом политики ИБ.
Действие №2. Взять в штат специалиста по ИБ, который будет заниматься контролем за соблюдением политики ИБ, поддерживать/обслуживать/обновлять/адаптировать динамическую систему ИБ, вырабатывать новую политику ИБ (модели угроз и т.д.).
Действие №3. Организация непрерывного обучения штата: обязательность и непрерывность; регулярная рассылка с выявляемыми проблемами и просьба решить эти проблемы тем, в зоне чьей ответственности они находятся; создать ресурс по ИБ в интрасети, пересматривать написанный код с позиции возможных ошибок ИБ и наличия ныне известных и потенциально возможных уязвимостей.
Действие №4. Классификация ошибок систем ИБ. Можно расширить и назвать данный пункт: составление классифицированной модели угроз. Смысл ясен.
Общие принципы проектирования защищённых приложений:
1. Защита должна ставиться, как неотъемлемая функция создаваемого ПО.
2. На обеспечение безопасности ПО должно быть отведено достаточно времени.
3. Обязательно должна быть составлена модель угроз: декомпозиция ПО с выявлением присущих уязвимостей; определение степени опасности и вероятности возникновения каждой уязвимости/опасности; составление матрицы угроз; определение противодействий, а также действий в случае реализации угрозы.
4. Определение процедуры удаления небезопасных функций и частей в ПО.
5. Должны быть созданы метрики безопасности, соответствующие модели угроз, в которых должны быть определены предельные пороги.
6. Разработка тест-планов и периодическая проверка и контроль процесса создания ПО отделом ИБ на каждом этапе разработки по созданным тест-планам, по возможности, - приглашёнными специалистами.
7. Обязательный контроль безопасности модуля не тем, кто разработал данный модуль.
8. Безопасность должна обеспечиваться в конфигурации по умолчанию и при развёртывании.
9. Особый контроль за предоставлением прав на внесение изменений в ПО.
10. «Площадь уязвимости» (потенциальная) должна быть как можно меньше (всевозможные открытые TCP/UDPпорты, запускаемые и зависимые службы, динамические веб-страницы, части приложения или службы, запускаемые с высокими привилегиями и т.д.).
11. Должны быть защищены все уровни (независимо друг от друга и от других уровней защиты).
12. Используйте правило минимальных привилегий (и + грамотно составленный ACL).
13. Следует вести разработку с учётом аксиомы: внешние системы по умолчанию не защищены.
14. Разработайте план действий на случай сбоев или отказов.
15. Не стройте систему безопасности на ограничении информации о ПО.
16. Разделяйте код и данные (исключение любой смеси данных и JS- или SQL-кода).
17. Исправляя ошибки в защите, проверяйте всю систему – все модули, пытаясь найти там те же проблемы.
Общие принципы безопасного кодирования:
1. Не предоставляйте взломщику никакой информации.
2. Не позволяйте информации просочиться через заголовки.
3. Не включайте ничего лишнего в код!
4. Следите за квотами, буферами и сериализацией.
5. Используйте стандартные средства операционной системы.
6. Не рассчитывайте, что пользователи всегда принимают правильные решения: проверяйте все входные данные в широком смысле.
7. Не размещайте никаких пользовательских файлов в каталоге \Program Files.
8. Безопасно создавайте временные файлы (GetTempPath, GetTempFileName)
9. Никаких внутрикорпоративных имен в приложении!
10. Ведите журналы безопасности в приложении.
11. Перенос кода, написанного на С/С++, на управляемый язык (C#).
Безопасность написания защищённого кода на конкретных примерах
Поговорим об основных проблемах и принципах программирования, связанных с написанием безопасного приложения:
1. Переполнение буфера (стека, кучи, переполнение в результате ошибок индексации массивов, переполнение в результате использования некорректной кодировки). Способ лечения: строгая проверка всех входных данных на корректность во всех отношениях, аккуратность при обработке данных; проверка корректности подаваемых на вход strcpy/strlenи т.д. данных; использование параметра компиляции /gs компилятора gcc/VisualС++ .NET.
2. Использование злоумышленниками ПО или его службы, запущенного/ой с высокими привилегиями (примеров много, и они очевидны). Решение: а) Выясните, какие ресурсы нужны ПО; б) выясните, какие APIиспользует ПО; в) определите, какая требуется учётная запись и какой ей нужен маркер; г) Отладка ошибок, возникающих из-за ограничения привилегий.
3. Слабые случайные числа. Решение: использовать ГСЧ на основе хороших блочных шифров с полным набором раундов, работающих в режимах CBC, CFBили OFB (хотя допускается и режим ECB). Генерация – только на основании пароля, который в свою очередь должен удовлетворять определённым условиям сложности (в ПО должна быть проверка).
4. Слабая криптография. Решение: использование по возможности краткосрочных (сеансовых) ключей. Аутентификационные данные должны храниться строго централизованно, а обрабатываться – локально. В случае возникновения задачи обмена ключами по небезопасному каналу – использовать ассиметричную криптографию, передавая таким способом лишь ключи к симметричному шифру. В случае оборота ЭД, использовать механизм ЭЦП.
5. Универсальная защита конфиденциальных данных. Проблема: её нет. Решение: шифрование данных мощным симметричным алгоритмом (AES, RC6, Blowfish, 3DESи т.д.), хранение пароля в надёжном разделе реестра (в случае несистемного использование – вообще нехранение пароля!), требование ввода пароля, защита списками ACLфайла и раздела реестра.
6. Опасность входных данных (SQL-injection, XSSи многое другое). Проблема: очевидна. Решение: особое внимание всякого рода регулярным выражениям; строгий контроль корректности и длины входных данных и их фильтрация. Указывайте полные пути в адресах, представленные в канонической форме.
7. Опасности работы с БД. Решения: а) Использование параметризованных запросов к БД, отсутствие конструирования запросов внутри приложения; жёсткий контроль корректности отправляемых запросов; б) не подключаться к БД от имени system; г) Используйте безопасно хранимые процедуры.
8. Защита от XSS-атак: а) кодирование выходных данных; б) использование двойных кавычек во всех атрибутах тэга; в) Как можно чаще используйте innerText; г) Используйте только одну кодовую страницу.
Выводы
Итак, мы рассмотрели основные правила и принципы написания защищённого кода в приложениях; способах защиты его от узявимостей и проблемах программирования. Конечно, данные методы не являются исчерпывающими и не претендуют на полноту - они лишь показывают основные закономерности, тенденции и принципы граммотного проектирования архитектуры проекта и моментов, стоящих внимания. Не стоит забывать и об организационной безопасности, роль которой сложно переоценить, а также принципах информационной безопасности в общем.
A.S.