Passed
Pull Request — master (#1005)
by Fabio
17:26 queued 11:05
created

THttpHeaderCSP::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
/**
4
 * THttpHeaderCSP class
5
 *
6
 * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
7
 * @link https://github.com/pradosoft/prado
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 */
10
11
namespace Prado\Web;
12
13
use Prado\Prado;
14
15
/**
16
 * THttpHeaderCSP class.
17
 *
18
 * THttpHeaderCSP adds a Content-security-policy header to all responses.
19
 * If you want to use this header, load your manager class
20
 * {@see \Prado\Web\THttpHeadersManager THttpHeadersManager},
21
 * add this class as an header and define the needed policies, eg.:
22
 *
23
 * ```xml
24
 * <module id="headers" class="THttpHeadersManager">
25
 *   <header Name="Strict-Transport-Security" Value="max-age=31536000" />
26
 *   <header Name="X-Content-Type-Options" Value="nosniff" />
27
 *   <header Name="X-Frame-Options" Value="DENY" />
28
 *   <header class="THttpHeaderCSP">
29
 *     <policy Name="default-src">'self' 'unsafe-inline' www.gstatic.com NONCE</policy>
30
 *     <policy Name="frame-src">'self' www.google.com</policy>
31
 *   </header>
32
 * </module>
33
 * <module id="response" class="THttpResponse" HeadersManager="headers" />
34
 * ```
35
 *
36
 * The special value {@see \Prado\Web\THttpHeaderCSP::NONCE NONCE} will get
37
 * automatically replaced with a valid Content-security-policy nonce.
38
 *
39
 * @author Fabio Bas <ctrlaltca[at]gmail[dot]com>
40
 * @since 4.3.2
41
 */
42
class THttpHeaderCSP extends \Prado\Web\THttpHeader
43
{
44
	/**
45
	 * @var string[] list of key:value policies.
46
	 */
47
	protected $_policies = [];
48
49
	public const NONCE = 'NONCE';
50
51
	/**
52
	 * Initializes the CSP header.
53
	 * @param \Prado\Xml\TXmlElement $config configuration for this module.
54
	 */
55
	public function init($config)
56
	{
57
		parent::init($config);
58
		$this->loadPolicies($config);
59
	}
60
61
	/**
62
	 * Load and configure each header.
63
	 * @param mixed $config configuration node
64
	 */
65
	protected function loadPolicies($config)
66
	{
67
		if (is_array($config)) {
68
			if (isset($config['policies']) && is_array($config['policies'])) {
69
				foreach ($config['policies'] as $policy) {
70
					$name = $policy['name'];
71
					$this->_policies[$name] = $policy['value'];
72
				}
73
			}
74
		} else {
75
			foreach ($config->getElementsByTagName('policy') as $header) {
76
				$properties = $header->getAttributes();
77
				$name = $properties->remove('Name');
78
				$this->_policies[$name] = $header->getValue();
79
			}
80
		}
81
	}
82
83
	/**
84
	 * @return string the textual name of the header.
85
	 */
86
	public function getName()
87
	{
88
		return 'Content-Security-Policy';
89
	}
90
91
	/**
92
	 * @return string the textual value of the header.
93
	 */
94
	public function getValue()
95
	{
96
		$nonce = '\'nonce-' . Prado::getApplication()->getSecurityManager()->getCSPNonce() . '\'';
97
		$ret = '';
98
		foreach ($this->_policies as $name => $value) {
99
			$ret .= $name . ' ' . str_replace(self::NONCE, $nonce, $value) . '; ';
100
		}
101
		return $ret;
102
	}
103
}
104