Уязвимости  системного и прикладного Программного Обеспечения (ПО) стабильно и уже долгое время занимают лидирующие строки в рейтинге кибер-угроз. Не смотря на совершенствование инструментов разработки, созданию новых подходов к проектированию и программированию, непрерывно растет сложность задач, а следовательно и написанного кода. Это в свою очередь ведет к увеличению риска появления критических ошибок в ПО. Для обеспечения безопасности кода пользуются современные технологии проверки - статический и динамический анализ, ручная инспекция, 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; 
г) используйте только одну кодовую страницу.
Комментариев нет:
Отправить комментарий
Вы можете добавить свой комментарий...
Примечание. Отправлять комментарии могут только участники этого блога.