Печенье «Помни меня» и лак

Я пытаюсь заставить функцию запоминания Spring Security работать с Varnish, но это кажется невероятно сложным. При обычном входе это легко, я просто настраиваю Varnish для обхода кеша для URL-адреса j_spring_security_check, но с функцией «запомнить меня» любой URL-адрес может быть точкой входа для входа в систему. Если первое, на что пользователь нажимает, когда открывает свой браузер, — это URL-адрес, который Varnish пропускает (т. е. обходит кеширование), тогда все в порядке, но если пользователь попадает на домашнюю страницу (или на что-либо, что кэшируется Varnish), происходит нечто странное: пользователь входит в систему, я получаю CookieTheftException и, таким образом, cookie-файл Remember-me отменяется, поэтому дальнейший автоматический вход в систему невозможен. Когда я думаю об этом, кажется, что эти двое (remember-me и Varnish) просто никогда не смогут работать вместе! Может ли это быть правдой?

Есть идеи, что могло пойти не так? Как сделать так, чтобы функция Remember-me работала с 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;
    }
}

ОБНОВЛЕНИЕ: я хорошо задокументировал свою окончательную реализацию здесь.


person kaqqao    schedule 09.09.2011    source источник


Ответы (1)


Функция RememberMe работает, отправляя на сервер специальный файл cookie. Сервер знает, как интерпретировать значение cookie (например, имя пользователя и пароль закодированы там, или он содержит постоянный токен, связанный с пользователем), и может выполнить вход для пользователя.

По умолчанию (default.vcl) Varnish не будет вмешиваться в запросы, содержащие куки: они пропускаются. Однако ваш файл vcl не просматривает куки-файлы запроса и указывает лаку все равно выполнить поиск (в vcl_recv). У каждого клиента, вероятно, есть файл cookie (SESSION), поэтому имеет смысл игнорировать файлы cookie запроса во многих, но не во всех случаях.

Ваш файл vcl должен обнаружить файл cookie запроса Rememberme в vcl_recv и выполнить соответствующий проход. Что-то вроде (но проверьте имя файла cookie):

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

Кроме того, если вы продолжаете получать CookieTheftExceptions, проверьте, кэшируете ли вы какие-либо ответы, содержащие заголовки set-cookie. Таким образом, люди заканчивают теми же сеансами...

person ivy    schedule 12.09.2011
comment
Я думал в том же духе... но пропуск кеша для всех запросов, у которых есть файл cookie Spring, казался агрессивным, поэтому я так и сделал. Я изменил Spring, чтобы добавить дополнительный файл cookie при успешном входе в систему. Этот файл cookie является временным, поэтому браузер удаляет его при закрытии. Я заставил Varnish пропускать кеш для запросов, содержащих файл cookie REMEMBER_ME, но без этого нового файла cookie. Таким образом, попытки входа в систему останутся нетронутыми, а все остальное будет регулярно кэшироваться. Если бы пользователь полностью отключил cookie, он все равно никогда не активировал бы это правило, так что это казалось достаточно безопасным. Что вы думаете об этом подходе? - person kaqqao; 26.09.2011
comment
Достаточно умно, это должно сработать. Кроме того, примите во внимание устаревшие файлы cookie SESSIONID / Rememberme. Не забудьте удалить их на сервере (например, SESSIONID с истекшим сроком действия или недействительный файл cookie Rememberme), чтобы кэширование было оптимальным. - person ivy; 26.09.2011
comment
Хммм... Я только что снова подумал об этом... Может быть, это поможет, если я просто включу значение пользовательского файла cookie REMEMBER_ME в вычисление хэша? - person kaqqao; 11.10.2011
comment
Вы могли бы, но каждый пользователь получит разные кэшированные результаты для одних и тех же ресурсов (даже для изображений и т. д.). Это серьезно повлияет на коэффициент попаданий в кэш (кешированные ресурсы не распределяются между пользователями). - person ivy; 12.10.2011