1<?php 2 3use ComboStrap\LogUtility; 4use ComboStrap\Site; 5use ComboStrap\StringUtility; 6 7if (!defined('DOKU_INC')) die(); 8 9/** 10 * 11 * Adding security directive 12 * 13 */ 14class action_plugin_combo_metacsp extends DokuWiki_Action_Plugin 15{ 16 17 18 function __construct() 19 { 20 // enable direct access to language strings 21 // ie $this->lang 22 $this->setupLocale(); 23 } 24 25 public function register(Doku_Event_Handler $controller) 26 { 27 28 $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'httpHeaderCsp', array()); 29 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'htmlMetaCsp', array()); 30 31 } 32 33 /** 34 * Dokuwiki has already a canonical methodology 35 * https://www.dokuwiki.org/canonical 36 * 37 * @param $event 38 */ 39 function htmlMetaCsp($event) 40 { 41 42 43 /** 44 * HTML meta directives 45 */ 46 $directives = [ 47 'block-all-mixed-content', // no http, https 48 ]; 49 50 // Search if the CSP property is already present 51 $cspKey = null; 52 foreach ($event->data['meta'] as $key => $meta) { 53 if (isset($meta["http-equiv"])) { 54 if ($meta["http-equiv"] == "content-security-policy") { 55 $cspKey = $key; 56 } 57 } 58 } 59 if ($cspKey != null) { 60 $actualDirectives = StringUtility::explodeAndTrim($event->data['meta'][$cspKey]["content"], ","); 61 $directives = array_merge($actualDirectives, $directives); 62 $event->data['meta'][$cspKey] = [ 63 "http-equiv" => "content-security-policy", 64 "content" => join(", ", $directives) 65 ]; 66 } else { 67 $event->data['meta'][] = [ 68 "http-equiv" => "content-security-policy", 69 "content" => join(",", $directives) 70 ]; 71 } 72 73 } 74 75 function httpHeaderCsp($event) 76 { 77 /** 78 * Http header CSP directives 79 */ 80 $httpHeaderReferer = $_SERVER['HTTP_REFERER']; 81 $httpDirectives = []; 82 if (strpos($httpHeaderReferer, Site::getBaseUrl()) === false) { 83 // not same origin 84 $httpDirectives = [ 85 // the page cannot be used in a iframe (clickjacking), 86 "content-security-policy: frame-ancestors 'none'", 87 // the page cannot be used in a iframe (clickjacking) - deprecated for frame ancestores 88 "X-Frame-Options: SAMEORIGIN", 89 // stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type 90 "X-Content-Type-Options: nosniff", 91 // sends the origin if cross origin otherwise the full refer for same origin 92 "Referrer-Policy: strict-origin-when-cross-origin", 93 // controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the DNS is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link. 94 "X-DNS-Prefetch-Control: on", 95 // This header stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. Although this protection is not necessary when sites implement a strong Content-Security-Policy disabling the use of inline JavaScript ('unsafe-inline'), it can still provide protection for older web browsers that don't support CSP. 96 "X-XSS-Protection: 1; mode=block" 97 ]; 98 } 99 if (!headers_sent()) { 100 foreach ($httpDirectives as $httpDirective) { 101 header($httpDirective); 102 } 103 } else { 104 LogUtility::msg("HTTP Headers have already ben sent. We couldn't add the CSP security header", LogUtility::LVL_MSG_WARNING,"security"); 105 } 106 } 107 108} 109