Een gids voor Java GSS API

Java Top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

In deze tutorial zullen we de Generic Security Service API (GSS API) begrijpen en hoe we deze in Java kunnen implementeren. We zullen zien hoe we netwerkcommunicatie kunnen beveiligen met behulp van de GSS API in Java.

Tijdens het proces zullen we eenvoudige client- en servercomponenten maken en deze beveiligen met GSS API.

2. Wat is GSS API?

Dus, wat is eigenlijk de Generic Security Service API? GSS API biedt een generiek raamwerk voor applicaties om verschillende beveiligingsmechanismen zoals Kerberos te gebruiken, NTLM en SPNEGO op een plugbare manier. Bijgevolg helpt het applicaties om zichzelf direct los te koppelen van de beveiligingsmechanismen.

Ter verduidelijking: beveiliging omvat hier authenticatie, gegevensintegriteit en vertrouwelijkheid.

2.1. Waarom hebben we nodig GSS API?

Beveiligingsmechanismen zoals Kerberos, NTLM en Digest-MD5 verschillen behoorlijk in hun mogelijkheden en implementaties. Een applicatie die een van deze mechanismen ondersteunt, vindt het doorgaans nogal beangstigend om naar een andere over te schakelen.

Dit is waar een generiek framework zoals GSS API biedt applicaties een abstractie. Daarom kunnen applicaties die GSS API gebruiken, onderhandelen over een geschikt beveiligingsmechanisme en dat gebruiken voor communicatie. En dat alles zonder echt mechanismespecifieke details te hoeven implementeren.

2.2. Hoe werkt GSS API-werk?

GSS API is een op tokens gebaseerd mechanisme. Het werkt door de uitwisseling van beveiligingstokens tussen peers. Deze uitwisseling vindt meestal plaats via een netwerk, maar de GSS-API is agnostisch voor die details.

Deze tokens worden gegenereerd en verwerkt door de specifieke implementaties van de GSS API. De syntaxis en semantiek van deze tokens zijn specifiek voor het beveiligingsmechanisme onderhandeld tussen de peers:

Het centrale thema van GSS API draait om een ​​beveiligingscontext. We kunnen deze context tussen peers tot stand brengen door het uitwisselen van tokens. Wij mogelijk meerdere uitwisselingen van tokens tussen peers nodig hebben om de context vast te stellen.

Eenmaal succesvol vastgesteld aan beide uiteinden, kunnen we de beveiligingscontext gebruiken om veilig gegevens uit te wisselen. Dit kan controle van de gegevensintegriteit en gegevensversleuteling omvatten, afhankelijk van het onderliggende beveiligingsmechanisme.

3. GSS API-ondersteuning in Java

Java ondersteunt GSS API als onderdeel van het pakket “org.ietf.jgss”. De pakketnaam lijkt misschien vreemd. Dat komt omdat de Java-bindingen voor GSS API zijn gedefinieerd in een IETF-specificatie. De specificatie zelf is onafhankelijk van het beveiligingsmechanisme.

Een van de populaire beveiligingsmechanismen voor Java GSS is Kerberos v5.

3.1. Java GSS API

Laten we proberen enkele van de kern-API's te begrijpen die Java GSS bouwen:

  • GSSContext omvat de GSS API-beveiligingscontext en biedt services die onder de context beschikbaar zijn
  • GSSCredential bevat de GSS API-inloggegevens voor een entiteit die nodig zijn om de beveiligingscontext vast te stellen
  • GSSName omvat de GSS API-hoofdentiteit die een abstractie biedt voor verschillende naamruimten die door onderliggende mechanismen worden gebruikt

