Архив рубрики: Разработка

Yii, пишем фильтр для предотвращения XSS атак.

Начну с небольшого отступления.

И все таки правильно говорят, а на некторых форумах (особенно UNIX-овых), прямо кричат — RTFM! Кто не понял очем идет речь — RTFM в переводе означает «читай эту чертову документацию!».  Это все я собственно вот к чему: изучая и что-то пытаясь написать на фреймворке Yii,  возникла задача фильтрации входных данных от различного рода «зловредных» символов (аля XSS-атака) и первое что пришло в голову — это написать свой фильтр (что я все таки и сделал), однако creocoder, на форуме Yii , совершенно спрпаведливо заметил, что не зачем изобретать велосипед, все уже есть готовое, необходимо только RTFM! Речь шла о классе CHtmlPurifier, который является оберткой для библиотеки HTML Purifier , и выполняет все те функции, которые мне необходимы (правда я так и не попробывал его в действии, может и зря конечно). Но раз уж я начал писать свой фильтр — решил все таки это дело завершить, да и просто написать статью о фильтрах в Yii.

И так!

Фильтры — фрагменты кода, которые могут быть выполнены до и\или после выполнения экшена  контроллера.  Фильтры, при необходимости, могут  не допустить выполнения запрошенного экшена.

Фильтры могут быть как методами текущего контроллера, так и отдельными классами — что позволяет повторно их использовать. Если фильтр реализуется как метод класса, он должен иметь префикс «filter».

Пример:

public function filterAccessControl()
{
 .......
}

Фильтр, реализованный в виде отдельного класса, должен быть наследником класса CFilter.

Пример:

class XssFilter extends CFilter
{
   // код который выполнится до выполнения экшена
 public function preFilter()
 {
  .......
 }
 // код который выполнится после выполнения экшена
 public function postFilter()
 {
 .......
 }
}

Для активации фильтров, необходимо в контроллере переопределить метод filters,который должен вернуть массив всех фильтров для данного контроллера (или его отдельных экшенов).

Пример:

public function filters()
{
 return array(
           'accessControl',
           array(
             'application.filters.XssFilter',
             'clean' => 'all'
          )
  );
}

В этом примере ‘accessControl’ — фильтр, реализованный как метод контроллера, а ‘application.filters.XssFilter’ — фильтр, реализованный в виде отдельного класса, который хранится в каталоге /protected/filters/. ‘clean’ — устанавливаем свойство фильтра.

Это была краткая справка  по фильтрам в Yii, более подробно можно почитать тут.

Теперь непосредственно приступим к реализации нашего фильтра. Функцию очистки данных, которая и выполняет всю работу — я взял из фреймворка Kohana. Ну на этом достаточно слов, приведу сам код фильтра — он  совсем простой, так что думаю проблем быть не должно.

  /**
   *  @author  Opeykin A. <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: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\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;
}

}

Я совсем немного протестировал это фильтр — на первый взгляд — все работает!

Любые замечания и комментарии приветствуются!

Хочу добавить свои замечания к реализации фильтров в Yii…

Мне кажется было удобно иметь метод, который вызывается перед выполнением preFilter и postFilter, например init() — который выполняет инициализацию фильтра, при этом в нем должны быть доступны параметры, передавемые в фильтр из контроллера  (по этой причине невозможно использовать __construct). Конечно можно расширить CFilter для этих целей, но «родная» возможность сделать это была бы лучшим вариантом.

Надеюсь, описанный материал окажется полезен!

Ищите разработчиков на Yii ?

Мы решим Ваши задачи!

Скачать xssfilter

Оптимизация php кода

Интересная заметка по оптимизации php  кода. Описанные способы  обсуждались и раньше, но все равно полезно иметь этот список под рукой.

Читаем (на английском)

Yii создаем свою мега CMS !!!

В любом деле — главное ПРАКТИКА!
Вдоволь начитавшись документации и рассмотрев демо-примеры фреймворка Yii, я решил написать что-нибудь    «более» функциональное чeм «testDrive». А что должен сделать любой web-программист в своей жизни???? Правильно!!! Написать свою супер-цмс!!!Ну если не цмс, то хотя бы что-то похожее.
И так…Начиная с этой статьи и на протяжении еще примерно 5-8 (ну как максимум 10), я буду рассказывать о процессе написания простенькой ЦМС, с использованием замечательного фреймворка Yii. Многое, что здесь будет написано, так или иначе пересекается с руководством Yii по созданию блога.
Для начала определимся с основными требованиями:

— администратор может управлять контентом двух основных типов:

  • страницы
  • посты

— администратор может удалять или одобрять комментарии к постам;
— посты могут сопровождаться произвольным количеством тэгов;
— пользователи могу просматривать посты и страницы и оставлять комментарии к ним;
— движок должен позволять менять темы оформления;

Конечно, это не полный список требований, и в процессе разработки он будет обновляться и корректироваться, но для начала этого вполне достаточно.
Определимся с технической стороной вопроса.

Писать все это мы будем на PHP, с использованием фреймворка Yii, в качестве БД будет использоваться MySQL. На клиенской стороне я буду использовать jquery и jquery UI.

И так с вступлением закончено, начиная со следующей статьи будет больше технических моментов и вопросов, решать которые, я предлагаю сообща, так что в случае любых замечаний  и предложений, прошу не стесняться (:-)) и высказываться в комментариях.
Приступим!!!

p.s. А вот и первое «домашнее задание»: предлагаю придумать название для будущего творения, обязательное условие — в название должна присутствовать буква «Y» (Yii всетаки!!!).

p.s.s Названия типа YACS (yet another cms system) или YaBe! (yet another blog engine) — которые я хотел было «прикрутить» к этому творению — уже заняты!!! Так что, если есть какие то идеи и предложения — добро пожаловать в комментарии!

Основной сайт Юпи! — http://yupe.ru

Исходный код — https://github.com/yupe/yupe

Присоединяйтесь!

yii 1.0.3

Вчера вышел yii 1.0.3. из нововведений мне понравились следующие:

  • Если контроллеры расположены в поддиректориях — для указания пути к ним в адрессной строке исколльзуется формат вида /path/to/controller (в ранних версиях был формат path.to.controller);
  • Введен механизм модулей;

Весь список изменений можно посмотреть здесь.

p.s. хотя версия вышла только вчера, нашел интересное сравнение Yii 1.0.3, Codeigniter 1.7.1 и Kohana 2.3.1

обсудить на форуме

yii немного ссылочек

С момента моего знакомства с Yii (см. статью) прошло уже больше двух месяцев, за это время я более подробно рассмотрел его возможности — и они мне очень понравились!

Фреймворк достаточно молодой, поэтому статей по нему еще очень мало. Однако хотелось бы упомянуть несколько ресурсов — которые могут помочь в освоении.

Прежде всего официальная документация — практически, здесь есть все что необходимо!

Особенно стоит выделить постепенно развивающийся кукбук, содержащий очень полезные статьи и примеры кода.

Так  же, хотелось бы отметить, частично переведенную на русский язык документацию.

На форуме появилась русско-язычная ветка, ответы поступают достаточно быстро, спасибо модератору!

Еще хочу отметить вот этот блог автор опубликовал несколько статей о Yii, думаю будут и еще!

Думаю скоро (правда насколько скоро — неизвестно )))) должен запуститься ресурс yiiframework.ru, очень бы хотелось!

От себя хочу добавить, если у кого-нибудь возникнет желание организовать форум или специализированный ресурс по Yii и понадобиться помощь — с удовольствием принял бы участие.