Секреты и ложь. Безопасность данных в цифровом мире — страница 87 из 93

Первая причина – количество изъянов систем защиты. В главе 13 я рассказывал о надежности программного обеспечения и о ее связи с безопасностью. По мере усложнения системы возрастает и количество ошибок при выполнении программ, и число уязвимых мест защиты. Это происходит всегда. При усложнении программного обеспечения возрастает и количество ошибок. И процент этих ошибок будет влиять на безопасность, хотя это не всегда очевидно.

Вторая причина – модульная структура сложных систем. В главе 10 говорилось о модульном коде и связанных с ним проблемах безопасности. Сложные системы обязательно модульные; нет никакого другого способа управиться со сложностью системы, кроме как разбить ее на части, поддающиеся управлению. Мы никогда не смогли бы сделать Интернет таким сложным и интересным, каким он является, не прибегая к модульности. Но разрастание модульной структуры грозит ослаблением безопасности, поскольку взаимодействие модулей создает дополнительные возможности для взлома защиты.

Третья причина – это взаимосвязь сложных систем. Распределенные и объединенные в сети системы опасны по своей природе. Усложнение систем может привести к тому, что незначительные проблемы становятся неразрешимыми, – повлечь за собой эффект «бабочки»[62]. Мы уже наблюдали примеры того, как все становится доступным благодаря Интернету. В течение нескольких лет мы считали, что такие интернет-приложения, как почтовые программы, безопасны, но недавняя эпидемия макровирусов показала, что и Microsoft Word и Excel нуждаются в укреплении средств защиты. Апплеты Java должны не только быть безопасными в использовании, но также не допускать возможности применения их для нападения. При написании программного кода для веб-страниц используются тонкие взаимодействия между сценариями CGI, HTML, фреймами, программным обеспечением веб-сервера и cookies. В 2000 году баг Internet Explorer 5.0 блокировал правильную работу Windows 2000 при установке 128-битового шифрования. Фотокопировальные устройства, порты маршрутизаторов, RAID-массивы – ко всему этому можно получить доступ через Интернет, со всеми вытекающими отсюда угрозами для безопасности. Мошеннические драйверы принтера могут скомпрометировать Windows NT; файлы PostScript могут содержать вирусы. Вредоносный код, вложенный в сообщение электронной почты, может проникнуть через брандмауэр. Помните, я говорил о версии Windows NT, которая имела оценку безопасности С2, но только в том случае, если компьютер не подключен к сети и не имеет накопителя на гибких магнитных дисках? Помните WebTV-вирус?[63] Сколько пройдет времени, прежде чем кто-нибудь придумает вирус, поражающий сотовые телефоны?[64]

Четвертая причина в том, что чем сложнее система, тем она труднее для понимания. В главе 17 я рассказывал о манипуляциях людьми и о негативном влиянии человеческого фактора на безопасность. Эти проблемы обостряются из-за сложности систем. Люди, управляющие реальной системой, как правило, не обладают полным пониманием ее устройства, в том числе и проблем, связанных с безопасностью безопасности. А если кто-то плохо разбирается в вопросе, он, скорее всего, воспользуется помощью знающего человека. Сложность не только делает фактически невозможным создание безопасной системы, но и приводит к чрезвычайным трудностям в управлении ею.

Пятая причина – трудность анализа. В 18-21 главах я обрисовал процедуру проектирования и анализа систем безопасности: моделирование возможных угроз, определение механизмов защиты и проектирование системы безопасности. Чем сложнее система, тем тяжелее выполнить такой анализ. Все становится очень запутанным: спецификации, проект, создание и использование системы. Дерево атак для любой сложной системы становится гигантским. И, как мы уже неоднократно убедились, все это релевантно анализу безопасности.

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

Предельно упрощая, допустим, что система имеет 10 различных настроек, по 2 возможных варианта. Тогда 45 различных комбинаторных сочетаний могут взаимодействовать самым неожиданным образом, и в целом наберется 1024 различные конфигурации. Каждое взаимодействие способно привести к недостаткам безопасности и должно быть особо проверено. Теперь предположите, что система имеет 20 различных настроек. Это означает 190 различных сочетаний (по 2 из 20) и примерно 1 миллион конфигураций (2^20). 30 различных настроек определяют 435 различных пар и миллиард конфигураций. Даже небольшие увеличения в сложности системы означают стремительный рост количества различных конфигураций.

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

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

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

Это ухудшает положение. Увеличение числа недостатков безопасности пагубно влияет на защиту: безопасность всей системы зависит от прочности ее самого слабого звена. Один-единственный недостаток может свести на нет защиту всей системы.

Реальные системы не показывают никаких признаков уменьшения сложности. Фактически они становятся более громоздкими все быстрее и быстрее. Microsoft Windows – пример такой тенденции. Windows 3.1, выпущенная в 1992 году, имеет 3 миллиона строк кода. В 1998 году Windows NT 5.0 насчитывала уже 20 миллионов строк кода, а в 1999 году она была переименована в Windows 2000 и содержала в среднем от 35 до 60 миллионов строк кода. Сравнительные данные приведены в табл. 23.1.

Таблица 23.1.
Тенденция к сложности исходного кода

Операционная система (Год)Количество строк кода

Windows 3.1 (1992) – 3 млн

Windows NT (1992) – 4 млн

Windows 95 (1995) – 15 млн

Windows NT 4.0 (1996) – 16,5 млн

Windows 98 (1998) – 18 млн

Windows 2000 (2000) – 35-60 млн (приблизительно)

Windows 2000 ошеломляет своим размером, и будет иметь больше изъянов защиты, чем Windows NT 4.0 и Windows 98 вместе взятые. В свое оправдание Microsoft утверждала, что нужно потратить 500 человеко-лет, чтобы сделать Windows 2000 безопасной. Я привел эти цифры только для того, чтобы продемонстрировать, насколько неадекватна эта оценка[65].

Вы также можете видеть, что сложность увеличивается, по количеству системных вызовов. Версия UNIX 1971 года имела 33 вызова. В начале 1990-х их количество в операционных системах достигало уже 150. Windows NT 4.0 SP3 имеет 3433. Количество системных вызовов для различных операционных систем представлено в табл. 23.2.

Вначале брандмауэры имели дело только с FTP (протоколом передачи файлов), протоколами Telnet, SMTP, NNTP и службой DNS. И это все. Современные брандмауэры должны взаимодействовать с сотнями протоколов и с запутанным набором правил доступа к сети. Некоторые новые протоколы разработаны подобно HTTP, чтобы они могли «работать с брандмауэром» (то есть обходить его). И пользователи, устанавливающие автоматическую связь, могут не беспокоиться о брандмауэре; теперь для этой цели существуют широкополосные аппаратно-программные средства с DSL и кабельными модемами. Хуже того, существует доступное программное обеспечение, позволяющее пользователям домашних компьютеров представлять себя в качестве веб-серверов. Больше особенностей, больше сложности, меньше надежности.

Таблица 23.2.
Тенденция к сложности в операционных системах

Операционная система(Год) – Количество системных вызовов

UNIX 1ed (1971) – 33

UNIX 2ed (1979) – 47

SunOS 4.1 (1989) – 171

4.3 BSD Net 2 (1991) – 136

SunOS 4.5 (1992) – 219

HP UX 9.05 (1994) – 163

Line 1.2 (1996) – 211

SunOS 5.6 (1997) – 190

Linux 2.0 (1998) – 229