De basisprincipes van Java-beveiliging

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 zelfstudie bespreken we de basisprincipes van beveiliging op het Java-platform. We zullen ons ook concentreren op wat er beschikbaar is voor het schrijven van veilige applicaties.

Beveiliging is een enorm onderwerp dat veel gebieden omvat. Sommige hiervan maken deel uit van de taal zelf, zoals toegangsmodificatoren en klassenladers. Bovendien zijn andere beschikbaar als services, waaronder gegevensversleuteling, beveiligde communicatie, authenticatie en autorisatie, om er maar een paar te noemen.

Daarom is het niet praktisch om in deze tutorial zinvol inzicht te krijgen in al deze factoren. We zullen echter proberen om op zijn minst een zinvolle woordenschat te krijgen.

2. Taalkenmerken

Bovenal, beveiliging in Java begint precies op het niveau van taalkenmerken. Dit stelt ons in staat om beveiligde code te schrijven en te profiteren van vele impliciete beveiligingsfuncties:

  • Statisch typen van gegevens: Java is een statisch getypeerde taal, die vermindert de mogelijkheden van runtime-detectie van typegerelateerde fouten
  • Toegangsmodificatoren: Java stelt ons in staat om verschillende toegangsmodificatoren zoals openbaar en privé om de toegang tot velden, methoden en klassen te regelen
  • Automatisch geheugenbeheer: Java heeft op garbage collection gebaseerd geheugenbeheer, waardoor ontwikkelaars dit niet handmatig hoeven te beheren
  • Bytecode-verificatie: Java is een gecompileerde taal, wat betekent dat het code omzet in platform-agnostische bytecode, en runtime verifieert elke bytecode die wordt geladen voor uitvoering

Dit is geen volledige lijst met beveiligingsfuncties die Java biedt, maar het is goed genoeg om ons enige zekerheid te geven!

3. Beveiligingsarchitectuur in Java

Voordat we beginnen met het verkennen van specifieke gebieden, moeten we wat tijd besteden aan het begrijpen van de kernarchitectuur van beveiliging in Java.

De kernprincipes van beveiliging in Java worden gedreven door interoperabel en uitbreidbaar Aanbieder implementaties. Een bijzondere implementatie van Aanbieder kan sommige of alle beveiligingsdiensten implementeren.

Enkele van de typische services a Aanbieder kunnen implementeren zijn:

  • Cryptografische algoritmen (zoals DSA, RSA of SHA-256)
  • Sleutelgeneratie-, conversie- en beheerfaciliteiten (zoals voor algoritme-specifieke sleutels)

Java wordt geleverd met veel ingebouwde providers. Het is ook mogelijk dat een applicatie meerdere providers configureert met een volgorde van voorkeur.

Bijgevolg is het provider-framework in Java zoekt bij alle providers naar een specifieke implementatie van een dienst in de volgorde van voorkeur zet op hen.

Bovendien is het altijd mogelijk om maatwerkproviders met pluggable beveiligingsfuncties in deze architectuur te implementeren.

4. Cryptografie

Cryptografie is de hoeksteen van beveiligingsfuncties in het algemeen en in Java. Dit verwijst naar hulpmiddelen en technieken voor veilige communicatie in aanwezigheid van tegenstanders.

4.1. Java-cryptografie

De Java Cryptographic Architecture (JCA) biedt een raamwerk voor toegang tot en implementatie van cryptografische functionaliteiten in Java, waaronder:

  • Digitale handtekeningen
  • Berichtensamenvattingen
  • Symmetrische en asymmetrische cijfers
  • Berichtverificatiecodes
  • Sleutelgeneratoren en sleutelfabrieken

Het belangrijkste is dat Java gebruik maakt van Aanbieder-gebaseerde implementaties voor cryptografische functies.

Bovendien bevat Java ingebouwde providers voor veelgebruikte cryptografische algoritmen zoals RSA, DSA en AES, om er maar een paar te noemen. Wij kunnen gebruik deze algoritmen om gegevens te beveiligen in rust, in gebruik of in beweging.

