Security 如何为jsessionid cookie启用samesite
如何为在wildfly上运行的web应用程序启用samesite。 选中了Security 如何为jsessionid cookie启用samesite,security,web,cookies,wildfly-10,Security,Web,Cookies,Wildfly 10,如何为在wildfly上运行的web应用程序启用samesite。 选中了standalone.xml,但在中找不到合适的标记 目前,Java Servlet 4.0规范不支持SameSite cookie属性。您可以通过打开java类来查看可用的属性 然而,有几个变通办法。您可以手动覆盖设置Cookie属性 方法#1(使用定制的Spring HttpFirewall和包装请求): 您需要在创建会话后立即包装请求并调整cookies。您可以通过定义以下类来实现: 一个bean(如果你想把所有东西
standalone.xml
,但在中找不到合适的标记
目前,Java Servlet 4.0规范不支持SameSite cookie属性。您可以通过打开java类来查看可用的属性 然而,有几个变通办法。您可以手动覆盖设置Cookie属性 方法#1(使用定制的Spring HttpFirewall和包装请求): 您需要在创建会话后立即包装请求并调整cookies。您可以通过定义以下类来实现: 一个bean(如果你想把所有东西都放在一个地方,你可以在SecurityConfig中定义它。为了简洁起见,我在它上面加了@Component注释)
包hello.approach 1;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.springframework.security.web.firewall.FirewalledRequest;
导入org.springframework.security.web.firewall.HttpFirewall;
导入org.springframework.security.web.firewall.RequestRejectedException;
导入org.springframework.stereotype.Component;
@组成部分
公共类CustomHttpFirewall实现HttpFirewall{
@凌驾
公共FirewalledRequest getFirewalledRequest(HttpServletRequest请求)抛出RequestRejectedException{
返回新的RequestWrapper(请求);
}
@凌驾
公共HttpServletResponse获取防火墙响应(HttpServletResponse){
返回新的ResponseWrapper(response);
}
}
第一包装类
包hello.approach 1;
导入java.util.Collection;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入javax.servlet.http.HttpSession;
导入org.springframework.http.HttpHeaders;
导入org.springframework.security.web.firewall.FirewalledRequest;
导入org.springframework.web.context.request.RequestContextHolder;
导入org.springframework.web.context.request.ServletRequestAttributes;
/**
*围绕HttpServletRequest的包装器,覆盖Set-Cookie响应头并添加SameSite=None部分。
*/
公共类RequestWrapper扩展了FirewalledRequest{
/**
*构造一个封装给定请求的请求对象。
*
*@param请求包装请求
*如果请求为空,@将引发IllegalArgumentException
*/
公共请求包装器(HttpServletRequest请求){
超级(请求);
}
/**
*在Spring引导中默认情况下必须为空。请参阅FirewalledRequest。
*/
@凌驾
公共无效重置(){
}
@凌驾
公共HttpSession getSession(布尔创建){
HttpSession session=super.getSession(创建);
如果(创建){
ServletRequestAttributes ra=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
如果(ra!=null){
覆盖setBookie(ra.getResponse());
}
}
返回会议;
}
@凌驾
公共字符串changeSessionId(){
字符串newSessionId=super.changeSessionId();
ServletRequestAttributes ra=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
如果(ra!=null){
覆盖setBookie(ra.getResponse());
}
返回newSessionId;
}
私有void overwritescookie(HttpServletResponse){
if(响应!=null){
Collection headers=response.getHeaders(HttpHeaders.SET\u COOKIE);
布尔值firstHeader=true;
对于(字符串头:头){//可以有多个集Cookie属性
如果(第一个标题){
response.setHeader(HttpHeaders.SET_COOKIE,String.format(“%s;%s”,header,“SameSite=None”);//SET
firstHeader=false;
继续;
}
response.addHeader(HttpHeaders.SET_COOKIE,String.format(“%s;%s”,header,“SameSite=None”);//添加
}
}
}
}
第二包装类
包hello.approach 1;
导入javax.servlet.http.HttpServletResponse;
导入javax.servlet.http.HttpServletResponseWrapper;
/**
*虚拟实现。
*要与RequestWrapper对齐。
*/
公共类ResponseWrapper扩展了HttpServletResponseWrapper{
/**
*构造一个封装给定响应的响应适配器。
*
*@param response要包装的响应
*如果响应为空,@将引发IllegalArgumentException
*/
公共响应包装器(HttpServletResponse){
超级(响应);
}
}
方法#2(使用Spring的AuthenticationSuccessHandler):
这种方法不适用于基本身份验证。
在基本身份验证的情况下,响应在控制器返回响应对象之后,在调用AuthenticationSuccessHandlerImpl#addSameSiteCookieAttribute之前立即刷新/提交
package hello.approach 2;
导入java.io.IOException;
导入java.util.Collection;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.springframework.http.HttpHeaders;
导入org.springframework.security.core.Authentication;
导入org.springframework.security.web.authentication.AuthenticationSuccessHandler;
公共类AuthenticationSuccessHandlerImpl实现AuthenticationSuccessHandler{
@凌驾
AuthenticationSuccess(HttpServletRequest请求、HttpServletResponse响应、身份验证)上的公共void引发IOException{
addSameSiteCookieAttribute(响应);//添加SameSite=strict以设置Cookie属性
response.sendRedirect(“/hello”);//验证成功后重定向到hello.html
}
私有void addSameSiteCookieAttribute(HttpServletResponse){
收集
<Context>
<CookieProcessor sameSiteCookies="strict" />
</Context>
./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true
@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);
}
});
}
}
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>
$ cat src/main/webapp/WEB-INF/undertow-handlers.conf
samesite-cookie(mode=Lax)
path(/app2)->samesite-cookie(mode=Lax, cookie-pattern=abc*)
<Context>
<CookieProcessor sameSiteCookies="strict" />
</Context>