В ноябре 2022 года американское Агентство национальной безопасности выпустило бюллетень, посвященный безопасности при работе с оперативной памятью. Если посмотреть другие бюллетени АНБ по нашей теме, будет заметно, что они посвящены в основном либо шифрованию данных, либо защите производственных циклов и другим организационным вопросам. Обращаться напрямую к разработчикам программного обеспечения — достаточно необычный шаг для агентства. И если уж он был сделан, то явно речь идет о чем-то особенно важном. Если совсем коротко: АНБ призывает разработчиков ПО переключаться на использование языков программирования, архитектура которых подразумевает повышенную безопасность при работе с памятью, — то есть, по сути, перестать использовать языки С и С++. В иных случаях рекомендуется внедрять комплекс мер по тестированию ПО на уязвимости и предотвращению их эксплуатации.
Для программистов это достаточно очевидные вещи, и призыв АНБ скорее адресован не им напрямую, а их руководству — представителям бизнеса. Поэтому бюллетень составлен в понятных для бизнеса выражениях. Давайте попробуем проанализировать изложенные в нем аргументы, не залезая в технические дебри.
Безопасность памяти
Откроем наш свежий отчет об эволюции угроз за третий квартал 2022 года и посмотрим на уязвимости, наиболее часто используемые в кибератаках. В топе до сих пор уязвимость CVE-2018-0802 в компоненте Equation Editor офисного пакета Microsoft Office, обнаруженная еще в 2018 году. Она вызвана некорректной обработкой данных в оперативной памяти, в результате чего открытие «подготовленного» документа Microsoft Word может привести к запуску произвольного кода. Еще одна популярная у преступников уязвимость — CVE-2022-2294 в компоненте WebRTC браузера Google Chrome: она приводит к выполнению произвольного кода в результате ошибки переполнения памяти. Еще одна проблема, CVE-2022-2624, содержащаяся в инструменте для просмотра PDF в Chrome, также может привести к переполнению памяти.
Разумеется, не все уязвимости в ПО вызваны небезопасной работой с оперативной памятью, но очень и очень многие. Бюллетень АНБ ссылается на статистику Microsoft, согласно которой ошибки при работе с памятью — причина 70% обнаруживаемых уязвимостей.
Почему так выходит? Если вопрос утечек памяти настолько серьезен, почему нельзя как-то организоваться и перестать писать уязвимый код? Корень проблемы в использовании языков программирования С и С++. По своей архитектуре они предоставляют разработчикам большую свободу при работе с данными в оперативной памяти. Вместе со свободой приходит и ответственность: внедрять механизмы безопасной записи данных и их чтения программистам на C/C++ приходится самостоятельно. В то же время такие высокоуровневые языки программирования как C#, Rust, Go и другие берут часть этой заботы «на себя». Речь идет о том, что при компиляции исходных кодов программы средства безопасной работы с памятью внедряются автоматически, и разработчикам не надо тратить на них время. В языке Rust применены и другие средства повышения безопасности — вплоть до того, что потенциально опасный код просто не будет скомпилирован, а программисту укажут на ошибку.
Конечно, просто отказаться от использования C/C++ не получится — для некоторых задач эти языки незаменимы. Например, когда требуется писать код для микроконтроллеров и других устройств с серьезными ограничениями по вычислительной мощности и объему оперативной памяти. Высокоуровневые языки программирования могут при прочих равных приводить к созданию более требовательных к ресурсам программ. Но из статистики распространенных угроз мы знаем, что наиболее часто атакуется обычное пользовательское ПО (браузер, текстовый редактор), которые выполняются на очень мощных (конечно же, по сравнению с микроконтроллерами) компьютерах.
Нельзя просто так взять и поменять язык программирования
Это в АНБ очень хорошо понимают. Огромная база программного обеспечения, написанная на «небезопасных» языках программирования, не может в одночасье быть портирована на другой язык. Даже если речь идет о написании программного продукта с нуля, вокруг определенного языка программирования может существовать сложившаяся команда, инфраструктура, методы разработки.
Если поискать аналогию, то это как если бы вам предложили переехать из вашего дома просто потому, что он слишком давно построен. При этом вы знаете, что дом еще крепок, развалится только в случае серьезного землетрясения, и вообще вы привыкли в нем жить! В блоге команды разработчиков Google Chrome есть заметка, в которой прямо сказано: они не могут прямо сейчас перейти на другой язык программирования (в данном случае Rust), в котором безопасность заложена в архитектуру. В будущем — да, возможно. Сейчас же нужны другие решения.
В той же заметке разработчиков Google Chrome также объясняется, почему не получится принципиально изменить безопасность кода на C/C++. Подобные языки программирования просто не были спроектированы так, чтобы можно было одним махом решить все проблемы при компиляции. Поэтому в бюллетене АНБ в качестве альтернативы речь идет о двух комплексах мер:
- тестирование кода на потенциальные уязвимости с помощью приемов динамического и статического анализа;
- использование приемов, предотвращающих эксплуатацию ошибки в коде, даже если она была допущена.
О сложностях переезда
Технические специалисты с мнением АНБ в целом согласны. У специалистов могут быть разные мнения о том, как конкретно переходить на высокоуровневые языки программирования там, где это продиктовано в том числе требованиями безопасности. Важно понимать, что, во-первых, такой переход если и случится, то займет много лет. Во-вторых, у подобной эволюции есть своя цена, и не каждый бизнес готов ее заплатить. Проблема небезопасной работы с памятью в языках программирования с низким уровнем абстракции — это системная проблема. Призывать к ее радикальному решению надо, но не стоит ожидать, что завтра все перейдут на разработку на C#, Go, Java, Ruby, Rust или Swift. Точно так же вряд ли можно заставить весь город или всю страну в одночасье переехать из старого и ветхого жилья.
Наконец, проблема небезопасной работы с памятью — может быть, и гигантская, но далеко не единственная проблема с защищенностью программного обеспечения. За несколько десятилетий существования IT-индустрии еще ни разу не удавалось создать универсальную, полностью защищенную систему для всех задач (разве что для узкоспециализированных решений). С точки зрения бизнеса есть смысл инвестировать как в новые технологии (развивая соответствующие компетенции, нанимая специалистов с опытом), так и в максимальную защиту существующих. Применительно к разработке ПО это могут быть новые языки программирования и технологии тестирования имеющегося кода. Применительно к любому другому бизнесу можно говорить об инвестировании в новые технологии защиты от кибератак, а также постоянную проверку всей существующей инфраструктуры на прочность. Иными словами, комплексный подход к безопасности — самый оптимальный, и останется таким еще очень долго.