Comment puis-je activer samesite pour mon application web qui fonctionne sur wildfly as. Checkal standalone.xml n'a cependant pas pu trouver une balise appropriée dans
<servlet-container name="default">
<session-cookie http-only="true" secure="true"/>
<jsp-config/>
</servlet-container>
Pour l'instant, la spécification Java Servlet 4.0 ne prend pas en charge l'attribut de cookie SameSite. Vous pouvez voir les attributs disponibles en ouvrant javax.servlet.http.Cookie Java.
Cependant, il existe quelques solutions de contournement. Vous pouvez remplacer l'attribut Set-Cookie manuellement.
La première approche (à l'aide de Spring's 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"));
}
}
}
La deuxième approche (en utilisant 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() {
}
}
Vous pouvez consulter ce projet de démonstration sur le GitHub pour plus de détails sur la configuration de org.springframework.security.web.authentication.AuthenticationSuccessHandler ou javax.servlet.Filter.
WebSecurityConfig contient toute la configuration nécessaire.
L'utilisation d'addHeader n'est pas garantie de fonctionner car, fondamentalement, le conteneur Servlet gère la création de la session et du cookie. Par exemple, les deux approches ne fonctionneront pas si vous retournez JSON dans le corps de la réponse, car le serveur d'applications remplacera l'en-tête Set-Cookie lors du vidage de la réponse. Cependant, les approches ci-dessus fonctionnent dans les cas où vous redirigez un utilisateur vers une autre page après l'authentification réussie.
Une solution de contournement consiste à pirater le paramètre SameSite
dans le cookie en utilisant un autre attribut (par exemple comment
):
<servlet-container name="default">
<jsp-config/>
<session-cookie comment="; SameSite=None"/>
<websockets/>
</servlet-container>
Mais comme Undertow cite les valeurs de commentaire (et autres) lors de l'utilisation des cookies de la version 0 ou de la version 1, JBoss/WildFly doit être exécuté avec le io.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION
propriété système définie sur true
:
./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true
Cela vous donnera le résultat souhaité:
Cette approche est évidemment hacky, et repose entièrement sur les détails d'implémentation de Undertow, donc je recommanderais plutôt la configuration sur le serveur Web ou au niveau de l'équilibreur de charge.
Pour Spring Boot avec la dernière version actuellement disponible:
Si vous ne disposez pas de la dernière version Spring-boot-starter-Tomcat, vérifiez l'énumération SameSiteCookies pour la valeur UNSET
, si la valeur est manquante, vous avez besoin d'une version plus récente car elle ignorera la valeur 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);
}
});
}
}
Ma solution de contournement, qui fonctionne dans JBoss EAP 7.2, est un gestionnaire personnalisé. Je l'utilise comme gestionnaire global. Mais vous pouvez également l'utiliser dans le jboss-web.xml. Vous devez jouer avec l'implémentation des cookies, car le sous-titre n'autorise que Strict ou Lax pour le même site (il renvoie "" UT000162: attribut de même site Aucun n'est pas valide. Il doit être Strict ou Lax "'si vous utilisez cookie.setSameSiteMode (" Aucun " ))
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);
});
}
}
configuration du gestionnaire:
<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>