Um guia para API Java GSS

Um guia para API Java GSS

1. Visão geral

Neste tutorial, vamos entender oGeneric Security Service API (GSS API) e como podemos implementá-lo em Java. Veremos como podemos proteger a comunicação de rede usando a API GSS em Java.

No processo, criaremos componentes simples de cliente e servidor, protegendo-os com GSS API.

2. O que é a API GSS

Então, o que realmente é a API do Generic Security Service? GSS API provides a generic framework for applications to use different security mechanisms like Kerberos, NTLM e SPNEGO de maneira conectável. Consequentemente, ajuda os aplicativos a se separarem dos mecanismos de segurança diretamente.

Para esclarecer, a segurança aqui se estende porauthentication, data integrity, and confidentiality.

2.1. Por que precisamos da API GSS?

Mecanismos de segurança como Kerberos, NTLM e Digest-MD5 são bastante diferentes em seus recursos e implementações. Normalmente, um aplicativo que suporta um desses mecanismos considera bastante assustador mudar para outro.

É aqui quea generic framework like GSS API provides applications with an abstraction. Portanto, os aplicativos que usam a API GSS podem negociar um mecanismo de segurança adequado e usá-lo para comunicação. Tudo isso sem ter que implementar nenhum detalhe específico do mecanismo.

2.2. Como a API GSS funciona?

GSS API éa token-based mechanism. Funciona porthe exchange of security tokens between peers. Essa troca geralmente ocorre em uma rede, mas a API do GSS é independente desses detalhes.

Esses tokens são gerados e processados ​​pelas implementações específicas da API do GSS. Osyntax and semantics of these tokens are specific to the security mechanism negociado entre os pares:

image

O tema central da API do GSS gira em torno de um contexto de segurança. Podemos estabelecer esse contexto entre pares por meio da troca de tokens. Usamosmay need multiple exchanges of tokens between peers para estabelecer o contexto.

Uma vez estabelecidos com êxito nas duas extremidades, podemos usar o contexto de segurança para trocar dados com segurança. Isso pode incluir verificações de integridade e criptografia de dados, dependendo do mecanismo de segurança subjacente.

3. Suporte à API GSS em Java

Java suporta API GSS como parte do pacote "org.ietf.jgss". O nome do pacote pode parecer peculiar. Isso ocorre porque oJava bindings for GSS API are defined in an IETF specification. A especificação em si é independente do mecanismo de segurança.

Um dos mecanismos de segurança populares do Java GSS é o Kerberos v5.

3.1. API Java GSS

Vamos tentar entender algumas das principais APIs que constroem Java GSS:

  • GSSContext encapsula o contexto de segurança GSS API e fornece serviços disponíveis sob o contexto

  • GSSCredential encapsula as credenciais da API GSS para uma entidade que é necessária para estabelecer o contexto de segurança

  • GSSName encapsula a entidade principal da API GSS que fornece uma abstração para diferentes namespaces usados ​​por mecanismos subjacentes

Além das interfaces acima, existem algumas outras classes importantes a serem observadas:

  • GSSManager serve como a classe de fábrica para outras classes GSS API importantes comoGSSName,GSSCredential eGSSContext

  • Oid representa os identificadores de objeto universal (OIDs), que são identificadores hierárquicos usados ​​na API GSS para identificar mecanismos e formatos de nome

  • MessageProp envolve propriedades para indicar GSSContext em coisas como Qualidade de Proteção (QoP) e confidencialidade para troca de dados

  • ChannelBinding encapsula as informações de ligação de canal opcional usadas para fortalecer a qualidade com a qual a autenticação de entidade de mesmo nível é fornecida

3.2. Provedor de segurança Java GSS

Embora o Java GSS defina a estrutura principal para implementar a API GSS em Java, ele não fornece uma implementação. Java adotaProvider-based pluggable implementations for security services incluindo Java GSS.

Pode haver um ou maissecurity providers registered with the Java Cryptography Architecture (JCA). Cada provedor de segurança pode implementar um ou mais serviços de segurança, como Java GSSAPI e mecanismos de segurança abaixo.

