Шрифт:
Побочным эффектом введения этого механизма стало появление в составе стандартной библиотеки Java криптографических функций – Crypto API.
Модель безопасности JDK 1.1 отличалась черно-белым взглядом на мир – мы либо полностью доверяем загруженному коду, либо нет. В Java 2 (JDK 1.2), вышедшей в декабре 1998, была представлена новая гибкая модель безопасности, основанная на привилегиях и правах доступа (рис. 10.3).
Дополнительно к существующим классам в Java 2 добавились:
• новый загрузчик классов java.security.SecureClassLoader;
• класс java.security.Permission, наследники которого используются для определения прав доступа к различным ресурсам, и класс java.security.PermissionCollection, позволяющий группировать права доступа. За доступ к файлам отвечает java.io.FilePermission, к сети – java.net.SocketPermission, к графическим ресурсам – java.awt.AWTPermission и т. д.;
• класс java.security.AccessController, используемый для контроля доступа FilePermission p = new FilePermission("/tmp/junk", "read"), и AccessController.checkPermission(p);
• класс java.security.ProtectionDomain, позволяющий объединить классы, которым предоставляются одинаковые права доступа;
• класс java.security.Policy, отвечающий за политику безопасности. В каждый момент активен только один объект Policy, считывающий настройки из файла конфигурации. В этом файле можно описать, какие права доступа связаны с той или иной подписью и/или местом расположения файлов:grant codeBase «http://www.somehost.com/*», signedBy «Signer»
{
permission java.io.FilePermission "/tmp/*", "read";
permission java.io.SocketPermission "*", "connect";
};Новая модель безопасности имеет следующие особенности:
• настраиваемый контроль доступа, дающий возможность указать, что код, обладающий определенными правами доступа, имеет право на определенные действия. Этого можно было добиться и раньше, с помощью создания специализированных менеджеров безопасности и загрузчиков классов, новая же архитектура значительно упростила такую процедуру;
• легко конфигурируемая политика безопасности. Опять же ключевое слово здесь – «легко»;
• возможность легкого расширения множества прав доступа, то есть фактически контролируемых действий. Если раньше это требовало введения новых методов check* в SecurityManager, теперь достаточно описать еще одного наследника класса java.security.Permission;
• усиление контроля за всеми Java-приложениями: в настоящее время никакой код не считается безопасным априори. Локальный код может быть подвержен тем же проверкам, что и код апплета, хотя, конечно, никто не мешает ослабить этот контроль с помощью настроек.
Таким образом, схема работы довольно гибкая и позволяет эффективно реализовать любую политику безопасности.Суровая действительность
До сих пор мы говорили о том, каким образом системы безопасности клиентских решений выглядят в идеальном случае, как это должно работать. Реально же большая часть проблем безопасности пользователей связана именно с ошибками в исполнении этих стройных схем.
Апплеты, мешающие работе
Java-приложения зависят от существующей для данной платформы виртуальной Java-машины. Java-машины реализованы для всех наиболее распространенных платформ, а также входят в состав самых популярных браузеров, но они достаточно ресурсоемки и зачастую довольно нестабильны. Кроме того, остаются проблемы совместимости – поскольку Java изначально проектировалась для написания многоплатформенных приложений, в нее преимущественно входили элементы, существующие на всех платформах, что привело к некоторой аскетичности доступных средств. Отдельные разработчики расширяют возможности виртуальных машин для конкретной платформы, и получается, что Java-приложение, использующее все эти возможности, утрачивает способность запускаться на других платформах.
Для начала рассмотрим ряд атак, прекрасно функционирующих в рамках существующей модели безопасности (на сегодняшний день – середина 1999 года – для большинства пользователей популярных браузеров таковой является схема из JDK1.1). Java достаточно хорошо справляется с защитой от нарушения целостности системы, но вот c оставшимися видами атак у нее явные проблемы. Большинство представленных здесь примеров прекрасно функционирует в Netscape Communicator 4.5. Internet Explorer 4.01 справляется с некоторыми из них намного лучше, но и у него есть «любимые мозоли». Так, один из вредоносных апплетов, приводящий к зависанию Windows 9x, активно использовал расширения Java от Microsoft, позволяющие работать напрямую с библиотеками DirectX.
Проще всего создаются апплеты, затрудняющие работу пользователя. К примеру, мы открываем какую-то WWW-страницу и вздрагиваем от несущегося из колонок раздражающего звука. Нами овладевает естественное желание немедленно уйти с этой страницы, но тут-то и выясняется, что звук никуда не делся и будет продолжаться до тех пор, пока мы не выйдем из браузера. А на дворе 2 часа ночи, в соседнем окне скачивается третий мегабайт 10-мегабайтного архива, сервер не поддерживает докачки и т. п. И вся проблема – в том, что автор апплета случайно или по злому умыслу пропустил код, выключающий звук при остановке апплета.
Мощное средство борьбы с пользователем – потоки. Они вовсе не обязаны остановиться при уходе со страницы, с которой был загружен апплет. В сочетании с установкой приоритета MAX_PRIORITY и обработчика исключительной ситуации ThreadDeath можно получить весьма живучего вредителя, который, к примеру, начнет следить за всеми запускаемыми апплетами и останавливать их потоки.
Еще один вариант сценария отказа в обслуживании (Denial of Service – DoS): открываем поток с большим приоритетом и начинаем искать в нем простые числа в диапазоне от 1 до 10100, не забывая насвистывать любимую мелодию, либо запускаем бесконечный цикл и создаем в нем окна размером, например, миллион на миллион пикселей (клавиатура и мышь у клиента будут заблокированы очень скоро):
while(true)
{
try
{
littleWindow = new bigFrame("Hello!");
littleWindow.resize(1000000, 1000000);
littleWindow.move(-1000, -1000);
littleWindow.show;
}
catch (OutOfMemoryError o)
{
repaint;
}
}
class bigFrame extends Frame
{
Label 1;
bigFrame(String title)
{
super(title);
setLayout(new GridLayout(1, 1));
Canvas whiteCanvas = new Canvas;
whiteCanvas.setBackground(Color.white);
add(whiteCanvas);
}
}