* @link https://www.dokuwiki.org/plugin:cspheader */ class action_plugin_cspheader extends DokuWiki_Action_Plugin { /** * CSP HTTP Header */ const CSP_HEADER = 'Content-Security-Policy:'; /** * @var array CSP directives names * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#directives */ const DIRECTIVES = [ 'base-uri', //'block-all-mixed-content', // this is a yes/no field and should be handled separately 'child-src', 'connect-src', 'default-src', 'font-src', 'form-action', 'frame-ancestors', 'frame-src', 'img-src', 'manifest-src', 'media-src', 'navigate-to', 'object-src', 'plugin-types', 'prefetch-src', //'referrer', // deprecated //'report-to', // this one isn't widely supported and expects a more complicated setup, skip for now 'report-uri', //'require-sri-for', // obsolete 'sandbox', 'script-src', 'script-src-attr', 'script-src-elem', 'style-src', 'style-src-attr', 'style-src-elem', 'trusted-types', //'upgrade-insecure-requests', // this is a yes/no field and should be handled separately 'worker-src', ]; public function register(Doku_Event_Handler $controller) { $controller->register_hook('ACTION_HEADERS_SEND', 'BEFORE', $this, 'handleHeadersSend'); } /** * Handler for the ACTION_HEADERS_SEND event * * @param Doku_Event $event * @param $params * * @noinspection PhpUnused, PhpUnusedParameterInspection */ public function handleHeadersSend(Doku_Event $event, $params) { $policies = []; foreach (self::DIRECTIVES as $directive) { $option = str_replace('-', '', $directive) . 'Value'; $values = $this->getConf($option); $values = explode("\n", $values); $values = array_map('trim', $values); $values = array_unique($values); $values = array_filter($values); if (!count($values)) continue; $policies[$directive] = join(' ', $values); } $cspheader = self::CSP_HEADER; foreach ($policies as $directive => $value) { $cspheader .= " $directive $value;"; } // create nonce for inline scripts and replace placeholder in header $nonce = bin2hex(random_bytes(16)); putenv("NONCE=$nonce"); $cspheader = str_replace('NONCE', $nonce, $cspheader); array_push($event->data, $cspheader); } }