サイトアイコン 知的好奇心

SpringBootにおけるcookie使用有無のセッション情報の管理について

SpringBootにおけるcookie使用有無のセッション情報の管理についてご紹介します。

条件

セッション情報の保持について

セッション情報は通常、クライアントのブラウザとcookieを送受信することによって管理されます。
しかし、cookieを使用できないブラウザについては、
URLパラメータにセッション情報を付加することでセッション管理を行う方法もあります。
(この方法は、セッションハイジャックなどのリスクが高まるため非推奨です。)

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

簡単なプログラムを用いて、Spring Bootにおけるセッション管理の動作を確認してみます。
ここでは以下のようなプロジェクト構成としました。

ソース等

SampleController.java

以下のURLにアクセスすると、入力フォームを表示します。
http://localhost:8080/first

入力フォームから値が送信されたら、
「/recieve」で受信し受け取ったデータをセッションに保存します。
その後、http://localhost:8080/secondへリダイレクトします。

http://localhost:8080/second では、
入力フォームで入力した文字列をセッションから取り出します。

package com.example.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class SampleCotroller {

    private final String strAttribute = "inputString";

    @GetMapping("/first")
    public String first() {
        return "first";
    }

    @GetMapping("/second")
    public String second(HttpServletRequest request) {

        // セッションの取得
        HttpSession session = request.getSession();

        String inputString = (String) session.getAttribute(strAttribute);
        System.out.println("inputString = " + inputString);

        return "second";
    }

    @PostMapping("/recieve")
    public String recieve(@RequestParam String message, HttpServletRequest request,
            HttpServletResponse response) {

        // セッションの取得
        HttpSession session = request.getSession();

        // セッションに情報を保持
        session.setAttribute(strAttribute, message);

        return "redirect:/second";
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.6</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</groupId>
  <artifactId>sessionTest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>sessionTest</name>
  <description>Example Project</description>
  <properties>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

first.html

入力フォームだけの単純な画面です。

<html lang="ja" xmlns:th="http://www.thymeleaf.org">

<head>
  <meta charset="UTF-8">
  <title>form</title>
  <script type="text/javascript"></script>
</head>

<body>
  <form th:action="@{/recieve}" method="post">
    <label>
      メッセージ:<input type="text" name="message"><br>
    </label>
    <button>送信</button>
  </form>
</body>

</html>

second.html

「セッションID」と「フォームで入力した文字列(セッションから取得)」を表示する画面です。

<html lang="ja" xmlns:th="http://www.thymeleaf.org">

<head>
  <meta charset="UTF-8">
  <title>form</title>
  <script type="text/javascript"></script>
</head>

<body>
  <h3>Session Id</h3>
    <p th:text="${#httpSession.id}"/>
    <h3>InputString</h3>
    <p th:text="${#httpSession.getAttribute('inputString')}"/>
  <input type="button" onclick="window.history.back();" value="直前のページに戻る">
  </body>

</html>

動作確認:ブラウザのcookieが有効の場合

ブラウザ(Chrome)を右クリック > 検証 で確認したところ、
cookieによってセッション情報のやり取りが行われていることが分かります。

動作確認:ブラウザのcookieが無効の場合

ブラウザの設定でcookieを使用不可にします。

URLに「;jsessionid=59CA475E0CC821E479B13F32D28054FB」という値が付加されました。
イコールの後ろの文字列はセッションIDです。
cookieもブラウザ上で確認出来ますが、Value値が異なっています。
これは、前回使用したcookieがただ残っているだけであると分かります。
つまり、ブラウザがcookieを受け入れない設定になったため、
自動でURLにセッションIDを付加する動作に変わったということです。

自動でセッションIDをURLに付加したくない場合

ブラウザのcookie使用可否に応じて、自動でセッション情報のやり取り方法を変えてくれるのは便利です。
しかし、セキュリティ上の問題から、セッションIDをURLに付加したくないケースもあるかと思います。

その場合、以下のようなソースを追加することで実現可能です。

MyConfig.java

package com.example;

import java.util.Collections;
import javax.servlet.SessionTrackingMode;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyConfig {

    @Bean
    public ServletContextInitializer servletContextInitializer() {

        ServletContextInitializer initializer = servletContext -> {
            servletContext
                    .setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE));
        };
        return initializer;
    }
}

動作確認:ブラウザのcookieが無効の場合

URLにセッション情報が付加されていないことがわかります。
ただし、セッション情報が使用できなくなり、InputStringが表示されていないことが分かります。

動作確認:ブラウザのcookieが有効の場合

ブラウザのcookieが有効であれば、問題なくセッション情報を使用することが出来ます。

参考

Qiita:SpringBootでCookie設定をする

https://qiita.com/dmnlk/items/b7d189d4dc09df1ee6b6

モバイルバージョンを終了