如何在具有Spring Security 的响应头中使用key而不是set cookie?

c0vxltue  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(328)

我很难储存 cookies 在本地应用程序中。
我的目标是 JSESSIONID 以及 XSRF-TOKEN 作为响应头的键而不是 Set-Cookie ,客户机将处理以手动将其存储为cookie。
我会把这些钱存起来 JSESSIONID 就像饼干一样 HttpOnly 设置为true。
我会把这些钱存起来 XSRF-TOKEN 就像饼干一样 HttpOnly 设置为false。

628mspwn

628mspwn1#

基本安全概念:
1.会话cookie(例如jsessionid)。
应该始终是httponly,有一个域集(或者使用默认值作为提供它的服务器)。绝不能存储在浏览器以外的任何地方。您的js/html应该对jsession cookie一无所知,只有当用户从端点获得401(未经授权)时才将其移动到登录屏幕。
2.csrf代币。
回到过去(5年一次可能哈!),大多数站点都是在服务器上呈现的。服务器创建了html,然后通过uri发回。就像你去了/profile,然后服务器知道你是谁,然后在服务器上创建了profile页面,并反馈了html文档。
当想要获得一些用户输入时,服务器呈现的这个html将包含 <form/> 它将收集用户的数据(密码/银行详细信息等),然后 onSubmit 以一种简单的方式将其传回服务器 application/x-www-form-urlencoded 格式
如。 https://thewebsite.com/sendmoney_to?account=512&amount=1milliondollars 只需将该链接发送给与该站点有活动会话的人 thewebsite.com 浏览器将访问它并执行请求。
受害者只要登录到该站点,就会很高兴地运行攻击者发送的请求。通过简单地加载 <img> 比如贴在墙上或是发邮件等。
他们是怎么解决的?
通过将一些字段添加到名为 hidden fields . 这些隐藏字段是在呈现页面时由服务器创建的。它们包含一个值,该值是csrf令牌,也包含在csrf cookie中。所以当 application/x-www-form-urlencoded 表单发送时,必须在呈现表单时在服务器上生成这些值。然后服务器可以验证表单是他们创建的表单,而不是攻击者创建的恶意链接。攻击者在进行调皮链接时无法知道/猜测这些。
3.现在
由于只有json请求,许多站点(如react apps)都呈现在客户端,并使用axios/fetch…csrf有些多余。你不张贴表格/ application/x-www-form-urlencoded …仅使用json主体发出post请求。
会话作为xss攻击>csrf攻击仍然很重要。正确地存储会话(不管是否是jwt令牌……不要跳上jwt的风车,开始在本地存储周围抛出jwt auth令牌,这似乎已经成为新开发人员的某种奇怪的默认值)。
如果你确定你只有 application/json 有能力的端点,那么攻击者让你发布他们的内容而不是你想要的内容的唯一方法就是通过xss攻击。但一旦他们有了xss攻击,游戏就结束了。他们只是那么你就服务器而言,因为他们使用他们的调皮 <script> 在请求发送之前对其进行操作,服务器将无法知道该请求已被动态操作(通常)。
4.通过标题获取csrf令牌,因为它不会在表单中生成
xsrf令牌您可能需要通过使用过滤器公开xsrf令牌,该过滤器将提取csrf令牌(通过会话)并将其添加到响应实体上的头中。
我写了我自己的,但基本上是一样的,在一个图书馆,有些人用做同样的事情。

@Log4j2
public class CsrfBindingFilter extends OncePerRequestFilter {
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
    protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
    protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
        CsrfToken csrfToken = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
        log.debug("CRSF Token from session : {}", csrfToken != null ? csrfToken.getToken() : "CsrfToken is NULL");
        if (csrfToken != null) {
            response.setHeader(RESPONSE_HEADER_NAME, csrfToken.getHeaderName());
            response.setHeader(RESPONSE_PARAM_NAME, csrfToken.getParameterName());
            response.setHeader(RESPONSE_TOKEN_NAME, csrfToken.getToken());
        }

        filterChain.doFilter(request, response);
    }
}

就会话而言,浏览器应该处理这个问题,你不应该在客户端搞乱它,除非它是出于一个非常具体的原因(我无法理解一个原因)。会话的cookies被设置为httponly是因为特定的原因,不允许客户端中运行的任何js编辑/读取/添加它。一个小厚脸皮的广告/xss和一些顽皮的代码,如 get the cookie called JSESSION ID if the host is myvictim.com and post it over here... 可能意味着你妥协了。
阅读本文了解更多细节:通过js添加httponly cookie浏览器应该处理 Set-Cookie 头是预期的,也是最佳实践(出于安全原因,也只是为了简单易用)。
websocket stomp身份验证
一旦用户通过您的 /login ,spring应该发送一个带有 JSESSIONID 饼干。此cookie将由浏览器存储,您的前端javascript应用程序应该无法访问它。
如果随后使用stompspringwebsocket实现,则可以通过 StompHeaderAccessor@MessageMapping Controller 参数。 stompHeaderAccessor.getUser().getName() 将给spring安全认证用户的主体名称(通常是他们的用户名或id,username是默认值)。

@MessageMapping("/agents/start")
    public void start(StompHeaderAccessor stompHeaderAccessor) {
        log.info("Subscriber Start! {}-{}", stompHeaderAccessor.getUser() != null ? stompHeaderAccessor.getUser().getName() : "ANON", stompHeaderAccessor.getSessionId());
        mysessionstore.addSessionId(stompHeaderAccessor.getSessionId());
    }

如果要编辑用户的会话属性,则需要从spring\u session表中获取他们的会话id,然后可以使用spring SessionRepository 去拿它。
https://docs.spring.io/spring-session/docs/current/api/org/springframework/session/sessionrepository.html

相关问题