Атака на Internet
Шрифт:
Безопасность браузеров
Популярные браузеры в своем развитии уже вышли далеко за рамки простых средств отображения гипертекстовых документов. HTML (HyperText Markup Language – язык разметки гипертекстовых документов) изначально был ориентирован исключительно на отображение структурированного текста. Имелась также возможность включить в документ отдельные управляющие элементы для передачи информации на сервер, который после этого мог вернуть клиенту результаты обработки, то есть чисто клиент-серверное решение. Этим и исчерпывались интерактивные возможности Web. По мере развития Сети выяснилось, что ее выразительных средств становится недостаточно для удовлетворения растущих запросов пользователей, и HTML стал включать в себя средства для работы с таблицами, графикой, звуком.
Кроме того, не все устраивало и разработчиков Web-приложений – иногда им хотелось бы иметь дело с более интеллектуальным
Наибольшую популярность завоевали следующие подходы к реализации вспомогательных приложений для клиентской стороны:
• подключаемые модули (plug-ins);
• элементы ActiveX;
• средства подготовки сценариев JavaScript, VBScript, Dynamic HTML;
• приложения Java.
Рассмотрим их подробнее.
Использование подключаемых модулей получило в свое время широкое распространение в связи с популярностью браузера Netscape Navigator, предоставляющего такую возможность. С точки зрения безопасности этот подход не выдерживает никакой критики: не обеспечивается ни защита от сбоев, ни защита от злонамеренных действий, предпринимаемых модулем, который имеет полный доступ ко всем ресурсам системы пользователя. Все строится исключительно на доверии к автору модуля.
Управляющие элементы ActiveX – решение компании Microsoft, основанное на вездесущей технологии COM (Component Object Model – модель компонентных объектов), перенесенной на этот раз в Internet. Проблема безопасности решается с помощью введения института сертификатов – объекты ActiveX подписываются цифровой подписью автора, заверенной независимой организацией (например, VeriSign Inc.). Таким образом, работа с ActiveX отличается от работы с подключаемыми модулями Netscape только тем, что доверие к автору управляющего элемента может быть подкреплено авторитетом солидной организации. В то же время эта подпись гарантирует лишь возможность определения авторства объекта, а вовсе не его благонадежности.
При загрузке объекта ActiveX поведение браузера зависит от настроек его системы безопасности – как подписанные, так и неподписанные (либо заверенные неизвестной организацией) объекты могут быть либо автоматически загружены или отвергнуты, либо предъявлены пользователю, с тем чтобы дальнейшее решение принимал он. В Internet Explorer также можно задать разные настройки для различных зон безопасности – для локальной сети, Internet, отдельных подозрительных хостов, и наоборот, достойных особого доверия.
JavaScript, VBScript и т. п. представляют собой упрощенные языки подготовки сценариев, код которых встраивается непосредственно в html-файл и выполняется браузером. Они непригодны для реализации серьезных приложений, в них отсутствуют средства для работы с файлами, сетевого взаимодействия и т. д. Но они широко используются во вспомогательных целях, в качестве средства первоначальной обработки результатов, для оформления, «оживления» html-документов и т. д. Казалось бы, что ограничения, присущие этим языкам, делают их абсолютно безопасными, в действительности же львиная доля ошибок в браузерах связана именно с реализацией этих простейших средств разработки.
Безопасность Java-приложений
Java – язык, разработанный Sun Microsystems изначально для приложений бытовой электроники и позднее перенесенный в Internet, что стало для него вторым рождением. Различают обычные Java-приложения и апплеты, предназначенные для загрузки по сети и выполнения в окне браузера.
Вопросы безопасности Java-апплетов заслуживают того, чтобы о них говорить отдельно, поскольку это единственное распространенное средство разработки клиентских приложений, в котором решение проблемы безопасности предлагается уже на уровне архитектуры.
Основным достоинством Java-приложений является независимость от клиентской платформы. В отличие от традиционных приложений, транслирующихся в исполняемые коды процессора, Java-приложения транслируются в так называемый байт-код, интерпретируемый в дальнейшем виртуальной Java-машиной. При этом байт-код независим от платформы, на которой он в дальнейшем будет выполняться, – достаточно, чтобы для этой платформы существовала Java-машина. Поскольку большинство основных функций реализовано на уровне виртуальной Java-машины, это приводит к существенному уменьшению размеров байт-кода,
что является как достоинством, так и недостатком Java-приложений. Так как байт-код интерпретируется виртуальной машиной, производительность Java-приложений уступает производительности традиционных откомпилированных программ. Частично с этим удается бороться, применяя компиляторы времени исполнения (JIT – just in time compilers), осуществляющие компиляцию приложения при его загрузке в «родной» для данного процессора код. Также возможен вызов функций, реализованных на других языках программирования (С, С++) и откомпилированных для данной платформы, – так называемый native code (родной код). Он применяется при реализации наиболее критичных ко времени исполнения фрагментов кода.Другим достоинством Java-приложений является защищенность. Во-первых, сам язык способствует написанию более надежных и устойчивых к сбоям программ. Помимо строгой типизации, управления доступом, работы с исключениями, знакомых программистам и по С++, в Java добавлена автоматическая «сборка мусора» (освобождение неиспользуемой памяти), проверка на выход за границы массива, возможность указать, что данный метод или объект не может быть изменен или переопределен. В языке нет указателей и переопределенных операторов.
Все эти нововведения помогают создавать более безопасный код. Рассмотрим теперь особенности Java, вынуждающие писать безопасный код.
По мере развития Java развивалась и система безопасности. В JDK 1.0 (Java Development Kit) основу системы безопасности составляли три компонента – Verifier (верификатор), ClassLoader (загрузчик классов) и SecurityManager (менеджер безопасности). Эта модель известна под названием sandbox (песочница), в ней выполняются Java-приложения, загруженные из сети (рис. 10.1).
Рис. 10.1. Модель безопасности JDK 1.0
Для полноценного функционирования модели безопасности каждый ее компонент должен работать безошибочно, поскольку только четкая совместная работа компонентов обеспечивает контроль над приложением во время загрузки и исполнения кода.
Первый рубеж обороны – верификатор, проверяющий загружаемый байт-код на корректность, так как у нас нет никакой гарантии, что загружаемый код был получен в результате работы компилятора Java, а не подправлен вручную или не сгенерирован специальным «враждебным» компилятором. После того как код прошел верификацию, гарантируется, что файл класса имеет корректный формат, параметры всех операций имеют правильный тип, в коде не происходит некорректных преобразований типов (например, целого числа в указатель), нет нарушений доступа и т. п. Таким образом, проверяется все, что только можно проверить до начала исполнения программы. Верификатор встроен в виртуальную машину и недоступен из Java-программы.
Загрузчики классов определяют, когда и каким образом классы могут быть добавлены в работающую систему. Частью их работы является защита важных составляющих системы, например запрет на загрузку поддельного менеджера безопасности. Они выполняют две основные функции – собственно загрузку байт-кода (с локального диска, по сети, из области памяти и т. д.), определение namespaces (пространства имен) для различных классов и способов их взаимодействия (отделяя, к примеру, локальные классы от загруженных по сети).
Есть два вида загрузчиков – primordial (первичный) и Class Loader Object (реализованный в виде объекта). Первичный существует в единственном экземпляре и является составной частью виртуальной машины. Он занимается загрузкой доверенных классов (обычно находящихся на локальном диске). Загрузчик второго типа представляет собой экземпляр обычного Java-класса, унаследованного от абстрактного класса java.lang.ClassLoader. С его помощью можно осуществить загрузку класса по сети либо динамическое конструирование класса приложением. Метод defineClass преобразует массив байтов в экземпляр класса Class, а экземпляры нового класса создаются с помощью метода newInstance класса Class. Если метод созданного класса ссылается на другие классы, виртуальная машина вызывает метод loadClass его загрузчика, передавая ему имя запрашиваемого класса. При создании экземпляра класса или вызове любого из его методов потребуется также загрузка его предка и других используемых им классов, за это отвечает функция resolveClass.
Примерная реализация класса NetworkClassLoader может выглядеть следующим образом: