【问题标题】:Remember-me cookie and Varnish记住我的饼干和清漆
【发布时间】:2011-11-13 14:18:10
【问题描述】:

我正在尝试让 Spring Security 的记住我功能与 Varnish 一起使用,但这似乎非常困难。使用常规登录很容易,我只需设置 Varnish 以绕过 j_spring_security_check URL 的缓存,但使用记住我,任何 URL 都可以作为登录的入口点。如果用户在打开浏览器时点击的第一件事是 Varnish 跳过的 URL(即绕过缓存),那么一切都很好,但是如果用户点击主页(或 Varnish 缓存的任何内容),就会发生一些奇怪的事情:用户确实登录了,我得到了一个 CookieTheftException ,因此记住我的 cookie 被取消了,因此无法进行进一步的自动登录。 当我想到它时,听起来这两个(记住我和 Varnish)根本无法一起工作!这是真的吗?

有什么可能出错的想法吗?怎么可能让记住我与 Varnish 一起工作?哈希函数会不会有问题?

我在下面发布了我的 Varnish 配置的一部分(跳过了哈希函数定义,如果你认为它相关,请说出来):

sub vcl_recv {
    # Forward IP to Apache log
    unset req.http.X-Forwarded-For;
    set req.http.X-Forwarded-For = client.ip;

        if (req.http.host ~ "(?i)mysite\.com$") {
        if (req.restarts == 0) {
                    set req.backend = mysite;
        }
        else {
            error 750 "mysite";
        }
    }

    # static content should always be cached
    if (req.url ~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|pdf|mp3)$") {
        unset req.http.Cookie;
        return(lookup);
    }

    # only cache "get" or "head" requests
    if (req.request != "GET" && req.request != "HEAD") {
        return (pass);
    }

    # do not cache http authentication
    if (req.http.Authorization || req.http.Authenticate) {
        return (pass);
    }

    # do not cache Spring Security URLs, esi, personal pages etc.
        if (req.url ~ "^(/logout|/j_spring_security_check|/personal/)" || req.url ~ "\?service=esi") {
            return(pass);
    }

    return (lookup); # skip default vcl_recv
}

sub vcl_fetch { 
    # Try again if backend not responding
    if (beresp.status != 200 && beresp.status != 403 && beresp.status != 404 && beresp.status != 301 && beresp.status != 302 && beresp.status != 401) {
        return(restart);
    }

    # block sensitive files
    if (req.url ~ "\.(bak|conf|config|ear|exe|gz|jar|log|old|properties|tar|tmp|tgz|war)$") {
        error 405 "Not allowed";
    }

    # do esi processing for all non-static resources
    if (req.url !~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|xml|html|htm|pdf|mp3|doc)$") {       
        esi;
    }

    # do not cache when told not to
    if (req.http.Cache-Control ~ "no-cache") {
        return (pass);
    }

    # do not cache Spring Security URLs, esi, personal pages etc.
    if (req.url ~ "^(/logout|/j_spring_security_check|/personal/)" || req.url ~ "\?service=esi") {
        set beresp.http.Cache-Control = "private, no-cache, no-store, must-revalidate";
        set beresp.http.Pragma = "no-cache";
        set beresp.http.Expires = "Sat, 01 Jan 2000 00:00:00 GMT";
        return(pass);
    }

    # static content should always be cached
    if (req.url ~ "\.(js|css|gif|jpg|jpeg|png|swf|flv|txt|xml|html|htm|pdf|mp3|doc)$") {
        unset beresp.http.set-cookie;
        set beresp.ttl = 1h;
    } else {
        set beresp.ttl = 300s;
    }
}

更新:我很好地记录了我的最终实现here

【问题讨论】:

    标签: spring-security varnish remember-me


    【解决方案1】:

    RememberMe 功能通过向服务器发送一个特殊的 cookie 来工作。服务器知道如何解释 cookie 值(例如,用户名 + 密码在其中编码,或者它包含链接到用户的持久令牌)并且可以为用户进行登录。

    默认情况下(default.vcl),Varnish 不会干扰包含 cookie 的请求:它们会被传递。但是,您的 vcl 文件不会查看请求 cookie,而是指示 varnish 进行查找(在 vcl_recv 中)。每个客户端可能都有一个 (SESSION) cookie,因此在许多(但不是所有)情况下忽略请求 cookie 是有意义的。

    您的 vcl 文件应该检测到 vcl_recv 中的 rememberme 请求 cookie,并相应地进行传递。类似的东西(但请检查 cookie 名称):

    if (req.http.Cookie ~ "rememberme=" ) {
       return (pass);
    }
    

    此外,如果您一直有 CookieTheftExceptions,请检查您是否缓存了任何包含 set-cookie 标头的响应。这样,人们最终会得到相同的会话......

    【讨论】:

    • 我的想法是一样的......但是为所有具有 Spring cookie 的请求跳过缓存似乎很激进,所以这就是我所做的。我修改了 Spring 以在成功登录时添加一个额外的 cookie。此 cookie 是临时的,因此浏览器会在关闭时删除。我为包含 REMEMBER_ME cookie 但缺少这个新 cookie 的请求制作了 Varnish 跳过缓存。这样,登录尝试将保持不变,而其他所有内容仍会定期缓存。如果用户完全禁用 cookie,他们仍然永远不会触发此规则,因此它似乎足够安全。您如何看待这种方法?
    • 足够聪明,这应该可以。此外,还要考虑过时的 SESSIONID / rememberme cookie。确保在后端删除它们(例如过期的 SESSIONID 或无效的记忆 cookie),这样缓存是最佳的。
    • 嗯...我又开始考虑这件事了...如果我简单地将用户的 REMEMBER_ME cookie 的值包含在哈希计算中会有所帮助吗?
    • 你可以,但是每个用户对于相同的资源(即使是图像等)都会得到不同的缓存结果。这会严重影响缓存命中率(缓存资源不会在用户之间共享)。
    猜你喜欢
    • 2011-01-11
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 2012-07-20
    • 2011-07-31
    • 2011-09-28
    • 1970-01-01
    • 2015-06-06
    相关资源
    最近更新 更多