Einführung in Sicherheit und WebSockets

Einführung in Sicherheit und WebSockets

1. Einführung

Inprevious article haben wir gezeigt, wie WebSockets zu einem Spring MVC-Projekt hinzugefügt werden.

Hier beschreiben wir, wieadd security to Spring WebSockets in Spring MVC. Bevor Sie fortfahren, stellen Sie sicher, dass Sie bereits über eine grundlegende Spring MVC-Sicherheitsabdeckung verfügen. Wenn nicht, überprüfen Siethis article.

2. Maven-Abhängigkeiten

Es gibttwo main groups of Maven dependencies, die wir für unsere WebSocket-Implementierung benötigen.

Geben Sie zunächst die übergeordneten Versionen von Spring Framework und Spring Security an, die wir verwenden werden:


    5.0.6.RELEASE
    5.0.6.RELEASE

Zweitens fügen wir die Kernbibliotheken Spring MVC und Spring Security hinzu, die für die Implementierung der grundlegenden Authentifizierung und Autorisierung erforderlich sind:


    org.springframework
    spring-core
    ${spring.version}


    org.springframework
    spring-web
    ${spring.version}


    org.springframework
    spring-webmvc
    ${spring.version}


    org.springframework.security
    spring-security-web
    ${spring-security.version}


    org.springframework.security
    spring-security-config
    ${spring-security.version}

Die neuesten Versionen vonspring-core,spring-web,spring-webmvc,spring-security-web,spring-security-config finden Sie auf Maven Central.

Zuletzt fügen wir die erforderlichen Abhängigkeiten hinzu:


    org.springframework
    spring-websocket
    ${spring.version}


    org.springframework
    spring-messaging
    ${spring.version}


    org.springframework.security
    spring-security-messaging
    ${spring-security.version}

Sie finden die neueste Version vonspring-websocket,spring-messaging undspring-security-messaging in Maven Central.

3. Grundlegende WebSocket-Sicherheit

Die WebSocket-spezifische Sicherheit unter Verwendung der Bibliothekspring-security-messagingkonzentriert sich auf die KlasseAbstractSecurityWebSocketMessageBrokerConfigurerund deren Implementierung in Ihrem Projekt:

@Configuration
public class SocketSecurityConfig
  extends AbstractSecurityWebSocketMessageBrokerConfigurer {
      //...
}

DieAbstractSecurityWebSocketMessageBrokerConfigurer Klasseprovides additional security coverage wird durchWebSecurityConfigurerAdapter. bereitgestellt

Die Bibliothekspring-security-messagingist nicht die einzige Möglichkeit, die Sicherheit für WebSockets zu implementieren. Wenn wir uns an die normalespring-websocket-Bibliothek halten, können wir dieWebSocketConfigurer-Schnittstelle implementieren und Sicherheitsabfangjäger an unsere Socket-Handler anhängen.

Da wir die Bibliothekspring-security-messagingverwenden, verwenden wir den AnsatzAbstractSecurityWebSocketMessageBrokerConfigurer.

3.1. configureInbound() implementieren

Die Implementierung vonconfigureInbound() ist der wichtigste Schritt bei der Konfiguration IhrerAbstractSecurityWebSocketMessageBrokerConfigurer-Unterklasse:

@Override
protected void configureInbound(
  MessageSecurityMetadataSourceRegistry messages) {
    messages
      .simpDestMatchers("/secured/**").authenticated()
      .anyMessage().authenticated();
}

Während Sie mitWebSecurityConfigurerAdapter verschiedene anwendungsweite Autorisierungsanforderungen für verschiedene Routen angeben können, können Sie mitAbstractSecurityWebSocketMessageBrokerConfigurer die spezifischen Autorisierungsanforderungen für Socket-Ziele angeben.

3.2. Typ- und Zielübereinstimmung

MitMessageSecurityMetadataSourceRegistry können wir Sicherheitsbeschränkungen wie Pfade, Benutzerrollen und die zulässigen Nachrichten angeben.

Type matchers constrain which SimpMessageType are allowed und auf welche Weise:

.simpTypeMatchers(CONNECT, UNSUBSCRIBE, DISCONNECT).permitAll()

Destination matchers constrain which endpoint patterns are accessible und auf welche Weise:

.simpDestMatchers("/app/**").hasRole("ADMIN")

Subscribe destination matchers map a ListofSimpDestinationMessageMatcher instancesthat match on SimpMessageType.SUBSCRIBE:

.simpSubscribeDestMatchers("/topic/**").authenticated()

Hier ist die vollständige Liste vonall available methods for type and destination matching.

4. Socket-Routen sichern

Nachdem wir die grundlegende Konfiguration für Socketsicherheit und Typanpassung kennengelernt haben, können wir Socketsicherheit, Ansichten, STOMP (ein SMS-Protokoll), Nachrichtenbroker und Socket-Controller kombinieren, um sichere WebSockets in unserer Spring MVC-Anwendung zu aktivieren.

Lassen Sie uns zunächst unsere Socket-Ansichten und Controller für die grundlegende Spring Security-Abdeckung einrichten:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
@ComponentScan("com.example.springsecuredsockets")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .antMatchers("/", "/index", "/authenticate").permitAll()
          .antMatchers(
            "/secured/**/**",
            "/secured/success",
            "/secured/socket",
            "/secured/success").authenticated()
          .anyRequest().authenticated()
          .and()
          .formLogin()
          .loginPage("/login").permitAll()
          .usernameParameter("username")
          .passwordParameter("password")
          .loginProcessingUrl("/authenticate")
          //...
    }
}

Zweitens richten wir das eigentliche Nachrichtenziel mit den Authentifizierungsanforderungen ein:

@Configuration
public class SocketSecurityConfig
  extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
          .simpDestMatchers("/secured/**").authenticated()
          .anyMessage().authenticated();
    }
}

Jetzt können wir in unseren WebSocketMessageBrokerConfigurer, die tatsächlichen Nachrichten- und STOMP-Endpunkte registrieren:

@Configuration
@EnableWebSocketMessageBroker
public class SocketBrokerConfig
  implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/secured/history");
        config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/secured/chat")
          .withSockJS();
    }
}

Definieren wiran example socket controller und den Endpunkt, für den wir oben eine Sicherheitsabdeckung bereitgestellt haben:

@Controller
public class SocketController {

    @MessageMapping("/secured/chat")
    @SendTo("/secured/history")
    public OutputMessage send(Message msg) throws Exception {
        return new OutputMessage(
           msg.getFrom(),
           msg.getText(),
           new SimpleDateFormat("HH:mm").format(new Date()));
    }
}

5. Gleiche Ursprungsrichtlinie

FürSame Origin Policy müssen alle Interaktionen mit einem Endpunkt aus derselben Domäne stammen, in der die Interaktion initiiert wurde.

Angenommen, Ihre WebSockets-Implementierung wird beifoo.com gehostet, und Sie sindenforcing same origin policy. Wenn ein Benutzer eine Verbindung zu Ihrem Client herstellt, der beifoo.com gehostet wird, und dann einen anderen Browser fürbar.com öffnet, hatbar.com keinen Zugriff auf Ihre WebSocket-Implementierung.

5.1. Überschreiben der gleichen Ursprungsrichtlinie

Spring WebSockets erzwingen sofort die gleiche Ursprungsrichtlinie, normale WebSockets jedoch nicht.

Tatsächlich istSpring Security requires a CSRF (Cross Site Request Forgery) token für jeden gültigenCONNECT-Nachrichtentyp:

@Controller
public class CsrfTokenController {
    @GetMapping("/csrf")
    public @ResponseBody String getCsrfToken(HttpServletRequest request) {
        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
        return csrf.getToken();
    }
}

Durch Aufrufen des Endpunkts bei/csrf kann ein Client das Token abrufen und sich über die CSRF-Sicherheitsschicht authentifizieren.

DieSame Origin Policy for Spring can be overridden durch Hinzufügen der folgenden Konfiguration zu IhrenAbstractSecurityWebSocketMessageBrokerConfigurer:

@Override
protected boolean sameOriginDisabled() {
    return true;
}

5.2. STOMP-, SockJS-Support- und Frame-Optionen

Es ist üblich,STOMP zusammen mitSockJS zu verwenden, um die clientseitige Unterstützung für Spring WebSockets zu implementieren.

SockJS is configured to disallow transports through HTML iframe elements by default. This is to prevent the threat of clickjacking.

Es gibt jedoch bestimmte Anwendungsfälle, in denen es vorteilhaft sein kann,iframes die Nutzung von SockJS-Transporten zu ermöglichen. Dazu können Sie die Standardkonfiguration inWebSecurityConfigurerAdapter überschreiben:

@Override
protected void configure(HttpSecurity http)
  throws Exception {
    http
      .csrf()
        //...
        .and()
      .headers()
        .frameOptions().sameOrigin()
      .and()
        .authorizeRequests();
}

Beachten Sie, dass wir in diesem Beispiel denSame Origin Policy folgen, obwohl Transporte durchiframes zulässig sind.

6. Oauth2-Coverage

Die Oauth2-spezifische Unterstützung für Spring WebSockets wird ermöglicht, indem die Oauth2-Sicherheitsabdeckung zusätzlich zu Ihrer StandardabdeckungWebSecurityConfigurerAdapter.Here’simplementiert und erweitert wird. Dies ist ein Beispiel für die Implementierung von Oauth2.

Um sich zu authentifizieren und Zugriff auf einen WebSocket-Endpunkt zu erhalten, können Sie Oauth2access_token an einen Abfrageparameter übergeben, wenn Sie eine Verbindung von Ihrem Client zu Ihrem Back-End-WebSocket herstellen.

Hier ist ein Beispiel, das dieses Konzept mit SockJS und STOMP demonstriert:

var endpoint = '/ws/?access_token=' + auth.access_token;
var socket = new SockJS(endpoint);
var stompClient = Stomp.over(socket);

7. Fazit

In diesem kurzen Tutorial haben wir gezeigt, wie Sie Spring WebSockets sicherer machen. Sehen Sie sich die ReferenzdokumentationWebSocket undWebSocket Securityvon Spring an, um mehr über diese Integration zu erfahren.

Überprüfen Sie wie immerour Github project auf Beispiele, die in diesem Artikel verwendet werden.