ServletでSameSite Cookieを設定する
概要
2021年4月現在、Servletの仕様範囲内ではCookieのSameSite属性を設定できません。
そのため各アプリケーションサーバー(サーブレットコンテナー)が用意している独自の方法に頼る必要があります。
この記事ではTomcat 9、WildFly 23.0.0.Final、Jetty 9を使ってそれぞれどのようにしてSameSite属性を設定するのか見てみます。
事前準備として次のリポジトリをcloneしておいてください。
サーブレットが1つ入ったWebアプリケーションとなっています。
サーブレットではセッションの取得を行なってセッションID入りのCookieが発行されるようにしています。
また、名前がdemoで値がfoobarのCookieを明示的に作っています。
つまり、2つのCookieが発行されるようになっています。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // Cookieを返すためにセッションを作る
    req.getSession();
    // 明示的なCookieの追加もしておく
    Cookie cookie = new Cookie("demo", "foobar");
    resp.addCookie(cookie);
    resp.setContentType("text/plain");
    try (PrintWriter out = resp.getWriter()) {
        out.print("Hello, world!");
        out.flush();
    }
}
Tomcat
TomcatはCookieを読み書きするorg.apache.tomcat.util.http.CookieProcessorというインターフェースを持っています。
これの実装クラスであるorg.apache.tomcat.util.http.Rfc6265CookieProcessorを設定することでSameSite属性を書き出せます。
次のような内容でWARファイル内にMETA-INF/context.xmlを作ります(つまりMavenでのビルド前はsrc/main/webapp/META-INF/context.xmlです)。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <CookieProcessor
      className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
      sameSiteCookies="none"/>
</Context>
mvn packageでWARファイルを作って、次のコマンドでTomcatを実行してWARファイルをデプロイします。
docker run --rm -p 8080:8080 \
       -v $PWD/target/demo.war:/usr/local/tomcat/webapps/demo.war \
       tomcat:9
curlで動作確認します。
curl -vL localhost:8080/demo
レスポンスからSet-Cookieヘッダを抜粋します。
< Set-Cookie: JSESSIONID=310DBCB36C68017E053650569D93D431; Path=/demo; HttpOnly; SameSite=None
< Set-Cookie: demo=foobar; SameSite=None
SameSite属性が設定されていますね。
WildFly
WildFlyはバージョン19からSameSiteのサポートが入ったようです。
次の内容でWEB-INF/undertow-handlers.confを作ります。
samesite-cookie(mode=none)
Tomcatの場合と同じく、mvn packageでWARファイルを作って動作確認です。
docker run --rm -p 8080:8080 \
       -v $PWD/target/demo.war:/opt/jboss/wildfly/standalone/deployments/demo.war \
       jboss/wildfly:23.0.0.Final
Tomcatの場合と同じく、curlを実行してSet-Cookieレスポンスヘッダを確認します。
< Set-Cookie: JSESSIONID=4WORL56grEURqybqfuSqRSnwkRxnzUCt516a1iGm.7b70a942134b; path=/demo; secure; SameSite=None
< Set-Cookie: demo=foobar; secure; SameSite=None
SameSite属性が設定されていますね。
Jetty
最後はJettyです。
web.xmlでcomment要素(cookie-config要素の子要素)に特定のコメントを設定する、という不思議な方法で実現しています(正直、あまり好みの方法ではありません)。
<session-config>
  <cookie-config>
    <comment>__SAME_SITE_NONE__</comment>
  </cookie-config>
</session-config>
mvn packageでWARファイルを作って動作確認です。
docker run --rm -p 8080:8080 \
       -v $PWD/target/demo.war:/var/lib/jetty/webapps/demo.war \
       jetty:9
curlを実行して得たSet-Cookieレスポンスヘッダが次の通りです。
< Set-Cookie: JSESSIONID=node07t0uojz6ahpu17u2eknzti9dl0.node0; Path=/demo; SameSite=None
< Set-Cookie: demo=foobar
このようにセッションIDだけにSameSiteが付いています。
明示的に作るCookieにはコードでコメントを設定する必要がありそうです。
cookie.setComment("__SAME_SITE_NONE__");
これでもう一度動作確認したところ、demo=foobarにもSameSite属性が付きました。
< Set-Cookie: JSESSIONID=node02lu7plc1tgx51vwiwqigcr75n0.node0; Path=/demo; SameSite=None
< Set-Cookie: demo=foobar; SameSite=None
以上です。





Discussion