]> BookStack Code Mirror - bookstack/blob - app/Http/Middleware/ApplyCspRules.php
Started application of CSP headers
[bookstack] / app / Http / Middleware / ApplyCspRules.php
1 <?php
2
3 namespace BookStack\Http\Middleware;
4
5 use Closure;
6 use Illuminate\Http\Request;
7 use Illuminate\Support\Str;
8 use Symfony\Component\HttpFoundation\Response;
9
10
11 class ApplyCspRules
12 {
13     /**
14      * Handle an incoming request.
15      *
16      * @param Request $request
17      * @param Closure $next
18      *
19      * @return mixed
20      */
21     public function handle($request, Closure $next)
22     {
23         $nonce = Str::random(24);
24         view()->share('cspNonce', $nonce);
25
26         // TODO - Assess whether image/style/iframe CSP rules should be set
27         // TODO - Extract nonce application to custom head content in a way that's cacheable.
28         // TODO - Fix remaining CSP issues and test lots
29
30         $response = $next($request);
31
32         $this->setFrameAncestors($response);
33         $this->setScriptSrc($response, $nonce);
34
35         return $response;
36     }
37
38     /**
39      * Sets CSP 'script-src' headers to restrict the forms of script that can
40      * run on the page.
41      */
42     public function setScriptSrc(Response $response, string $nonce)
43     {
44         $parts = [
45             '\'self\'',
46             '\'nonce-' . $nonce . '\'',
47             '\'strict-dynamic\'',
48         ];
49         $response->headers->set('Content-Security-Policy', 'script-src ' . implode(' ', $parts));
50     }
51
52     /**
53      * Sets CSP "frame-ancestors" headers to restrict the hosts that BookStack can be
54      * iframed within. Also adjusts the cookie samesite options so that cookies will
55      * operate in the third-party context.
56      */
57     protected function setFrameAncestors(Response $response)
58     {
59         $iframeHosts = collect(explode(' ', config('app.iframe_hosts', '')))->filter();
60
61         if ($iframeHosts->count() > 0) {
62             config()->set('session.same_site', 'none');
63         }
64
65         $iframeHosts->prepend("'self'");
66         $cspValue = 'frame-ancestors ' . $iframeHosts->join(' ');
67         $response->headers->set('Content-Security-Policy', $cspValue);
68     }
69 }