47 Sicherheit

Sicherheit ist ein essenzieller Aspekt von RESTful Webservices, insbesondere wenn sensible Daten über das Internet übertragen werden. In Spring Boot bietet das Spring Security Framework robuste Mechanismen zur Sicherung von Anwendungen, indem es Authentifizierung, Autorisierung, Schutz vor gängigen Angriffen (wie CSRF und XSS), sowie Verschlüsselung und sicheres Datenmanagement unterstützt.

In diesem Kapitel werden wir uns auf verschiedene Sicherheitsaspekte in Spring Boot REST Services konzentrieren und zeigen, wie Sie gängige Bedrohungen abwehren und Ihre API absichern können.

47.1 1. Überblick über Sicherheitsaspekte

Die Sicherheit von RESTful Webservices lässt sich in zwei Hauptbereiche unterteilen:

Neben diesen beiden zentralen Aspekten müssen moderne APIs Schutzmaßnahmen gegen verschiedene Arten von Angriffen bieten, wie z.B.:

47.2 2. Aktivieren von Spring Security in Spring Boot

Spring Boot verwendet Spring Security als zentrales Sicherheitsframework. Um Sicherheitsfunktionen in Spring Boot zu aktivieren, fügen Sie die Spring Security-Abhängigkeit in Ihrer pom.xml hinzu:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Sobald diese Abhängigkeit hinzugefügt wird, schützt Spring Boot automatisch alle Endpunkte der Anwendung und fordert eine Authentifizierung an. Weitere Anpassungen können über eine Sicherheitskonfigurationsklasse vorgenommen werden.

47.3 3. Authentifizierung und Autorisierung

Die gängigsten Methoden zur Authentifizierung in Spring Boot REST Services sind:

47.3.1 Beispiel: Konfiguration von Basic Authentication

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // CSRF-Schutz ausschalten (nur für APIs)
            .authorizeRequests()
            .antMatchers("/public/**").permitAll() // Öffentliche Endpunkte
            .anyRequest().authenticated() // Authentifizierung für alle anderen Endpunkte
            .and()
            .httpBasic(); // Basic Authentication aktivieren

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User
            .withUsername("admin")
            .password("password")
            .roles("ADMIN")
            .build();

        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance(); // Keine Passwortverschlüsselung (nur zu Demo-Zwecken)
    }
}

In diesem Beispiel wird Basic Authentication für alle nicht-öffentlichen Endpunkte aktiviert. Benutzer mit dem Benutzernamen admin und dem Passwort password können auf die geschützten Endpunkte zugreifen.

47.3.2 Beispiel: Token-basierte Authentifizierung (JWT)

Für die Absicherung von APIs bietet sich die Verwendung von JWT an, da diese Authentifizierungsmethode effizienter und sicherer als Basic Authentication ist.

  1. Generieren eines JWT:

    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import java.util.Date;
    
    public class JwtUtil {
        private String SECRET_KEY = "my_secret_key";
    
        public String generateToken(String username) {
            return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Token für 10 Stunden
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
        }
    }
  2. Validierung eines JWT:

    public boolean validateToken(String token, String username) {
        String extractedUsername = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }
    
    private boolean isTokenExpired(String token) {
        Date expiration = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
        return expiration.before(new Date());
    }
  3. Absicherung von Endpunkten mit JWT: Bei jeder Anfrage wird das JWT-Token im Authorization-Header mitgesendet.

    curl -H "Authorization: Bearer <JWT-Token>" http://localhost:8080/products

47.4 4. Schutz vor CSRF

Cross-Site Request Forgery (CSRF) ist ein Angriff, bei dem ein böswilliger Benutzer eine authentifizierte Sitzung eines Benutzers ausnutzt, um unerwünschte Aktionen auszuführen. In REST-APIs wird der CSRF-Schutz in der Regel deaktiviert, da diese APIs stateless sind und die Authentifizierung über Tokens (z.B. JWT) erfolgt.

47.4.1 Deaktivierung von CSRF-Schutz für REST-APIs

http
    .csrf().disable() // Deaktiviert CSRF-Schutz

47.5 5. Schutz vor XSS

Cross-Site Scripting (XSS) ist eine Angriffsmethode, bei der bösartiger JavaScript-Code in Webseiten eingeschleust wird. Um APIs vor XSS-Angriffen zu schützen, sollten alle Eingaben auf Benutzerseite validiert und auf der Serverseite überprüft werden. In Spring Boot sollten insbesondere die folgenden Schritte beachtet werden:

Beispiel für die Validierung von Benutzereingaben:

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class ProductDto {

    @NotBlank(message = "Name darf nicht leer sein.")
    @Size(max = 100, message = "Name darf nicht länger als 100 Zeichen sein.")
    private String name;
    
    // Weitere Felder mit Validierungen
}

47.6 6. HTTPS verwenden

Um sicherzustellen, dass alle Anfragen und Antworten verschlüsselt werden, sollten RESTful Webservices immer über HTTPS (SSL/TLS) laufen. Dies schützt vor Man-in-the-Middle-Angriffen, bei denen Daten während der Übertragung abgefangen oder manipuliert werden könnten.

47.6.1 HTTPS in Spring Boot aktivieren

  1. Generieren Sie ein SSL-Zertifikat (z.B. mit keytool oder Let’s Encrypt).

  2. Fügen Sie das Zertifikat in Ihre application.properties ein:

    server.port=8443
    server.ssl.key-store=classpath:keystore.jks
    server.ssl.key-store-password=secret
    server.ssl.key-password=secret

47.7 7. Sicherheitslücken und Best Practices

Es ist wichtig, bewährte Sicherheitspraktiken zu befolgen, um RESTful Webservices sicher zu gestalten:

47.8 tl;dr

Die Sicherheit von RESTful Webservices ist von entscheidender Bedeutung, um Daten vor unbefugtem Zugriff und Manipulation zu schützen. Mit den integrierten Funktionen von Spring Security in Kombination mit Best Practices für die Web-Sicherheit können Sie robuste und sichere APIs entwickeln. Durch die Implementierung von Authentifizierungs- und Autorisierungsmechanismen, den Schutz vor gängigen Angriffen wie CSRF und XSS, sowie die Nutzung von HTTPS können Sie sicherstellen, dass Ihre REST-Services den modernen Sicherheitsanforderungen entsprechen.