9.1. Spring Security概要

Spring Securityは、アプリケーションにセキュリティ対策機能を実装する際に使用するフレームワークである。 Spring Securityはスタンドアロンなアプリケーションでも利用できるが、サーブレットコンテナにデプロイするWebアプリケーションに対してセキュリティ対策を行う際に利用するのが一般的である。 本章では、Spring Securityが提供する機能のうち、一般的なWebアプリケーションでの利用頻度が高いと思われる機能にしぼって説明する。

Tip

ガイドラインで紹介していない機能

Spring Securityは、本ガイドラインで紹介していない機能も多く提供している。 Spring Securityが提供するすべての機能を知りたい場合は、Spring Security Reference -Servlet Applications-を参照されたい。

9.1.1. Spring Securityの機能

9.1.1.1. セキュリティ対策の基本機能

Spring Securityは、セキュリティ対策の基本機能として以下の機能を提供している。

セキュリティ対策の基本機能

機能

説明

認証機能

アプリケーションを利用するユーザーの正当性を確認する機能。

認可機能

アプリケーションが提供するリソースや処理に対してアクセスを制御する機能。


9.1.1.2. セキュリティ対策の強化機能

Spring Securityでは認証と認可という基本的な機能に加え、Webアプリケーションのセキュリティを強化するための機能をいくつか提供している。

セキュリティ対策の強化機能

機能

説明

セッション管理機能

セッションハイジャック攻撃やセッション固定攻撃からユーザーを守る機能、 セッションのライフサイクル(生成、破棄、タイムアウト)を制御するための機能。

CSRF対策機能

クロスサイトリクエストフォージェリ(CSRF)攻撃からユーザーを守るための機能。

セキュリティヘッダ出力機能

Webブラウザのセキュリティ対策機能と連携し、ブラウザの機能を悪用した攻撃からユーザーを守るための機能。


9.1.2. Spring Securityのアーキテクチャ

各機能の詳細な説明を行う前に、Spring Securityのアーキテクチャ概要とSpring Securityを構成する主要なコンポーネントの役割を説明する。

Note

ここで説明する内容は、Spring Securityが提供するデフォルトの動作をそのまま利用する場合や、 Spring Securityのコンフィギュレーションをサポートする仕組みを利用する場合は、開発者が直接意識する必要ない。 そのため、まず各機能の使い方を知りたい場合は、本節を読み飛ばしても問題はない。

ただし、ここで説明する内容は、Spring Securityのデフォルトの動作をカスタマイズする際に必要になるので、 アプリケーションのアーキテクトは一読しておくことを推奨する。


9.1.2.1. Spring Securityのモジュール

まずフレームワークスタックとなっているSpring Securityの提供モジュールを紹介する。

9.1.2.1.1. フレームワークスタックモジュール群

フレームワークスタックモジュールは、以下の通りである。 本ガイドラインでもこれらのモジュールを使用してセキュリティ対策を行う方法について説明する。

フレームワークスタックモジュール群

モジュール名

説明

spring-security-core

認証と認可機能を実現するために必要となるコアなコンポーネントが格納されている。 このモジュールに含まれるコンポーネントは、スタンドアロン環境で実行するアプリケーションでも使用することができる。

spring-security-web

Webアプリケーションのセキュリティ対策を実現するために必要となるコンポーネントが格納されている。 このモジュールに含まれるコンポーネントは、Web層(サーブレットAPIなど)に依存する処理を行う。

spring-security-config

各モジュールから提供されているコンポーネントのセットアップをサポートするためのコンポーネント(コンフィギュレーションをサポートするクラスやXMLネームスペースを解析するクラスなど)が格納されている。 このモジュールを使用すると、Spring Securityのbean定義を簡単に行うことができる。

spring-security-taglibs

認証情報や認可機能にアクセスするためのJSPタグライブラリが格納されている。

spring-security-acl

EntityなどのドメインオブジェクトをAccess Control List(ACL)を使用して認可制御するために必要となるコンポーネントが格納されている。 本モジュールは依存関係の都合上、フレームワークスタックに含まれているモジュールであるため、本ガイドラインにおいて使用方法の説明は行わない。

9.1.2.1.2. 要件に合わせて使用するモジュール群

フレームワークスタックではないが、一般的に利用される認証方法などをサポートするために、 以下のようなモジュールも提供されている。 セキュリティ要件に応じて、これらのモジュールの使用も検討されたい。

要件に合わせて使用するモジュール群

モジュール名

説明

spring-security-remoting

JNDI経由でDNSにアクセス、Basic認証が必要なWebサイトにアクセス、Spring Securityを使用してセキュリティ対策しているメソッドにRMI経由でアクセスする際に必要となるコンポーネントが格納されている。

spring-security-aspects

AspectJを使用してJavaのメソッドに認可機能を適用する際、必要となるコンポーネントが格納されている。 このモジュールは、AOPとしてSpring AOPを使う場合は不要である。

spring-security-messaging[5]

SpringのWeb Socket機能に対してセキュリティ対策を追加するためのコンポーネントが格納されている。

spring-security-data[5]

Spring Dataの機能から認証情報にアクセスできるようにするためのコンポーネントが格納されている。

spring-security-ldap

Lightweight Directory Access Protocol(LDAP)を使用した認証を実現するために必要となるコンポーネントが格納されている。

spring-security-openid

OpenID[1]を使用した認証を実現するために必要となるコンポーネントが格納されている。

spring-security-cas

Central Authentication Service(CAS)[2]と連携するために必要となるコンポーネントが格納されている。

spring-security-crypto

暗号化、キーの生成、ハッシュアルゴリズムを利用したパスワードエンコーディングを行うためのコンポーネントが格納されている。 このモジュールに含まれるクラスは、フレームワークスタックモジュールであるspring-security-coreにも含まれている。

9.1.2.1.3. テスト用のモジュール

Spring Security 4.0からはテストを支援するためのモジュールが追加されている。

テスト用のモジュール

モジュール名

説明

spring-security-test[5]

Spring Securityに依存しているクラスのテストを支援するためのコンポーネントが格納されている。 このモジュールを使用すると、JUnitテスト時に必要となる認証情報を簡単にセットアップすることができる。 また、Spring MVCのテスト用コンポーネント(MockMvc)と連携して使用するコンポーネントも含まれている。

9.1.2.1.4. 要件に合わせて利用する関連モジュール群

また、いくつかの関連モジュールも提供されている。

要件に合わせて利用する主な関連モジュール群

モジュール名

説明

spring-security-oauth2[3]

OAuth 2.0[4]の仕組みを使用してAPIの認可を実現するために必要となるコンポーネントが格納されている。

spring-security-oauth[3]

OAuth 1.0の仕組みを使用してAPIの認可を実現するために必要となるコンポーネントが格納されている。



9.1.2.2. フレームワーク処理

Spring Securityは、サーブレットフィルタの仕組みを使用してWebアプリケーションのセキュリティ対策を行うアーキテクチャを採用しており、以下のような流れで処理を実行している。

../_images/Architecture.png

Spring Securityのフレームワークアーキテクチャ

項番

説明

(1)

クライアントは、Webアプリケーションに対してリクエストを送る。

(2)

Spring SecurityのFilterChainProxyクラス(サーブレットフィルタ)がリクエストを受け取り、 HttpFirewallインタフェースのメソッドを呼び出してHttpServletRequestHttpServletResponseに対してファイアウォール機能を組み込む。

(3)

FilterChainProxyクラスは、Spring Securityが提供しているセキュリティ対策用のSecurity Filter(サーブレットフィルタ)クラスに処理を委譲する。

(4)

Security Filterは複数のクラスで構成されており、サーブレットフィルタの処理が正常に終了すると後続のサーブレットフィルタが呼び出される。

(5)

最後のSecurity Filterの処理が正常に終了した場合、後続処理(サーブレットフィルタやサーブレットなど)を呼びだし、Webアプリケーション内のリソースへアクセスする。

(6)

FilterChainProxyクラスは、Webアプリケーションから返却されたリソースをクライアントへレスポンスする。


Webアプリケーション向けのフレームワーク処理を構成する主要なコンポーネントは以下の通りである。 詳細は Spring Security Reference -Servlet Applications:Architecture-を参照されたい。

9.1.2.2.1. FilterChainProxy

FilterChainProxyクラスは、Webアプリケーション向けのフレームワーク処理のエントリーポイントとなるサーブレットフィルタクラスである。 このクラスはフレームワーク処理の全体の流れを制御するクラスであり、具体的なセキュリティ対策処理はSecurity Filterに委譲している。

9.1.2.2.2. HttpFirewall

HttpFirewallインタフェースは、HttpServletRequestHttpServletResponseに対してファイアウォール機能を組み込むためのインタフェースである。 デフォルトでは、StrictHttpFirewallクラスが使用され、ディレクトリトラバーサル攻撃やHTTPレスポンス分割攻撃に対するチェックなどが実装されている。

Note

Spring Security 5.0.1, 4.2.4, 4.1.5より、 デフォルトで使用されるHttpFirewallインタフェースの実装クラスはDefaultHttpFirewallからStrictHttpFirewallへ変更された。

DefaultHttpFirewallRFC 2396に基づきリクエストURLの正規化を行うことで悪意あるURLを拒否するが、 StrictHttpFirewallはより厳密にURLを構成する文字に不正な値がないことをチェックし、悪意あるURLを拒否する。 これにより、認証認可のバイパスやReflected File Download(RFD)攻撃への対策がなされている。

URLの正規化は脆弱性対策としては不十分であるため、従来通りDefaultHttpFirewallを利用するように変更することは推奨しない。 また、StrictHttpFirewallのチェックについても、一部カスタマイズ可能なパラメータも存在するが、脆弱性の原因となりうるため変更することは推奨しない。

StrictHttpFirewallの詳細については、Javadocを参照されたい。

9.1.2.2.3. SecurityFilterChain

SecurityFilterChainインタフェースは、FilterChainProxyが受け取ったリクエストに対して、適用するSecurity Filterのリストを管理するためのインタフェースである。 デフォルトではDefaultSecurityFilterChainクラスが使用され、適用するSecurity Filterのリストを、リクエストURLのパターン毎に管理する。

たとえば、以下のようなbean定義を行うと、URLに応じて異なる内容のセキュリティ対策を適用することができる。

  • xxx-web/src/main/resources/META-INF/spring/spring-security.xmlの定義例

<sec:http pattern="/api/**" once-per-request="false">
    <!-- ... -->
</sec:http>

<sec:http pattern="/ui/**" once-per-request="false">
    <!-- ... -->
</sec:http>

Warning

web.xmlの<filter-mapping>には業務要件に応じて適切なDispatcherTypeを設定すること

web.xmlの<filter-mapping>で業務要件に応じてREQUEST+ FORWARD等、ディスパッチ先でもFilterを動作させて認可処理を行う必要があるケースでは、web.xmlの<filter-mapping>/<dispatcher>DispatcherTypeを設定するだけではなく、spring-security.xmlで<sec:http>タグのonce-per-request属性をfalseに設定する必要がある。once-per-request属性を設定しない場合、Spring Security 5.7.5のデフォルト設定ではonce-per-request属性がtrueとなっているため、リクエストがservletによってディスパッチされた先では認可処理が実施されず、ディスパッチ先がディスパッチ元よりも上位の権限を必要とする場合に認可処理がバイパスされてしまう。

この問題は、AuthorizationFilterの脆弱性CVE-2022-31692で説明されている内容と同様の問題となるため、詳しくはCVE-2022-31692を参照されたい。

上記のような認可処理のバイパスを防ぐため、ブランクプロジェクトのデフォルト設定では、<sec:http>タグのonce-per-request属性をfalseに設定している。

なお、ブランクプロジェクトのデフォルト設定では、web.xmlの<filter-mapping>/<dispatcher>には明示的に設定を行っていないため、デフォルト設定であるREQUESTのみを対象として認可処理が実行される。業務要件に応じてweb.xmlの<filter-mapping>/<dispatcher>REQUEST+ FORWARD等、ディスパッチ先でもFilterが動作するように設定するように留意すること。なお、<filter-mapping>/<dispatcher>を設定するとデフォルト設定の上書きになるため、REQUESTも含めて動作することを期待する場合は REQUESTも含めて設定する必要があることに注意すること。


9.1.2.2.4. Security Filter

Security Filterクラスは、フレームワーク機能やセキュリティ対策機能を実現する上で必要となる処理を提供するサーブレットフィルタクラスである。

Spring Securityは、複数のSecurity Filterを連鎖させることでWebアプリケーションのセキュリティ対策を行う仕組みになっている。
ここでは、認証と認可機能を実現するために必要となるコアなクラスを紹介する。
詳細は Spring Security Reference -Security Filters-を参照されたい。
コアなSecurity Filter

クラス名

説明

SecurityContextPersistenceFilter

認証情報についてリクエストを跨いで共有するための処理を提供するクラス。 デフォルトの実装では、HttpSessionに認証情報を格納することで、リクエストをまたいで認証情報を共有している。

UsernamePasswordAuthenticationFilter

リクエストパラメータで指定されたユーザー名とパスワードを使用して認証処理を行うクラス。 HttpSessionSecurityContextRepositoryに認証情報を格納することで、リクエストをまたいで認証情報を共有している。 フォーム認証を行う際に使用する。

LogoutFilter

ログアウト処理を行うクラス。

FilterSecurityInterceptor

HTTPリクエスト(HttpServletRequest)に対して認可処理を実行するためのクラス。

ExceptionTranslationFilter

FilterSecurityInterceptorで発生した例外をハンドリングし、クライアントへ返却するレスポンスを制御するクラス。 デフォルトの実装では、未認証ユーザーからのアクセスの場合は認証を促すレスポンス、 認証済みのユーザーからのアクセスの場合は認可エラーを通知するレスポンスを返却する。


9.1.3. Spring Securityのセットアップ

WebアプリケーションにSpring Securityを適用するためのセットアップ方法について説明する。

ここでは、WebアプリケーションにSpring Securityを適用し、Spring Securityが提供しているデフォルトのログイン画面を表示させる最もシンプルなセットアップ方法を説明する。 実際のアプリケーション開発で必要となるカスタマイズ方法や拡張方法については、次節以降で順次説明する。

Note

開発プロジェクトをブランクプロジェクトから作成すると、ここで説明する各設定はセットアップ済みの状態になっている。 開発プロジェクトの作成方法については、「Webアプリケーション向け開発プロジェクトの作成」を参照されたい。


9.1.3.1. 依存ライブラリの適用

まず、Spring Securityを依存関係として使用している共通ライブラリを適用する。 Spring Securityと共通ライブラリの関連については、共通ライブラリの構成要素 を参照されたい。

本ガイドラインでは、Mavenを使って開発プロジェクトを作成していることを前提とする。

  • xxx-domain/pom.xmlの設定例

<dependency>
    <groupId>org.terasoluna.gfw</groupId>
    <artifactId>terasoluna-gfw-security-core</artifactId>  <!-- (1) -->
</dependency>
  • xxx-web/pom.xmlの設定例

<dependency>
    <groupId>org.terasoluna.gfw</groupId>
    <artifactId>terasoluna-gfw-security-web</artifactId>  <!-- (2) -->
</dependency>

項番

説明

(1)

ドメイン層のプロジェクトでSpring Securityの機能を使用する場合は、terasoluna-gfw-security-coreをdependencyに追加する。

(2)

アプリケーション層のプロジェクトでSpring Securityの機能を使用する場合は、terasoluna-gfw-security-webをdependencyに追加する。

Note

上記設定例は、依存ライブラリのバージョンを親プロジェクトである terasoluna-gfw-parent で管理する前提であるため、pom.xmlでのバージョンの指定は不要である。


9.1.3.2. bean定義ファイルの作成

Spring Securityのコンポーネントをbean定義するため、以下のようなXMLファイルを作成する。(ブランクプロジェクトより抜粋)

  • xxx-web/src/main/resources/META-INF/spring/spring-security.xmlの定義例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="
        http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    "> <!-- (1) -->

    <sec:http pattern="/resources/**" security="none"/> <!-- (2) -->
    <sec:http once-per-request="false"> <!-- (3) -->
        <sec:form-login /> <!-- (4) -->
        <sec:logout /> <!-- (5) -->
        <sec:access-denied-handler ref="accessDeniedHandler"/> <!-- (6) -->
        <sec:custom-filter ref="userIdMDCPutFilter" after="ANONYMOUS_FILTER"/> <!-- (7) -->
        <sec:session-management /> <!-- (8) -->
    </sec:http>

    <sec:authentication-manager /> <!-- (9) -->

    <!-- CSRF Protection -->
    <bean id="accessDeniedHandler"
        class="org.springframework.security.web.access.DelegatingAccessDeniedHandler"> <!-- (10) -->
        <!-- omitted -->
    </bean>

    <!-- Put UserID into MDC -->
    <bean id="userIdMDCPutFilter" class="org.terasoluna.gfw.security.web.logging.UserIdMDCPutFilter">  <!-- (11) -->
    </bean>

