サンプルアプリケーションの概要
サンプルアプリケーションは、図1に示す通り、郵便番号と住所データを提供する簡単なアプリケーションです。
今回は管理者を想定したWeb側からのアクセスに対してBasic認証と任意のヘッダ値をチェックする2種類のセキュリティ設定を行う方法について説明します。
通常、APIサーバの場合には、APIキーやAPIシークレットキーなどを用いてトークンをリクエストヘッダに設定するといった使い方が多いです。
Spring Security Web(1)
Webでのセキュリティを扱う場合には、Filterなどを使って自分で作成することも可能ですが、セキュリティ関連のトレンドについていきながら安全なアプリケーションを維持するのは難しいことでもあります。
しかし、Spring Security Webを使えば簡単に図2に示すようにWebアプリケーションにセキュリティ機能を追加できます。
現在セキュリティ要件を満たしている場合でも、Spring Securityのようなフレームワークを使うことは、セキュリティのトレンドが変化しても対応しやすくなるためメリットがあります。
また、Spring SecurityはWebセキュリティ機能以外のLDAPやOAuthなどもありますが、Web機能が最もよく利用されています。
また、Spring Security Webには主に表1の機能があり、Spring Security Webを追加すると、これらの機能は自動的に有効になります。
主な機能 | 説明 |
---|---|
認証・認可 | ログイン機能やロール設定などの機能があります。 |
セッション管理 | セッションのライフサイクルや二重ログイン防止などの機能があります。 |
セキュリティ用ヘッダ | frame-optionsなどセキュリティに関連するレスポンスヘッダをコントロールします。 |
CSRF対策機能 | クロスサイトリクエストフォージェリ攻撃対策機能。 |
ファイアウォール機能 | 不正なURLなどのチェック機能。 |
Spring BootでのSpring Securityの設定
Spring BootでSpring SecurityをGradleで使う場合には、リスト1のように「org.springframework.boot:spring-boot-starter-security」というスターターを追加します。
dependencies { : // (省略) implementation 'org.springframework.boot:spring-boot-starter-security' }
基本的な使い方
Spring BootでSpring Securityを使うには、リスト2のようにWebSecurityConfigurerAdapterクラスを継承して定義を行います。
クラスを追加するだけで、既存のRestController側に何も記述せずにセキュリティ機能が追加できるため、セキュリティ部分とビジネス要件を完全に分離して管理できるのも利点です。
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @Configuration @EnableWebSecurity // (1) Spring Securityを使うための設定 public class WebBasicAuthSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { // (2) 主に全体に対するセキュリティ設定を行う // web.ignoring().antMatchers("/css/**","/js/**","/images/**"); } @Override protected void configure(HttpSecurity http) throws Exception { // (3) 主にURLごとに異なるセキュリティ設定を行う } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // (4) 主に認証方法の実装の設定を行う } }
まず、(1)のEnableWebSecurityアノテーションでSpring Securityを有効にします。WebSecurityConfigurerAdapterには3つの設定メソッドがあり、おおよその設定区分が異なっています。
(2)のWebSecurityのconfigureメソッドでは全体に対するセキュリティ設定を行います。一般的によく行われる設定は、特定のパスのみセキュリティ設定を無効にするなどがあります。今回はAPIサーバなので静的リソースなどはありませんが、通常のWebアプリなどの場合にはCSSやJavaScriptファイル、画像ファイルなどをアクセス制限から除外する指定がよく行われます。
(3)のHttpSecurityのconfigureメソッドではURLごとにセキュリティ設定を行います。複数のURLで異なるポリシーを設定する場合にはWebSecurityConfigurerAdapterインターフェースを実装したクラスを複数定義するのが簡単です。また、さまざまな記述方法がありますので、詳しくはSpring Securityのリファレンスなども参照してください。
そして、(4)のAuthenticationManagerBuilderのconfigureメソッドでは、認証方法の実装方法などの設定を行います。
これらの使い方は、後述するBasic認証での設定やヘッダでの認証で説明します。
Basic認証でのアクセス制限方法
先ほどの基本的な使い方で紹介したメソッドに必要な実装を追加し、Basic認証を実装していきます。
/admin以下のパスに対してBasic認証でアクセス制限を行うコードがリスト3のようになります。
public class WebBasicAuthSecurityConfiguration extends WebSecurityConfigurerAdapter { // (1) Basic認証のID @Value("${zipcode.admin.username}") private String username; // (2) Basic認証のパスワード @Value("${zipcode.admin.password") private String password; @Override protected void configure(HttpSecurity http) throws Exception { // (3) Basic認証の対象となるパス http.antMatcher("/admin/**"); // (4) Basic認証を指定 http.httpBasic(); // (5) 対象のすべてのパスに対して認証を有効にする http.authorizeRequests().anyRequest().authenticated(); // (6) すべてのリクエストをステートレスとして設定 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // : 省略 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // (7) Basic認証の実装を指定 auth.authenticationProvider(new BasicAuthenticationProvider()); } // (8) 認証処理の実装クラス public class BasicAuthenticationProvider implements AuthenticationProvider { // (9) 認証チェック @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name = authentication.getName(); String password = authentication.getCredentials().toString(); // 入力された name / password をチェックする if( name.equals(username) && password.equals(password) ){ return new UsernamePasswordAuthenticationToken(name,password,authentication.getAuthorities()); } throw new AuthenticationCredentialsNotFoundException("basic auth error"); } // (10) 処理すべきAuthenticationクラスのチェック @Override public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } } // : 省略 }
(1)(2)で設定ファイルからBasic認証のIDとパスワードを取得するようにします。(3)ではアクセス制限をかけるパスのAnt形式でのパターンを指定しています。Ant形式以外にも、Spring MVC形式でのパターン指定のmvcMatcherなど、異なる指定方法があります。
次に(4)のようにhttpBasic()にてBasic認証を行う指定をします。(5)では(3)で指定したすべてのパスに対して(4)の認証方法を行う設定にします。
今回は、説明しやすいように(3)から(6)までの記述を1行ずつ記述していきましたが、これらを1行で記述していくことも可能です。
ここでの記述がどのような設定となるのかがわかりにくい場合は、JavaがXML上ではどのようになるのかがわかるとよりわかりやすくなります。より詳しい内容は、Spring Securityのリファレンスを参照してください。
(6)はセッション管理の指定ですが、Spring Securityではデフォルトでは自動的にセッションを作成してしまうため、APIサーバのような用途の場合には、ステートレスとして動作するように設定します。(7)で認証の実装を指定し、実際のBasic認証でのチェック処理はAuthenticationProviderインターフェースを実装したクラスを(8)のように実装します。
(9)のauthenticateメソッドでは具体的なIDとパスワードをチェックする処理を実装し、(10)のsupportsメソッドは、AuthenticationProviderの実装クラスが処理すべきAuthenticationクラスかどうかをチェックしています。
このように2つのメソッドを組み合わせて実装することで、他の認証形式の場合には処理を行わないようにし、複数の認証形式をサポートすることができるようになっています。