Уязвимости системного и прикладного Программного Обеспечения (ПО) стабильно и уже долгое время занимают лидирующие строки в рейтинге кибер-угроз. Не смотря на совершенствование инструментов разработки, созданию новых подходов к проектированию и программированию, непрерывно растет сложность задач, а следовательно и написанного кода. Это в свою очередь ведет к увеличению риска появления критических ошибок в ПО. Для обеспечения безопасности кода пользуются современные технологии проверки - статический и динамический анализ, ручная инспекция, Fuzz testing и другие. Но сегодня в публикации речь пойдет не об инструментальных средствах, а о концепции проектирования и написания безопасного кода, которые мы собрали из различных источников и собственного опыта.
В нынешнее время весьма хорошим результатом для опытного программиста считается 1 серьёзная ошибка на 1000 строк кода. Для примера, в новомодной Windows 8 содержится 7 миллионов строк. В таком случае, количественно потенциальных критических ошибок подсчитать сможет даже ученик начальных классов.
В помощь программистам для выявления ошибок кода в ПО созданы специальны инструменты - статические и динамические анализаторы кода, а так же зарекомендовавший себя ручной анализ, получивший название инспекция кода (code inspection). Дополнительными инструментами можно считать системы управления версиями и ветками релизов, например такие как SVN и Git. И система отслеживания ошибок (bug tracking system)
Если кратко, то все ошибки (баги) можно разделить на несколько видов:
- Борбаг — легко обнаруживаемый стабильный баг
- Гейзенбаг — сложно обнаруживаемый, периодически исчезающий и меняющий свойства баг при попытке его обнаружения
- Мандельбаг — баг с очень сложным, хаотичным, поведением
- Шрёдинбаг — критическая ошибка, которая не проявляется пока кто-нибудь на неё не наткнется в исходном коде, после чего программа совершенно перестает работать
Если тема тестирования ПО стала интересна, том могу предложить продолжить чтение на эту тему статьи на Хабре
А вот в этой статье можно больше узнать о этимология и энтомология Багов.
А сейчас приведу общие правила и рекомендации по написанию базопасного кода вне зависимости от целевой платформы, языка программирования или используемого компилятора.
- Проверяйте входящие данные.
- Учитывайте предупреждения компилятора.
- Проектируйте с возможностью разделения привелегий.
- Делайте все простым.
- По умолчанию запрещайте.
- Используйте наименее возможные привелегии.
- Уберите лишюю информацию при отправке в сторонние системы.
- Защищайтесь на всех уровнях.
- Используйте хорошие системы контроля качества.
- Разработайте правила/стандарт безопасного написания кода.
Общие принципы проектирования защищённых приложений
- Защита должна ставиться, как неотъемлемая функция создаваемого ПО.
- На обеспечение безопасности ПО должно быть отведено достаточно времени.
- Обязательно должна быть составлена модель угроз: декомпозиция ПО с выявлением присущих уязвимостей; определение степени опасности и вероятности возникновения каждой уязвимости/опасности; составление матрицы угроз; определение противодействий, а также действий в случае реализации угрозы.
- Определение процедуры удаления небезопасных функций и частей в ПО.
- Должны быть созданы метрики безопасности, соответствующие модели угроз, в которых должны быть определены предельные пороги.
- Разработка тест-планов и периодическая проверка и контроль процесса создания ПО отделом ИБ на каждом этапе разработки по созданным тест-планам, по возможности, - приглашёнными специалистами.
- Обязательный контроль безопасности модуля не тем, кто разработал данный модуль.
- Безопасность должна обеспечиваться в конфигурации по умолчанию и при развёртывании.
- Особый контроль за предоставлением прав на внесение изменений в ПО.
- «Площадь уязвимости» (потенциальная) должна быть как можно меньше (всевозможные открытые TCP/UDPпорты, запускаемые и зависимые службы, динамические веб-страницы, части приложения или службы, запускаемые с высокими привилегиями и т.д.).
- Должны быть защищены все уровни (независимо друг от друга и от других уровней защиты).
- Используйте правило минимальных привилегий (и + грамотно составленный ACL).
- Следует вести разработку с учётом аксиомы: внешние системы по умолчанию не защищены.
- Разработайте план действий на случай сбоев или отказов.
- Не стройте систему безопасности на ограничении информации о ПО.
- Разделяйте код и данные (исключение любой смеси данных и JS- или SQL-кода).
- Исправляя ошибки в защите, проверяйте всю систему – все модули, пытаясь найти там те же проблемы.
Общие принципы безопасного кодирования
1.Не предоставляйте взломщику никакой информации.
2.Не позволяйте информации просочиться через заголовки.
3.Не включайте ничего лишнего в код!
4.Следите за квотами, буферами и сериализацией.
5.Используйте стандартные средства операционной системы.
6.Не рассчитывайте, что пользователи всегда принимают правильные решения: проверяйте все входные данные в широком смысле.
7.Не размещайте никаких пользовательских файлов в каталоге \Program Files.
8. Безопасно создавайте временные файлы (GetTempPath, GetTempFileName)
9. Никаких внутрикорпоративных имен в приложении!
10.Ведите журналы безопасности в приложении.
Безопасность написания защищённого кода на конкретных примерах
Поговорим об основных проблемах и принципах программирования, связанных с написанием безопасного приложения:
1. Переполнение буфера (стека, кучи, переполнение в результате ошибок индексации массивов, переполнение в результате использования некорректной кодировки).
Способ лечения: строгая проверка всех входных данных на корректность во всех отношениях, аккуратность при обработке данных; проверка корректности подаваемых на вход
2. Использование злоумышленниками ПО или его службы, запущенного/ой с высокими привилегиями (примеров много, и они очевидны).
Решение:
а) Выясните, какие ресурсы нужны ПО;
б) выясните, какие API использует ПО;
в) определите, какая требуется учётная запись и какой ей нужен маркер;
г) отладка ошибок, возникающих из-за ограничения привилегий.
3. Слабые случайные числа.
Решение: использовать ГСЧ на основе хороших блочных шифров с полным набором раундов, работающих в режимах CBC, CFBили OFB (хотя допускается и режим ECB). Генерация – только на основании пароля, который в свою очередь должен удовлетворять определённым условиям сложности (в ПО должна быть проверка).
4. Слабая криптография.
Решение: использование по возможности краткосрочных (сеансовых) ключей. Аутентификационные данные должны храниться строго централизованно, а обрабатываться – локально. В случае возникновения задачи обмена ключами по небезопасному каналу – использовать ассиметричную криптографию, передавая таким способом лишь ключи к симметричному шифру. В случае оборота ЭД, использовать механизм ЭЦП.
5. Универсальная защита конфиденциальных данных.
Проблема: её нет.
Решение: шифрование данных мощным симметричным алгоритмом (AES, RC6, Blowfish, 3DESи т.д.), хранение пароля в надёжном разделе реестра (в случае несистемного использование – вообще нехранение пароля!), требование ввода пароля, защита списками ACL файла и раздела реестра.
6. Опасность входных данных (SQL-injection, XSSи многое другое). Проблема: очевидна. Решение: особое внимание всякого рода регулярным выражениям; строгий контроль корректности и длины входных данных и их фильтрация. Указывайте полные пути в адресах, представленные в канонической форме.
7.Опасности работы с БД.
Решения:
а) Использование параметризованных запросов к БД, отсутствие конструирования запросов внутри приложения; жёсткий контроль корректности отправляемых запросов; б) не подключаться к БД от имени system;
г) Используйте безопасно хранимые процедуры.
8. Защита от XSS-атак:
а) кодирование выходных данных;
б) использование двойных кавычек во всех атрибутах тэга;
в) как можно чаще используйте innerText;
г) используйте только одну кодовую страницу.
Комментариев нет:
Отправить комментарий
Вы можете добавить свой комментарий...
Примечание. Отправлять комментарии могут только участники этого блога.