4.2. Cryptografie in de praktijk

Een veelvoorkomend gebruik in applicaties is het opslaan van gebruikerswachtwoorden. We gebruiken dit voor authenticatie op een later tijdstip. Nu is het duidelijk dat het opslaan van wachtwoorden in platte tekst de beveiliging in gevaar brengt.

Een oplossing is dus om de wachtwoorden zo te versleutelen dat het proces herhaalbaar is, maar slechts in één richting. Dit proces staat bekend als de cryptografische hash-functie en SHA1 is zo'n populair algoritme.

Laten we dus eens kijken hoe we dit in Java kunnen doen:

MessageDigest md = MessageDigest.getInstance ("SHA-1"); byte [] hashedPassword = md.digest ("wachtwoord" .getBytes ());

Hier, MessageDigest is een cryptografische dienst waarin we geïnteresseerd zijn. We zijn met behulp van de methode getInstance() om deze service aan te vragen bij een van de beschikbare beveiligingsproviders.

5. Infrastructuur met openbare sleutel

Public Key Infrastructure (PKI) verwijst naar de installatie die de veilige uitwisseling van informatie via het netwerk mogelijk maakt met behulp van codering met openbare sleutels. Deze opzet is gebaseerd op vertrouwen dat is opgebouwd tussen de partijen die bij de communicatie zijn betrokken. Dit vertrouwen is gebaseerd op digitale certificaten die zijn uitgegeven door een neutrale en vertrouwde autoriteit die bekend staat als een certificeringsinstantie (CA).

5.1. PKI-ondersteuning in Java

Het Java-platform heeft API's om het maken, opslaan en valideren van digitale certificaten te vergemakkelijken:

  • KeyStore: Java biedt de KeyStore klasse voor permanente opslag van cryptografische sleutels en vertrouwde certificaten. Hier, KeyStore kan zowel key-store- als trust-store-bestanden vertegenwoordigen. Deze bestanden hebben vergelijkbare inhoud, maar variëren in gebruik.
  • CertStore: Bovendien heeft Java de CertStore class, die een openbare opslagplaats van mogelijk niet-vertrouwde certificaten en intrekkingslijsten vertegenwoordigt. We moeten certificaten en intrekkingslijsten ophalen voor onder andere het bouwen van certificaatpaden.

Java heeft een ingebouwde trust-store genaamd "cacerts" die certificaten bevat voor bekende CA's.

5.2. Java Tools voor PKI

Java heeft een aantal echt handige tools om vertrouwde communicatie mogelijk te maken:

  • Er is een ingebouwde tool genaamd “keytool” om key-store en trust-store aan te maken en te beheren
  • Er is ook een andere tool "jarsigner" die we kunnen gebruiken om JAR-bestanden te ondertekenen en verifiëren

5.3. Werken met certificaten in Java

Laten we eens kijken hoe we met certificaten in Java kunnen werken om een ​​beveiligde verbinding tot stand te brengen met behulp van SSL. Een wederzijds geverifieerde SSL-verbinding vereist dat we twee dingen doen:

  • Aanwezig certificaat - We moeten een geldig certificaat aan een andere partij in de communicatie presenteren. Daarvoor moeten we het key-store-bestand laden, waar we onze openbare sleutels moeten hebben:
KeyStore keyStore = KeyStore.getInstance (KeyStore.getDefaultType ()); char [] keyStorePassword = "changeit" .toCharArray (); probeer (InputStream keyStoreData = nieuwe FileInputStream ("keystore.jks")) {keyStore.load (keyStoreData, keyStorePassword); }
  • Certificaat verifiëren - We moeten ook het certificaat verifiëren dat door een andere partij in de communicatie is gepresenteerd. Hiervoor moeten we de trust-store laden, waar we eerder vertrouwde certificaten van andere partijen moeten hebben:
KeyStore trustStore = KeyStore.getInstance (KeyStore.getDefaultType ()); // Laad de trust-store uit het bestandssysteem zoals eerder

