xref: /plugin/combo/action/metacsp.php (revision c3437056399326d621a01da73b649707fbb0ae69)
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