Фильтрация POST&GET или xss защита

Собственно наткнувшись на основном форуме на топик о фильтрации POST запросов у меня возник вопрос. А как в Yii фильтровать данные? Почти во всех фреймворках есть встроенные классы xss защиты… в Yii нету.

qiang советует напрямую заюзать filter_input, товарищ jimezam предложил связку Yii с Kohana, чтобы пользоваться функциями Kohan'ы…

Последний вариант кажется удобным, но как-то не хочется в проект еще и кохану втыкать…

Может у кого есть идеи на этот счет? Или готовые варианты?

я сейчас как раз пишу такой фильтр (именно как фильтр будет работать)…

Начинку (регулярки, которые все и фильтруют - взял их Kohana 2.3.1)…

Думаю за выходные допишу (к сожалению раньше не получится)…

Андрей, если закончишь и выложишь как экстеншн - большой респект :)

А поподробнее про данный варинат защиты где почитать, а то по ходу у мен в образовании пробел… Ну что такое XSS я знаю, а вот как защищаться - не.

Как правило для защиты от атаки подобного рода достаточно более тщательно вычистить от нежелательных символов входные данные…тут можно поступать двумя способами:

  1. Вычищать данные при сохранении (например инсерт в базу)

  2. Вычищать данные при отображение (при выводе на страницу)

Лично я предпочитаю первый способ - для чего хранить ненужные мне данные )))…

Вот код, который используется в kohana (один из вариантов xss_clean)



	$data = preg_replace('#([a-z]*)[x00-x20]*=[x00-x20]*([`'"]*)[x00-x20]*j[x00-x20]*a[x00-x20]*v[x00-x20]*a[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2nojavascript...', $data);


				$data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*v[x00-x20]*b[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2novbscript...', $data);


				$data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*-moz-​binding[x00-x20]*:#u', '$1=$2nomozbinding...', $data);





				// Only works in IE: <span style="width: exp​ression(alert('Ping!'));"></span>


				$data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?exp​ression[x00-x20]*([^>]*+>#i', '$1>', $data);


				$data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?behaviour[x00-x20]*([^>]*+>#i', '$1>', $data);


				$data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:*[^>]*+>#iu', '$1>', $data);





				// Remove namespaced elements (we do not need them)


				$data = preg_replace('#</*w+:w[^>]*+>#i', '', $data);





				do


				{


					// Remove really unwanted tags


					$old_data = $data;


					$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);


				}


				while ($old_data !== $data);


Красота, срочно нужен фильтр :)

А то я проект собираюсь сдвать, там это есть, но примитивно, без отлова экзотики типа <span style="width: exp​ression(alert('Ping!'));"></span>

я о таком даже не знал :)

Нужно ли изобретать велосипед или проще почитать досконально доку? Yii содержит “из коробки” компонент CHtmlPurifier, который в свою очередь является оберткой для библиотеки HTML Purifier. Библиотека предназначена для защиты от XSS атак. Компонент работает как фильтр и как виджет.

Ну разговор шел больше не о том КАК обрабатывать, а именно чтобы встроить в Yii фильтр. Мне вот влом на каждый GET и POST запрос вешать html purifier вручную… хочется чтобы он отрабатывал сам…

а вообще, так, по хорошему - надо бы написать класс который на себя возьмет обработку этих запросов. А то для такого фреймворка код типа $_POST['lalala'] не оч красиво… лучше бы что-то типа Yii::request()->lalala или на подобии…

И если мне память не изменяет - CHtmlPurifier используется для обработки данных перед выводом пользователю, а не перед вставкой в базу. это раз. и во вторых - он громоздкий и тормознутый… имхо не лучший вариант при оптимизации скорости…

  1. Ну я думаю, что его можно юзать и для обработки перед вставкой в базу (доки еще не читал)

  2. А что межает наследовать класс запроса и повесить по событию начала обработки обработку данных? Или можно не морочиться с наследованием, а прицепить поведение (Behaviour), которое приаттачится к событиям и будет обрабатывать вход с помощью того же CtmlPurifier

  3. Между прочим, заюзать CHtmlPurifier в фильтре - вообще запросто. Только проблема - фильтр надо будет в каждом контроллере прописывать. Хотя может это и удобно, может ыть будут действия, где фильтрация не понадобится, их можно добавить в исключения фильтра

Quote

Компонент работает как фильтр и как виджет.

Не дочитал, даже писать ниче не надо. Что медленно - так в доках написано:

Quote

Note: since HTML Purifier is a big package, its performance is not very good. You should consider either caching the purification result or purifying the user input before saving to database.

Сохраняем перед вставкой в БД и все дела.

Но можно, конечно, написать что-то типа того что Андрей показал, наверное быстрее будет :)

Друзья, вот мой вариант фильтра (по функционалу он получился проще, чем я планировал изначально, но зато можно его проверить уже сейчас)…