We hoeven dit zelden programmatisch te doen en normaal gesproken geven we systeemparameters door aan Java tijdens runtime:

-Djavax.net.ssl.trustStore = truststore.jks -Djavax.net.ssl.keyStore = keystore.jks

6. Authenticatie

Authenticatie is het proces voor het verifiëren van de gepresenteerde identiteit van een gebruiker of machine op basis van aanvullende gegevens zoals wachtwoord, token of een verscheidenheid aan andere inloggegevens die vandaag beschikbaar zijn.

6.1. Authenticatie in Java

Java API's maken gebruik van insteekbare inlogmodules om verschillende en vaak meerdere authenticatiemechanismen voor applicaties te bieden. LoginContext biedt deze abstractie, die op zijn beurt verwijst naar de configuratie en een passend laadt LoginModule.

Hoewel meerdere providers hun inlogmodules beschikbaar stellen, Java heeft enkele standaard beschikbare versies voor gebruik:

  • Krb5LoginModule, voor op Kerberos gebaseerde authenticatie
  • JndiLoginModule, voor verificatie op basis van gebruikersnaam en wachtwoord, ondersteund door een LDAP-winkel
  • KeyStoreLoginModule, voor op cryptografische sleutel gebaseerde authenticatie

6.2. Inloggen door voorbeeld

Een van de meest voorkomende authenticatiemechanismen is de gebruikersnaam en het wachtwoord. Laten we eens kijken hoe we dit kunnen bereiken JndiLoginModule.

Deze module is verantwoordelijk voor het verkrijgen van de gebruikersnaam en het wachtwoord van een gebruiker en verifieert deze met een directoryservice die is geconfigureerd in JNDI:

LoginContext loginContext = nieuwe LoginContext ("Sample", nieuwe SampleCallbackHandler ()); loginContext.login ();

Hier zijn we met behulp van een instantie van LoginContext om de login uit te voeren. LoginContext neemt de naam van een item in de aanmeldingsconfiguratie - in dit geval is het "Sample". We moeten ook een exemplaar van CallbackHandler, de ... gebruiken LoginModule die interactie heeft met de gebruiker voor details zoals gebruikersnaam en wachtwoord.

Laten we eens kijken naar onze inlogconfiguratie:

Voorbeeld {com.sun.security.auth.module.JndiLoginModule vereist; };

Simpel genoeg suggereert het dat we JndiLoginModule als verplicht LoginModule.

7. Veilige communicatie

Communicatie via het netwerk is kwetsbaar voor veel aanvalsvectoren. Iemand kan bijvoorbeeld verbinding maken met het netwerk en onze datapakketten lezen terwijl ze worden overgedragen. De industrie heeft in de loop der jaren veel protocollen opgesteld om deze communicatie te beveiligen.

7.1. Java-ondersteuning voor veilige communicatie

Java biedt API's om netwerkcommunicatie mee te beveiligen versleuteling, berichtintegriteit en zowel client- als serververificatie:

  • SSL / TLS: SSL en zijn opvolger, TLS, bieden beveiliging via niet-vertrouwde netwerkcommunicatie door middel van gegevenscodering en openbare-sleutelinfrastructuur. Java biedt ondersteuning voor SSL / TLS via SSLSocket gedefinieerd in het pakket “java.security.ssl“.
  • SASL: Simple Authentication and Security Layer (SASL) is een standaard voor authenticatie tussen client en server. Java ondersteunt SASL als onderdeel van het pakket "java.security.sasl“.
  • GGS-API / Kerberos: Generic Security Service API (GSS-API) biedt uniforme toegang tot beveiligingsservices via verschillende beveiligingsmechanismen zoals Kerberos v5. Java ondersteunt GSS-API als onderdeel van het pakket "java.security.jgss“.

7.2. SSL-communicatie in actie

Laten we nu eens kijken hoe we een beveiligde verbinding kunnen openen met andere partijen in Java met behulp van SSLSocket:

SocketFactory factory = SSLSocketFactory.getDefault (); probeer (Socket-verbinding = factory.createSocket (host, poort)) {BufferedReader-invoer = nieuwe BufferedReader (nieuwe InputStreamReader (connection.getInputStream ())); return input.readLine (); }

Hier gebruiken we SSLSocketFactory maken SSLSocket. Als onderdeel hiervan kunnen we optionele parameters instellen, zoals coderingssuites en welk protocol we moeten gebruiken.

Om dit goed te laten werken, we moeten onze key-store en trust-store hebben gecreëerd en ingesteld zoals we eerder zagen.

8. Toegangscontrole

Toegangscontrole verwijst naar het beschermen van gevoelige bronnen zoals een bestandssysteem of codebase tegen ongegronde toegang. Dit wordt doorgaans bereikt door de toegang tot dergelijke bronnen te beperken.

8.1. Toegangscontrole in Java

We kunnen toegangscontrole krijgen in Java klassen gebruiken Het beleid en Toestemming bemiddeld via de Beveiligingsmanager klasse. Beveiligingsmanager maakt deel uit van de “java.lang”-Pakket en is verantwoordelijk voor het afdwingen van toegangscontroles in Java.

Wanneer de klassenlader een klasse laadt tijdens de runtime, verleent deze automatisch enkele standaardmachtigingen aan de klasse die is ingekapseld in de Toestemming voorwerp. Naast deze standaardmachtigingen kunnen we via beveiligingsbeleid meer invloed aan een klasse verlenen. Deze worden vertegenwoordigd door de klas Het beleid.

Als tijdens de uitvoering van de code een verzoek om een ​​beschermde bron wordt aangetroffen, Beveiligingsmanager verifieert het gevraagde Toestemming tegen de geïnstalleerde Het beleid door de call-stack. Bijgevolg verleent het ofwel toestemming of worpen Beveiligingsuitzondering.

8.2. Java-hulpprogramma's voor beleid

Java heeft een standaardimplementatie van Het beleid die autorisatiegegevens uit het eigenschappenbestand leest. De beleidsvermeldingen in deze beleidsbestanden moeten echter een specifieke indeling hebben.

Java wordt geleverd met "policytool", een grafisch hulpprogramma om beleidsbestanden samen te stellen.

8.3. Toegangscontrole via voorbeeld

Laten we eens kijken hoe we de toegang tot een bron zoals een bestand in Java kunnen beperken:

SecurityManager securityManager = System.getSecurityManager (); if (securityManager! = null) {securityManager.checkPermission (nieuwe FilePermission ("/ var / logs", "read")); }

Hier gebruiken we Beveiligingsmanager om ons leesverzoek voor een bestand, verpakt in FilePermission.

Maar, Beveiligingsmanager delegeert dit verzoek aan AccessController. AccessController maakt intern gebruik van de geïnstalleerde Het beleid om tot een beslissing te komen.

Laten we een voorbeeld van het beleidsbestand bekijken:

verleen {toestemming java.security.FilePermission <>, "read"; };

We verlenen in feite voor iedereen leesrechten aan alle bestanden. Maar, we kunnen veel fijnere controle bieden via beveiligingsbeleid.

Het is vermeldenswaard dat a Beveiligingsmanager wordt mogelijk niet standaard geïnstalleerd in Java. We kunnen hiervoor zorgen door Java altijd te starten met de parameter:

-Djava.security.manager -Djava.security.policy = / pad / naar / sample.policy

9. XML-handtekening

XML-handtekeningen zijn nuttig bij het beveiligen van gegevens en het bieden van gegevensintegriteit. W3C geeft aanbevelingen voor het beheer van XML-handtekeningen. We kunnen XML-handtekening gebruiken om gegevens van elk type te beveiligen, zoals binaire gegevens.

9.1. XML-handtekening in Java

Java API ondersteunt het genereren en valideren van XML-handtekeningen volgens de aanbevolen richtlijnen. Java XML Digital Signature API is ingekapseld in het pakket "java.xml.crypto“.

