1. Обзор
В этом руководстве мы разберемся с API универсальной службы безопасности (API GSS) и как мы можем реализовать его на Java. Мы увидим, как мы можем защитить сетевое соединение с помощью GSS API в Java.
В процессе мы создадим простые клиентские и серверные компоненты, защитив их с помощью GSS API.
2. Что такое GSS
API?
Итак, что на самом деле представляет собой Generic Security Service API? GSS API предоставляет общую структуру для приложений, позволяющих использовать различные механизмы безопасности, такие как Kerberos , NTLM и SPNEGO, подключаемым образом. Следовательно, это помогает приложениям напрямую отделить себя от механизмов безопасности.
Чтобы уточнить, безопасность здесь охватывает аутентификацию, целостность данных и конфиденциальность.
2.1. Зачем нам нужен GSS
API?
Такие механизмы безопасности, как Kerberos, NTLM и Digest-MD5, сильно различаются по своим возможностям и реализациям. Как правило, приложение, поддерживающее один из этих механизмов, сталкивается с трудностями при переключении на другой.
Именно здесь общая структура, такая как GSS API, предоставляет приложениям абстракцию . Поэтому приложения, использующие GSS API, могут согласовать подходящий механизм безопасности и использовать его для связи. Все это без необходимости реализовывать какие-либо детали, специфичные для механизма.
2.2. Как работает GSS
API?
GSS API — это механизм на основе токенов . Он работает путем обмена токенами безопасности между узлами . Этот обмен обычно происходит по сети, но API GSS не зависит от этих деталей.
Эти токены генерируются и обрабатываются конкретными реализациями GSS API. Синтаксис и семантика этих токенов зависят от механизма безопасности, согласованного между узлами:
Центральная тема GSS API вращается вокруг контекста безопасности. Мы можем установить этот контекст между узлами посредством обмена токенами. Нам может понадобиться несколько обменов токенами между узлами для установления контекста.
После успешной установки на обоих концах мы можем использовать контекст безопасности для безопасного обмена данными. Это может включать проверки целостности данных и шифрование данных, в зависимости от базового механизма безопасности.
3. Поддержка GSS API в Java
Java поддерживает GSS API как часть пакета «org.ietf.jgss». Название пакета может показаться странным. Это связано с тем, что привязки Java для GSS API определены в спецификации IETF . Сама спецификация не зависит от механизма безопасности.
Одним из популярных механизмов безопасности для Java GSS является Kerberos v5.
3.1. Java GSS-API
Давайте попробуем понять некоторые из основных API, которые создают Java GSS:
GSSContext
инкапсулирует контекст безопасности GSS API и предоставляет службы, доступные в этом контексте.GSSCredential
инкапсулирует учетные данные GSS API для сущности, необходимые для установления контекста безопасности.GSSName
инкапсулирует основную сущность GSS API, которая обеспечивает абстракцию для различных пространств имен, используемых базовыми механизмами.
Помимо вышеперечисленных интерфейсов, следует отметить еще несколько важных классов:
GSSManager
служит фабричным классом для других важных классов GSS API, таких какGSSName
,GSSCredential
иGSSContext.
Oid
представляет собой универсальные идентификаторы объектов (OID), которые представляют собой иерархические идентификаторы, используемые в GSS API для идентификации механизмов и форматов имен.MessageProp
оборачивает свойства, чтобы указать GSSContext на такие вещи, как качество защиты (QoP) и конфиденциальность при обмене данными.ChannelBinding
инкапсулирует необязательную информацию о привязке канала, используемую для повышения качества аутентификации однорангового объекта.
3.2. Поставщик безопасности Java GSS
Хотя Java GSS определяет базовую структуру для реализации GSS API в Java, она не обеспечивает реализацию. Java использует подключаемые реализации на основе провайдеров
для служб безопасности, включая Java GSS.
Может быть один или несколько таких поставщиков безопасности, зарегистрированных в архитектуре криптографии Java (JCA). Каждый поставщик безопасности может реализовать одну или несколько служб безопасности, таких как Java GSSAPI и лежащие в их основе механизмы безопасности.
Существует поставщик GSS по умолчанию, который поставляется с JDK. Однако есть и другие поставщики GSS с другими механизмами безопасности, которые мы можем использовать. Одним из таких поставщиков является IBM Java GSS . Мы должны зарегистрировать такого поставщика безопасности в JCA, чтобы иметь возможность их использовать.
Более того, при необходимости мы можем внедрить собственного поставщика безопасности с, возможно, настраиваемыми механизмами безопасности . Однако на практике это вряд ли нужно.
4. API GSS на примере
Теперь мы увидим Java GSS в действии на примере. Мы создадим простое клиент-серверное приложение. Клиент чаще называется инициатором, а сервер — акцептором в GSS. Мы будем использовать Java GSS и Kerberos v5 для аутентификации.
4.1. Контекст GSS для клиента и сервера
Для начала нам нужно установить GSSContext
как на стороне сервера, так и на стороне клиента приложения.
Давайте сначала посмотрим, как мы можем сделать это на стороне клиента:
GSSManager manager = GSSManager.getInstance();
String serverPrinciple = "HTTP/localhost@EXAMPLE.COM";
GSSName serverName = manager.createName(serverPrinciple, null);
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
GSSContext clientContext = manager.createContext(
serverName, krb5Oid, (GSSCredential)null, GSSContext.DEFAULT_LIFETIME);
clientContext.requestMutualAuth(true);
clientContext.requestConf(true);
clientContext.requestInteg(true);
Здесь происходит довольно много вещей, давайте разберем их:
Начнем с создания экземпляра
GSSManager.
Затем мы используем этот экземпляр для создания
GSSContext
, передавая:GSSName, представляющий
принципала
сервера, обратите внимание на конкретное имя принципала Kerberos .Oid
механизма для использования, Kerberos v5 здесьучетные данные инициатора,
нуль
здесь означает, что будут использоваться учетные данные по умолчаниювремя жизни для установленного контекста
Наконец, мы подготавливаем контекст для взаимной аутентификации, конфиденциальности и целостности данных.
Точно так же мы должны определить контекст на стороне сервера:
GSSManager manager = GSSManager.getInstance();
GSSContext serverContext = manager.createContext((GSSCredential) null);
Как мы видим, это намного проще, чем контекст на стороне клиента. Единственная разница здесь в том, что нам нужны учетные данные акцептора, которые мы использовали как null
. Как и прежде, нуль
означает, что будут использоваться учетные данные по умолчанию.
4.2. Аутентификация GSS API
Хотя мы создали GSSContext
на стороне сервера и на стороне клиента , обратите внимание, что на данном этапе они не установлены.
Чтобы установить эти контексты, нам нужно обменять токены, специфичные для указанного механизма безопасности, то есть Kerberos v5:
// On the client-side
clientToken = clientContext.initSecContext(new byte[0], 0, 0);
sendToServer(clientToken); // This is supposed to be send over the network
// On the server-side
serverToken = serverContext.acceptSecContext(clientToken, 0, clientToken.length);
sendToClient(serverToken); // This is supposed to be send over the network
// Back on the client side
clientContext.initSecContext(serverToken, 0, serverToken.length);
Это, наконец, делает контекст установленным на обоих концах:
assertTrue(serverContext.isEstablished());
assertTrue(clientContext.isEstablished());
4.3. Безопасная связь GSS API
Теперь, когда у нас есть контекст, установленный на обоих концах, мы можем начать отправлять данные с целостностью и конфиденциальностью :
// On the client-side
byte[] messageBytes = "ForEach".getBytes();
MessageProp clientProp = new MessageProp(0, true);
byte[] clientToken = clientContext.wrap(messageBytes, 0, messageBytes.length, clientProp);
sendToClient(serverToken); // This is supposed to be send over the network
// On the server-side
MessageProp serverProp = new MessageProp(0, false);
byte[] bytes = serverContext.unwrap(clientToken, 0, clientToken.length, serverProp);
String string = new String(bytes);
assertEquals("ForEach", string);
Здесь происходит несколько вещей, давайте проанализируем:
MessageProp
используется клиентом для установки методапереноса
и создания токена.Обертка
метода также добавляет криптографический MIC данных, MIC входит в состав токена.- Этот токен отправляется на сервер (возможно, по сетевому вызову)
- Сервер снова использует
MessageProp , чтобы установить метод
развертывания
и вернуть данные . - Кроме того, метод
unwrap
проверяет MIC для полученных данных, обеспечивая целостность данных.
Следовательно, клиент и сервер могут обмениваться данными с целостностью и конфиденциальностью.
4.4. Настройка Kerberos для примера
Теперь ожидается, что механизм GSS, такой как Kerberos, будет извлекать учетные данные из существующего Subject
. Класс Subject
здесь представляет собой абстракцию JAAS, представляющую сущность, такую как человек или услуга. Обычно он заполняется во время аутентификации на основе JAAS.
Однако в нашем примере мы не будем напрямую использовать аутентификацию на основе JAAS. Мы позволим Kerberos получать учетные данные напрямую, в нашем случае с помощью файла keytab. Для этого существует системный параметр JVM:
-Djavax.security.auth.useSubjectCredsOnly=false
Однако реализация Kerberos по умолчанию, предоставляемая Sun Microsystem, полагается на JAAS для обеспечения аутентификации.
Это может показаться противоречащим тому, что мы только что обсуждали. Обратите внимание, что мы можем явно использовать JAAS в нашем приложении, которое будет заполнять Subject
. Или оставьте базовому механизму прямую аутентификацию, где он в любом случае использует JAAS. Следовательно, нам нужно предоставить файл конфигурации JAAS базовому механизму:
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab=example.keytab
principal="client/localhost"
storeKey=true;
};
com.sun.security.jgss.accept {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab=example.keytab
storeKey=true
principal="HTTP/localhost";
};
Это простая конфигурация, в которой мы определили Kerberos в качестве необходимого модуля входа как для инициатора, так и для получателя. Кроме того, мы настроили использование соответствующих принципалов из файла keytab. Мы можем передать эту конфигурацию JAAS в JVM в качестве системного параметра:
-Djava.security.auth.login.config=login.conf
Здесь предполагается, что у нас есть доступ к Kerberos KDC. В KDC мы настроили необходимых принципалов и получили файл keytab для использования, скажем, «example.keytab».
Кроме того, нам нужен файл конфигурации Kerberos, указывающий на правильный KDC:
[libdefaults]
default_realm = EXAMPLE.COM
udp_preference_limit = 1
[realms]
EXAMPLE.COM = {
kdc = localhost:52135
}
Эта простая конфигурация определяет KDC, работающий на порту 52135, с областью по умолчанию EXAMPLE.COM. Мы можем передать это в JVM как системный параметр:
-Djava.security.krb5.conf=krb5.conf
4.5. Запуск примера
Чтобы запустить пример, мы должны использовать артефакты Kerberos, обсуждавшиеся в предыдущем разделе .
Также нам нужно передать необходимые параметры JVM:
java -Djava.security.krb5.conf=krb5.conf \
-Djavax.security.auth.useSubjectCredsOnly=false \
-Djava.security.auth.login.config=login.conf \
com.foreach.jgss.JgssUnitTest
Этого достаточно, чтобы Kerberos выполнил аутентификацию с учетными данными из keytab и GSS для установления контекстов.
5. GSS API в реальном мире
Хотя GSS API обещает решить множество проблем безопасности с помощью подключаемых механизмов, есть несколько вариантов использования, которые получили более широкое распространение:
- Он широко используется в SASL в качестве механизма безопасности , особенно там, где Kerberos является предпочтительным базовым механизмом. Kerberos — это широко используемый механизм аутентификации, особенно в корпоративной сети. Очень полезно использовать инфраструктуру Kerberized для аутентификации нового приложения. Следовательно, GSS API прекрасно устраняет этот пробел.
- Он также используется в сочетании с SPNEGO для согласования механизма безопасности, если он заранее неизвестен. В этом отношении SPNEGO в некотором смысле является псевдомеханизмом GSS API. Это широко поддерживается во всех современных браузерах, что позволяет им использовать аутентификацию на основе Kerberos.
6. GSS API в сравнении
GSS API достаточно эффективен для обеспечения безопасности приложений подключаемым способом. Однако это не единственный способ добиться этого в Java.
Давайте разберемся, что еще может предложить Java и как они соотносятся с GSS API:
- Java Secure Socket Extension (JSSE): JSSE — это набор пакетов в Java, который реализует Secure Sockets Layer (SSL) для Java . Он обеспечивает шифрование данных, аутентификацию клиента и сервера и целостность сообщений. В отличие от GSS API, JSSE для работы использует инфраструктуру открытых ключей (PKI). Следовательно, GSS API работает более гибко и легко, чем JSSE.
- Java Simple Authentication and Security Layer (SASL): SASL — это структура аутентификации и безопасности данных для интернет-протоколов, которая отделяет их от конкретных механизмов аутентификации. По объему это похоже на GSS API. Однако Java GSS имеет ограниченную поддержку базовых механизмов безопасности через доступных поставщиков безопасности.
В целом, GSS API довольно эффективен в предоставлении услуг безопасности независимо от механизма. Однако поддержка большего количества механизмов безопасности в Java будет способствовать дальнейшему внедрению.
7. Заключение
Подводя итог, в этом руководстве мы поняли основы GSS API как основы безопасности. Мы ознакомились с Java API для GSS и поняли, как мы можем их использовать. В процессе мы создали простые клиентские и серверные компоненты, которые выполняли взаимную аутентификацию и безопасно обменивались данными.
Кроме того, мы также увидели практическое применение GSS API и альтернативы, доступные в Java.
Как всегда, код можно найти на GitHub .