Некоторые соображения по безопасности после десяти лет qmail 1.0

Некоторые соображения по безопасности после десяти лет qmail 1.0 Bernstein, 2007

Я считаю безопасность гораздо более важной, чем скорость. Нам нужны неуязвимые программные системы, и мы нуждаемся в них сегодня, даже если они в десять раз медленнее наших текущих. Завтра мы можем начать работу над тем, чтобы сделать их быстрее.

Это было написано Даниэлем Бернстайном более десяти лет назад. И звучит так же верно, как и в тот день, когда он написал это, особенно с Meltdown и Spectre, нависшими над нами. Среди его многочисленных достижений Даниэля Бернштейна - qmail. Бернштейн создал qmail, потому что он накормил нас всеми уязвимостями безопасности в sendmail. Спустя десять лет после запуска qmail 1.0, и в то время, когда более миллиона интернет-серверов SMTP запускали qmail или netqmail, в выпусках qmail 1.0 обнаружены только четыре известных ошибки, и нет проблем с безопасностью. В этой статье излагаются принципы, которые сделали это возможным. ( С благодарностью Виктору Йодайкену, который указал мне документ в прошлом году ).

Как было разработано qmail для достижения беспрецедентного уровня безопасности? Что сделал qmail с точки зрения безопасности, и что он мог сделать лучше? Как мы можем создавать другие программные проекты с достаточной уверенностью для обеспечения сопоставимых гарантий безопасности?

Бернштейн предлагает три ответа на эти вопросы, а также предупреждает о трех отвлекающих моментах : вещи, которые, по нашему мнению, улучшают ситуацию, но на самом деле могут ухудшить ситуацию. Кажется, хорошее время вернуться к ним. Давайте сначала отвлечемся от этого.

Три отвлечения от написания безопасного программного обеспечения

Первое отвлечение - «преследование нападавших» - завершение в реактивном режиме, при котором вы постоянно изменяете программное обеспечение для предотвращения раскрытых атак. Это не значит, что вы не должны патч против обнаруженных атак, но это совсем другое дело в написании безопасного программного обеспечения в первую очередь:

Для многих людей «безопасность» заключается в наблюдении за текущими атаками и изменении чего-либо! - чтобы эти атаки потерпели неудачу ... изменения ничего не делают, чтобы исправить недостатки в разработке программного обеспечения, которые привели к возникновению дыр в безопасности. Если мы определяем успех как остановку вчерашних атак, а не как продвижение к остановке всех возможных атак, то мы не должны удивляться, что наши системы остаются уязвимыми для завтрашних атак. , (Акцент мой).

Второе отвлечение более удивительно: это принцип наименьшей привилегии! Это означает, что каждая программа и пользователь системы должны работать с минимальным набором привилегий, необходимых для завершения задания. Неужели это хорошо? Мы не должны давать власть там, где она не принадлежит. Но причина, по которой Бернштейн называет это отвлечением, заключается в том, что назначение наименьшей привилегии может усыпить нас ложным чувством безопасности:

Минимизация привилегий - это не то же самое, что минимизировать количество доверенного кода и не приближает нас к защищенной компьютерной системе ... Определяющая функция ненадежного кода заключается в том, что он не может нарушать требования безопасности пользователя.

Я не уверен , я согласен , что хотя бы привилегия не побудит нас какие - либо ближе к защищенной компьютерной системе, но я покупаю общий аргумент здесь. Мое мнение могло бы принести больше веса, хотя, если бы мне удалось написать сложное программное обеспечение, развернутое на миллионах систем с четырьмя известными ошибками и без проблем безопасности за десять лет работы!

Третье отвлечение очень актуально: скорость. Мы знаем о затраченном времени и усилиях по программированию за счет преждевременной оптимизации, но наше почитание скорости имеет и другие более тонкие издержки. Это заставляет нас отказаться от вариантов дизайна, которые были бы более безопасными (например, начать новый процесс для обработки задачи) - их даже не пробовали.

Любой, кто пытается улучшить языки программирования, архитектуры программ, системные архитектуры и т. Д., Должен преодолеть подобное препятствие. Конечно, какой-то программист, который пытается (или считает) улучшение, столкнется (или предвидят) некоторое замедление в каком-то контексте, а затем обвинит в улучшении «слишком медленного» - маркетинговой катастрофы ... Но я считаю безопасность гораздо более важной, чем скорость.

Сначала сделайте это безопасным, а затем сделайте это быстрее.

Как мы можем сделать наше программное обеспечение более безопасным?

Первый ответ, и, безусловно, самый очевидный ответ - уменьшить частоту ошибок.

ОШИБКИ безопасности - это ошибки в нашем программном обеспечении. Если мы можем уменьшить или устранить ошибки (по всем направлениям), мы также должны уменьшить или устранить дыры в безопасности.

Получение снижения уровня ошибок поможет, но заметьте, что это ставка : ошибки в строке кода. Это говорит о втором ответе: уменьшите количество кода в системе:

