|
|
|
| Всем привет. Написал сайт, теперь бьюсь с его безопасностью. В данный момент нужно корректно и безопасно записывать текст с его разметкой в БД. Пропускать в базу лишь те теги, которые я разрешу, а также преобразовывать символы в соответствующие 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> "Морковка > редиски", но < семак. Маша&Паша.
|
Еще один нюанс, читал на Хабре, что лучше писать в БД как есть экранируя спец. символы, а при выводе фильтровать. А Вы что скажете по этому поводу? И на сколько безопасен метод фильтрации о котором я писал выше, который предстоит еще сделать?
Спасибо за внимание. | |
|
|
|
|
|
|
|
для: TetRiska
(21.10.2012 в 23:44)
| | А вы смотрели во что превратиться ваша строка после htmlentities()? | |
|
|
|
|
|
|
|
для: confirm
(21.10.2012 в 23:50)
| | я же писал об этом
> Проблема в их объединении. Получается если мы сразу отфильтруем, а потом преобразуем, на выходе будет не совсем ожидаемое, т.к. в тегах будут символы преобразованы. | |
|
|
|
|
|
|
|
для: TetRiska
(22.10.2012 в 01:12)
| | Ну тогда чего вы хотите? Если вы знаете во что это превратиться, в каком виде будут храниться данные, и любая работа с ними как в базе, так и вне, это хлопоты, то выгодно ли хранить в таком виде? Если считаете, что это для вас не обременительно, храните. Но вряд ли это удобно, потому и читали вы о подобном на хабре. | |
|
|
|
|
|
|
|
для: confirm
(22.10.2012 в 01:18)
| | Не совсем понял о чем Вы говорите. Я хочу добиться оптимального решения - безопасно писать в БД не захламляя ее при этом запрещенными тегами, не вижу в этом смысла. Но на Хабре говорили, что нужно писать все, авось потом пригодится, останется лишь переписать фильтер на выводе. Вот и я призадумался, есть ли в этом смысл? | |
|
|
|
|
|
|
|
для: TetRiska
(22.10.2012 в 02:07)
| | Я уже тут однажды говорил одному, что htmlentities() к безопасности отношения никакого не имеет, а вот проблем с таким хранением данных хлебнете не мало. Что она вам обезопасит?
И еще, strip_tags() тоже содержит в себе мину замедленного действия, если вы читали все, что касается данной функции. | |
|
|
|
|
|
|
|
для: confirm
(22.10.2012 в 02:12)
| | Так как тогда лучше реализовать сохранение? Писать как есть в БД экранируя кавычки mysql_real_escape_string и потом на выводе пропускать через htmlspecialchars + парочка манипуляций с мэджик квотами | |
|
|
|
|
|
|
|
для: TetRiska
(22.10.2012 в 02:20)
| | А как вы при выводе сможете использовать htmlspecialchars(), если вы ведете речь о хранении в html-формате?
Исходя из того, что запись, это один раз, а вывод многократно, значит лучше применить htmlspecialchars() к строке между тегами при внесении в базу?
В данном случае, я бы использовал рег.выражения для удаления ненужного и преобразования нежелательного перед занесением в базу. Можно использовать и готовые решения, которые позволяют работать с таким документом (текстом) также как с DOM элементами на клиенте. | |
|
|
|
|
|
|
|
для: 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 , 0, strlen($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($data, ENT_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">
|
(разные кавычки), работает не правильно. | |
|
|
|
|
|
|
|
для: TetRiska
(23.10.2012 в 11:25)
| | Ваш шаблон не только наборы атрибутов некорректно обрабатывает, но и достаточно написать любой атрибут с новой строки, и вся ваша разрешенная html-разметка поплывет - открывающий тег будет превращен в html-представление. И почему удаляя запрещенные теги, вы оставляете их содержимое, как то js-код? Это ведь по сути грязь.
Оптимизация, так это очищать теги от атрибутов неразрешенных, удалять запрещенные теги и их содержимое, наверное надо при записи в базу, а не каждый раз при выводе из нее, не так ли?
PS. Говоря strip_tags как о мине, я имел ввиду его некорректную обработку некорректного html-кода. Почему и лучше применять решения на рег. выражениях. Ваш обработчик страдает тем же, то есть, вот такое: он так и выдаст на страницу. То есть, у вас нет проверки на парность тегов (или восприятие как тег текста описывающего этот тег). И если неправильные вложения тегов для разметки, это еще не беда, то незакрытые теги, или отсутствие открывающих тегов может быть для нее катастрофой. | |
|
|
|
|
|
|
|
для: 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');
|
Тут идет тег.его_атрибут которые пропускаем. Также нужно, я думаю, фильтровать содержимое атрибутов, чтоб не подсунули чего-либо, и преобразовывать символы в их хтмл сущности. | |
|
|
|
|
|
|
|
для: TetRiska
(23.10.2012 в 17:25)
| | >Также нужно, я думаю, фильтровать содержимое атрибутов, чтоб не подсунули чего-либо, и преобразовывать символы в их хтмл сущности.
Заменить в чем, атрибутную грязь в тегах? Если да, то зачем? Насчет шаблона для очистки. Если вы ожидаете, что в тегах может быть любая грязь любой длины, то зачем вам резать/чистить что-то, не проще ли взять разрешенное добавив это в чистый тег?
Если говорить о массиве допустимого, то наверное лучше иметь:
array(
a => array('href', 'title',...),
ul=>array('class'),
....
);
| Ключи вложений, это разрешенные теги, а элементы вложений разрешенные атрибуты. Но ведь кроме этого надо проверять ссылки и на фишинг, если уж в полном объеме проверку делать.
Если данные поступают от визуального редактора, то вы вправе ожидать корректной html-разметки разрешенной вами, включая и атрибуты. И если вы получаете запрещенные теги и атрибуты, или грязь в атрибутах, значит явно вам что-то подсовывают. Встает вопрос - а стоит ли тогда это сохранять вообще?
Но как вы справитесь с другой бедой - разрешенными тегами и содержанием описывающим теги? Можно проверить корректность html, если организовать массив, в который загружать полученный массив тегов, выполняющий роль стека по принципу первым вошел, последним вышел. Тогда проходом в цикле можно будет выяснить корректны ли теги на предмет "открывающий/открывающий вложенный/закрывающий вложенный/закрывающий" и т.п. и принять решение, дополнить незакрытые, как это делают браузеры, например, или удалить, или.... Но как вы сможете определить что тут разметка, а что мое сообщение?
<div>Существует тег параграфа: <p>Text</p></div>
| Как в этом случае вы поступите? | |
|
|
|
|