【Spring Security はじめました】#6 セッション管理

Web

今回の目標

前回はUserDetailsの実装について説明しました。

【Spring Security はじめました】#5 ユーザーの実装
今回はSpring Securityで認証に使用するユーザー情報の実装について説明します。具体的にはUserDetailsインターフェースを実装するクラスを作成します。

今回はSpring Securityで行えるセッション管理とRemember Meについて説明をします。

セッションの設定

セッションに関する設定はプロパティとしてapplication.yml(properties)に設定します。これはSpring Bootの共通の設定なので、Spring Securityに関係なく設定できます。

プロパティについてはこちらを参考にしてください。

Spring Boot アプリケーションプロパティ一覧 - ドキュメント
application.properties ファイル内、application.yml ファイル内、またはコマンドラインスイッチとして、さまざまなプロパティを指定できます。この付録では、一般的な Spring Boot プロパティの一覧と、使用する基になるクラスへの参照を提供し

ここからセッションに関するものだけピックアップしておきます。

プロパティ説明
server.servlet.session.cookie.commentセッションCookieのコメント。
server.servlet.session.cookie.domainセッションCookieのドメイン。
server.servlet.session.cookie.http-onlyHttpOnlyを使用するかどうか。
server.servlet.session.cookie.max-ageセッションCookieの最大有効期間(秒)。
server.servlet.session.cookie.nameセッションCookie名。
server.servlet.session.cookie.pathセッションCookieのパス。
server.servlet.session.cookie.secureセキュアCookieを有効にするかどうか。
server.servlet.session.persistent再起動でセッションを保持するかどうか。
server.servlet.session.store-dirセッションデータの保存に使用されるディレクトリ。
server.servlet.session.timeoutセッションタイムアウトの時間(デフォルトは30分)。
server.servlet.session.tracking-modesセッション追跡モード。

セッションハイジャックへの対策として、本番リリース時はhttp-onlyとsecureはtrueに設定しておきましょう。

Spring Securityにおけるセッション管理

セッション管理に関する設定

セッション管理に関する設定は、毎度の如く設定クラスに記載していきます。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .sessionManagement();
}

セッションの生成

セッションの生成については以下の4パターンがあります。

生成方法説明
always無条件に生成する。
ifRequired(デフォルト)必要な時に生成する。
never生成しない。ただし、存在する場合は利用する。
stateless生成せず、利用もしない。

あまりないとは思いますが、この設定を変更する場合は以下のようにします。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}

SessionCreationPolicyは列挙型になっているので適当なものを指定します。

URL Rewriting

URL Rewritingを有効にすることで以下のようにURLでセッションを管理できます。

http://localhost:8080/login;jsessionid=011F2A5B06EAB78299A9DB732DCDC9BB

しかし、セキュリティ的にはいろいろと問題があるのでSpring Securityではデフォルトで無効になっています。

有効化することもできますが、いろいろと手順があり面倒なのでここでは割愛します。

CSRF対策

こちらの記事でも記載した通り、Spring SecurityではCSRF対策としてセッションに一時トークンが登録されます。

【Spring Security はじめました】#4 ログインページの作成
Spring Securityにはデフォルトのログインページがあるのですが、それでは何かと味気ないので今回はログインページをカスタマイズする方法を説明します。またフォームのセキュリティの話としてCSRFについても少し説明します。

そのためすべてのページでセッションが生成されます。

不要な場合は、以下のようにすることで特定のページ対し除外することができます。以下の例ではH2 Databaseのコンソールに対するパスについて除外しています。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .csrf().ignoringAntMatchers("/h2-console/**");
}

セッション固定化攻撃対策

セッション固定化攻撃については以下を参考にしてください。

セッションID固定化攻撃とは?仕組みから対策方法まで徹底解説
さまざまなWebサービスでは、ログインすることであなた専用のサービスを受けることが可能です。その際に利用される「セッションID」を固定化することで、あなたになりすます攻撃があることをご存知でしょうか。セッションID固定化攻撃によってあなたに