De handtekening zelf is slechts een XML-document. XML-handtekeningen kunnen van drie typen zijn:

  • Vrijstaand: dit type handtekening heeft betrekking op de gegevens die buiten het handtekeningelement vallen
  • Enveloping: dit type handtekening is over de gegevens die intern zijn in het Signature-element
  • Enveloped: dit type handtekening is over de gegevens die het Signature-element zelf bevatten

Java ondersteunt zeker het maken en verifiëren van alle bovengenoemde typen XML-handtekeningen.

9.2. Een XML-handtekening maken

Nu stropen we onze mouwen op en genereren we een XML-handtekening voor onze gegevens. Het kan bijvoorbeeld zijn dat we op het punt staan ​​een XML-document over het netwerk te verzenden. Vandaar, we zouden willen dat onze ontvanger de integriteit ervan kan verifiëren.

Laten we dus eens kijken hoe we dit in Java kunnen bereiken:

XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance ("DOM"); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance (); documentBuilderFactory.setNamespaceAware (true); Document document = documentBuilderFactory .newDocumentBuilder (). Parse (nieuwe FileInputStream ("data.xml")); DOMSignContext domSignContext = nieuwe DOMSignContext (keyEntry.getPrivateKey (), document.getDocumentElement ()); XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature (signedInfo, keyInfo); xmlSignature.sign (domSignContext);

Ter verduidelijking: we genereren een XML-handtekening voor onze gegevens in het bestand "Data.xml". Ondertussen zijn er een paar dingen die u moet opmerken bij dit stuk code:

  • Ten eerste, XMLSignatureFactory is de fabrieksklasse voor het genereren van XML-handtekeningen
  • XMLSigntaure heeft nodig SignedInfo object waarover het de handtekening berekent
  • XMLSigntaure ook behoeften KeyInfo, die de ondertekeningssleutel en het certificaat omvat
  • Tenslotte, XML-handtekening ondertekent het document met de persoonlijke sleutel die is ingekapseld als DOMSignContext

Als resultaat, het XML-document bevat nu het Signature-element, die kan worden gebruikt om de integriteit ervan te verifiëren.

10. Beveiliging buiten Core Java

Zoals we inmiddels hebben gezien, biedt het Java-platform veel van de nodige functionaliteit om beveiligde applicaties te schrijven. Soms zijn deze echter vrij laag en niet direct toepasbaar op bijvoorbeeld het standaard beveiligingsmechanisme op internet.

Als u bijvoorbeeld aan ons systeem werkt, we willen over het algemeen niet de volledige OAuth RFC hoeven te lezen en die zelf te implementeren. We hebben vaak snellere, hogere manieren nodig om beveiliging te bereiken. Dit is waar applicatiekaders in beeld komen - deze helpen ons onze doelstelling te bereiken met veel minder standaardcode.

En, op het Java-platform - in het algemeen betekent dat Spring Security. Het framework maakt deel uit van het Spring-ecosysteem, maar kan ook buiten de pure Spring-toepassing worden gebruikt.

In eenvoudige bewoordingen helpt het om authenticatie, autorisatie en andere beveiligingsfuncties te bereiken op een eenvoudige, declaratieve manier op hoog niveau.

Natuurlijk wordt Spring Security uitgebreid behandeld in een reeks tutorials, maar ook op een begeleide manier in de cursus Learn Spring Security.

11. Conclusie

Kortom, in deze tutorial hebben we de architectuur op hoog niveau van beveiliging in Java doorgenomen. We begrepen ook hoe Java ons voorziet van implementaties van enkele van de standaard cryptografische services.

We zagen ook enkele van de algemene patronen die we kunnen toepassen om uitbreidbare en plugbare beveiliging te bereiken op gebieden als authenticatie en toegangscontrole.

Kortom, dit geeft ons slechts een voorproefje van de beveiligingsfuncties van Java. Daarom verdient elk van de gebieden die in deze tutorial worden besproken, verdere verkenning. Maar hopelijk hebben we genoeg inzicht om in deze richting aan de slag te gaan!

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