Passed
Push — csp ( 63856a...2ca554 )
by Fabio
06:52 queued 38s
created

THttpHeaderCSP::getValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 8
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;
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
	 * @throws TConfigurationException if service parameter is not specified
55
	 */
56
	public function init($config)
57
	{
58
		parent::init($config);
59
		$this->loadPolicies($config);
60
	}
61
62
	/**
63
	 * Load and configure each header.
64
	 * @param mixed $config configuration node
65
	 * @throws TConfigurationException if specific pattern class is invalid
66
	 */
67
	protected function loadPolicies($config)
68
	{
69
		if (is_array($config)) {
70
			if (isset($config['policies']) && is_array($config['policies'])) {
71
				foreach ($config['policies'] as $policy) {
72
					$name = $policy['name'];
73
					$this->_policies[$name] = $policy['value'];
74
				}
75
			}
76
		} else {
77
			foreach ($config->getElementsByTagName('policy') as $header) {
78
				$properties = $header->getAttributes();
79
				$name = $properties->remove('Name');
80
				$this->_policies[$name] = $header->getValue();
81
			}
82
		}
83
	}
84
85
	/**
86
	 * @return string the textual name of the header.
87
	 */
88
	public function getName()
89
	{
90
		return 'Content-Security-Policy';
91
	}
92
93
	/**
94
	 * @return string the textual value of the header.
95
	 */
96
	public function getValue()
97
	{
98
		$nonce = '\'nonce-' . Prado::getApplication()->getSecurityManager()->getCSPNonce() .'\'';
99
		$ret = '';
100
		foreach($this->_policies as $name => $value) {
101
			$ret .= $name . ': ' . str_replace(self::NONCE, $nonce, $value) . '; ';
102
		}
103
		return $ret;
104
	}
105
}