3 namespace BookStack\Util;
5 use Illuminate\Support\Str;
9 protected string $nonce;
11 public function __construct(string $nonce = '')
13 $this->nonce = $nonce ?: Str::random(24);
17 * Get the nonce value for CSP.
19 public function getNonce(): string
25 * Get the CSP headers for the application.
27 public function getCspHeader(): string
30 $this->getFrameAncestors(),
32 $this->getScriptSrc(),
33 $this->getObjectSrc(),
37 return implode('; ', array_filter($headers));
41 * Get the CSP rules for the application for a HTML meta tag.
43 public function getCspMetaTagValue(): string
47 $this->getScriptSrc(),
48 $this->getObjectSrc(),
52 return implode('; ', array_filter($headers));
56 * Check if the user has configured some allowed iframe hosts.
58 public function allowedIFrameHostsConfigured(): bool
60 return count($this->getAllowedIframeHosts()) > 0;
64 * Create CSP 'script-src' rule to restrict the forms of script that can run on the page.
66 protected function getScriptSrc(): string
68 if (config('app.allow_content_scripts')) {
75 '\'nonce-' . $this->nonce . '\'',
79 return 'script-src ' . implode(' ', $parts);
83 * Create CSP "frame-ancestors" rule to restrict the hosts that BookStack can be iframed within.
85 protected function getFrameAncestors(): string
87 $iframeHosts = $this->getAllowedIframeHosts();
88 array_unshift($iframeHosts, "'self'");
90 return 'frame-ancestors ' . implode(' ', $iframeHosts);
94 * Creates CSP "frame-src" rule to restrict what hosts/sources can be loaded
95 * within iframes to provide an allow-list-style approach to iframe content.
97 protected function getFrameSrc(): string
99 $iframeHosts = $this->getAllowedIframeSources();
100 array_unshift($iframeHosts, "'self'");
102 return 'frame-src ' . implode(' ', $iframeHosts);
106 * Creates CSP 'object-src' rule to restrict the types of dynamic content
107 * that can be embedded on the page.
109 protected function getObjectSrc(): string
111 if (config('app.allow_content_scripts')) {
115 return "object-src 'self'";
119 * Creates CSP 'base-uri' rule to restrict what base tags can be set on
120 * the page to prevent manipulation of relative links.
122 protected function getBaseUri(): string
124 return "base-uri 'self'";
127 protected function getAllowedIframeHosts(): array
129 $hosts = config('app.iframe_hosts', '');
131 return array_filter(explode(' ', $hosts));
134 protected function getAllowedIframeSources(): array
136 $sources = config('app.iframe_sources', '');
137 $hosts = array_filter(explode(' ', $sources));
139 // Extract drawing service url to allow embedding if active
140 $drawioConfigValue = config('services.drawio');
141 if ($drawioConfigValue) {
142 $drawioSource = is_string($drawioConfigValue) ? $drawioConfigValue : 'https://embed.diagrams.net/';
143 $drawioSourceParsed = parse_url($drawioSource);
144 $drawioHost = $drawioSourceParsed['scheme'] . '://' . $drawioSourceParsed['host'];
145 $hosts[] = $drawioHost;