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