Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Безопасная запись в БД, очистка от html и т.д.
 
 автор: TetRiska   (21.10.2012 в 23:44)   письмо автору
 
 

Всем привет. Написал сайт, теперь бьюсь с его безопасностью. В данный момент нужно корректно и безопасно записывать текст с его разметкой в БД. Пропускать в базу лишь те теги, которые я разрешу, а также преобразовывать символы в соответствующие html сущности.

Отфильтровывать левые теги буду при помощи ф-ции
strip_tags($text,'<a><p>')

Преобразовывать символы в соответствующие html сущности - при помощи ф-ции
htmlentities($text,'ENT_QUOTES')

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

Входная строка допустим такая
$text = '<script>alert(10)</script><p>Мишка, <a href="/" target="_blank">книжка</a>, <b>вспышка</b>!</p> "Морковка > редиски", но < семак. Маша&Паша.';

На выходе мы должны получить
alert(10)<p>Мишка, <a href="/" target="_blank">книжка</a>, вспышка!</p> &quot;Морковка &gt; редиски&quot;, но &lt; семак. Маша&amp;Паша.

Еще один нюанс, читал на Хабре, что лучше писать в БД как есть экранируя спец. символы, а при выводе фильтровать. А Вы что скажете по этому поводу? И на сколько безопасен метод фильтрации о котором я писал выше, который предстоит еще сделать?

Спасибо за внимание.

  Ответить  
 
 автор: confirm   (21.10.2012 в 23:50)   письмо автору
 
   для: TetRiska   (21.10.2012 в 23:44)
 

А вы смотрели во что превратиться ваша строка после htmlentities()?

  Ответить  
 
 автор: TetRiska   (22.10.2012 в 01:12)   письмо автору
 
   для: confirm   (21.10.2012 в 23:50)
 

я же писал об этом
> Проблема в их объединении. Получается если мы сразу отфильтруем, а потом преобразуем, на выходе будет не совсем ожидаемое, т.к. в тегах будут символы преобразованы.

  Ответить  
 
 автор: confirm   (22.10.2012 в 01:18)   письмо автору
 
   для: TetRiska   (22.10.2012 в 01:12)
 

Ну тогда чего вы хотите? Если вы знаете во что это превратиться, в каком виде будут храниться данные, и любая работа с ними как в базе, так и вне, это хлопоты, то выгодно ли хранить в таком виде? Если считаете, что это для вас не обременительно, храните. Но вряд ли это удобно, потому и читали вы о подобном на хабре.

  Ответить  
 
 автор: TetRiska   (22.10.2012 в 02:07)   письмо автору
 
   для: confirm   (22.10.2012 в 01:18)
 

Не совсем понял о чем Вы говорите. Я хочу добиться оптимального решения - безопасно писать в БД не захламляя ее при этом запрещенными тегами, не вижу в этом смысла. Но на Хабре говорили, что нужно писать все, авось потом пригодится, останется лишь переписать фильтер на выводе. Вот и я призадумался, есть ли в этом смысл?

  Ответить  
 
 автор: confirm   (22.10.2012 в 02:12)   письмо автору
 
   для: TetRiska   (22.10.2012 в 02:07)
 

Я уже тут однажды говорил одному, что htmlentities() к безопасности отношения никакого не имеет, а вот проблем с таким хранением данных хлебнете не мало. Что она вам обезопасит?
И еще, strip_tags() тоже содержит в себе мину замедленного действия, если вы читали все, что касается данной функции.

  Ответить  
 
 автор: TetRiska   (22.10.2012 в 02:20)   письмо автору
 
   для: confirm   (22.10.2012 в 02:12)
 

Так как тогда лучше реализовать сохранение? Писать как есть в БД экранируя кавычки mysql_real_escape_string и потом на выводе пропускать через htmlspecialchars + парочка манипуляций с мэджик квотами

  Ответить  
 
 автор: confirm   (22.10.2012 в 02:26)   письмо автору
 
   для: TetRiska   (22.10.2012 в 02:20)
 

А как вы при выводе сможете использовать htmlspecialchars(), если вы ведете речь о хранении в html-формате?
Исходя из того, что запись, это один раз, а вывод многократно, значит лучше применить htmlspecialchars() к строке между тегами при внесении в базу?
В данном случае, я бы использовал рег.выражения для удаления ненужного и преобразования нежелательного перед занесением в базу. Можно использовать и готовые решения, которые позволяют работать с таким документом (текстом) также как с DOM элементами на клиенте.

  Ответить  
 
 автор: TetRiska   (23.10.2012 в 11:25)   письмо автору
 
   для: confirm   (22.10.2012 в 02:26)
 

Полазив по форумам многие советуют писать в базу как есть экранируя через mysql_real_escape_string, а при выводе фильтровать от лишних тегов, атрибутов у подходящих тегов и также переводить спец символы.

Вот что у меня включено/выключено:
magic_quotes_gpc    On
magic_quotes_runtime    Off
magic_quotes_sybase    Off
register_globals    Off

Вот код который нуждается в рассмотрении и оптимизации:
<?php

//Экранируем скобки
function magic_off($data) {
    if(
get_magic_quotes_gpc()){
        if(
is_array($data)) $data array_map("stripslashes"$data);
            else 
$data stripslashes($data);
    }else{
        if(
is_array($data)) $data array_map("mysql_real_escape_string"$data);
            else 
$data mysql_real_escape_string($data);
    }

    return 
$data;
}

//Очищаем параметры тегов
function clear_tag_param($data$allowable_params=0) {
    
$str $data;
    if(!
$allowable_params$allowable_params 'name,id,class,type,img,href,src,alt,value,size,border,width,cellspacing,cellpadding';

    if(
is_array($allowable_params)) { $arr $allowable_params; }
        else 
$arr explode(","$allowable_params);

    
preg_match_all('#[ ](.{1,20}?)=[\'"](.*?)[\'"]#is',$str,$params); /* нужно сделать проверку на символы вокруг значения (скобки и их отсутствие) */
    
for($i=0$i<count($params[1]); $i++) {
        if(
array_search($params[1][$i], $arr)!==FALSE) { }
            else 
$str str_replace($params[0][$i], ''$str);
    }

    return 
$str;
}

//Очищаем теги
function clear_tag($data$allowable_tags=0) {
    
$str htmlspecialchars($data);
    if(!
$allowable_tags$allowable_tags '<a><b><i><u><p><br><li><ul><strike><sup><sub><blockquote><strong><em><img><table><tr><td><span><div><hr>';

    if(
is_array($allowable_tags)) { $arr $allowable_tags; }
    else {
        
$allowable_tags substr($allowable_tags 0strlen($allowable_tags)-1);
         
$arr explode('><'$allowable_tags);
     }

    
preg_match_all("#<([a-z]+)( .*)?(?!/)>#iU",$data,$tag1);
    for(
$i=0$i<count($tag1[0]); $i++) {
        if(
array_search($tag1[1][$i], $arr)!==FALSE) {
            
$s clear_tag_param($tag1[0][$i]);
            
$str str_replace(htmlspecialchars($tag1[0][$i], ENT_QUOTES|ENT_DISALLOWED), $s$str);
        } else 
$str str_replace(htmlspecialchars($tag1[0][$i], ENT_QUOTES|ENT_DISALLOWED), ''$str);
    }

    
preg_match_all("#</([a-z]+)>#iU",$data,$tag2);
    for(
$j=0$j<count($tag2[0]); $j++) {
        if(
array_search($tag2[1][$j], $arr)!==FALSE) {
            
$s clear_tag_param($tag2[0][$j]);
            
$str str_replace(htmlspecialchars($tag2[0][$j], ENT_QUOTES|ENT_DISALLOWED), $s$str);
        } else 
$str str_replace(htmlspecialchars($tag2[0][$j], ENT_QUOTES|ENT_DISALLOWED), ''$str);
    }

    return 
$str;
}

//Защищаем текст
function safe_text($data$type=0) {
  if (
$type==0//Запись в БД
  
{
      
$data magic_off($data);
  }
  else if (
$type==1//Заголовок (вывод из базы)
  
{
    
$data stripslashes($data);
      
$data htmlspecialchars($dataENT_QUOTES|ENT_DISALLOWED);
  }
  else if (
$type==2//Текст (новость и т.д.) (вывод из базы)
  
{
      
$data stripslashes($data);
      
$data clear_tag($data);
  }

  return 
$data;
}

$text '<b><script>alert(100)</script><div style="blabla: 11px;" name="!!!!" id="!!!!" style="12323"><u>>Про\'верка<</u></div></b><br /><input name="Name" type="checkbox" 111="222" value="ON" checked>';
$text safe_text($text,2);
echo 
$text;
?>

Ну и есть по этому поводу несколько вопросов:
- Как она вообще?
- Как его можно оптимизировать?
- Как правильно обработать
preg_match_all('#[ ](.{1,20}?)=[\'"](.*?)[\'"]#is',$str,$params);

, а то скрипт при
<div style="blabla: 11px;" name="!!!!" id='!!!!' style="12323">

(разные кавычки), работает не правильно.

  Ответить  
 
 автор: confirm   (23.10.2012 в 13:34)   письмо автору
 
   для: TetRiska   (23.10.2012 в 11:25)
 

Ваш шаблон не только наборы атрибутов некорректно обрабатывает, но и достаточно написать любой атрибут с новой строки, и вся ваша разрешенная html-разметка поплывет - открывающий тег будет превращен в html-представление. И почему удаляя запрещенные теги, вы оставляете их содержимое, как то js-код? Это ведь по сути грязь.
Оптимизация, так это очищать теги от атрибутов неразрешенных, удалять запрещенные теги и их содержимое, наверное надо при записи в базу, а не каждый раз при выводе из нее, не так ли?

PS. Говоря strip_tags как о мине, я имел ввиду его некорректную обработку некорректного html-кода. Почему и лучше применять решения на рег. выражениях. Ваш обработчик страдает тем же, то есть, вот такое:
<div>
text <div>
</div>
он так и выдаст на страницу. То есть, у вас нет проверки на парность тегов (или восприятие как тег текста описывающего этот тег). И если неправильные вложения тегов для разметки, это еще не беда, то незакрытые теги, или отсутствие открывающих тегов может быть для нее катастрофой.

  Ответить  
 
 автор: TetRiska   (23.10.2012 в 17:25)   письмо автору
 
   для: confirm   (23.10.2012 в 13:34)
 

ехх, а не могли бы тогда помочь с реализацией рег выражения, чтобы он корректно обрабатывал перед записью в БД?

для начала я создам массив, допустим такой:
$tags = array([0] => 'a.href',[1] => 'a.title',[2] => 'a.target',[3] => 'b',[4] => 'p',[5] => 'br',[6] => 'ul.class');

Тут идет тег.его_атрибут которые пропускаем. Также нужно, я думаю, фильтровать содержимое атрибутов, чтоб не подсунули чего-либо, и преобразовывать символы в их хтмл сущности.

  Ответить  
 
 автор: confirm   (23.10.2012 в 22:18)   письмо автору
 
   для: TetRiska   (23.10.2012 в 17:25)
 

>Также нужно, я думаю, фильтровать содержимое атрибутов, чтоб не подсунули чего-либо, и преобразовывать символы в их хтмл сущности.

Заменить в чем, атрибутную грязь в тегах? Если да, то зачем? Насчет шаблона для очистки. Если вы ожидаете, что в тегах может быть любая грязь любой длины, то зачем вам резать/чистить что-то, не проще ли взять разрешенное добавив это в чистый тег?
Если говорить о массиве допустимого, то наверное лучше иметь:
array(
  a => array('href', 'title',...),
  ul=>array('class'),
  ....
);
Ключи вложений, это разрешенные теги, а элементы вложений разрешенные атрибуты. Но ведь кроме этого надо проверять ссылки и на фишинг, если уж в полном объеме проверку делать.

Если данные поступают от визуального редактора, то вы вправе ожидать корректной html-разметки разрешенной вами, включая и атрибуты. И если вы получаете запрещенные теги и атрибуты, или грязь в атрибутах, значит явно вам что-то подсовывают. Встает вопрос - а стоит ли тогда это сохранять вообще?

Но как вы справитесь с другой бедой - разрешенными тегами и содержанием описывающим теги? Можно проверить корректность html, если организовать массив, в который загружать полученный массив тегов, выполняющий роль стека по принципу первым вошел, последним вышел. Тогда проходом в цикле можно будет выяснить корректны ли теги на предмет "открывающий/открывающий вложенный/закрывающий вложенный/закрывающий" и т.п. и принять решение, дополнить незакрытые, как это делают браузеры, например, или удалить, или.... Но как вы сможете определить что тут разметка, а что мое сообщение?
<div>Существует тег параграфа: <p>Text</p></div>
Как в этом случае вы поступите?

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования