Содержание


Комментарии

Шифрование системных паролей в среде WebSphere Application Server — если оно вам действительно необходимо

Comments

Серия контента:

Этот контент является частью # из серии # статей: Комментарии

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Комментарии

Следите за выходом новых статей этой серии.

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

Вследствие такого медийного фона шифрование паролей в системах IBM WebSphere Application Server является, возможно, одной из самых распространенных тем обсуждений между заказчиками и нашими консультантами по безопасности продуктов WebSphere, техническими специалистами по поддержке продаж и архитекторами по разработки систем безопасности WebSphere. Нам снова и снова говорят: “Среды WebSphere в основном удовлетворяют своему притязанию на то, чтобы быть безопасными по умолчанию, однако пароли, хранящиеся в файловой системе, просто закодированы, а не зашифрованы”. Далее обычно следует нечто вроде: “и наша система безопасности не прошла аудит, поскольку эти пароли не были зашифрованы”.

Во-первых, позиция подразделений IBM Software Services for WebSphere и IBM WebSphere Development состоит в том, что с точки зрения безопасности хранение системных паролей в закодированном виде не является уязвимостью. Аудиторы, предъявляющие подобные претензии, не понимают последствий для безопасности того, что, по их мнению, является предпочтительным решением. Далее я обосную этот тезис.

Тем не менее, поскольку некоторые клиенты настаивают, что шифрование системных паролей, используемых продуктом WebSphere Application Server, предпочтительнее кодирования, начиная с версии 6.0.2 продукта WebSphere Application Server предусмотрен интерфейс системного программирования (SPI), с помощью которого можно реализовать любое решение для "сокрытия" паролей по желанию клиента. Используя этот SPI-интерфейс, подразделение IBM Software Services for WebSphere реализовало такое решение для ряда клиентов. Сначала я сформулирую несколько базовых концепций безопасности, а затем опишу проектировочные соображения, применяемые в этом специализированном решении.

Основы: Сравнение кодирования и шифрования

В чем состоит различие между кодированием и шифрованием? Мы используем термин "кодирование" применительно к схеме, в которой сокрытие информации осуществляется с помощью формулы или алгоритма. Рассмотрим пример с секретным паролем, который мы хотим скрыть. Для иллюстрации предположим, что я использую, безусловно, очень плохой пароль: SecretMonkey. Эту фразу можно закодировать с помощью обратимого алгоритма, тем самым "скрыв" ее истинное значение.

Юлию Цезарю приписывается использование схемы кодирования под названием "шифр сдвига" (ROT), при которой каждая буква алфавита заменяется буквой, смещенной относительно исходной буквы на определенное количество позиций в алфавите. Современные историки называют эту схему кодом Цезаря. Код ROT3 заменяет каждый символ символом, расположенным на три позиции правее. Результаты применения ROT3 выглядят следующим образом (для английского алфавита):

Исходный текст: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Закодированный текст: DEFGHIJKLMNOPQRSTUVWXYZABC

Мой пароль после применения кода ROT3 имеет следующий вид:

Исходный текст: SecretMonkey
Закодированный текст: VhfuhwPrqnhb

При получении этой закодированной строки профессиональный криптоаналитик быстро разгадает алгоритм кодирования и декодирует ее с помощью обратного алгоритма (ROT-3). Сила кодирования заключатся в секретности алгоритма. Не следует забывать, что атакующие являются специалистами по анализу алгоритмов. Как только алгоритм становится известен, данные становятся незащищенными.

В отличие от кодирования, безопасность шифрования базируется не на используемом алгоритме, а на трудных для разгадывания ключах. В этом случае также используются алгоритмы, однако эти алгоритмы (как правило) широко известны и понятны. Алгоритмы шифрования отличаются от алгоритмов кодирования тем, что на их вход поступают две "сущности" – текст и секретный ключ. Примерно таким же образом, как для четырехразрядного PIN-кода банковской карты используется одна из 10000 (104) возможных секретных комбинаций, в шифровании используется секретный ключ, который требует значительных усилий при отгадывании методом "грубой силы".

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

cipherText = Encrypt(plainText, secretKey);

и обратную:

plainText = Decrypt(cipherText, secretKey);

Чтобы защитить свои данные, я выбрал ключ из очень большого набора возможных ключей (например, 256-разрядный ключ выбирается из набора 2256 возможных чисел, что является огромным числом; в десятичном представлении это число имеет вид 1,15x1077 – 115 и затем еще 75 цифр). Очевидно, что злоумышленнику потребуется значительное время, чтобы поочередно применить функцию дешифрования со всеми возможными ключами.

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

cipherText = Encrypt(plainText, KeyA);

а обратная (асимметричная) функция выглядит как:

plainText = Decrypt(cipherText, KeyB);

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

Хеширование паролей

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

digest = hash(inputString);

который преобразует строку inputString в так называемый дайджест (digest) и для которого обратный процесс является невозможным с вычислительной точки зрения (отсюда термин "однонаправленная"). Каждый раз, подавая на вход одинаковую строку inputString, вы получаете один и тот же дайджест. Дайджест, получаемый с помощью конкретной хеш-функции, обычно имеет постоянную длину. Дополнительное свойство хеш-функций состоит в том, что изменение любого двоичного разряда во входной информации полностью изменяет выходной дайджест.

Представим себе очень простую хеш-функцию, создающую дайджест длиной 8 разрядов. Каждая входная строка породит один из 28 возможных дайджестов. Если один разряд входных данных изменится, в результате получится совершенной иной дайджест. Если вы еще продолжаете следить за моими рассуждениями, то поймете, что существует бесконечное количество входных строк, порождающих один и тот же дайджест. Однако нам известно, что по данному дайджесту невозможно разгадать истинную входную строку inputString. Если размер дайджеста становится достаточно большим (например, 256 разрядов, что соответствует 2256 возможных значений), вероятность того, что другая случайная входная строка произведет тот же дайджест, становится очень малой.

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

digest = hash(inputString||salt);

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

Вы можете спросить, почему я постоянно отклоняюсь от заявленной темы и никак не перейду к делу? Все упомянутые выше сообщения прессы об украденных базах данных с паролями относятся к системам, в которых пароли пользователей pпроверялись по базе данных, а данные в этой базе данных, к сожалению, не были должным образом защищены. ИТ-специалистам хорошо известно, что такие пароли следует хранить не в виде открытого текста, а в виде дайджеста с солью. Другими словами, хранилище паролей не должно содержать строку моего пароля SecretMonkey. При проверке моего пароля система должна связать конкретную соль, которую она использует, с моей строкой, вычислить хеш полученной в результате строки и сравнить этот дайджест с сохраненным дайджестом пароля. Если эти два дайджеста совпадают, то строка inputString – SecretMonkey – с чрезвычайно высокой вероятностью является моим паролем.

Ниже показан гипотетический пример хеширования моей строки с различными солями.

  • SecretMonkey (without salt) > !GHD&@DB&!DJD
  • SecretMonkey||(salt=1111) > UCHAKJ$HDJS
  • SecretMonkey||(salt=2222) > njurnasiurrjfdd

Чрезвычайно важно, чтобы аудит вашей безопасности гарантировал хранение этих паролей в хешированном виде. Заметьте, что я не сказал "в зашифрованном виде". Надеюсь, что вы понимаете тонкое различие между этими вариантами (один из них является обратимым, а другой – необратимым).

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

Пользовательские пароли не являются системными паролями

Если какая-либо система WebSphere "проваливает" аудит, поскольку ее системные пароли не являются "безопасными", аудитор рассматривает не "пользовательские" пароли. Речь идет о паролях, ассоциированных с идентификаторами пользователей операционной системы, под управлением которой исполняется продукт WebSphere Application Server, или паролях, которые приложения WebSphere Application Server используют для подключения к другим системам. Например, можно предположить, что когда я вхожу в приложение Financial, происходит следующее.

  • Я прохожу LDAP-аутентификацию. Мои идентификатор пользователя и пароль используются в операции связывания LDAP. LDAP-сервер хеширует пароль (вместе с его уникальной солью) и сравнивает получающийся в результате этого дайджест с моим сохраненным дайджестом, подтверждая или отклоняя подлинность моих учетных данных.
  • После успешного прохождения аутентификации веб-приложение подключается к определенным серверным базам данных, проверяя наличие новых уведомлений и сетевых запросов. Это может быть, например, SQL-команда select notifications where userid=Lansche. Чтобы предотвратить доступ к этим данным со стороны любого компьютера в сети, приложение Financial подключается к этой базе данных с учетными данными FinancialApp. В рамках этого обсуждения предположим, что эти учетные данные представляют собой идентификатор пользователя и пароль.