</beans>

項番

説明

(1)

Spring Securityから提供されているXMLネームスペースを有効にする。 上記例では、secという名前を割り当てている。 XMLネームスペースを使用すると、Spring Securityのコンポーネントのbean定義を簡単に行うことができる。

(2)

<sec:http>タグを定義し、セキュリティ対策が不要なリソースパスの設定を行う。 詳細は セキュリティ対策を適用しないため設定 を参照されたい。

(3)

<sec:http>タグを定義する。 <sec:http>タグを定義すると、Spring Securityを利用するために必要となるコンポーネントのbean定義が自動的に行われる。

(4)

<sec:form-login>タグを定義し、フォーム認証を使用したログインに関する設定を行う。 詳細は フォーム認証 を参照されたい。

(5)

<sec:logout>タグ を定義し、ログアウトに関する設定を行う。 詳細は ログアウト を参照されたい。

(6)

<sec:access-denied-handler>タグを定義し、アクセスエラー時の制御を行うための設定を定義する。 詳細は AccessDeniedHandlerの適用認可エラー時の遷移先 を参照されたい。

(7)

ログ出力するユーザ情報をMDCに格納するための共通ライブラリのフィルタを定義する。

(8)

<sec:session-management>タグ を定義し、セッション管理に関する設定を行う。 詳細は セッション管理 を参照されたい。

(9)

<sec:authentication-manager>タグを定義して、認証機能用のコンポーネントをbean定義する。 このタグを定義しておかないとサーバ起動時にエラーが発生する。

(10)

アクセスエラー時のエラーハンドリングを行うコンポーネントをbean定義する。

(11)

ログ出力するユーザ情報をMDCにする共通ライブラリのコンポーネントをbean定義する。


作成したbean定義ファイルを使用してSpringのDIコンテナを生成するように定義する。

  • xxx-web/src/main/webapp/WEB-INF/web.xmlの設定例

<!-- (1) -->
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<!-- (2) -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath*:META-INF/spring/applicationContext.xml
        classpath*:META-INF/spring/spring-security.xml
    </param-value>
</context-param>

項番

説明

(1)

サーブレットコンテナのリスナクラスとして、ContextLoaderListenerクラスを指定する。

(2)

サーブレットコンテナのcontextClassパラメータに、applicationContext.xmlに加えて、Spring Security用のbean定義ファイルを追加する。


9.1.3.3. サーブレットフィルタの設定

最後に、Spring Securityが提供しているサーブレットフィルタクラス(FilterChainProxy) をサーブレットコンテナに登録する。

  • xxx-web/src/main/webapp/WEB-INF/web.xmlの設定例

<!-- (1) -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>
<!-- (2) -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

項番

説明

(1)

Spring Frameworkから提供されているDelegatingFilterProxyを使用して、 SpringのDIコンテナで管理されているbean(FilterChainProxy)をサーブレットコンテナに登録する。 サーブレットフィルタの名前には、SpringのDIコンテナで管理されているbeanのbean名(springSecurityFilterChain)を指定する。

(2)

Spring Securityを適用するURLのパターンを指定する。 上記例では、すべてのリクエストに対してSpring Securityを適用する。


9.1.3.4. セキュリティ対策を適用しないため設定

セキュリティ対策が不要なリソースのパス(cssファイルやimageファイルにアクセスするためのパスなど)に対しては、 <sec:http>タグを使用して、Spring Securityのセキュリティ機能(Security Filter)が適用されないように制御することができる。

  • xxx-web/src/main/resources/META-INF/spring/spring-security.xmlの定義例

<sec:http pattern="/resources/**" security="none"/>  <!-- (1) (2) -->
<sec:http once-per-request="false">
    <!-- omitted -->
</sec:http>

項番

説明

(1)
pattern属性にセキュリティ機能を適用しないパスのパターンを指定する。
(2)
security属性にnoneを指定する。
noneを指定すると、Spring Securityのセキュリティ機能(Security Filter)が適用されない。