Wildflyで実行されているWebアプリケーションでSamesiteを有効にするにはどうすればよいですか? standalone.xmlをチェックしましたが、適切なタグが見つかりませんでした
<servlet-container name="default">
<session-cookie http-only="true" secure="true"/>
<jsp-config/>
</servlet-container>
現時点では、Javaサーブレット4.0仕様はSameSite cookie属性をサポートしていません。 javax.servlet.http.Cookie Javaクラスを開くと、使用可能な属性を確認できます。
ただし、いくつかの回避策があります。 Set-Cookie属性を手動で上書きできます。
最初のアプローチ(SpringのAuthenticationSuccessHandlerを使用):
import Java.io.IOException;
import Java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
addSameSiteCookieAttribute(response); // add SameSite=strict to Set-Cookie attribute
response.sendRedirect("/hello"); // redirect to hello.html after success auth
}
private void addSameSiteCookieAttribute(HttpServletResponse response) {
Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
boolean firstHeader = true;
for (String header : headers) { // there can be multiple Set-Cookie attributes
if (firstHeader) {
response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
firstHeader = false;
continue;
}
response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
}
}
}
2番目のアプローチ(javax.servlet.Filterを使用):
import Java.io.IOException;
import Java.util.Collection;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
public class SameSiteFilter implements javax.servlet.Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
addSameSiteCookieAttribute((HttpServletResponse) response); // add SameSite=strict cookie attribute
}
private void addSameSiteCookieAttribute(HttpServletResponse response) {
Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
boolean firstHeader = true;
for (String header : headers) { // there can be multiple Set-Cookie attributes
if (firstHeader) {
response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
firstHeader = false;
continue;
}
response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
}
}
@Override
public void destroy() {
}
}
Org.springframework.security.web.authentication.AuthenticationSuccessHandlerまたはjavax.servlet.Filterの構成の詳細については、GitHubの このデモプロジェクト を参照してください。
WebSecurityConfig には、必要なすべての構成が含まれています。
基本的にサーブレットコンテナがセッションとCookieの作成を管理するため、addHeaderの使用は動作が保証されていません。たとえば、アプリケーションサーバーが応答のフラッシュ中にSet-Cookieヘッダーを上書きするため、応答本文でJSONを返す場合、どちらのアプローチも機能しません。ただし、認証が成功した後でユーザーを別のページにリダイレクトする場合、上記のアプローチは機能します。
回避策の1つは、別の属性(SameSite
など)を使用してcomment
設定をCookieにハッキングすることです。
<servlet-container name="default">
<jsp-config/>
<session-cookie comment="; SameSite=None"/>
<websockets/>
</servlet-container>
ただし、Undertowはバージョン0またはバージョン1のCookieを使用するときにコメント(およびその他の)値を引用するため、io.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION
システムプロパティをtrue
に設定してJBoss/WildFlyを実行する必要があります。
./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true
このアプローチは明らかにハックで、Undertow実装の詳細に完全に依存しているため、代わりにWebサーバーまたはロードバランサーレベルで構成することをお勧めします。
現在最新リリースのSpring Bootの場合:
最新のspring-boot-starter-Tomcatがない場合は、SameSiteCookies列挙の値UNSET
を確認してください。値がない場合は、値SameSite=None
をスキップするため、新しいリリースが必要です。
@Component
public class SameSiteTomcatCookieProcessorCustomizationBean implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>
{
@Override
public void customize(TomcatServletWebServerFactory server) {
server.getTomcatContextCustomizers().add(new TomcatContextCustomizer()
{
@Override
public void customize(Context context)
{
Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
cookieProcessor.setSameSiteCookies("None");
context.setCookieProcessor(cookieProcessor);
}
});
}
}
JBoss EAP 7.2で機能する私の回避策はカスタムハンドラーです。グローバルハンドラーとして使用します。ただし、jboss-web.xmlでも使用できます。 Undertowは同一サイトに対してStrictまたはLaxしか許可しないため、Cookieの実装を試す必要があります( '"UT000162:Same-site attribute Noneは無効です。cookie.setSameSiteMode(" None "を使用する場合は、StrictまたはLax"'でなければなりません。 ))
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.Cookie;
import Java.lang.reflect.Proxy;
import Java.util.Map;
public class CookieSameSiteHandler implements HttpHandler
{
private HttpHandler next;
public CookieSameSiteHandler(HttpHandler next){
this.next = next;
}
@Override
public void handleRequest(final HttpServerExchange exchange)
throws Exception
{
exchange.addResponseCommitListener(serverExchange -> {
for (Map.Entry<String, Cookie> responcecookie : serverExchange.getResponseCookies().entrySet()){
serverExchange.getResponseCookies().replace(responcecookie.getKey(), proxyCookie(responcecookie.getValue()));
}
});
next.handleRequest(exchange);
}
private Cookie proxyCookie(Cookie cookie)
{
return (Cookie)Proxy.newProxyInstance(
cookie.getClass().getClassLoader(),
cookie.getClass().getInterfaces(),
(proxy, method, args) -> {
if ("isSameSite".equals(method.getName())){
return true;
}
if ("getSameSiteMode".equals(method.getName()) && cookie.getSameSiteMode() == null){
return "None";
}
if ("isSecure".equals(method.getName()) && cookie.getSameSiteMode() == null){
return true;
}
return method.invoke(cookie, args);
});
}
}
ハンドラー構成:
<subsystem xmlns="urn:jboss:domain:undertow:7.0" default-virtual-Host="default-Host">
<buffer-cache name="default"/>
<server name="default-server" default-Host="default-Host">
...
<Host name="default-Host" alias="localhost,example.com">
...
<filter-ref name="cookiehandler"/>
...
</Host>
</server>
...
<filters>
<filter class-name="nl.myownstuff.handler.CookieSameSiteHandler" module="nl.myownstuff.undertow" name="cookiehandler"/>
</filters>
</subsystem>