Há um provedor GSS padrão enviado com o JDK. No entanto, existem outros fornecedores de GSS específicos do fornecedor com diferentes mecanismos de segurança que podemos usar. Um desses provedores éIBM Java GSS. Temos que registrar um provedor de segurança na JCA para poder usá-lo.

Além disso, se necessário, nóscan implement our own security provider with possibly custom security mechanisms. No entanto, isso dificilmente é necessário na prática.

4. API GSS por meio de um exemplo

Agora, veremos o Java GSS em ação por meio de um exemplo. Vamos criar um aplicativo cliente e servidor simples. O cliente é mais comumente referido como iniciador e servidor como um aceitador no GSS. Usaremos Java GSS e Kerberos v5 abaixo para autenticação.

4.1. Contexto GSS para cliente e servidor

Para começar, teremos deestablish a GSSContext, both at the server and client-side do aplicativo.

Vejamos primeiro como podemos fazer isso no lado do cliente:

GSSManager manager = GSSManager.getInstance();
String serverPrinciple = "HTTP/[email protected]";
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);

Muitas coisas estão acontecendo aqui, vamos analisá-las:

  • Começamos criando uma instância doGSSManager

  • Em seguida, usamos esta instância para criarGSSContext, passando adiante:

    • aGSSName representando o servidor principal, observethe Kerberos specific principal name aqui

    • oOid do mecanismo a ser usado, Kerberos v5 aqui

    • as credenciais do iniciador,null aqui significa que as credenciais padrão serão usadas

    • a vida útil para o contexto estabelecido

  • Finalmente, preparamosthe context for mutual authentication, confidentiality, and data integrity

Da mesma forma, temos que definir o contexto do servidor:

GSSManager manager = GSSManager.getInstance();
GSSContext serverContext = manager.createContext((GSSCredential) null);

Como podemos ver, isso é muito mais simples que o contexto do lado do cliente. A única diferença aqui é que precisamos das credenciais do aceitante, que usamos comonull. Como antes,null means that the default credentials will be used.

4.2. Autenticação da API GSS

Embora tenhamos criadoGSSContext do lado do servidor e do cliente, observe que eles não foram estabelecidos neste estágio.

Para estabelecer esses contextos, precisamos trocar tokens específicos para o mecanismo de segurança especificado, que é o 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);

Isso finalmente cria o contexto estabelecido nos dois extremos:

assertTrue(serverContext.isEstablished());
assertTrue(clientContext.isEstablished());

4.3. Comunicação segura da API GSS

Agora, que temos contexto estabelecido em ambas as extremidades,we can start sending data with integrity and confidentiality:

// On the client-side
byte[] messageBytes = "example".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("example", string);

Há algumas coisas acontecendo aqui, vamos analisar:

  • MessageProp é usado pelo cliente para definir owrap method and generate the token

  • O métodowrap também adiciona MIC criptográfico dos dados, o MIC é agrupado como parte do token

  • Esse token é enviado ao servidor (possivelmente através de uma chamada de rede)

  • O servidor aproveitaMessageProp novamente para definir ounwrap method and get data back

  • Além disso, o métodounwrap verifica o MIC para os dados recebidos, garantindo a integridade dos dados

Portanto, o cliente e o servidor podem trocar dados com integridade e confidencialidade.

4.4. Configuração do Kerberos para o exemplo

Agora, um mecanismo GSS comoKerberos is typically expected to fetch credentials from an existing Subject. A classeSubject aqui é uma abstração JAAS que representa uma entidade como uma pessoa ou um serviço. Isso geralmente é preenchido durante uma autenticação baseada em JAAS.

No entanto, para nosso exemplo, não usaremos diretamente uma autenticação baseada em JAAS. Vamos permitir que o Kerberos obtenha credenciais diretamente, em nosso caso usando um arquivo keytab. Há um parâmetro do sistema JVM para conseguir isso:

-Djavax.security.auth.useSubjectCredsOnly=false

No entanto, a implementação padrão do Kerberos fornecida pela Sun Microsystem depende do JAAS para fornecer autenticação.

Isso pode parecer contrário ao que acabamos de discutir. Observe que podemos usar JAAS explicitamente em nosso aplicativo, que preencherá oSubject. Ou deixe que o mecanismo subjacente se autentique diretamente, onde ele usa o JAAS de qualquer maneira. Portanto, precisamos fornecer um arquivo de configuração JAAS para o mecanismo subjacente:

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";
};

