Mercurial > hg > cmmr2012-drupal-site
comparison vendor/zendframework/zend-diactoros/src/HeaderSecurity.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 5311817fb629 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 /** | |
3 * Zend Framework (http://framework.zend.com/) | |
4 * | |
5 * @see http://github.com/zendframework/zend-diactoros for the canonical source repository | |
6 * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com) | |
7 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License | |
8 */ | |
9 | |
10 namespace Zend\Diactoros; | |
11 | |
12 use InvalidArgumentException; | |
13 | |
14 /** | |
15 * Provide security tools around HTTP headers to prevent common injection vectors. | |
16 * | |
17 * Code is largely lifted from the Zend\Http\Header\HeaderValue implementation in | |
18 * Zend Framework, released with the copyright and license below. | |
19 * | |
20 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) | |
21 * @license http://framework.zend.com/license/new-bsd New BSD License | |
22 */ | |
23 final class HeaderSecurity | |
24 { | |
25 /** | |
26 * Private constructor; non-instantiable. | |
27 * @codeCoverageIgnore | |
28 */ | |
29 private function __construct() | |
30 { | |
31 } | |
32 | |
33 /** | |
34 * Filter a header value | |
35 * | |
36 * Ensures CRLF header injection vectors are filtered. | |
37 * | |
38 * Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal | |
39 * tabs are allowed in values; header continuations MUST consist of | |
40 * a single CRLF sequence followed by a space or horizontal tab. | |
41 * | |
42 * This method filters any values not allowed from the string, and is | |
43 * lossy. | |
44 * | |
45 * @see http://en.wikipedia.org/wiki/HTTP_response_splitting | |
46 * @param string $value | |
47 * @return string | |
48 */ | |
49 public static function filter($value) | |
50 { | |
51 $value = (string) $value; | |
52 $length = strlen($value); | |
53 $string = ''; | |
54 for ($i = 0; $i < $length; $i += 1) { | |
55 $ascii = ord($value[$i]); | |
56 | |
57 // Detect continuation sequences | |
58 if ($ascii === 13) { | |
59 $lf = ord($value[$i + 1]); | |
60 $ws = ord($value[$i + 2]); | |
61 if ($lf === 10 && in_array($ws, [9, 32], true)) { | |
62 $string .= $value[$i] . $value[$i + 1]; | |
63 $i += 1; | |
64 } | |
65 | |
66 continue; | |
67 } | |
68 | |
69 // Non-visible, non-whitespace characters | |
70 // 9 === horizontal tab | |
71 // 32-126, 128-254 === visible | |
72 // 127 === DEL | |
73 // 255 === null byte | |
74 if (($ascii < 32 && $ascii !== 9) | |
75 || $ascii === 127 | |
76 || $ascii > 254 | |
77 ) { | |
78 continue; | |
79 } | |
80 | |
81 $string .= $value[$i]; | |
82 } | |
83 | |
84 return $string; | |
85 } | |
86 | |
87 /** | |
88 * Validate a header value. | |
89 * | |
90 * Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal | |
91 * tabs are allowed in values; header continuations MUST consist of | |
92 * a single CRLF sequence followed by a space or horizontal tab. | |
93 * | |
94 * @see http://en.wikipedia.org/wiki/HTTP_response_splitting | |
95 * @param string $value | |
96 * @return bool | |
97 */ | |
98 public static function isValid($value) | |
99 { | |
100 $value = (string) $value; | |
101 | |
102 // Look for: | |
103 // \n not preceded by \r, OR | |
104 // \r not followed by \n, OR | |
105 // \r\n not followed by space or horizontal tab; these are all CRLF attacks | |
106 if (preg_match("#(?:(?:(?<!\r)\n)|(?:\r(?!\n))|(?:\r\n(?![ \t])))#", $value)) { | |
107 return false; | |
108 } | |
109 | |
110 // Non-visible, non-whitespace characters | |
111 // 9 === horizontal tab | |
112 // 10 === line feed | |
113 // 13 === carriage return | |
114 // 32-126, 128-254 === visible | |
115 // 127 === DEL (disallowed) | |
116 // 255 === null byte (disallowed) | |
117 if (preg_match('/[^\x09\x0a\x0d\x20-\x7E\x80-\xFE]/', $value)) { | |
118 return false; | |
119 } | |
120 | |
121 return true; | |
122 } | |
123 | |
124 /** | |
125 * Assert a header value is valid. | |
126 * | |
127 * @param string $value | |
128 * @throws InvalidArgumentException for invalid values | |
129 */ | |
130 public static function assertValid($value) | |
131 { | |
132 if (! is_string($value) && ! is_numeric($value)) { | |
133 throw new InvalidArgumentException(sprintf( | |
134 'Invalid header value type; must be a string or numeric; received %s', | |
135 (is_object($value) ? get_class($value) : gettype($value)) | |
136 )); | |
137 } | |
138 if (! self::isValid($value)) { | |
139 throw new InvalidArgumentException(sprintf( | |
140 '"%s" is not valid header value', | |
141 $value | |
142 )); | |
143 } | |
144 } | |
145 | |
146 /** | |
147 * Assert whether or not a header name is valid. | |
148 * | |
149 * @see http://tools.ietf.org/html/rfc7230#section-3.2 | |
150 * @param mixed $name | |
151 * @throws InvalidArgumentException | |
152 */ | |
153 public static function assertValidName($name) | |
154 { | |
155 if (! is_string($name)) { | |
156 throw new InvalidArgumentException(sprintf( | |
157 'Invalid header name type; expected string; received %s', | |
158 (is_object($name) ? get_class($name) : gettype($name)) | |
159 )); | |
160 } | |
161 if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) { | |
162 throw new InvalidArgumentException(sprintf( | |
163 '"%s" is not valid header name', | |
164 $name | |
165 )); | |
166 } | |
167 } | |
168 } |