Процессы разработки программного обеспечения различаются не только количеством ошибок в заданном объеме кода, но и объемом кода, используемым для предоставления функций, которые хотят пользователи ... мы можем мета-инженерные процессы, которые выполняют работу с меньшими объемами кода ,

Обратите внимание на важность меньшего количества строк кода для каждой требуемой функции . Как мы видели в прошлом году при рассмотрении инцидентов, связанных с безопасностью («Анализ ошибок программного обеспечения », « Роль программного обеспечения в авариях на космических аппаратах»), многие проблемы возникают из-за упущений - неспособность делать то, что вы действительно должны были сделать. И это требует большего количества кода, не меньше.

Если мы просто остановимся на снижении частоты ошибок и уменьшении количества строк кода, у нас должно быть меньше дыр в безопасности. К сожалению, конечный результат только одногоуязвимого дыра в безопасности одинаковый в программном обеспечении с одним отверстием, как в программном обеспечении с множеством. Вероятно, есть какая-то экспоненциальная кривая, которая может быть построена на графике разработки программного обеспечения против количества ошибок, благодаря чему ранние прибыли поступают относительно легко, но изгнание последних из них становится чрезмерно дорогостоящим. (Напомню, например, Эмпирическое исследование правильности формально проверенных распределенных систем.) Теперь усилия, которые мы должны предпринять для достижения наивысшего уровня уверенности, должны каким-то образом быть функцией размера кода, который должен быть гарантирован. Поэтому желательно устранить необходимость достижения такого уровня уверенности в максимально возможном количестве мест. Таким образом,

Третий ответ - уменьшить количество доверенного кода в компьютерной системе. Мы можем архитектовать компьютерные системы, чтобы разместить большую часть кода в ненадежных тюрьмах. «Untrusted» означает, что код в этих тюрьмах - не то, что делает код, независимо от того, насколько плохо он себя ведет, независимо от того, сколько ошибок он имеет - не может нарушать требования безопасности пользователя ... Существует приятная синергия между удалением доверенного кода и устранением ошибок : мы можем позволить себе относительно дорогостоящие методы устранения ошибок в доверенном коде просто потому, что объем кода меньше.

Мета-инжиниринг для сокращения ошибок

В разделе, посвященном методам устранения ошибок, содержится абзац, на который нужно оповещать какое-то время. Я сильно подозреваю реальную тайну успеха Бернштейна, когда qmail предоставляется нам прямо здесь:

В течение многих лет я систематически определял склонность к ошибкам в программировании - просмотрел литературу, проанализировал ошибки других людей и проанализировал свои собственные ошибки - и перепроектировал свою среду программирования, чтобы устранить эти привычки.

Некоторые из рекомендованных методов включают в себя обеспечение четкого потока данных (проектирование больших частей qmail для запуска в отдельных процессах, связанных с конвейерами, что облегчает просмотр большей части внутреннего потока данных qmail), упрощая целую семантику (используя большие целые числа и регулярную арифметику, чем обычная модульная арифметика) и код факторинга, чтобы упростить проверку ошибок.

Большинство программных сред имеют метаинструкцию, чтобы упростить запись типичного программного обеспечения. Вместо этого они должны быть мета-инженерами, чтобы затруднить запись неправильного программного обеспечения.

Устранение кода

Чтобы уменьшить объем кода, мы можем изменить языки и структуры программирования и, если это возможно, повторно использовать существующие средства.

Когда я писал qmail, я отклонил многие языки как более болезненные, чем C для конечного пользователя для компиляции и использования. Я был необъяснимо слепым к возможности написания кода на лучшем языке, а затем с помощью автоматизированного переводчика, чтобы преобразовать код в C как язык распространения.

Вот интересный пример дизайна, позволяющий повторное использование: вместо того, чтобы выполнять собственные проверки прав, чтобы узнать, имеет ли пользователь разрешение на чтение файла, qmail просто запускает программу доставки под правильным uid. Это означает, что есть дополнительный процесс (см. Более раннее обсуждение «отвлечения внимания»), но избегает многих других проблем.

Думая о TCB

Программисты, записывающие текстовые процессоры и музыкальные проигрыватели, обычно не беспокоятся о безопасности. Но пользователи ожидают, что эти программы смогут обрабатывать файлы, полученные по электронной почте или загруженные из Интернета. Некоторые из этих файлов подготовлены злоумышленниками. Часто в программах есть ошибки, которые могут быть использованы злоумышленниками ...

Бернштейн предлагает в качестве примера более совершенную практику перемещения обработки пользовательского ввода (в данном случае для преобразования jpegs в растровые изображения) изнутри одного и того же процесса, к тому, что по существу является заблокированным контейнером.

Я не знаю точно, насколько небольшой конечный TCB будет, но я с нетерпением жду, чтобы узнать. Конечно, нам все равно нужно устранить ошибки из оставшегося кода!

Meltdown и Spectre должны дать нам повод задуматься над тем, что мы делаем и куда движемся. Если результатом этого является немного более метаинжиниринг в стиле Бернштейна, чтобы улучшить безопасность программного обеспечения, созданного нашими процессами, то, возможно, в конце концов может получиться что-то хорошее.