Afgezien van de bovenstaande interfaces, zijn er enkele andere belangrijke klassen om op te merken:

  • GSSManager dient als de fabrieksklasse voor andere belangrijke GSS API-klassen zoals GSSName, GSSCredential, en GSSContext
  • Oid staat voor de Universal Object Identifiers (OID's), dit zijn hiërarchische ID's die binnen de GSS API worden gebruikt om mechanismen en naamindelingen te identificeren
  • MessageProp wraps eigenschappen om GSSContext aan te duiden over zaken als Quality of Protection (QoP) en vertrouwelijkheid voor gegevensuitwisseling
  • Kanaalbinding bevat de optionele kanaalbindingsinformatie die wordt gebruikt om de kwaliteit te versterken waarmee peer-entiteitsauthenticatie wordt geboden

3.2. Java GSS-beveiligingsprovider

Hoewel de Java GSS het kernraamwerk definieert voor het implementeren van de GSS API in Java, biedt het geen implementatie. Java gebruikt Aanbieder-gebaseerde pluggable implementaties voor beveiligingsdiensten inclusief Java GSS.

Er kunnen er een of meer zijn beveiligingsproviders die zijn geregistreerd bij de Java Cryptography Architecture (JCA). Elke beveiligingsprovider kan een of meer beveiligingsservices implementeren, zoals Java GSSAPI en onderliggende beveiligingsmechanismen.

Er is een standaard GSS-provider die met de JDK wordt geleverd. Er zijn echter andere leverancierspecifieke GSS-providers met verschillende beveiligingsmechanismen die we kunnen gebruiken. Een van die providers is IBM Java GSS. We moeten zo'n beveiligingsprovider bij JCA registreren om ze te kunnen gebruiken.

Bovendien kunnen wij kan onze eigen beveiligingsprovider implementeren met eventueel aangepaste beveiligingsmechanismen. In de praktijk is dit echter nauwelijks nodig.

4. GSS API aan de hand van een voorbeeld

Nu zullen we Java GSS in actie zien aan de hand van een voorbeeld. We maken een eenvoudige client- en servertoepassing. De client wordt in GSS vaker initiator genoemd en server als acceptor. We gebruiken Java GSS en Kerberos v5 hieronder voor authenticatie.

4.1. GSS-context voor client en server

Om te beginnen zullen we moeten vestigen een GSSContext, zowel aan de server- als aan de clientzijde van de aanvraag.

Laten we eerst kijken hoe we dit aan de klantzijde kunnen doen:

GSSManager-manager = GSSManager.getInstance (); String serverPrinciple = "HTTP / [e-mail beveiligd]"; GSSName serverName = manager.createName (serverPrinciple, null); Oid krb5Oid = nieuwe Oid ("1.2.840.113554.1.2.2"); GSSContext clientContext = manager.createContext (servernaam, krb5Oid, (GSSCredential) null, GSSContext.DEFAULT_LIFETIME); clientContext.requestMutualAuth (true); clientContext.requestConf (true); clientContext.requestInteg (true);

Er gebeuren hier nogal wat dingen, laten we ze opsplitsen:

  • We beginnen met het maken van een instantie van het GSSManager
  • Vervolgens gebruiken we deze instantie om GSSContext, doorgeven:
    • een GSSName die de server-principal vertegenwoordigt, let op de Kerberos-specifieke hoofdnaam hier
    • de Oid van het te gebruiken mechanisme, Kerberos v5 hier
    • de inloggegevens van de initiator, nul hier betekent dat standaardreferenties worden gebruikt
    • de levensduur voor de gevestigde context
  • Eindelijk bereiden we ons voor de context voor wederzijdse authenticatie, vertrouwelijkheid en gegevensintegriteit

Evenzo moeten we de server-side context definiëren:

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

Zoals we kunnen zien, is dit veel eenvoudiger dan de context aan de clientzijde. Het enige verschil hier is dat we de inloggegevens van de acceptant nodig hebben die we hebben gebruikt als nul. Zoals eerder, nul betekent dat de standaardreferenties worden gebruikt.

4.2. GSS API-verificatie

Hoewel we de server- en client-side hebben gemaakt GSSContext, houd er rekening mee dat ze in dit stadium nog niet zijn vastgesteld.

Om deze contexten vast te stellen, moeten we tokens uitwisselen die specifiek zijn voor het gespecificeerde beveiligingsmechanisme, dat wil zeggen Kerberos v5:

// Op de client-side clientToken = clientContext.initSecContext (nieuwe byte [0], 0, 0); sendToServer (clientToken); // Dit wordt verondersteld te worden verzonden via het netwerk // Aan de serverzijde serverToken = serverContext.acceptSecContext (clientToken, 0, clientToken.length); sendToClient (serverToken); // Dit wordt verondersteld te worden verzonden via het netwerk // Terug aan de clientzijde clientContext.initSecContext (serverToken, 0, serverToken.length);

Dit maakt uiteindelijk de context die aan beide uiteinden is vastgesteld:

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

4.3. GSS API beveiligde communicatie

Nu we aan beide uiteinden een context hebben vastgesteld, we kunnen beginnen met het verzenden van gegevens met integriteit en vertrouwelijkheid:

// Aan de clientzijde byte [] messageBytes = "Baeldung" .getBytes (); MessageProp clientProp = nieuwe MessageProp (0, true); byte [] clientToken = clientContext.wrap (messageBytes, 0, messageBytes.length, clientProp); sendToClient (serverToken); // Dit wordt verondersteld te worden verzonden via het netwerk // Aan de serverzijde MessageProp serverProp = new MessageProp (0, false); byte [] bytes = serverContext.unwrap (clientToken, 0, clientToken.length, serverProp); String string = nieuwe String (bytes); assertEquals ("Baeldung", string);

Er gebeuren hier een aantal dingen, laten we analyseren:

  • MessageProp wordt door de client gebruikt om de wikkelen methode en genereer het token
  • De methode wikkelen voegt ook cryptografische MIC van de gegevens toe, de MIC wordt gebundeld als onderdeel van het token
  • Dat token wordt naar de server gestuurd (mogelijk via een netwerkoproep)
  • De server maakt gebruik van MessageProp opnieuw om de uitpakken methode en krijg gegevens terug
  • Ook de methode uitpakken verifieert de MIC voor de ontvangen gegevens, waardoor de gegevensintegriteit wordt gewaarborgd

Daarom kunnen de client en de server gegevens met integriteit en vertrouwelijkheid uitwisselen.

4.4. Kerberos-opzet voor het voorbeeld

Nu, een GSS-mechanisme zoals Van Kerberos wordt doorgaans verwacht dat het inloggegevens ophaalt van een bestaand Onderwerpen. De klas Onderwerpen hier is een JAAS-abstractie die een entiteit vertegenwoordigt zoals een persoon of een dienst. Dit wordt meestal ingevuld tijdens een JAAS-gebaseerde authenticatie.

Voor ons voorbeeld zullen we echter niet rechtstreeks een op JAAS gebaseerde authenticatie gebruiken. We laten Kerberos rechtstreeks inloggegevens verkrijgen, in ons geval met behulp van een keytab-bestand. Er is een JVM-systeemparameter om dat te bereiken:

-Djavax.security.auth.useSubjectCredsOnly = false

De standaard Kerberos-implementatie die door Sun Microsystem wordt geleverd, vertrouwt echter op JAAS om authenticatie te bieden.

Dit klinkt misschien in strijd met wat we zojuist hebben besproken. Houd er rekening mee dat we JAAS expliciet kunnen gebruiken in onze applicatie die het Onderwerpen. Of laat het aan het onderliggende mechanisme over om direct te authenticeren, waar het hoe dan ook JAAS gebruikt. Daarom moeten we een JAAS-configuratiebestand leveren aan het onderliggende mechanisme:

com.sun.security.jgss.initiate {com.sun.security.auth.module.Krb5LoginModule vereist useKeyTab = true keyTab = example.keytab principal = "client / localhost" storeKey = true; }; com.sun.security.jgss.accept {com.sun.security.auth.module.Krb5LoginModule vereist useKeyTab = true keyTab = example.keytab storeKey = true principal = "HTTP / localhost"; };

Deze configuratie is ongecompliceerd, waarbij we Kerberos hebben gedefinieerd als de vereiste inlogmodule voor zowel initiator als acceptor. Bovendien hebben we geconfigureerd om de respectieve principals uit een keytab-bestand te gebruiken. We kunnen deze JAAS-configuratie doorgeven aan JVM als een systeemparameter:

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

Hier is de aanname dat we toegang hebben tot een Kerberos KDC. In de KDC hebben we de vereiste principals ingesteld en het keytab-bestand verkregen om, laten we zeggen, te gebruiken "Voorbeeld.keytab".

Bovendien hebben we het Kerberos-configuratiebestand nodig dat naar de juiste KDC wijst:

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

Deze eenvoudige configuratie definieert een KDC die draait op poort 52135 met een standaard realm als EXAMPLE.COM. We kunnen dit doorgeven aan JVM als een systeemparameter:

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

4.5. Het voorbeeld uitvoeren

Om het voorbeeld te geven, moeten we maak gebruik van de Kerberos-artefacten die in de laatste sectie zijn besproken.

We moeten ook de vereiste JVM-parameters doorgeven:

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

Dit is voldoende voor Kerberos om de authenticatie uit te voeren met inloggegevens van keytab en GSS om de contexten vast te stellen.

5. GSS API in de echte wereld

Hoewel GSS API een groot aantal beveiligingsproblemen belooft op te lossen via insteekbare mechanismen, zijn er maar weinig use-cases die op grotere schaal worden toegepast:

  • Haar veel gebruikt in SASL als beveiligingsmechanisme, vooral waar Kerberos het onderliggende mechanisme is bij uitstek. Kerberos is een veelgebruikt authenticatiemechanisme, vooral binnen een bedrijfsnetwerk. Het is erg handig om een ​​Kerberized-infrastructuur te gebruiken om een ​​nieuwe applicatie te authenticeren. Vandaar dat GSS API die kloof mooi overbrugt.
  • Het is ook gebruikt in vervoeging met SPNEGO om te onderhandelen over een beveiligingsmechanisme wanneer dit niet van tevoren bekend is. In dit opzicht is SPNEGO in zekere zin een pseudo-mechanisme van GSS API. Dit wordt breed ondersteund in alle moderne browsers waardoor ze gebruik kunnen maken van op Kerberos gebaseerde authenticatie.

6. GSS API in vergelijking

GSS API is behoorlijk effectief in het leveren van beveiligingsdiensten aan applicaties op een plugbare manier. Het is echter niet de enige keuze om dit in Java te bereiken.

Laten we eens kijken wat Java nog meer te bieden heeft en hoe ze zich verhouden tot GSS API:

  • Java Secure Socket Extension (JSSE): JSSE is een set pakketten in Java die Secure Sockets Layer (SSL) voor Java implementeert. Het biedt gegevenscodering, client- en serververificatie en berichtintegriteit. In tegenstelling tot GSS API, vertrouwt JSSE op een Public Key Infrastructure (PKI) om te werken. Daarom is de GSS API flexibeler en lichter dan JSSE.
  • Java Simple Authentication and Security Layer (SASL): SASL is een raamwerk voor authenticatie en gegevensbeveiliging voor internetprotocollen waardoor ze worden losgekoppeld van specifieke authenticatiemechanismen. Dit is vergelijkbaar met GSS API. Java GSS biedt echter beperkte ondersteuning voor onderliggende beveiligingsmechanismen via beschikbare beveiligingsproviders.

Over het algemeen is GSS API behoorlijk krachtig in het leveren van beveiligingsservices op een mechanisme-agnostische manier. Ondersteuning voor meer beveiligingsmechanismen in Java zal dit echter verder bij de acceptatie brengen.

7. Conclusie

Samenvattend, in deze tutorial hebben we de basisprincipes van GSS API als beveiligingsframework begrepen. We hebben de Java API voor GSS doorlopen en begrepen hoe we deze kunnen gebruiken. Daarbij hebben we eenvoudige client- en servercomponenten gemaakt die wederzijdse authenticatie uitvoeren en veilig gegevens uitwisselen.

Verder hebben we ook gezien wat de praktische toepassingen van GSS API zijn en welke alternatieven beschikbaar zijn in Java.

Zoals altijd is de code te vinden op GitHub.

Java onderkant

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS