是否真的可以使用 PHP 会话通过 nginx fastcgi 缓存进行身份验证?

是否真的可以使用 PHP 会话通过 nginx fastcgi 缓存进行身份验证?

我最近将 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] 根据 fastcgi_cache_valid 下的 nginx 文档...

如果标头包含“Set-Cookie”字段,则此类响应将不会被缓存。

通过包括设置Cookie使用 fastcgi_ignore_headers,我是否告诉它缓存 set-cookie?在许多示例中,设置Cookie是 fastcgi_ignore_headers 参数的一部分。或者它是否应该阻止处理 Set-Cookie,即使它显然在缓存文件中?

以下是我的配置的相关部分:

位置 ~ .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 Cache Settings

# if we find a PHP session cookie, let's cache it's contents

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

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;
}

################## Cache Header

add_header X-Cache $upstream_cache_status;

################## Cache Bypass Maps

#Don't cache the following URLs
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; #exclude account links
    ~*route=checkout/ 1; #exclude checkout links
    ~*route=module/founders 1;
    ~*route=module/cart 1;
    ~*route=product/product/captcha 1;
    ~*nocache=1 1; # exclude ajax blocks and provide for manual cache override
}

map $http_cookie $no_cache_cookie {
    default 0;
}  

map $http_x_requested_with $no_cache_ajax {
    default 0;
    XMLHttpRequest 1; # Don't cache AJAX
}

map $sent_http_x_no_cache $no_no_cache {
    default 0;
    on 1; # Don't cache generic header when present and set to "on"
}

## Combine all results to get the cache bypass mapping.
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 session 对我来说大部分都没什么用。如果有办法防止 Set-Cookie 标头进入缓存,那么这种方法可能对我有用。

有人能给我指出正确的方向吗?

答案1

您还应该检查缓存文件中的内容。

例如,我在一些缓存文件中设置了“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()) ) { 
    // No session Cookie for PHP render Images
    // No session Cookie Bots (They create one for each page visisted!)
    $session_lifetime = 30*24*3600; //30 days
    session_set_cookie_params($session_lifetime,"/");
    ini_set('session.gc_maxlifetime', $session_lifetime);
    ini_set('session.name', 'Blackart');
    session_start();
}

答案2

默认情况下,nginx 不会缓存带有 Set-Cookie 标头的页面(这是有道理的 - 私有数据!),除非你将其放入fastcgi_ignore_headers

fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

无论如何,您都告诉 nginx 忽略 Set-Cookie 标头和缓存。

但要说清楚,我不知道您的服务器,但我猜测所有动态页面都发送了 cookie 来保持会话。

如果用户登录,则查明 opencart 是否发送特定的 cookie,然后测试该 cookie。

其他方法:从 ignore_headers 中删除 CacheControl 标头,并在代码中设置正确的标头。对于 php

header('Cache-Control: public'); 

如果你想缓存页面

相关内容