Серверам приложений требуются пароли для выполнения поиска в LDAP, для подключения к базам данных, диспетчерам очередей, веб-сервисам и другим приложениям и для выполнения приложений с определенными идентификационными данными (runAs). В тех случаях, когда сервер приложений проходит аутентификацию на этих системах с помощью идентификатора пользователя и пароля, пароль должен быть отправлен в "пригодном к употреблению" формате — то есть в виде открытого текста. Мой коллега Роб Уайетт (T. Rob Wyatt) объясняет это в своем блоге следующим образом.

Отрывок из заметки в блоге Store and Forward: Encrypting passwords in config files – secure or not? (Безопасно ли шифрование паролей в конфигурационных файлах)

В конечном итоге все сводится к следующему: любой системе, которая должна самостоятельно загружаться до рабочего состояния, требуется доступ к пригодным к употреблению аутентификационным учетным данным. Термин "самостоятельно" означает, что система должна пройти путь от выключенного состояния до состояния полноценного функционирования без вмешательства человека. Допустима ли при этом ситуация, когда после перезагрузки сервера все приложения запускают командную строку и ждут, пока пользователь-человек введет все пароли? Как правило, "нет". Категорически "нет". В некоторых ситуациях подобное имеет место, однако у меня нет допуска безопасности для работы с такими системами, и даже если бы он у меня был, то я все равно не имел бы права писать об этом. Во всех остальных случаях нам всем нужны системы, способные загружаться автоматически без вмешательства человека. Итак: "самостоятельно" означает, что учетные данные должны храниться там, где приложение может обратиться к ним в ходе исполнения (обычно – в файловой системе).

Другими словами, при запуске приложения Financial у нас имеется два варианта на выбор.

  1. Ждать, пока оператор введет в консоли пароль для идентификатора пользователя FinancialApp (и все остальные требуемые системные учетные сведения).
  2. Предоставить приложению возможность получить этот пароль из какого-либо места в файловой системе.

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

Стандарт DSS PCI и системные пароли

Итак, ваш аудитор заявил, что вышеупомянутые системные пароли должны быть зашифрованы. Это конкретное требование отсутствует в стандарте PCI-DSS. В действительности о системных паролях в этом стандарте сказано лишь следующее: “Do not use vendor-supplied defaults for system passwords and other security parameters” (Не применяйте выставленные по умолчанию производителем системные пароли и другие параметры безопасности).

Рисунок 1. Таблица из стандарта PCI DSS – Требования и процедуры оценки безопасности, Версия 2.0
Figure 1 Table from PCI DSS - Requirements and Security Assessment Procedures, Version 2.0
Figure 1 Table from PCI DSS - Requirements and Security Assessment Procedures, Version 2.0

Несомненно, в этом стандарте есть и другие упоминания о паролях, однако они явно относятся к пользовательским паролям. Например, пункт 8 требований гласит: “Assign a unique ID to each person with computer access” (Каждому лицу, имеющему доступ к компьютеру, должен быть присвоен уникальный идентификатор), а подпункт 8.4 гласит: “Passwords must be “unreadable during transmission and storage on all system components using strong cryptography” (Во время передачи паролей и их хранения на всех компонентах системы они должны быть с помощью сильных криптографических средств представлены в недоступном для прочтения виде). Это требование является критически важным – пользовательские пароли недопустимо хранить где бы то ни было в нехешированном виде; и действительно, как говорилось выше, единственным вариантом хранения должен быть односторонний хеш с солью! Однако это требование явно относится к пользовательским паролям, а не к системным паролям.

Почему зашифрованные пароли не более безопасны, чем закодированные пароли

Однако предположим, что аудитор настаивает на своем. Логически проанализируем процесс, который в этом случае проходит система.

  1. Предположим, что кодирования паролей недостаточно. Почему? Потому что любое лицо с доступом к файловой системе "по чтению" может прочитать учетные данные.
    • Возможно, пользователи имеют доступ к файловой системе.
    • Приложения, исполняющиеся в среде WebSphere Application Server, имеют возможность читать пароли.
    • Приложения, исполняющиеся за пределами среды WebSphere Application Server (возможно, приложения, входящие в состав операционной системы) вследствие некоторой непредвиденной уязвимости допускают удаленный просмотр файлов или утечку файлов из файловой системы.
  2. Вы реализуете SPI-интерфейс для кодирования пароля и шифруете пароль. Для этого вам требуется ключ. Теперь пароль хранится в файловой системе в зашифрованном виде. Предположим, что применяется симметричное шифрование (оно работает быстрее, чем асимметричное). Вы храните ключ в хранилище ключей.
  3. Чтобы сервер мог осуществить преобразование из зашифрованного текста обратно в открытый текст, ему требуется ключ дешифрования. Сервер читает этот ключ из хранилища ключей. Чтобы исключить возможность тривиального получения этого ключа из хранилища ключей любым приложением, вы защищаете это хранилище ключей с помощью пароля. Среде WebSphere Application Server требуется доступ к этому паролю, чтобы быть в состоянии читать это хранилище ключей. Где хранится этот пароль? Поскольку запрос к человеку-оператору не является приемлемым, этот пароль хранится (барабанная дробь, пожалуйста) в файле файловой системы; файл, содержащий пароль, позволяющий приложению читать хранилище ключей, называется stash-файл.

Но погодите! На шаге 1 мы говорили, что наша принципиальная проблема состоит в том, что мы неспособны контролировать, какие процессы имеют доступ к файловой системе. Эта проблема никуда не делась. Теперь все стало немного неудобнее, однако все элементы, необходимые для получения системного пароля, остались в файловой системе и доступны для продукта WebSphere Application Server и для приложений, исполняющихся на сервере приложений.

  1. Пароль, представленный в виде зашифрованного текста в конфигурационных файлах WebSphere Application Server.
  2. Хранилище ключей, содержащее ключ, необходимый для дешифрования этого зашифрованного текста.
  3. Stash-файл, содержащий пароль для чтения ключа из хранилища ключей.

Мы лишь передвинули проблему на два шага дальше. Это не более безопасно, чем просто кодировать пароли в файле. На самом деле Роб Уайетт в вышеупомянутой заметке из своего блога убедительно показывает, что шифрование системных паролей снижает уровень безопасности системы.

Реальная проблема безопасности, подлежащая устранению, состоит в управлении тем, кто (люди или приложения) имеет доступ к файловой системе. Лучший способ преодоления этой реальной проблемы безопасности рассматривается в моей статье по укреплению безопасности. (Подсказка. Используйте управление доступом к файловой системе)

В каких случаях шифрование системных паролей может оказаться полезным

В первой редакции этой статьи сравнение кодирования паролей с шифрованием паролей на этом заканчивалось. Однако из сказанного не следует, что шифрование пароля - плохая идея. Напротив, следует указать, что в дополнение к укреплению инфраструктуры необходимо учитывать человеческий фактор и слабые места других приложений за пределами среды WebSphere Application Server и приложений Java EE, развернутых и исполняющихся в среде WebSphere Application Server.

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

Любое другое приложение в вашей системе может содержать прорехи в безопасности, дающие возможность прочитать и извлечь файлы. Если такое приложение способно исполняться от имени пользователя WebSphere (или пользователя root) и файлы могут быть извлечены из системы, шифрование паролей к файлам WebSphere Application Server лишь слегка затруднит дешифрование паролей.

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

