PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.3.1
CloudSecure WP Security v1.3.1
1.4.10 1.4.9 trunk 0.9.0 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.22 1.3.23 1.3.24 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8
cloudsecure-wp-security / modules / waf-engine.php
cloudsecure-wp-security / modules Last commit date
admin 1 year ago lib 1 year ago captcha.php 2 years ago cloudsecure-wp.php 1 year ago common.php 1 year ago config.php 2 years ago disable-access-system-file.php 1 year ago disable-author-query.php 2 years ago disable-login.php 1 year ago disable-restapi.php 2 years ago disable-xmlrpc.php 2 years ago htaccess.php 1 year ago login-log.php 1 year ago login-notification.php 1 year ago rename-login-page.php 2 years ago restrict-admin-page.php 1 year ago server-error-notification.php 1 year ago two-factor-authentication.php 1 year ago unify-messages.php 2 years ago update-notice.php 2 years ago waf-engine.php 1 year ago waf.php 1 year ago
waf-engine.php
754 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class CloudSecureWP_Waf_Engine extends CloudSecureWP_Common {
8 protected const VARIABLE_ARGS = 'args';
9 protected const VARIABLE_ARGS_NAMES = 'args_names';
10 protected const VARIABLE_REQUEST_COOKIES = 'request_cookies';
11 protected const VARIABLE_REQUEST_COOKIES_NAMES = 'request_cookies_names';
12 protected const VARIABLE_REQUEST_HEADERS = 'request_headers';
13 protected const VARIABLE_REQUEST_FILENAME = 'request_filename';
14 protected const VARIABLE_XML = 'xml';
15 private $parsed_xml;
16
17
18
19 function __construct( array $info ) {
20 parent::__construct( $info );
21
22 }
23
24
25 /**
26 * XML パース時のコールバック関数
27 *
28 * @return void
29 */
30 public function char( $parser, $data ): void {
31 $this->parsed_xml .= $data;
32 }
33
34
35 /**
36 * XML パース
37 *
38 * @return string
39 */
40 public function xml_parser(): string {
41 $request_body = file_get_contents( 'php://input' );
42 $this->parsed_xml = '';
43
44 if ( ! empty( $request_body ) ) {
45 $parser = xml_parser_create();
46
47 xml_set_object( $parser, $this );
48 xml_set_character_data_handler( $parser, 'char' );
49
50 if ( ! xml_parse( $parser, $request_body ) ) {
51 $this->parsed_xml .= 'xml_parse_failed';
52 };
53
54 xml_parser_free( $parser );
55 }
56
57 return $this->parsed_xml;
58 }
59
60
61 /**
62 * ARGS、ARGS_NAMES 用 クエリ文字列、POSTデータ取得
63 *
64 * @return array
65 */
66 public function get_request_args_data(): array {
67 $args = array();
68
69 if ( ! empty( $_GET ) ) {
70 $args = $_GET;
71 }
72
73 if ( ! empty( $_POST ) ) {
74 $args = array_merge( $args, $_POST );
75
76 } else {
77 $post_data = file_get_contents( 'php://input' );
78
79 if ( ! empty( $post_data ) ) {
80 $json_decoded_post_data = json_decode( $post_data, true );
81
82 // nullでなければjsonとなる
83 if ( isset( $json_decoded_post_data ) ) {
84 $args = array_merge( $args, $json_decoded_post_data );
85 }
86 }
87 }
88
89 return $args;
90 }
91
92
93 /**
94 * Cookie�
95 報取得
96 *
97 * @return array
98 */
99 public function get_request_cookies(): array {
100 if ( ! empty( $_COOKIE ) ) {
101 return $_COOKIE;
102 } else {
103 return array();
104 }
105 }
106
107
108 /**
109 * リクエスト�
110 報取得
111 * 取得・パースできなかったものに関しては空白で返す
112 *
113 * @return array
114 */
115 public function get_request_items(): array {
116 $request_items = array(
117 'access_at' => current_time( 'mysql' ),
118 'ip' => $this->get_client_ip(),
119 self::VARIABLE_XML => $this->xml_parser(),
120 self::VARIABLE_REQUEST_FILENAME => $this->get_request_uri(),
121 self::VARIABLE_REQUEST_HEADERS => $this->get_http_request_headers(),
122 self::VARIABLE_ARGS => $this->get_request_args_data(),
123 self::VARIABLE_REQUEST_COOKIES => $this->get_request_cookies(),
124 );
125
126 return $request_items;
127 }
128
129
130 /**
131 * ルールの設定を参考に1つのリクエスト�
132 報に対して複数の変換を行う処理
133 *
134 * @param array $transformations
135 * @param string $request_item
136 * @return string
137 */
138 public function transform( $transformations, $request_item ): string {
139 $converted_request_item = $request_item;
140
141 foreach ( $transformations as $transformation ) {
142 switch ( $transformation ) {
143 case 'htmlentitydecode':
144 $converted_request_item = html_entity_decode( $converted_request_item, ENT_QUOTES, 'utf-8' );
145 break;
146 case 'lowercase':
147 $converted_request_item = strtolower( $converted_request_item );
148 break;
149 case 'replacecomments':
150 $converted_request_item = preg_replace( '/(\/\*.*?\*\/|\/\*.*(?!\*\/).*)/s', ' ', $converted_request_item );
151 break;
152 case 'compresswhitespace':
153 $converted_request_item = preg_replace( '/(\s|\xa0)/s', ' ', $converted_request_item );
154 $converted_request_item = preg_replace( '/\s{2,}/s', ' ', $converted_request_item );
155 break;
156 default:
157 $converted_request_item = '変換に失敗しました';
158 break 2;
159 }
160 }
161
162 return $converted_request_item;
163 }
164
165
166 /**
167 * LocationMatch設定によるルールのスキップ用関数
168 *
169 * @param array $locationmatch_rules
170 * @param string $request_uri
171 * @return array
172 */
173 public function locationmatch_remove_rules( $locationmatch_rules, $request_uri ): array {
174 $locationmatch_removed_rule_ids = array();
175
176 foreach ( $locationmatch_rules as $locationmatch_rule ) {
177 if ( preg_match( '/' . $locationmatch_rule['path'] . '/', $request_uri ) ) {
178 $locationmatch_removed_rule_ids = array_merge( $locationmatch_removed_rule_ids, $locationmatch_rule['remove_rule_ids'] );
179 }
180 }
181
182 $locationmatch_removed_rule_ids = array_unique( $locationmatch_removed_rule_ids );
183
184 return $locationmatch_removed_rule_ids;
185 }
186
187
188 /**
189 * skip表記の存在確認
190 *
191 * @param int $skip
192 * @return int
193 */
194 public function check_skip( $skip ): int {
195 if ( $skip !== 0 ) {
196 return $skip;
197 } else {
198 return 0;
199 }
200 }
201
202
203 /**
204 * skipafter表記の存在確認
205 *
206 * @param string $skipafter
207 * @return string
208 */
209 public function check_skipafter( $skipafter ): string {
210 if ( ! empty( $skipafter ) ) {
211 return $skipafter;
212 } else {
213 return '';
214 }
215 }
216
217
218 /**
219 * skipが有効か判定
220 *
221 * @param int $skip
222 * @return bool
223 */
224 public function is_skip_enabled( $skip ): bool {
225 if ( 0 < $skip ) {
226 return true;
227 } else {
228 return false;
229 }
230 }
231
232
233 /**
234 * skipafterが有効か判定
235 *
236 * @param string $skipafter
237 * @return bool
238 */
239 public function is_skipafter_enabled( $skipafter ): bool {
240 if ( ! empty( $skipafter ) ) {
241 return true;
242 } else {
243 return false;
244 }
245 }
246
247 /**
248 * ルールが終了したか判定
249 *
250 * @param string $chain
251 * @param string $skip
252 * @param string $skipafter
253 * @return bool
254 */
255 public function is_rule_finished( $chain, $skip, $skipafter ): bool {
256 if ( ! empty( $chain ) || $this->is_skip_enabled( $skip ) || $this->is_skipafter_enabled( $skipafter ) ) {
257 return false;
258 } else {
259 return true;
260 }
261 }
262
263
264 /**
265 * ルール�
266 に除外の表記があるか確認
267 *
268 * @param array $remove_variables
269 * @param string $variable
270 * @param string $request_item
271 * @return bool
272 */
273 public function is_remove_variables( $remove_variables, $variable, $request_item ): bool {
274 if ( ! empty( $remove_variables ) ) {
275 foreach ( $remove_variables as $remove_variable => $remove_values ) {
276 if ( $remove_variable === $variable ) {
277 foreach ( $remove_values as $remove_value ) {
278
279 // REQUEST_HEADERSの場合は大文字小文字関係なく判定する
280 if ( $variable === self::VARIABLE_REQUEST_HEADERS ) {
281 if ( preg_match( '/' . $remove_value . '/i', $request_item ) ) {
282 return true;
283 }
284 }
285
286 if ( preg_match( '/^\/.+\/$/', $remove_value ) ) {
287 // 除外の値が部分一致(/で囲まれているもの)の場合
288 if ( preg_match( $remove_value . 's', $request_item ) ) {
289 return true;
290 }
291 } else {
292 // 除外の値が完�
293 �一致の場合
294 if ( $remove_value === $request_item ) {
295 return true;
296 }
297 }
298 }
299 }
300 }
301 }
302
303 return false;
304 }
305
306 /**
307 * マッチした結果を�
308 �列に格納
309 *
310 * @param array $rule
311 * @param array $request_items
312 * @param string $variable
313 * @param string $match_string
314 * @return array
315 */
316 public function get_match_results( $rule, $request_items, $variable, $match_string ): array {
317
318 if ( isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_URI'] ) ) {
319 $complete_url = ( empty( $_SERVER['HTTPS'] ) ? 'http://' : 'https://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
320 } else {
321 $complete_url = '';
322 }
323
324 $match_results = array(
325 'id' => $rule['id'],
326 'attack' => $rule['attack'],
327 'variable' => $variable,
328 'matched' => $match_string,
329 'ip' => $request_items['ip'],
330 'access_at' => $request_items['access_at'],
331 'url' => $complete_url,
332 );
333
334 return $match_results;
335 }
336
337
338 /**
339 * chain_itemsの取得
340 *
341 * @param array $rule
342 * @return array
343 */
344 public function get_chain_items( $rule ): array {
345 $chain_items = array(
346 'id' => $rule['id'],
347 'attack' => $rule['attack'],
348 'skip' => $rule['skip'],
349 'skipafter' => $rule['skipafter'],
350 );
351
352 return $chain_items;
353 }
354
355
356 /**
357 * マッチしたルールの設定、結果を取得
358 *
359 * @param array $waf_rule
360 * @param array $request_items
361 * @param string $variable
362 * @param array $chain_items
363 * @param array $match_string
364 * @return array
365 */
366 public function get_rule_settings_and_results( $waf_rule, $request_items, $variable, $chain_items, $match_string ): array {
367 $results = array(
368 'is_matched' => true,
369 'chain_items' => array(),
370 'skip' => 0,
371 'skipafter' => '',
372 'match_results' => array(),
373 );
374
375 // 前ルールからchainの設定を引き継いでいるか確認
376 if ( ! empty( $chain_items ) ) {
377 if ( $waf_rule['attack'] === '' && $this->is_rule_finished( $waf_rule['chain'], $waf_rule['skip'], $waf_rule['skipafter'] ) ) {
378 // ルールの終了判定がtrueではあるが、攻撃種別が設定されていない場合はマッチ用のルールではないのでマッチしていないと判定
379 $results['is_matched'] = false;
380
381 } elseif ( $this->is_rule_finished( $waf_rule['chain'], $chain_items['skip'], $chain_items['skipafter'] ) ) {
382 $results['match_results'] = $this->get_match_results( $chain_items, $request_items, $variable, $match_string );
383
384 } elseif ( $waf_rule['chain'] ) {
385 // 現在のルールにchainの設定がある場合
386 $results['chain_items'] = $chain_items;
387
388 } else {
389 $results['skip'] = $this->check_skip( $chain_items['skip'] );
390 $results['skipafter'] = $this->check_skipafter( $chain_items['skipafter'] );
391 }
392 } else {
393 if ( $waf_rule['attack'] === '' && $this->is_rule_finished( $waf_rule['chain'], $waf_rule['skip'], $waf_rule['skipafter'] ) ) {
394 // ルールの終了判定がtrueではあるが、攻撃種別が設定されていない場合はマッチ用のルールではないのでマッチしていないと判定
395 $results['is_matched'] = false;
396
397 } elseif ( $this->is_rule_finished( $waf_rule['chain'], $waf_rule['skip'], $waf_rule['skipafter'] ) ) {
398 $results['match_results'] = $this->get_match_results( $waf_rule, $request_items, $variable, $match_string );
399
400 } elseif ( $waf_rule['chain'] ) {
401 // 現在のルールにchainの設定がある場合
402 $results['chain_items'] = $this->get_chain_items( $waf_rule );
403
404 } else {
405 $results['skip'] = $this->check_skip( $waf_rule['skip'] );
406 $results['skipafter'] = $this->check_skipafter( $waf_rule['skipafter'] );
407 }
408 }
409 return $results;
410 }
411
412 /**
413 * ネストした�
414 �列をパース
415 *
416 * @param string $name
417 * @param array $array
418 */
419 public function parse_array( $name, $array ) {
420 $parsed_array = array();
421
422 foreach ( $array as $key => $val ) {
423 if ( is_array( $val ) ) {
424 $tmp_name = $name . '[' . $key . ']';
425 $tmp_parsed_array = $this->parse_array( $tmp_name, $val );
426 $parsed_array = array_merge( $parsed_array, $tmp_parsed_array );
427
428 } else {
429 $parsed_array_key = $name . '[' . $key . ']';
430 $parsed_array[ $parsed_array_key ] = $val;
431 }
432 }
433 return $parsed_array;
434 }
435
436
437 /**
438 * リクエスト�
439 報�
440 �列を使用するルール判定
441 *
442 * @param array $waf_rule
443 * @param array $request_items
444 * @param string $variable
445 * @param array $chain_items
446 * @return array
447 */
448 public function check_request_item_array( $waf_rule, $request_items, $variable, $chain_items ) {
449 $results = array(
450 'is_matched' => false,
451 'chain_items' => array(),
452 'skip' => 0,
453 'skipafter' => '',
454 'match_results' => array(),
455 );
456
457 $get_request_item_variable = preg_replace( '/_names/', '', $variable );
458
459 if ( ! isset( $get_request_item_variable ) ) {
460 return $results;
461 }
462
463 foreach ( $request_items[ $get_request_item_variable ] as $key => $val ) {
464 switch ( $variable ) {
465
466 case self::VARIABLE_ARGS:
467 case self::VARIABLE_REQUEST_COOKIES:
468 case self::VARIABLE_REQUEST_HEADERS:
469 if ( is_array( $val ) ) {
470 $parsed_vals = $this->parse_array( $key, $val );
471
472 foreach ( $parsed_vals as $key => $val ) {
473 $checked_request_item = $this->check_request_item_value( $waf_rule, $key, $val, $variable );
474
475 if ( $checked_request_item['is_matched'] ) {
476 $results = $this->get_rule_settings_and_results( $waf_rule, $request_items, $variable, $chain_items, $checked_request_item['match_string'] );
477 break;
478 }
479 }
480
481 } else {
482 $checked_request_item = $this->check_request_item_value( $waf_rule, $key, $val, $variable );
483 }
484
485 break;
486
487 case self::VARIABLE_ARGS_NAMES:
488 case self::VARIABLE_REQUEST_COOKIES_NAMES:
489 $checked_request_item = $this->check_request_item_key( $waf_rule, $key, $variable );
490 break;
491 }
492
493 if ( $checked_request_item['is_matched'] ) {
494 $results = $this->get_rule_settings_and_results( $waf_rule, $request_items, $variable, $chain_items, $checked_request_item['match_string'] );
495
496 break;
497 }
498 }
499 return $results;
500 }
501
502
503
504 /**
505 * リクエスト�
506 報�
507 �列のうちvalueの値を使用するルール判定
508 *
509 * @param array $waf_rule
510 * @param string $request_items_key
511 * @param string $request_items_value
512 * @param string $variable
513 * @return array
514 */
515 public function check_request_item_value( $waf_rule, $request_items_key, $request_items_value, $variable ): array {
516 $results['is_matched'] = false;
517 $matches = array();
518
519 // リクエスト�
520 報�
521 �列のkeyとvalueの変換
522 $tmp_key = $this->transform( $waf_rule['transformations'], $request_items_key );
523 $tmp_val = $this->transform( $waf_rule['transformations'], $request_items_value );
524
525 if ( preg_match( '/' . $waf_rule['regex_pattern'] . '/s', $tmp_val, $matches ) ) {
526 if ( ! empty( $matches ) ) {
527 if ( false === $this->is_remove_variables( $waf_rule['remove_variables'], $variable, $tmp_key ) ) {
528 // 除外の設定が無ければマッチしたと判定
529 $results['is_matched'] = true;
530 $results['match_string'] = $matches[0];
531 }
532 }
533 }
534
535 return $results;
536 }
537
538
539 /**
540 * リクエスト�
541 報�
542 �列のうちkeyの値を使用するルール判定
543 *
544 * @param array $waf_rule
545 * @param string $request_items_key
546 * @param string $variable
547 * @return array
548 */
549 public function check_request_item_key( $waf_rule, $request_items_key, $variable ): array {
550 $results['is_matched'] = false;
551 $matches = array();
552
553 // リクエスト�
554 報�
555 �列のkeyの変換
556 $tmp_key = $this->transform( $waf_rule['transformations'], $request_items_key );
557
558 if ( preg_match( '/' . $waf_rule['regex_pattern'] . '/s', $tmp_key, $matches ) ) {
559 if ( ! empty( $matches ) ) {
560 if ( false === $this->is_remove_variables( $waf_rule['remove_variables'], $variable, $tmp_key ) ) {
561 // 除外の設定が無ければマッチしたと判定
562 $results['is_matched'] = true;
563 $results['match_string'] = $matches[0];
564 }
565 }
566 }
567
568 return $results;
569 }
570
571
572 /**
573 * リクエスト�
574 報�
575 �列のうち文字列の値を使用するルール判定
576 *
577 * @param array $waf_rule
578 * @param array $request_items
579 * @param string $variable
580 * @param array $chain_items
581 * @return array
582 */
583 public function check_request_item_strings( $waf_rule, $request_items, $variable, $chain_items ): array {
584 $results = array(
585 'is_matched' => false,
586 'chain_items' => array(),
587 'skip' => 0,
588 'skipafter' => '',
589 'match_results' => array(),
590 );
591
592 if ( empty( $request_items[ $variable ] ) ) {
593 return $results;
594 }
595
596 if ( $variable === self::VARIABLE_XML ) {
597 if ( $request_items[ self::VARIABLE_XML ] === 'xml_parse_failed' ) {
598 return $results;
599 } else {
600 $request_items[ self::VARIABLE_XML ] = str_replace( 'xml_parse_failed', '', $request_items[ self::VARIABLE_XML ] );
601 }
602 }
603
604 // リクエスト�
605 報の変換
606 $tmp_string = $this->transform( $waf_rule['transformations'], $request_items[ $variable ] );
607
608 // REQUEST_FILENAMEに関しては、urlデコード済の値も判定し、マッチしたら結果を出力
609 if ( $variable === self::VARIABLE_REQUEST_FILENAME ) {
610 // リクエスト�
611 報のデコード&変換
612 $request_items_urldecoded = urldecode( $request_items[ $variable ] );
613 $tmp_urldecoded = $this->transform( $waf_rule['transformations'], $request_items_urldecoded );
614
615 if ( preg_match( '/' . $waf_rule['regex_pattern'] . '/s', $tmp_urldecoded, $matches ) ) {
616 if ( ! empty( $matches ) ) {
617 $results = $this->get_rule_settings_and_results( $waf_rule, $request_items, $variable, $chain_items, $matches[0] );
618 return $results;
619 }
620 }
621 }
622
623 if ( false === preg_match( '/' . $waf_rule['regex_pattern'] . '/s', $tmp_string, $matches ) ) {
624 // preg_matchが失敗したときは終了
625 return $results;
626 }
627
628 if ( empty( $matches ) ) {
629 // 正規表現パターンにマッチしなければ終了
630 return $results;
631 }
632
633 $results = $this->get_rule_settings_and_results( $waf_rule, $request_items, $variable, $chain_items, $matches[0] );
634
635 return $results;
636 }
637
638 public function waf_engine( $waf_rules, $locationmatch_rules, $available_rules ) {
639 $request_items = $this->get_request_items();
640
641 $locationmatch_removed_rule_ids = $this->locationmatch_remove_rules( $locationmatch_rules, $_SERVER['REQUEST_URI'] ?? '' );
642 $skip = 0;
643 $skipafter = '';
644 $chain_items = array();
645
646 foreach ( $waf_rules as $waf_rule ) {
647 // 前回マッチしたルールからskipの設定を引き継いでいる場合はスキップ
648 if ( $this->is_skip_enabled( $skip ) ) {
649 $skip--;
650 continue;
651 }
652
653 // 前回マッチしたルールからskipafterの設定を引き継いでいる場合は現在のルールIDと比較し、一致するまでスキップ
654 // ルールIDの比較結果が同じの場合は、$skipafterを初期化して次のルールから判定を行う
655 if ( $this->is_skipafter_enabled( $skipafter ) ) {
656 if ( $skipafter !== $waf_rule['id'] ) {
657 continue;
658 } else {
659 $skipafter = '';
660 continue;
661 }
662 }
663
664 // LocationMatchによるルールの除外があるか確認。ある場合は現在のルールIDと比較し、一致する場合はスキップ
665 if ( ! empty( $locationmatch_removed_rule_ids ) ) {
666 if ( in_array( $waf_rule['id'], $locationmatch_removed_rule_ids, true ) ) {
667 continue;
668 }
669 }
670
671 // ルールにvariables設定がない場合、skip,akipafterの設定を確認して次のルール判定へ
672 if ( empty( $waf_rule['variables'] ) ) {
673 $skip = $this->check_skip( $waf_rule['skip'] );
674 $skipafter = $this->check_skipafter( $waf_rule['skipafter'] );
675 continue;
676 }
677
678 foreach ( $waf_rule['variables'] as $variable ) {
679 switch ( $variable ) {
680 case self::VARIABLE_ARGS:
681 $results = $this->check_request_item_array( $waf_rule, $request_items, self::VARIABLE_ARGS, $chain_items );
682 break;
683
684 case self::VARIABLE_ARGS_NAMES:
685 $results = $this->check_request_item_array( $waf_rule, $request_items, self::VARIABLE_ARGS_NAMES, $chain_items );
686 break;
687
688 case self::VARIABLE_REQUEST_COOKIES:
689 $results = $this->check_request_item_array( $waf_rule, $request_items, self::VARIABLE_REQUEST_COOKIES, $chain_items );
690 break;
691
692 case self::VARIABLE_REQUEST_COOKIES_NAMES:
693 $results = $this->check_request_item_array( $waf_rule, $request_items, self::VARIABLE_REQUEST_COOKIES_NAMES, $chain_items );
694 break;
695
696 case self::VARIABLE_REQUEST_HEADERS:
697 $results = $this->check_request_item_array( $waf_rule, $request_items, self::VARIABLE_REQUEST_HEADERS, $chain_items );
698 break;
699
700 case self::VARIABLE_REQUEST_FILENAME:
701 $results = $this->check_request_item_strings( $waf_rule, $request_items, self::VARIABLE_REQUEST_FILENAME, $chain_items );
702 break;
703
704 case self::VARIABLE_XML:
705 $results = $this->check_request_item_strings( $waf_rule, $request_items, self::VARIABLE_XML, $chain_items );
706 break;
707 }
708
709 $is_matched = $results['is_matched'];
710
711 if ( $is_matched ) {
712 $skip = $results['skip'];
713 $skipafter = $results['skipafter'];
714 $chain_items = $results['chain_items'];
715 $match_results = $results['match_results'];
716
717 // マッチしたが、chain,skip,skipafterの設定がある場合は次のルール判定へ
718 if ( ! empty( $chain_items ) || 0 < $skip || ! empty( $skipafter ) ) {
719 break;
720 }
721
722 // マッチしたが、除外設定されているルールの場合は値を保持して次のルール判定へ
723 if ( ( $waf_rule['attack'] & $available_rules ) === 0 ) {
724 $tmp_match_results = $match_results;
725 break;
726 }
727
728 // マッチした結果がある場合は終了処理へ(ログ記述、通知、画面表示)
729 if ( ! empty( $match_results ) ) {
730 $match_results['is_deny'] = true;
731 $match_results['is_write_log'] = true;
732
733 return $match_results;
734 }
735 }
736
737 $chain_items = array();
738 }
739 }
740
741 if ( ! empty( $tmp_match_results ) ) {
742 $match_results = $tmp_match_results;
743 $match_results['is_deny'] = false;
744 $match_results['is_write_log'] = true;
745
746 } else {
747 $match_results['is_deny'] = false;
748 $match_results['is_write_log'] = false;
749 }
750
751 return $match_results;
752 }
753 }
754