Действительно ли возможно использовать сессии PHP для аутентификации с кешем fastcgi nginx?

Вопрос или проблема

Я недавно переключил экземпляр OpenCart с Apache+mod_php на nginx+fastcgi+php-fpm. Я пытался использовать кэширование для большинства страниц через fastcgi-cache.

К сожалению, многие пользователи начали сообщать о призрачных заказах или захвате учетных записей других пользователей (йеей!!!!) В результате тщательных поисков обнаружилось, что страницы кэшировались с заголовком set-cookie! Поэтому последующие пользователи, которые не отправляли существующий cookie сессии, получали cookie сессии инициатора кэша. Плохо!

Согласно всей документации, которая есть, следующие настройки должны предотвратить это (по крайней мере, насколько я понимаю):

 fastcgi_pass_header Set-Cookie;
 fastcgi_pass_header Cookie;
 fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

Когда я просматривал отдельные кэши, я заметил несколько страниц с set-cookie: [somerandomsessionid] Согласно документации nginx под fastcgi_cache_valid…

Если заголовок включает поле “Set-Cookie”, такой ответ не будет кэшироваться.

Включая Set-Cookie в fastcgi_ignore_headers, я говорю ему кэшировать set-cookie? Во многих примерах Set-Cookie является частью аргументов для fastcgi_ignore_headers. Или это должно предотвратить обработку Set-Cookie, даже если он явно присутствует в кэшированных файлах?

Вот соответствующие части моей конфигурации:

