X.509-verificatie in Spring Security
1. Overzicht
In dit artikel zullen we ons concentreren op de belangrijkste gebruiksscenario's voor X.509-certificaatverificatie - het verifiëren van de identiteit van een communicatie-peer bij gebruik van het HTTPS-protocol (HTTP over SSL).
Simpel gezegd - terwijl een beveiligde verbinding tot stand wordt gebracht, verifieert de client de server aan de hand van zijn certificaat (uitgegeven door een vertrouwde certificeringsinstantie).
Maar verder kan X.509 in Spring Security worden gebruikt verifieer de identiteit van een klant door de server tijdens het verbinden. Dit heet "Wederzijdse authenticatie", en we zullen hier ook kijken hoe dat wordt gedaan.
Ten slotte gaan we verder wanneer het zinvol is om dit soort authenticatie te gebruiken.
Om serververificatie te demonstreren, maken we een eenvoudige webtoepassing en installeren we een aangepaste certificeringsinstantie in een browser.
Bovendien, voor wederzijdse authenticatie, maken we een clientcertificaat aan en passen we onze server aan om alleen geverifieerde clients toe te staan.
Het wordt ten zeerste aanbevolen om de tutorial stap voor stap te volgen en de certificaten, evenals de keystore en de truststore, zelf aan te maken volgens de instructies in de volgende secties. Alle kant-en-klare bestanden zijn echter te vinden in onze GitHub-repository.
2. Zelfondertekende basis-CA
Om onze server-side en client-side certificaten te kunnen ondertekenen, moeten we eerst ons eigen zelfondertekende root CA-certificaat aanmaken. Op deze manier wij treden op als onze eigen certificeringsinstantie.
Voor dit doel gebruiken we de openssl-bibliotheek, dus we moeten deze hebben geïnstalleerd voordat we de volgende stap volgen.
Laten we nu het CA-certificaat maken:
openssl req -x509 -sha256 -days 3650 -newkey rsa: 4096 -keyout rootCA.key -out rootCA.crt
Wanneer we de bovenstaande opdracht uitvoeren, moeten we het wachtwoord voor onze privésleutel opgeven. Voor deze tutorial gebruiken we verander het als een wachtwoordzin.
Bovendien, we moeten informatie invoeren die een zogenaamde DN-naam vormt. Hier verstrekken we alleen de CN (Common Name) - Baeldung.com - en laten we andere delen leeg.
3. Sleutelarchief
Facultatieve vereiste: Om cryptografisch sterke sleutels te gebruiken in combinatie met coderings- en decoderingsfuncties hebben we de "Java Cryptography Extension (JCE) Onbeperkte machtsbeleidsbestanden voor jurisdictie”Geïnstalleerd in onze JVM.
Deze kunnen bijvoorbeeld worden gedownload van Oracle (volg de installatie-instructies die bij de download zijn meegeleverd). Sommige Linux-distributies bieden ook een installeerbaar pakket via hun pakketbeheerders.
Een keystore is een opslagplaats die onze Spring Boot-applicatie zal gebruiken om de privésleutel en het certificaat van onze server te bewaren. Met andere woorden, onze applicatie zal de keystore gebruiken om het certificaat aan de klanten te serveren tijdens de SSL-handshake.
In deze tutorial gebruiken we de Java Key-Store (JKS) -indeling en een keytool-opdrachtregelprogramma.
3.1. Certificaat aan serverzijde
Om de server-side X.509-authenticatie in onze Spring Boot-applicatie te implementeren, hebben we moet eerst een server-side certificaat aanmaken. Laten we beginnen met het maken van een zogenaamd certificaatondertekeningsverzoek (CSR): Evenzo moeten we, net als voor het CA-certificaat, het wachtwoord voor de privésleutel opgeven. Laten we bovendien localhost als een algemene naam (CN). Voordat we verder gaan, moeten we een configuratiebestand maken - localhost.ext. Het slaat enkele aanvullende parameters op die nodig zijn tijdens het ondertekenen van het certificaat. Een kant-en-klaar bestand is hier ook beschikbaar. Nu is het tijd om teken het verzoek met onze rootCA.crt certificaat en de bijbehorende privésleutel: Houd er rekening mee dat we hetzelfde wachtwoord moeten opgeven dat we hebben gebruikt bij het maken van ons CA-certificaat. In dit stadium we hebben eindelijk een klaar voor gebruik localhost.crt certificaat ondertekend door onze eigen certificeringsinstantie. Om de details van ons certificaat af te drukken in een voor mensen leesbare vorm, kunnen we het volgende commando gebruiken: In dit gedeelte zullen we zien hoe u dat doet importeer het ondertekende certificaat en de bijbehorende privésleutel naar het keystore.jks het dossier. We gebruiken het PKCS 12-archief om de privésleutel van onze server samen met het ondertekende certificaat te verpakken. Vervolgens importeren we het naar het nieuw gemaakte keystore.jks. We kunnen de volgende opdracht gebruiken om een .p12 het dossier: Dus we hebben nu de localhost.key en de localhost.crt gebundeld in de single localhost.p12 het dossier. Laten we nu keytool gebruiken om Maak een keystore.jks repository en importeer het localhost.p12 bestand met een enkele opdracht: In dit stadium hebben we alles voor het serverauthenticatiegedeelte. Laten we doorgaan met de configuratie van onze Spring Boot-applicatie. Ons SSL-beveiligde serverproject bestaat uit een @SpringBootApplication geannoteerde toepassingsklasse (wat een soort @Configuratie), een application.properties configuratiebestand en een zeer eenvoudige front-end in MVC-stijl. Het enige wat de applicatie hoeft te doen, is een HTML-pagina presenteren met een "Hallo {User}!" bericht. Op deze manier kunnen we het servercertificaat in een browser inspecteren om er zeker van te zijn dat de verbinding is geverifieerd en beveiligd. Eerst maken we een nieuw Maven-project met drie Spring Boot Starter-bundels inbegrepen: Als referentie: we kunnen de bundels vinden op Maven Central (beveiliging, web, thymeleaf). Als volgende stap maken we de hoofdtoepassingsklasse en de gebruikerscontroller: Nu vertellen we de applicatie waar ze onze keystore.jks en hoe u er toegang toe krijgt. We stellen SSL in op de status "ingeschakeld" en wijzigen de standaard luisterpoort in duiden op een beveiligde verbinding. Bovendien configureren we enkele gebruikersdetails voor toegang tot onze server via basisverificatie: Dit wordt de HTML-sjabloon, die zich bevindt in het bronnen / sjablonen map: Voordat we deze sectie afronden en naar de site kijken, we moeten onze gegenereerde rootcertificeringsinstantie installeren als een vertrouwd certificaat in een browser. Een voorbeeldige installatie van onze certificeringsinstantie voor Mozilla Firefox zou er als volgt uitzien: Opmerking: Als u onze certificeringsinstantie naar de lijst van vertrouwde autoriteiten, heb je later de mogelijkheid om een uitzondering en de website stoer laten zien, zelfs als deze als onveilig wordt genoemd. Maar dan zie je een 'geel uitroepteken'-symbool in de adresbalk, wat de onveilige verbinding aangeeft! Daarna navigeren we naar het spring-security-x509-basic-auth module en voer uit: Eindelijk raakten we // localhost: 8443 / gebruiker, voer onze gebruikersgegevens in vanuit het application.properties en zou een "Hallo beheerder!" bericht. Nu kunnen we de verbindingsstatus controleren door op het "groene slot" -symbool in de adresbalk te klikken. Het zou een beveiligde verbinding moeten zijn. In de vorige sectie hebben we laten zien hoe het meest voorkomende SSL-authenticatieschema geïmplementeerd kan worden: server-side authenticatie. Dit betekent dat alleen een server zichzelf heeft geverifieerd bij clients. In deze sectie we zullen beschrijven hoe u het andere deel van de authenticatie toevoegt - client-side authenticatie. Op deze manier hebben alleen klanten met geldige certificaten ondertekend door de autoriteit die onze server vertrouwt toegang tot onze beveiligde website. Maar laten we, voordat we verder gaan, eens kijken wat de voor- en nadelen zijn van het gebruik van wederzijdse SSL-authenticatie. Voordelen: Nadelen: Een trustsore is op de een of andere manier het tegenovergestelde van een keystore. Het bevat de certificaten van de externe entiteiten die we vertrouwen. In ons geval is het voldoende om het root-CA-certificaat in de truststore te bewaren. Laten we eens kijken hoe we een truststore.jks bestand en importeer het rootCA.crt keytool gebruiken: Let op, we moeten het wachtwoord opgeven voor het nieuw aangemaakte trusstore.jks. Hier hebben we opnieuw de verander het wachtwoordzin. Dat is alles, we hebben ons eigen CA-certificaat geïmporteerd en de truststore is klaar voor gebruik. Om door te gaan, zijn we onze X509AuthenticationServer om uit te breiden WebSecurityConfigurerAdapter en overschrijf een van de aangeboden configuratiemethoden. Hier configureren we het x.509-mechanisme om het Algemene naam (CN) veld van een certificaat voor het extraheren van gebruikersnamen. Met deze geëxtraheerde gebruikersnamen zoekt Spring Security op in een opgegeven UserDetailsService voor het matchen van gebruikers. Daarom implementeren we ook deze service-interface met één demo-gebruiker. Tip: In productieomgevingen is dit UserDetailsService kan zijn gebruikers bijvoorbeeld laden vanuit een JDBC Datasource. U moet opmerken dat we onze klas annoteren met @EnableWebSecurity en @EnableGlobalMethodSecurity met ingeschakelde pre- / post-autorisatie. Met de laatste kunnen we onze bronnen annoteren met @PreAuthorize en @PostAuthorize voor fijnmazige toegangscontrole: Zoals eerder gezegd, kunnen we nu gebruiken Expressie-gebaseerde toegangscontrole in onze controller. Meer specifiek worden onze autorisatie-annotaties gerespecteerd vanwege de @EnableGlobalMethodSecurity annotatie in onze @Configuratie: Een overzicht van alle mogelijke autorisatiemogelijkheden vindt u in het officiële documentatie. Als laatste modificatiestap moeten we de applicatie vertellen waar onze truststore is gelegen en dat SSL-clientverificatie is noodzakelijk (server.ssl.client-auth = nodig). Dus we hebben het volgende in onze application.properties: Als we nu de applicatie uitvoeren en onze browser naar // localhost: 8443 / gebruiker, vernemen we dat de peer niet kan worden geverifieerd en hij weigert onze website te openen. Nu is het tijd om het client-side certificaat te maken. De stappen die we moeten nemen, zijn vrijwel hetzelfde als voor het server-side certificaat dat we al hebben gemaakt. Eerst moeten we een certificaatondertekeningsverzoek maken: We zullen informatie moeten verstrekken die in het certificaat wordt opgenomen. Voor deze oefening laten we alleen de algemene naam (CN) invoeren - Bob. Het is belangrijk omdat we deze invoer gebruiken tijdens de autorisatie en alleen Bob wordt herkend door onze voorbeeldtoepassing. Vervolgens moeten we het verzoek ondertekenen met onze CA: De laatste stap die we moeten nemen, is het ondertekende certificaat en de privésleutel verpakken in het PKCS-bestand: Tenslotte, we zijn klaar om het clientcertificaat in de browser te installeren. Nogmaals, we zullen Firefox gebruiken: Wanneer we onze website vernieuwen, wordt ons gevraagd om het clientcertificaat te selecteren dat we willen gebruiken: Als we een welkomstbericht zien zoals "Hallo Bob!", dat betekent dat alles werkt zoals verwacht! X.509-clientverificatie toevoegen aan een http beveiligingsconfiguratie in XML is ook mogelijk: Om een onderliggende Tomcat te configureren, moeten we onze keystore en onze truststore in zijn conf map en bewerk het server.xml: Tip: Met clientAuth ingesteld op "willen", SSL is nog steeds ingeschakeld, zelfs als de client geen geldig certificaat verstrekt. Maar in dit geval moeten we een tweede authenticatiemechanisme gebruiken, bijvoorbeeld een inlogformulier, om toegang te krijgen tot de beveiligde bronnen. Samenvattend hebben we geleerd hoe u een zelfondertekend CA-certificaat maakt en hoe u dit gebruikt om andere certificaten te ondertekenen. Daarnaast hebben we zowel server-side als client-side certificaten gemaakt. Vervolgens hebben we uitgelegd hoe u ze kunt importeren in een keystore en een dienovereenkomstig truststore. Bovendien zou je dat nu moeten kunnen verpak een certificaat samen met de bijbehorende privésleutel in het PKCS12-formaat. We hebben ook besproken wanneer het zinvol is om Spring Security X.509-clientverificatie te gebruiken, dus het is aan jou om te beslissen of je het in je webtoepassing wilt implementeren of niet. En om af te ronden, zoek de broncode van dit artikel op Github.openssl req -new -newkey rsa: 4096 -keyout localhost.key –out localhost.csr
AuthorityKeyIdentifier = keyid, uitgever basicConstraints = CA: FALSE subjectAltName = @alt_names [alt_names] DNS.1 = localhost
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.ext
openssl x509 -in localhost.crt -text
3.2. Importeer naar de Keystore
openssl pkcs12 -export -out localhost.p12 -naam "localhost" -inkey localhost.key -in localhost.crt
keytool -importkeystore -srckeystore localhost.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS
4. Voorbeeldtoepassing
4.1. Afhankelijkheden van Maven
org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf
4.2. Spring Boot-applicatie
@SpringBootApplication openbare klasse X509AuthenticationServer {openbare statische leegte hoofd (String [] args) {SpringApplication.run (X509AuthenticationServer.class, args); }} @Controller public class UserController {@RequestMapping (value = "/ user") public String gebruiker (Model model, Principal principal) {UserDetails currentUser = (UserDetails) ((Authentication) principal) .getPrincipal (); model.addAttribute ("gebruikersnaam", currentUser.getUsername ()); retourneer "gebruiker"; }}
server.ssl.key-store = .. / store / keystore.jks server.ssl.key-store-password = $ {PASSWORD} server.ssl.key-alias = localhost server.ssl.key-wachtwoord = $ {PASSWORD } server.ssl.enabled = true server.port = 8443 spring.security.user.name = Beheerder spring.security.user.password = admin
Demo voor X.509-authenticatie
Hallo !
4.3. Root CA-installatie
mvn spring-boot: run
5. Wederzijdse authenticatie
5.1. Truststore
keytool -import -trustcacerts -noprompt -alias ca -ext san = dns: localhost, ip: 127.0.0.1 -file rootCA.crt -keystore truststore.jks
5.2. Spring-beveiligingsconfiguratie
@SpringBootApplication @EnableWebSecurity @EnableGlobalMethodSecurity (prePostEnabled = true) openbare klasse X509AuthenticationServer breidt WebSecurityConfigurerAdapter uit {... @Override beschermde ongeldige configuratie (HttpSecurity @ http) gooit Uitzondering $) Details UserDetails UserDetails UserDetails UserDetails UserDetails UserDetails (userDetails) UserDetails {retourneer nieuwe UserDetailsService () {@Override openbare UserDetails loadUserByUsername (String gebruikersnaam) {if (gebruikersnaam.equals ("Bob")) {retourneer nieuwe gebruiker (gebruikersnaam, "", AuthorityUtils .commaSeparatedStringToAuthorityList ("ROLE_USER"));} new UsernameNotFoundException ("Gebruiker niet gevonden!");}};}}
@Controller public class UserController {@PreAuthorize ("hasAuthority ('ROLE_USER')") @RequestMapping (value = "/ user") public String-gebruiker (Modelmodel, Principal-principal) {...}}
server.ssl.trust-store = store / truststore.jks server.ssl.trust-store-password = $ {PASSWORD} server.ssl.client-auth = nodig
5.3. Certificaat aan clientzijde
openssl req -new -newkey rsa: 4096 -nodes -keyout clientBob.key –out clientBob.csr
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in clientBob.csr -out clientBob.crt -days 365 -CAcreateserial
openssl pkcs12 -export -out clientBob.p12 -naam "clientBob" -inkey clientBob.key -in clientBob.crt
6. Wederzijdse authenticatie met XML
... ...
7. Conclusie