xref: /plugin/combo/action/metacsp.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
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::getUrl()) === false) {
83            // not same origin
84            $httpDirectives = [
85                "content-security-policy: frame-ancestors 'none'", // the page cannot be used in a iframe (clickjacking),
86                "X-Frame-Options: deny" // the page cannot be used in a iframe (clickjacking) - deprecated for frame ancestores
87            ];
88        }
89        if (!headers_sent()) {
90            foreach ($httpDirectives as $httpDirective) {
91                header($httpDirective);
92            }
93        } else {
94            LogUtility::msg("HTTP Headers have already ben sent. We couldn't add the CSP security header", LogUtility::LVL_MSG_WARNING,"security");
95        }
96    }
97
98}
99