Вернемся к небрежному программисту. Рассмотрим гипотетическое приложение, которое позволяет пользователю отображать содержимое журнального файла в своем браузере. Вместо того чтобы показывать пользователю список файлов, программист предоставляет поле ввода данных, в которое пользователь может ввести имя файла. В плохо реализованном приложении отсутствует проверка вводимой информации, позволяющая предотвратить указание абсолютных или относительных маршрутов. Такое отсутствие валидации порождает уязвимости типа Path Traversal. Злоумышленник пробует осуществлять атаки типа Path Traversal, проверяя, можно ли увидеть содержимое случайных файлов в файловой системе. Если атакующий может указать путь к файлу в файловой системе, содержащему незашифрованный пароль, и этот файл отображается на экране, то это, безусловно, плохо.

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

Если атакующий также способен извлечь из файловой системы файл, содержащий ключ шифрования (который WebSphere Application Server должен быть в состоянии читать), то у него есть обе составляющие, необходимые для представления пароля в виде открытого текста. Атакующему нужно будет узнать, какое имя носит этот файл – однако в конфигурационных файлах обязательно присутствует какое-либо свойство, задающее имя файла с ключом. Получить три файла труднее, чем один, но ненамного. Представление двоичного файла ключей при посредстве функции browse-file может затруднить определение ключа, но не делает его невозможным.

Меры по предотвращению уязвимостей типа Path traversal и других уязвимостей, которые возвращают пользователю содержимое файла без каких-либо ограничений, должны быть предприняты не только в приложениях собственной разработки, но и в приобретаемых у сторонних поставщиков. Такие уязвимости системы обеспечения безопасности имеют высокий приоритет. В случае обнаружения уязвимостей в продуктах IBM мы предоставляем патчи для прекращения такого доступа, но мы не имеем контроля над всеми приложениями, которые работают на системах заказчика, в среде продукта WebSphere Application Server или на других продуктах.

Вы можете спросить: "Что будет, если файл ключей, полученный из какого-либо другого места, хранить не в файловой системе?" В этом случае существует два альтернативных варианта: чтение из аппаратных хранилищ ключей (или аппаратного ключа), осуществляемое через какой-либо программный API-интерфейс – вызов сервиса, запрос к базе данных, HTTP-запрос и так далее. Если атакующий может видеть только файлы в файловой системе, а чтобы получить ключ, исполняющийся сервер WebSphere Application Server должен выполнить некоторый код, то шифрование может оказаться полезным. Однако не забывайте, что злонамеренный программист может написать программу для целенаправленного получения пароля с помощью тех же API-интерфейсов, которые использует WebSphere Application Server.

Если вы все же настаиваете...

Интерфейс для определения собственного обработчика паролей находится по адресу: com.ibm.wsspi.security.crypto.CustomPasswordEncryption. Создайте класс com.ibm.wsspi.security.crypto.CustomPasswordEncryptionImpl и поместите его в каталог <WAS>/lib/ext. Процессы WebSphere Application Server будут использовать этот класс без дальнейшего конфигурирования администратором. Может существовать только один класс, реализующий этот интерфейс. Этот интерфейс определяет следующие методы (как и следовало ожидать):

Листинг 1
EncryptedInfoencrypt(byte[] decrypted_bytes) throws PasswordEncryptException byte[] decrypt(EncryptedInfo info) throws PasswordDecryptException void initialize(java.util.HashMap initialization_data)

Последний метод зарезервирован для будущего использования; в настоящее время среда исполнения WebSphere Application Server не вызывает этот метод.

Среда WebSphere Application Server взаимодействует с этими паролями двумя способами: она хранит файлы, когда пароли изменяются, и читает эти файлы, чтобы получить пароли.

Когда среда WebSphere Application Server сохраняет пароль после обновления, она проверяет доступность поставщика специального шифрования. Если поставщик доступен, ему передается пароль в виде открытого текста. Поставщик должен произвести с этим паролем определенные манипуляции и вернуть в WebSphere Application Server двоичную информацию, которая имеет смысл для этого поставщика. После этого WebSphere Application Server сохранит эту двоичную информацию в соответствующем XML-файле обычным образом. Хранящиеся данные указывают, что они были закодированы с привлечением специального поставщика. Это влияет на процесс их чтения в будущем.

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

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

