blocks and onclick= * handlers; 'unsafe-eval' because alasql compiles its queries with new Function. */ if (!function_exists('send_page_security_headers')) { function send_page_security_headers(): void { if (headers_sent()) return; $script = ["'self'", "'unsafe-inline'", "'unsafe-eval'"]; $connect = ["'self'"]; if (defined('NODE_PUBLIC_URL')) { $node = parse_url(NODE_PUBLIC_URL); if (!empty($node['scheme']) && !empty($node['host'])) { $origin = $node['host'] . (isset($node['port']) ? ':' . $node['port'] : ''); $secure = strtolower($node['scheme']) === 'https'; $script[] = ($secure ? 'https://' : 'http://') . $origin; $connect[] = ($secure ? 'https://' : 'http://') . $origin; $connect[] = ($secure ? 'wss://' : 'ws://') . $origin; } } $csp = implode('; ', [ "default-src 'self'", 'script-src ' . implode(' ', $script), "style-src 'self' 'unsafe-inline'", "font-src 'self' data:", "img-src 'self' data: blob:", "media-src 'self' blob:", 'connect-src ' . implode(' ', $connect), "worker-src 'self' blob:", "frame-src 'self' blob:", "object-src 'none'", "base-uri 'self'", "form-action 'self'", "frame-ancestors 'self'", ]); header('Content-Security-Policy: ' . $csp, true); header('X-Content-Type-Options: nosniff', true); header('X-Frame-Options: SAMEORIGIN', true); header('Referrer-Policy: strict-origin-when-cross-origin', true); } }