この攻撃方法には、ログイン後にセッションIDを再発行することが最も有効な対策となります。

Spring Securityではこの対策もデフォルトで実装されています。ブラウザで確認すると以下のようにログイン後にセッションIDが変わっていることが分かります。

これを無効化することはないかもしれませんが、以下で無効化できます。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .sessionManagement().sessionFixation().none();
}

セッションタイムアウト

セッションタイムアウトの設定は先述したようにプロパティファイルに設定します。

セッションがタイムアウトしたときのリダイレクト先は以下で設定できます。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().antMatchers("/timeout").permitAll()
      //略
      .and()
      .sessionManagement().sessionFixation().invalidSessionUrl("/timeout");

あらかじめコントローラーに「/timeout」を実装し、permitAll()を設定しておきます。

この設定は、正確にはセッションが無効の場合の設定になります。とはいえほとんどがセッションタイムアウトのような気がするのでこれでも良いかなという感じです(私見)。

Remember Me

セッションに関わるところとしてRemember Meについて説明をしておきます。Remember Meは、ログイン情報をCookieに保存しておき、次回以降のログインを省略するための仕組みです。いわゆる自動ログインです。

Spring SecurityでRemember Meを実装するためには、以下のように設定クラスを変更します。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .rememberMe();
}

次にログイン画面にRemember Me用のチェックボックスを配置します。name属性を「remember-me」とする点がポイントです。

<input type="checkbox" name="remember-me">Remember Me

では追加したチェックボックスにチェックを入れてログインしてみましょう。そしてブラウザを一度閉じてログイン後のページにアクセスできるか確認してみてください。

Cookieを確認すると、「remember-me」という名前の値が保存されています。この値にはログイン情報などがハッシュ化された状態で保存されます。

ちなみにログアウトするとこのCookieは破棄されます。

Keyの設定

上述したハッシュ化にはKeyとなる値が使用されています。デフォルトでは、Spring Securityがサーバー起動時にランダムな値を生成し、ハッシュ時に使用するようになっています。

つまり再起動をすると、Cookieに保存している値とサーバー側の値が異なるものになってしまい、自動ログインは解除されます。

これを解消するためには、Key値を以下のように固定化します。値は安全なランダム値を使用するのがいいかと思います。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .rememberMe().key("hogehoge");
}

パラメーター名の設定

Remember Meを実装するにあたり、remember-meパラメーターを送信するようにログイン画面を修正しました。このパラメーター名は以下のようにすることで変更することができます。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .rememberMe().rememberMeParameter("hogehoge");
}

常に保存するようにする

remember-meパラメーターを送信せずとも、常にログイン情報を保存したい場合は以下のようにします。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .rememberMe().alwaysRemember(true);
}

Cookie情報の設定

Remember Meを保存するCookieについて、ドメイン、名前、Max-Age、Secure属性を以下のように設定することができます。

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //略
      .and()
      .rememberMe().rememberMeCookieDomain("hogehoge")
                   .rememberMeCookieName("fugafuga")
                   .tokenValiditySeconds(1209600)
                   .useSecureCookie(true);
}

Max-Ageは秒で指定し、デフォルトでは14日が設定されているようです。

実際に本番環境で使用する場合は、これらの設定はしておいたほうが良いかと思います。

Secure属性については、開発環境で有効にすると動作しなくなるので、プロパティファイルで制御するなど工夫することをおすすめします。

あとがき

さて、今回はセッションに関することを説明してきました。実は他にも設定はあるのですが今回はこのくらいにしておきます。

セッションはセキュリティー的に重要な部分でもあるので、デフォルトでいろいろ対策されているのは大変ありがたいことです。

 

- Spring Bootのおすすめ書籍はコチラ -

コメント

タイトルとURLをコピーしました