Соображения о проектировании поставщика шифрования

В оставшейся части этой статьи описывается специальный поставщик сервиса шифрования паролей, разработанного подразделением IBM Software Services for WebSphere. Этот программный код не является свободно распространяемым, поэтому к данной статье не прилагается программный код для загрузки. Этот код является активом организации IBM Software Services for WebSphere, который можно получить путем заключения контракта с подразделением IBM Software Services for WebSphere на платной основе. В рамках этого контракта консультант IBM Software Services for WebSphere совместно с организацией заказчика анализирует и документирует его требования и при необходимости адаптирует этот актив к требованиям сценария применения. После этого консультант предоставляет заказчику его копию кода актива, которую тот может использовать на своем предприятии.

Главная мотивация предоставления этого кода в виде актива IBM Software Services for WebSphere состоит в следующем: хотя использование этого кода имеет очень небольшую реальную ценность с точки зрения безопасности, его истинная ценность заключается в том, чтобы он позволяет заказчику успешно пройти аудит безопасности при возникновении проблем (несмотря на то, что кодирование системных паролей не является уязвимостью с точки зрения безопасности). По нашему опыту, если в рамках такого контракта у консультанта по безопасности из подразделения IBM Software Services for WebSphere есть возможность взаимодействовать с аудитором по стандарту PCI, высока вероятность того, что консультант сможет объяснить аудитору различия между системными и пользовательскими паролями и снять требование по развертыванию этого программного обеспечения (и соответственно по владению им и по ответственности за него)!

Важнейшее проектировочное решение в реализации специального поставщика шифрования паролей от IBM Software Services for WebSphere состоит в максимально возможном использовании существующей Java-инфраструктуры JCE. Так, симметричные ключи, которые используются для шифрования и дешифрования паролей, хранятся с использованием средств хранилища Java KeyStore. Мы специально выбрали формат JCEKS, поскольку он прекрасно поддерживает симметричные ключи. Хранилища Java KeyStore позволяют шифровать с использованием паролей и ключи, хранящиеся в хранилище ключей, и файл хранилища ключей. Вместо того чтобы просить человека придумать надлежащий пароль, мы автоматически генерируем очень длинный (более 30 символов) алфавитно-цифровой пароль и прячем его во втором файле – нашем stash-файле или файле главного пароля. Для предотвращения тривиального отслеживания содержимое файла подвергается операции XOR (с использованием четырехсимвольной маски XOR), чтобы затруднить разгадывание.

Если продукту WebSphere Application Server нужно зашифровать какую-либо систему или пароль WebSphere Application Server, он осуществляет вызов поставщика. Поставщик в ответ должен возвратить строку и зашифрованные байты. (Важно отметить, что при использовании основанного на файлах репозитария в реестре пользователей Federated Repositories, пользовательские пароли хранятся в виде дайджестов, полученных односторонним хешированием с добавлением соли. WebSphere Application Server не использует описываемый SPI-интерфейс для записи этих пользовательских паролей). Когда продукту WebSphere Application Server нужно дешифровать пароль, он проверяет, какой поставщик использовался – специальный поставщик или поставщик по умолчанию. Если использовался специальный поставщик, ему передаются соответствующая строка (зависящая от поставщика) и байты. Работа поставщика заключается в том, чтобы вернуть пароль в виде массива символов. Мы используем эту строку для хранения осмысленной информации.

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

Чтобы обеспечить возможность управления ключами шифрования и их периодического обновления без необходимости останавливать всю ячейку, нам необходимо одновременно поддерживать несколько версий ключа шифрования. Для этого мы встраиваем в строку, передаваемую в WebSphere Application Server, версию ключа, использованную для шифрования этого пароля. Класс, которому мы дали имя EncryptionKeyManager, сохраняет набор ключей шифрования (упорядоченный по времени создания). При дешифровании строки всегда используется ключ, использовавшийся для ее шифрования (в предположении, что он все еще доступен). При шифровании строки используется самый последний по времени ключ. При запуске серверов они считывают в память последнюю по времени версию хранилища ключей и, соответственно, все текущие ключи. В случае сбоя дешифрования по причине отсутствия версии ключа класс CustomPasswordEncryptImpl автоматически перезагружает хранилище ключей, чтобы проверить, имеется ли более новый доступный ключ. Это может произойти в том случае, если новый ключ шифрования был добавлен (и приложение DMgr перезапущено), а серверы приложений не были перезапущены. Таким образом, чтобы изменения ключей, используемых для шифрования, вступили в силу, наше решение не требует перезапуска сервера приложений после начального конфигурирования.

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

  • Мы используем поставщика хранилища ключей Java JCEKS, поскольку он способен хранить симметричные ключи.
  • Мы используем шифр Java JCE Cipher, который применяет AES-шифрование в режиме Cipher Feedback Mode. Мы также не используем заполнение (padding), чтобы избежать добавления символов к паролям. Таким образом, точная строка поставщика имеет вид AES/CFB/NoPadding (см. документацию по JCE).
  • Поскольку мы используем алгоритм CFB, мы должны также хранить вектор инициализации, использовавшийся для шифрования данных; мы предоставляем среде исполнения JCE создавать случайный вектор инициализации каждый раз, когда какой-либо шифр используется для шифрования пароля. Затем мы сохраняем этот вектор с паролем, чтобы инициализировать шифр перед дешифрованием. Использование отдельного вектора для каждого пароля ограничивает его повторное использование и повышает безопасность шифрования. Даже если один и тот же пароль шифруется с использованием одного и того же ключа, результирующие зашифрованные данные существенно различаются.
  • Для AES-шифрования мы используем ключи длиной 128 разрядов. Для ключей большей длины требуется пакет специальных файлов Jurisdiction Files. Эти специальные файлы подпадают под ограничения федеральных законов США об экспорте. Учитывая объем подвергаемых шифрованию данных и внутреннюю слабость этого подхода (хранение ключей дешифрования в той же файловой системе), мы не считаем, что увеличение длины ключей обеспечит значительное улучшение безопасности.
  • Перед шифрованием мы добавляем случайную соль в начале каждого пароля, чтобы дополнительно рандомизировать хранящуюся информацию: это дополнительно затрудняет дешифрование.

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

Один очевидный вопрос, который необходимо рассмотреть при добавлении поддержки шифрования паролей – какое влияние это может оказать на производительность. Конечно, криптография обходится дорого, а выполнение криптографических операций способно существенно ухудшить производительность приложений. К счастью, продукт WebSphere Application Server активно кэширует (в памяти) декодированные/дешифрованные пароли. Благодаря этому небольшие издержки производительности будут иметь место лишь при запуске серверов (когда они читают пароли) и при осуществлении административных изменений, влияющих на пароли, а производительность среды исполнения от этого решения не должна пострадать.

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

Последствия для безопасности

Как уже говорилось, необходимо помнить, что описываемый в этой статье подход лишь незначительно повышает безопасность среды WebSphere Application Server, затрудняя извлечение файлов с целью получения файлов, содержащих системные пароли, и что прослеживание и утечки файлов – это только самые очевидные направления атаки, при том что другие направления атаки являются не только возможными, но и неизбежными. До того, как мы начали использовать это улучшение, атакующему нужно было извлечь содержащий пароль файл, а затем обратить кодирование XOR и base64. В случае использования рассматриваемой здесь функциональности атакующий должен извлечь не только содержащий пароль файл, но и файл ключа шифрования (который должен находиться на той же машине и должен иметь такие же разрешения доступа по чтению, как и файл пароля). Затем атакующему нужно на основании этих файлов дешифровать пароли. Хотя это и нетривиальная задача, она необязательно является трудной для лиц с надлежащими навыками. Дополнительную пользу от этого решения можно получить в тех случаях, когда конфигурационные XML-файлы WebSphere Application Server передаются третьим сторонам; хранение паролей в зашифрованной форме не позволяет этим третьим сторонам определить реальные значения паролей, встроенных в конфигурационные XML-файлы. Конечно, при этом предполагается, что такой третьей стороне не предоставляется копия ключей шифрования — именно поэтому решение хранит ключи шифрования за пределами XML-дерева конфигурации.

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

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

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