location ~ .php$ { …

fastcgi_next_upstream error timeout invalid_header http_500 http_503;
fastcgi_cache OPENCART;
fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;
fastcgi_cache_purge $purge_method;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_valid 200 5m;
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_pass_header Set-Cookie;
#fastcgi_hide_header Set-Cookie;
fastcgi_pass_header Cookie;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

Мои правила обхода кэша (вызываются в /etc/conf.d)…

################## Настройки кэша Fast CGI

# если мы находим cookie сеанса PHP, давайте кэшировать его содержимое

map $http_cookie $php_session_cookie {
    default "";
    ~PHPSESSID=(?<sessionkey>[a-zA-Z0-9]+) $sessionkey; # cookie сеанса PHP
}

fastcgi_cache_path /var/nginx/cache levels=1:2 keys_zone=OPENCART:5m max_size=10000m inactive=15m;
fastcgi_cache_key "$scheme$request_method$host$request_uri$is_mobile$php_session_cookie";

map $request_method $purge_method {
    PURGE   1;
    default 0;
}

################## Заголовок кэша

add_header X-Cache $upstream_cache_status;

################## Карты обхода кэша

#Не кэшировать следующие URL
map $request_uri $no_cache_uri {
    default 0;
    ~*/admin/ 1;
    ~*/dl/ 1;
}

# ~*/music/mp3_[^/]+/[0-9]+/.+$ 1;

map $query_string $no_cache_query {
    default 0;
    ~*route=module/cart$ 1;
    ~*route=account/ 1; # исключить ссылки на аккаунты
    ~*route=checkout/ 1; # исключить ссылки на оформление
    ~*route=module/founders 1;
    ~*route=module/cart 1;
    ~*route=product/product/captcha 1;
    ~*nocache=1 1; # исключить ajax блоки и обеспечить ручной обход кэша
}

map $http_cookie $no_cache_cookie {
    default 0;
}  

map $http_x_requested_with $no_cache_ajax {
    default 0;
    XMLHttpRequest 1; # Не кэшировать AJAX
}

map $sent_http_x_no_cache $no_no_cache {
    default 0;
    on 1; # Не кэшировать общий заголовок, когда он присутствует и установлен на "on"
}

## Объедините все результаты, чтобы получить отображение обхода кэша.
map $no_cache_uri$no_cache_query$no_cache_cookie$no_cache_ajax$no_no_cache $no_cache {
        default 1;
        00000 0;
}

Настройки сеанса в php.ini

session.auto_start = 1
session.cache_expire = 180
session.cache_limiter = nocache
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_secure = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 3600
session.gc_probability = 0
session.hash_function = "sha256"
session.name = PHPSESSID
session.serialize_handler = php
session.use_cookies = 1
session.use_only_cookies = 1
session.use_strict_mode = 1
session.use_trans_sid = 0

OpenCart использует session_start() на каждой загрузке страницы, поэтому обход сессии PHP не приносит мне пользы в большинстве случаев. Если бы существовал способ предотвратить попадание заголовков Set-Cookie в кэш, это было бы полезно для меня.

Может кто-то подсказать мне правильное направление?

Вам также следует проверить, что находится в ваших кэшированных файлах.

Например, у меня был заголовок “Set-Cookie” в некоторых кэшированных файлах.

vi /var/www/cache/prod/a/05/9671214cbf3a27f79135a52cbd5b305a

Set-Cookie: Mywebsite=arj4m9egloj9jhrlsps7cu29ec; expires=Fri, 08-Jun-2018 14:39:21 GMT; Max-Age=2592000; path=/

Я удалил все свои кэшированные файлы.

rm -rf /var/www/cache/prod/*

И теперь я проверяю, есть ли новый заголовок Set-Cookie в новом кэшированном файле:

grep -rn  "Set-Cookie" /var/www/cache/prod/

Лучшее решение, которое я нашёл, это предотвратить на стороне PHP установку cookie сессии, когда страница будет кэшироваться:

if( (strpos($_SERVER['REQUEST_URI'], 'include/php/render') === FALSE) &&
    (!isBot()) ) { 
    // Нет cookie сессии для PHP рендеринга изображений
    // Нет cookie сессии для ботов (они создают по одному на каждую посещённую страницу!)
    $session_lifetime = 30*24*3600; //30 дней
    session_set_cookie_params($session_lifetime,"https://serverfault.com/");
    ini_set('session.gc_maxlifetime', $session_lifetime);
    ini_set('session.name', 'Blackart');
    session_start();
}

Из коробки nginx не кэширует страницы с заголовком Set-Cookie (что вполне логично – частные данные!), если вы не добавите его в fastcgi_ignore_headers

fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

Вы сказали nginx игнорировать заголовок Set-Cookie и все равно кэшировать.

Но чтобы было ясно, я не знаю ваш сервер, но я предполагаю, что все ваши динамические страницы отправляют cookie для поддержания сессии.

Выясните, отправляет ли OpenCart конкретный cookie, если пользователь вошёл в систему, и затем протестируйте этот cookie.

Другой метод: уберите заголовок CacheControl из ignore_headers и установите правильный заголовок в вашем коде.
для PHP

header('Cache-Control: public'); 

если вы хотите кэшировать страницу

Ответ или решение

Использование PHP-сессий для аутентификации с кешем Nginx FastCGI: Возможные проблемы и их решение

Введение

Переход на Nginx с кешированием FastCGI может привести к ряду проблем, особенно когда речь идет о безопасности сессий пользователей. Как показывает практика, неправильная конфигурация кеша может привести к тому, что пользовательские сессии будут неправильно обрабатываться, что и произошло в вашем случае с «лихорадкой заказов» и «перехватом учетных записей».

В данном ответе рассматриваются основные подходы к решению данной проблемы с кешированием Nginx и PHP-сессиями.

Проблемы с кешированием и сессиями

Как вы уже заметили, кеширование страниц с заголовком Set-Cookie недопустимо, поскольку это может привести к тому, что новые пользователи получат доступ к сессии, инициализированной предыдущим пользователем. Это связано с тем, что Nginx по умолчанию не кеширует страницы с заголовком Set-Cookie. Однако, если вы используете fastcgi_ignore_headers с Set-Cookie, это может неправильно трактоваться.

Параметр fastcgi_ignore_headers позволяет игнорировать заголовки в ответах от FastCGI, в том числе и Set-Cookie, что может привести к кешированию страниц с установленными сессионными данными.

Рекомендации по конфигурации Nginx

Чтобы устранить проблему с кешированием сессий, необходимо внести изменения в конфигурацию вашего Nginx.

  1. Не игнорировать Set-Cookie заголовок: Убедитесь, что заголовок Set-Cookie не игнорируется. Это значит, что Nginx не будет кешировать ответы, содержащие этот заголовок.

    Удалите строку:

    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

    Вместо этого оставьте Nginx с его стандартным поведением, чтобы он не кешировал страницы с заголовком Set-Cookie.

  2. Используйте fastcgi_cache_bypass для определения необходимости кеширования: Определите в вашей конфигурации, когда не нужно кешировать ответы, основываясь на наличии сессионной cookie или других условиях. Например:

    map $http_cookie $no_cache_cookie {
       default 0;
       ~PHPSESSID 1;
    }
    
    fastcgi_cache_bypass $no_cache_cookie;

    Это предотвратит кеширование страниц, если находилась сессионная cookie (например, PHPSESSID).

  3. Проверка содержимого кеша: Ваша проблема, скорее всего, также обусловлена тем, что в кеш попадают страницы с заголовком Set-Cookie. После внесения изменений проверьте содержимое кеша, чтобы убедиться, что в нем нет заголовка Set-Cookie. Используйте команду:

    grep -rn "Set-Cookie" /var/nginx/cache/
  4. Очистка кеша: После внесения изменений в конфигурацию, не забудьте очистить существующий кеш. Это поможет избежать проблем, связанных с устаревшими данными:

    rm -rf /var/nginx/cache/*

Изменение кода PHP

Если все же необходимо устанавливать сессионные cookie, убедитесь, что они не устанавливаются для кешируемых страниц. Вы можете использовать условную конструкцию для этого:

if (!isset($_COOKIE['PHPSESSID'])) {
    session_start();
}

Это позволит избежать установки cookie, если сессия нового пользователя не была инициализирована ранее.

Заключение

Итак, использование PHP-сессий для аутентификации в связке с кешированием Nginx FastCGI возможно, однако требует внимательной настройки конфигурации сервера и кода. Убедитесь, что ваши настройки гарантируют, что заголовки, касающиеся сессий, не кешируются и правила кеширования правильно применяются в зависимости от состояния сессии. Это поможет избежать потенциальных проблем с безопасностью и улучшит работу вашего сайта.

Оцените материал
Добавить комментарий

Капча загружается...