xref: /template/strap/action/metacsp.php (revision 1b6a1c169bf1bda925ccd1b811ac5c1eb081d809)
121913ab3SNickeau<?php
221913ab3SNickeau
3e8b2ff59SNickeauuse ComboStrap\LogUtility;
4531e725cSNickeauuse ComboStrap\Site;
521913ab3SNickeauuse ComboStrap\StringUtility;
621913ab3SNickeau
721913ab3SNickeau
821913ab3SNickeau/**
921913ab3SNickeau *
1021913ab3SNickeau * Adding security directive
1121913ab3SNickeau *
1221913ab3SNickeau */
1321913ab3SNickeauclass action_plugin_combo_metacsp extends DokuWiki_Action_Plugin
1421913ab3SNickeau{
1521913ab3SNickeau
1621913ab3SNickeau
1721913ab3SNickeau    function __construct()
1821913ab3SNickeau    {
1921913ab3SNickeau        // enable direct access to language strings
2021913ab3SNickeau        // ie $this->lang
2121913ab3SNickeau        $this->setupLocale();
2221913ab3SNickeau    }
2321913ab3SNickeau
2421913ab3SNickeau    public function register(Doku_Event_Handler $controller)
2521913ab3SNickeau    {
26e8b2ff59SNickeau
27e8b2ff59SNickeau        $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'httpHeaderCsp', array());
28e8b2ff59SNickeau        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'htmlMetaCsp', array());
29e8b2ff59SNickeau
3021913ab3SNickeau    }
3121913ab3SNickeau
3221913ab3SNickeau    /**
3321913ab3SNickeau     * Dokuwiki has already a canonical methodology
3421913ab3SNickeau     * https://www.dokuwiki.org/canonical
3521913ab3SNickeau     *
3621913ab3SNickeau     * @param $event
3721913ab3SNickeau     */
38e8b2ff59SNickeau    function htmlMetaCsp($event)
3921913ab3SNickeau    {
4021913ab3SNickeau
41531e725cSNickeau
42531e725cSNickeau        /**
43531e725cSNickeau         * HTML meta directives
44531e725cSNickeau         */
4521913ab3SNickeau        $directives = [
4621913ab3SNickeau            'block-all-mixed-content', // no http, https
4721913ab3SNickeau        ];
4821913ab3SNickeau
4921913ab3SNickeau        // Search if the CSP property is already present
5021913ab3SNickeau        $cspKey = null;
5121913ab3SNickeau        foreach ($event->data['meta'] as $key => $meta) {
5221913ab3SNickeau            if (isset($meta["http-equiv"])) {
5385e82846SNickeau                if ($meta["http-equiv"] == "content-security-policy") {
5421913ab3SNickeau                    $cspKey = $key;
5521913ab3SNickeau                }
5621913ab3SNickeau            }
5721913ab3SNickeau        }
5821913ab3SNickeau        if ($cspKey != null) {
5921913ab3SNickeau            $actualDirectives = StringUtility::explodeAndTrim($event->data['meta'][$cspKey]["content"], ",");
6021913ab3SNickeau            $directives = array_merge($actualDirectives, $directives);
6121913ab3SNickeau            $event->data['meta'][$cspKey] = [
6285e82846SNickeau                "http-equiv" => "content-security-policy",
6321913ab3SNickeau                "content" => join(", ", $directives)
6421913ab3SNickeau            ];
6521913ab3SNickeau        } else {
6621913ab3SNickeau            $event->data['meta'][] = [
6785e82846SNickeau                "http-equiv" => "content-security-policy",
6821913ab3SNickeau                "content" => join(",", $directives)
6921913ab3SNickeau            ];
7021913ab3SNickeau        }
7121913ab3SNickeau
72e8b2ff59SNickeau    }
73e8b2ff59SNickeau
74e8b2ff59SNickeau    function httpHeaderCsp($event)
75e8b2ff59SNickeau    {
76531e725cSNickeau        /**
77531e725cSNickeau         * Http header CSP directives
78531e725cSNickeau         */
79*1b6a1c16Sgerardnico        $httpHeaderReferer = $_SERVER['HTTP_REFERER'] ?? '';
80531e725cSNickeau        $httpDirectives = [];
81*1b6a1c16Sgerardnico        if (strpos($httpHeaderReferer, Site::getBaseUrl()) === false) {
82531e725cSNickeau            // not same origin
8321913ab3SNickeau            $httpDirectives = [
84c3437056SNickeau                // the page cannot be used in a iframe (clickjacking),
85c3437056SNickeau                "content-security-policy: frame-ancestors 'none'",
86c3437056SNickeau                // the page cannot be used in a iframe (clickjacking) - deprecated for frame ancestores
8704fd306cSNickeau                // indicate whether or not a browser should be allowed to render
8804fd306cSNickeau                // a page in a <frame>, <iframe>, <embed> or <object>. Sites can use this to avoid
8904fd306cSNickeau                // click-jacking attacks, by ensuring that their content is not embedded into other sites.
90c3437056SNickeau                "X-Frame-Options: SAMEORIGIN",
91c3437056SNickeau                // stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type
92c3437056SNickeau                "X-Content-Type-Options: nosniff",
93c3437056SNickeau                // sends the origin if cross origin otherwise the full refer for same origin
94c3437056SNickeau                "Referrer-Policy: strict-origin-when-cross-origin",
95c3437056SNickeau                // 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.
96c3437056SNickeau                "X-DNS-Prefetch-Control: on",
97c3437056SNickeau                // 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.
98c3437056SNickeau                "X-XSS-Protection: 1; mode=block"
9921913ab3SNickeau            ];
100531e725cSNickeau        }
101e8b2ff59SNickeau        if (!headers_sent()) {
10221913ab3SNickeau            foreach ($httpDirectives as $httpDirective) {
10321913ab3SNickeau                header($httpDirective);
10421913ab3SNickeau            }
105e8b2ff59SNickeau        } else {
106e8b2ff59SNickeau            LogUtility::msg("HTTP Headers have already ben sent. We couldn't add the CSP security header", LogUtility::LVL_MSG_WARNING, "security");
107e8b2ff59SNickeau        }
10821913ab3SNickeau    }
10921913ab3SNickeau
11021913ab3SNickeau}
111