Последствия для готовности

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

Управление ключами: утилита passmgr

Для управления параметрами шифрования предоставляется простая утилита командной строки (passmgr.bat/sh). Скрипт запуска имеет версии для UNIX® и Windows®. Скрипт passmgr соответствует документированному в стандартах подходу к запуску тонкого клиента.

После копирования утилиты passmgr.bat/sh в какой-либо каталог и редактирования скрипта с указанием надлежащего значения WASHOME этот инструмент легко запускается с использованием passmgr.bat/sh, например:

passmgr.bat

В большинстве случаев следует указать имя профиля WebSphere Application Server, с которым должен работать этот инструмент. Если профиль не задан, используется профиль по умолчанию. Чтобы указать профиль, запустите утилиту passmgr.bat с аргументом profileName. Пример:

passmgr.bat -profileName Dmgr01

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

Листинг 2
passmgr.bat No arguments specified Usage: <command> [-dir <dir>] [-key <key#>] [-host <dmgr host>] [-port <dmgr port>] [-trace] where <command> is one of: create - create keyfile addkey - add a key to keyfile info - print information about a keyfile deletekey - delete a key from keyfile scanall - scan/read all passwords (may aid in debugging app server issues forceencrypt - force the reencryption of all existing passwords changemasterkey - change the master key protecting the keyfile

Необязательные аргументы имеют следующие значения.

  • -dir: Указывает альтернативный маршрут для файлов ключей. Это полезно, если вы хотите создать файл ключей, но при этом не хотите обновлять файлы ключей, используемые текущим профилем. Это удобно для тестирования.
  • -key: Для команд, которые требуют номера ключа (например, deletekey), это номер ключа.
  • -host: Для команд, которые взаимодействуют с dmgr (например, scanall и forceencrypt), можно указать имя хоста dmgr, отличное от имени по умолчанию. По умолчанию используется имя localhost.
  • -port: Для команд, которые взаимодействуют с dmgr (например, scanall и forceencrypt), можно указать порт dmgr, отличный от порта по умолчанию. По умолчанию используется порт 8879.
  • -trace: Выводит на консоль трассировочную информацию, показывающую действия инструмента.

Заключение

IBM WebSphere Application Server (и продукты, созданные поверх WebSphere Application Server) хранит пароли системных учетных записей в различных файлах внутри структуры файлов профилей WebSphere Application Server. Эти пароли закодированы, но не зашифрованы. Шифрование этих паролей позволяет улучшить защиту от уязвимостей определенного класса.

Продукт WebSphere Application Server предоставляет SPI-интерфейс, позволяющий настроить обработку этих системных паролей. В статье была описана реализация этого SPI-протокола, созданная в подразделении IBM Software Services for WebSphere.

Если вы интересуетесь развертыванием этой специальной реализации от IBM Software Services for WebSphere или хотите узнать больше о безопасности продукта WebSphere Application Server, обратитесь в подразделение IBM Software Services for WebSphere tи обсудите возможность привлечения консультанта по безопасности или прохождения специализированного очного обучения по безопасности продукта WebSphere Application Server. Программа этого углубленного обучения охватывает такие темы, как укрепление безопасности, настройка аутентификации, интеграция, единый вход в систему, а также другие связанные темы.

Благодарности

Автор благодарит Билла О'Доннелла (Bill O’Donnell), Тома Элкотта (Tom Alcott), Симона Кападиа (Simon Kapadia), Роба Уайетта (T. Rob Wyatt), Пита Неергаарда (Pete Neergaard), Дэвида Мундхенка (David Mundhenck) и Пола Глезена (Paul Glezen) за ценный вклад и содействие при написании этой статьи.

Особую благодарность автор выражает Кейзу Ботзуму (Keys Botzum), который написал исходный актив, а также первоначальный вариант значительной части приведенного выше текста.


Ресурсы для скачивания


Похожие темы


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere
ArticleID=1030978
ArticleTitle=Комментарии: Шифрование системных паролей в среде WebSphere Application Server — если оно вам действительно необходимо
publish-date=05042016