Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
request.php
1<?php
10
14
21class Request implements IRequestFilter
22{
23 const ACTION_NONE = 'none';
24 const ACTION_CLEAR = 'clear';
25 const ACTION_FILTER = 'filter';
26
28 protected $auditors = [];
29 protected $changedContext = [];
30
31 private $action = 'filter';
32 private $doLog = false;
33 private $changedVars = [];
34 private $isAuditorsTriggered = false;
35 private $filteringMap = [
36 'get' => [
37 'Name' => '$_GET',
38 ],
39 'post' => [
40 'Name' => '$_POST',
41 'SkipRegExp' => '#^File\d+_\d+$#',
42 ],
43 'cookie' => [
44 'Name' => '$_COOKIE',
45 ],
46 'json' => [
47 'Name' => 'JSON',
48 ],
49 'data' => [
50 'Name' => 'data',
51 ]
52 ];
53 private static $validActions = [
57 ];
58
59 public function __construct($customOptions = array())
60 {
61 if (isset($customOptions['action']))
62 {
63 $this->setAction($customOptions['action']);
64 }
65 else
66 {
67 $this->setAction(Option::get('security', 'filter_action'));
68 }
69
70 if (isset($customOptions['log']))
71 {
72 $this->setLog($customOptions['log']);
73 }
74 else
75 {
76 $this->setLog(Option::get('security', 'filter_log'));
77 }
78 }
79
86 public function setAuditors(array $auditors)
87 {
88 $this->auditors = $auditors;
89 return $this;
90 }
91
97 public function getChangedVars()
98 {
99 return $this->changedVars;
100 }
101
135 public function filter(array $values, $isReturnChangedOnly = true)
136 {
137 $this->onFilterStarted();
138
139 foreach ($values as $key => &$val)
140 {
141 if (!isset($this->filteringMap[$key]))
142 {
143 continue;
144 }
145
146 if (!is_array($val))
147 {
148 continue;
149 }
150
151 $val = $this->filterArray(
152 $key,
153 $val,
154 $this->filteringMap[$key]['Name'],
155 $this->filteringMap[$key]['SkipRegExp'] ?? ''
156 );
157 }
158 unset($val);
159
160 $this->onFilterFinished();
161
162 if ($isReturnChangedOnly)
163 {
164 return array_intersect_key($values, $this->changedContext);
165 }
166 return $values;
167 }
168
169
174 public function isAuditorsTriggered()
175 {
176 return $this->isAuditorsTriggered;
177 }
178
179 protected function onFilterStarted()
180 {
181 $this->changedContext = array();
182 $this->changedVars = array();
183 $this->isAuditorsTriggered = false;
184 }
185
186 protected function onFilterFinished()
187 {
188 }
189
196 protected function filterVar($context, $value, $name)
197 {
198 if (preg_match('#^[A-Za-z0-9_.,-]*$#D', $value))
199 return $value;
200
201 $filteredValue = \CSecurityHtmlEntity::decodeString($value);
202 self::adjustPcreBacktrackLimit($filteredValue);
203
204 $isValueChanged = false;
205 foreach($this->auditors as $auditName => $auditor)
206 {
207 if ($auditor->process($filteredValue))
208 {
209 $this->isAuditorsTriggered = true;
210
211 if ($this->isLogNeeded())
212 {
213 $this->logVariable($value, $name, $auditName);
214 }
215
216 if ($this->isFilterAction())
217 {
218 $isValueChanged = true;
219 $filteredValue = $auditor->getFilteredValue();
220 }
221 elseif ($this->isClearAction())
222 {
223 $isValueChanged = true;
224 $filteredValue = '';
225 break;
226 }
227 }
228 }
229
230 if ($isValueChanged)
231 {
232 $this->pushChangedVar($context, $value, $name);
233 return $filteredValue;
234 }
235 else
236 {
237 return $value;
238 }
239 }
240
248 protected function filterArray($context, ?array $array, $name, $skipKeyPreg = '')
249 {
250 if (!is_array($array))
251 {
252 return null;
253 }
254
255 foreach($array as $key => $value)
256 {
257 if ($skipKeyPreg && preg_match($skipKeyPreg, $key))
258 continue;
259
260 $filteredKey = $this->filterVar($context, $key, "{$name}['{$key}']");
261 if ($filteredKey != $key)
262 {
263 unset($array[$key]);
264 $key = $filteredKey;
265 }
266
267 if (is_array($value))
268 {
269 $array[$key] = $this->filterArray($context, $value, "{$name}['{$key}']", $skipKeyPreg);
270 }
271 else
272 {
273 $array[$key] = $this->filterVar($context, $value, "{$name}['{$key}']");
274 }
275 }
276 return $array;
277 }
278
283 protected static function isActionValid($action)
284 {
285 return in_array($action, self::getValidActions());
286 }
287
294 protected static function logVariable($value, $name, $auditorName)
295 {
296 return \CSecurityEvent::getInstance()->doLog('SECURITY', 'SECURITY_FILTER_'.$auditorName, $name, $value);
297 }
298
303 protected static function adjustPcreBacktrackLimit($string)
304 {
305 if (!is_string($string))
306 return false;
307
308 $strlen = strlen($string) * 2;
310 return true;
311 }
312
316 protected static function getValidActions()
317 {
318 return self::$validActions;
319 }
320
325 protected function setAction($action)
326 {
327 if (self::isActionValid($action))
328 {
329 $this->action = $action;
330 }
331 return $this;
332 }
333
338 protected function setLog($log)
339 {
340 $this->doLog = (is_string($log) && $log == 'Y');
341 return $this;
342 }
343
347 protected function isFilterAction()
348 {
349 return ($this->action === self::ACTION_FILTER);
350 }
351
355 protected function isClearAction()
356 {
357 return ($this->action === self::ACTION_CLEAR);
358 }
359
363 protected function isLogNeeded()
364 {
365 return $this->doLog;
366 }
367
374 protected function pushChangedVar($context, $value, $name)
375 {
376 $this->changedVars[$name] = $value;
377 if (!isset($this->changedContext[$context]))
378 $this->changedContext[$context] = 1;
379 return $this;
380 }
381}
static adjustPcreBacktrackLimit(int $val)
Definition ini.php:45
setAuditors(array $auditors)
Definition request.php:86
filterArray($context, ?array $array, $name, $skipKeyPreg='')
Definition request.php:248
static logVariable($value, $name, $auditorName)
Definition request.php:294
static isActionValid($action)
Definition request.php:283
filterVar($context, $value, $name)
Definition request.php:196
filter(array $values, $isReturnChangedOnly=true)
Definition request.php:135
__construct($customOptions=array())
Definition request.php:59
pushChangedVar($context, $value, $name)
Definition request.php:374
static adjustPcreBacktrackLimit($string)
Definition request.php:303