Passed
Push — master ( 852c3e...2eace3 )
by Darko
17:49 queued 03:15
created

NoCacheForAuthenticatedUsers::handle()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 36
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 36
rs 9.4555
cc 5
nc 5
nop 2
1
<?php
2
3
namespace App\Http\Middleware;
4
5
use Closure;
6
use Illuminate\Http\Request;
7
use Illuminate\Support\Facades\Auth;
8
use Symfony\Component\HttpFoundation\Response;
9
10
/**
11
 * Middleware to prevent caching of authenticated user pages.
12
 *
13
 * This prevents issues where:
14
 * - CDNs (like Cloudflare) cache user-specific pages
15
 * - Reverse proxies cache authenticated pages showing wrong user data
16
 * - Browsers cache authenticated pages
17
 * - One user could see another user's data due to cache poisoning
18
 */
19
class NoCacheForAuthenticatedUsers
20
{
21
    /**
22
     * Handle an incoming request.
23
     */
24
    public function handle(Request $request, Closure $next): Response
25
    {
26
        $response = $next($request);
27
28
        // For authenticated users, add headers to prevent caching of personal data
29
        if (Auth::check()) {
30
            // Prevent any caching of authenticated user responses
31
            // 'private' tells CDNs like Cloudflare not to cache this response
32
            $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate, private, max-age=0, s-maxage=0');
33
            $response->headers->set('Pragma', 'no-cache');
34
            $response->headers->set('Expires', 'Thu, 01 Jan 1970 00:00:00 GMT');
35
36
            // Cloudflare-specific: Tell Cloudflare to bypass cache for this response
37
            // CDN-Cache-Control is respected by Cloudflare and other CDNs
38
            $response->headers->set('CDN-Cache-Control', 'no-store');
39
40
            // Cloudflare also respects this header
41
            $response->headers->set('Cloudflare-CDN-Cache-Control', 'no-store');
42
43
            // Add Vary header to ensure caches differentiate by user session
44
            $existingVary = $response->headers->get('Vary', '');
45
            $varyHeaders = array_filter(array_map('trim', explode(',', $existingVary)));
46
47
            // Add Cookie to Vary header if not already present
48
            if (! in_array('Cookie', $varyHeaders, true)) {
49
                $varyHeaders[] = 'Cookie';
50
            }
51
            // Add Authorization to Vary header for API requests
52
            if ($request->bearerToken() && ! in_array('Authorization', $varyHeaders, true)) {
53
                $varyHeaders[] = 'Authorization';
54
            }
55
56
            $response->headers->set('Vary', implode(', ', $varyHeaders));
57
        }
58
59
        return $response;
60
    }
61
}
62