<?php


  /**


   *  @author  Opeykin A. <andrey.opeykin.ru> <aopeykin@gmail.com>


   *  @version 0.0.1


   *  @package filters


   *


   * Фильтр предназначен для фильтрации входных данных, c целью предотвратить xss атаки.


   * Для фильтрации используются регулярные выражения из фреймворка Kohana 2.3.1


   * @example


   *


   *  public function filters()


   *  {


   *         return array(


   *                 array('application.filters.XssFilter',


   *                       'clean' => 'all'


   *                 )


   *         );


   *


   *   }


   *


   *   В качетве параметра 'clean' могут быть:


   *  - 'all' - фильтруются GET,POST,COOKIE,FILES массивы;


   *  - '*'   - аналог ALL;


   *  - так же возможно сочетание любых из параметров, например GET,COOKIE или POST,FILES  


   */





class XssFilter extends CFilter


{





        public  $clean = 'all';       





        protected function preFilter($filterChain)


        {              


                $this->clean  = trim(strtoupper($this->clean));


                $data = array(


                         'GET'    => &$_GET,


                         'POST'   => &$_POST,


                         'COOKIE' => &$_COOKIE,


                         'FILES'  => &$_FILES


                );


                


                if($this->clean === 'ALL' || $this->clean === '*')


                {                        


                        $this->clean = 'GET,POST,COOKIE,FILES';


                }





                $dataForClean = split(',',$this->clean);


                if(count($dataForClean))


                {                 


                        foreach ($dataForClean as $key => $value)


                        {                 


                                if(isset ($data[$value]) && count($data[$value]))


                                {


                                        $this->doXssClean($data[$value]);


                                }


                        }


                }





              return true;


        }


        





        protected function postFilter($filterChain)


        {


                // logic being applied after the action is executed


        }








        private function doXssClean(&$data)


        {


                if(is_array($data) && count($data))


                {                       


                       foreach($data as $k => $v)


                       {


                               $data[$k] = $this->doXssClean($v);


                       }


                       return $data;


                }





                if(trim($data) === '')


                {


                        return $data;


                }





                // xss_clean function from Kohana framework 2.3.1                


                $data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $data);


                $data = preg_replace('/(&#*w+)[x00-x20]+;/u', '$1;', $data);


                $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);


                $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');


                // Remove any attribute starting with "on" or xmlns


                $data = preg_replace('#(<[^>]+?[x00-x20"'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);


                // Remove javascript: and vbscript: protocols


                $data = preg_replace('#([a-z]*)[x00-x20]*=[x00-x20]*([`'"]*)[x00-x20]*j[x00-x20]*a[x00-x20]*v[x00-x20]*a[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2nojavascript...', $data);


                $data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*v[x00-x20]*b[x00-x20]*s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:#iu', '$1=$2novbscript...', $data);


                $data = preg_replace('#([a-z]*)[x00-x20]*=(['"]*)[x00-x20]*-moz-​binding[x00-x20]*:#u', '$1=$2nomozbinding...', $data);


                // Only works in IE: <span style="width: exp​ression(alert('Ping!'));"></span>


                $data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?exp​ression[x00-x20]*([^>]*+>#i', '$1>', $data);


                $data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?behaviour[x00-x20]*([^>]*+>#i', '$1>', $data);


                $data = preg_replace('#(<[^>]+?)style[x00-x20]*=[x00-x20]*[`'"]*.*?s[x00-x20]*c[x00-x20]*r[x00-x20]*i[x00-x20]*p[x00-x20]*t[x00-x20]*:*[^>]*+>#iu', '$1>', $data);


                // Remove namespaced elements (we do not need them)


                $data = preg_replace('#</*w+:w[^>]*+>#i', '', $data);


                do


                {


                        // Remove really unwanted tags


                        $old_data = $data;


                        $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);


                }


                while ($old_data !== $data);                


                return $data;


        }





}


?>





а вот тут (http://andrey.opeykin.ru/yii-xss-filter/)  маленькая статья про фильтры в Yii и в частности про этот xss-фильтр…

Респект тебе :) ща заюзаю ;)

Работает  ;D

к стати, а можно фильтр повесить на модуль? чето лень в каждый контроллер пихать фильтр

Quote

Работает  ;D

к стати, а можно фильтр повесить на модуль? чето лень в каждый контроллер пихать фильтр

я тоже думал над этим вопросом…помню очень давно, когда я пытался учить Java и в частности сервлеты - там  тоже были фильтры, которые настраивались в конфигурационном файле (т.е. можно было указать правила, что-то типа роутинга в Yii, например можно было “сказать” так : для всех УРЛ-ов, начинающихся с “admin” - необходимо выполнить фильтр XssClean). Как мне кажется в Yii  этого нет…Было бы не плохо эсли бы кто-нибудь это сделал  ;)

Можно контроллеры модуля наследовать от одного базового контроллера, в котором прописать фильтр.

Я еще не тестил, но то что есть - это круто :) Молодец!