Essa configuração é direta, onde definimos o Kerberos como o módulo de login necessário para iniciador e aceitador. Além disso, configuramos para usar as respectivas entidades a partir de um arquivo keytab. Podemos passar essa configuração do JAAS para a JVM como um parâmetro do sistema:

-Djava.security.auth.login.config=login.conf

Aqui, a suposição é que temos acesso a um KDC do Kerberos. No KDC, configuramos os principais necessários e obtemos o arquivo keytab para usar, digamos“example.keytab”.

Além disso, precisamos do arquivo de configuração Kerberos apontando para o KDC certo:

[libdefaults]
default_realm = EXAMPLE.COM
udp_preference_limit = 1
[realms]
EXAMPLE.COM = {
    kdc = localhost:52135
}

Essa configuração simples define um KDC em execução na porta 52135 com uma região padrão como EXAMPLE.COM. Podemos passar isso para a JVM como um parâmetro do sistema:

-Djava.security.krb5.conf=krb5.conf

4.5. Executando o Exemplo

Para executar o exemplo, temos quemake use of the Kerberos artifacts discussed in the last section.

Além disso, precisamos passar os parâmetros da JVM necessários:

java -Djava.security.krb5.conf=krb5.conf \
  -Djavax.security.auth.useSubjectCredsOnly=false \
  -Djava.security.auth.login.config=login.conf \
  com.example.jgss.JgssUnitTest

Isso é suficiente para o Kerberos executar a autenticação com credenciais do keytab e GSS para estabelecer os contextos.

5. API GSS no mundo real

Embora a API do GSS prometa resolver uma série de problemas de segurança por meio de mecanismos conectáveis, existem poucos casos de uso mais amplamente adotados:

  • Éwidely used in SASL as a security mechanism, especialmente onde Kerberos é o mecanismo básico de escolha. O Kerberos é um mecanismo de autenticação amplamente usado, especialmente dentro de uma rede corporativa. É realmente útil aproveitar uma infraestrutura Kerberizada para autenticar um novo aplicativo. Portanto, a API GSS preenche bem essa lacuna.

  • Também éused in conjugation with SPNEGO negociar um mecanismo de segurança quando nenhum é conhecido de antemão. Nesse sentido, o SPNEGO é um pseudo mecanismo da API do GSS em certo sentido. Isso é amplamente suportado em todos os navegadores modernos, tornando-os capazes de alavancar a autenticação baseada em Kerberos.

6. API GSS em comparação

A API GSS é bastante eficaz no fornecimento de serviços de segurança para aplicativos de maneira conectável. No entanto, não é a única opção para conseguir isso em Java.

Vamos entender o que mais o Java tem a oferecer e como eles se comparam à API GSS:

  • Java Secure Socket Extension (JSSE):JSSE is a set of packages in Java that implements Secure Sockets Layer (SSL) for Java. Ele fornece criptografia de dados, autenticação de cliente e servidor e integridade de mensagens. Ao contrário da API GSS, o JSSE conta com uma PKI (Public Key Infrastructure) para funcionar. Portanto, a API do GSS se mostra mais flexível e leve que o JSSE.

  • Java Simple Authentication and Security Layer (SASL):SASL is a framework for authentication and data security for internet protocols que os separa de mecanismos de autenticação específicos. Esse escopo é semelhante ao GSS API. No entanto, o Java GSS possui suporte limitado para mecanismos de segurança subjacentes por meio de provedores de segurança disponíveis.

No geral, a API GSS é bastante poderosa no fornecimento de serviços de segurança de maneira independente de mecanismo. No entanto, o suporte a mais mecanismos de segurança em Java levará isso adiante na adoção.

7. Conclusão

Para resumir, neste tutorial, entendemos o básico da API do GSS como uma estrutura de segurança. Analisamos a API Java para GSS e entendemos como podemos aproveitá-las. No processo, criamos componentes simples de cliente e servidor que executavam autenticação mútua e trocavam dados com segurança.

Além disso, vimos também quais são as aplicações práticas da API GSS e quais são as alternativas disponíveis em Java.

Como sempre, o código pode ser encontradoover on GitHub.