セキュリティとWebSocketの紹介

セキュリティとWebSocketの紹介

1. 前書き

previous articleで、SpringMVCプロジェクトにWebSocketを追加する方法を示しました。

ここでは、add security to Spring WebSockets in Spring MVCの方法について説明します。 続行する前に、基本的なSpring MVCセキュリティカバレッジがすでに設定されていることを確認してください。そうでない場合は、this articleを確認してください。

2. Mavenの依存関係

WebSocketの実装に必要なtwo main groups of Maven dependenciesがあります。

まず、使用するSpringFrameworkとSpringSecurityの包括的なバージョンを指定しましょう。


    5.0.6.RELEASE
    5.0.6.RELEASE

次に、基本認証と承認を実装するために必要なコアSpringMVCライブラリとSpringSecurityライブラリを追加しましょう。


    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}

spring-corespring-webspring-webmvcspring-security-webspring-security-configの最新バージョンは、MavenCentralにあります。

最後に、必要な依存関係を追加しましょう。


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


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


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

spring-websocketspring-messaging、およびspring-security-messagingの最新バージョンはMavenCentralで見つけることができます。

3. 基本的なWebSocketセキュリティ

spring-security-messagingライブラリを使用したWebSocket固有のセキュリティは、AbstractSecurityWebSocketMessageBrokerConfigurerクラスとプロジェクト内でのその実装に重点を置いています。

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

WebSecurityConfigurerAdapter.によって提供されるAbstractSecurityWebSocketMessageBrokerConfigurerクラスprovides additional security coverage

spring-security-messagingライブラリは、WebSocketのセキュリティを実装する唯一の方法ではありません。 通常のspring-websocketライブラリを使用する場合は、WebSocketConfigurerインターフェイスを実装し、セキュリティインターセプターをソケットハンドラーにアタッチできます。

spring-security-messagingライブラリを使用しているため、AbstractSecurityWebSocketMessageBrokerConfigurerアプローチを使用します。

3.1. configureInbound()の実装

configureInbound()の実装は、AbstractSecurityWebSocketMessageBrokerConfigurerサブクラスを構成する上で最も重要なステップです。

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

WebSecurityConfigurerAdapterを使用すると、さまざまなルートに対してアプリケーション全体のさまざまな許可要件を指定できますが、AbstractSecurityWebSocketMessageBrokerConfigurerを使用すると、ソケットの宛先に特定の許可要件を指定できます。

3.2. タイプと宛先のマッチング

MessageSecurityMetadataSourceRegistryを使用すると、パス、ユーザーロール、許可されるメッセージなどのセキュリティ制約を指定できます。

Type matchers constrain which SimpMessageType are allowedとその方法:

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

Destination matchers constrain which endpoint patterns are accessibleとその方法:

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

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

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

これがall available methods for type and destination matchingの完全なリストです。

4. ソケットルートの保護

基本的なソケットセキュリティとタイプマッチング構成を紹介したので、ソケットセキュリティ、ビュー、STOMP(テキストメッセージングプロトコル)、メッセージブローカー、およびソケットコントローラーを組み合わせて、SpringMVCアプリケーション内で安全なWebSocketを有効にすることができます。

まず、基本的なSpringSecurityカバレッジ用にソケットビューとコントローラーを設定しましょう。

@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")
          //...
    }
}

次に、認証要件を使用して実際のメッセージの宛先を設定しましょう。

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

これで、 WebSocketMessageBrokerConfigurer,に、実際のメッセージとSTOMPエンドポイントを登録できます。

@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();
    }
}

上記のセキュリティカバレッジを提供したan example socket controllerとエンドポイントを定義しましょう。

@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. 同起源ポリシー

Same Origin Policyでは、エンドポイントとのすべての対話が、対話が開始されたのと同じドメインからのものである必要があります。

たとえば、WebSocketの実装がfoo.comでホストされており、あなたがenforcing same origin policyであるとします。 ユーザーがfoo.comでホストされているクライアントに接続してから、bar.comで別のブラウザーを開いた場合、bar.comはWebSocket実装にアクセスできなくなります。

5.1. 同一生成元ポリシーのオーバーライド

Spring WebSocketは、そのままで同一生成元ポリシーを適用しますが、通常のWebSocketは適用しません。

実際、有効なCONNECTメッセージタイプのSpring Security requires a CSRF (Cross Site Request Forgery) tokenは次のとおりです。

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

/csrfでエンドポイントを呼び出すことにより、クライアントはトークンを取得し、CSRFセキュリティレイヤーを介して認証できます。

ただし、AbstractSecurityWebSocketMessageBrokerConfigurerに次の構成を追加することにより、Same Origin Policy for Spring can be overriddenは次のようになります。

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

5.2. STOMP、SockJSサポート、およびフレームオプション

Spring WebSocketのクライアント側サポートを実装するには、SockJSと一緒にSTOMPを使用するのが一般的です。

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

ただし、iframesがSockJSトランスポートを利用できるようにすることが有益な場合があります。 これを行うには、WebSecurityConfigurerAdapterのデフォルト構成をオーバーライドできます。

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

この例では、iframesを介したトランスポートを許可しているにもかかわらず、Same Origin Policyに従うことに注意してください。

6. Oauth2カバレッジ

Spring WebSocketのOauth2固有のサポートは、Oauth2の実装方法の例に加えて、標準のWebSecurityConfigurerAdapterカバレッジ.Here’sに加えて、Oauth2セキュリティカバレッジを実装することで可能になります。

認証してWebSocketエンドポイントにアクセスするために、クライアントからバックエンドWebSocketに接続するときに、Oauth2access_tokenをクエリパラメーターに渡すことができます。

SockJSとSTOMPを使用してその概念を示す例を次に示します。

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

7. 結論

この短いチュートリアルでは、Spring WebSocketにセキュリティを追加する方法を示しました。 この統合について詳しく知りたい場合は、SpringのWebSocketおよびWebSocket Securityのリファレンスドキュメントをご覧ください。

いつものように、この記事で使用されている例については、our Github projectを確認してください。