Безопасное извлечение вывода для обоих полей html и ввода

В моем веб-приложении пользователи могут вводить текстовые данные. Эти данные могут быть показаны другим пользователям, и исходный автор может также вернуться и редактировать свои данные. Я ищу правильный способ безопасного избежать этих данных.

Я использую только салфетки sql, так что все хранится по мере их чтения. Предположим, у меня есть «déjà vu» в базе данных. Или, что более экстремально, <script> . Возможно, это может быть действительным и даже не злонамеренно задуманным.

Я использую htmlentities() на выходе, чтобы убедиться, что все экранировано. Проблема в том, что html и поля ввода обрабатывают вещи по-разному. Я хочу убедиться, что это безопасно в HTML, но автор при редактировании текста видит точно, что они ввели в поля ввода. Я также использую jQuery для динамического заполнения полей формы данными.

Если я это сделаю:

  <p><?=htmlentities("déjà vu");?></p> <input type=text value="<?=htmlentities("déjà vu");?>"> 

Источник страницы помещает d&eacute;j&agrave; vu d&eacute;j&agrave; vu в обоих местах (мне пришлось отменить это, или вы увидите «déjà vu»!) Проблема в том, что вывод в <p> правильный, но на входе просто отображается экранированный текст. Если пользователь повторяет свою форму, они удваивают бегство и разрушают их вход.

Я знаю, что мне все еще нужно санировать текст, который выходит в поле, иначе вы можете закончить цитату с предложением и сделать плохие вещи. Единственное решение, которое я нашел, это. Опять же, я использую jQuery.

 var temp = $("<div></div>").html("<?=htmlentities("déjà vu");?>"); $("input").val(temp.html()); 

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

Поэтому мой вопрос: это все еще безопасно, или где-то есть дыра в безопасности? И что еще более важно, это единственный / правильный способ сделать это? Я что-то пропустил о том, как работает html и кодировка символов, что делает эту проблему тривиальной?

РЕДАКТИРОВАТЬ

Это на самом деле неправильно, я упростил мой пример до такой степени, что он не работает. Проблема в том, что я использую val () jQuery для вставки текста в поле.

 <input> <script>$("input").val("<?=htmlentities("déjà vu");?>");</script> 

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

Похоже, что jQuery ускользает от данных, чтобы войти во входные данные, но это не совсем хорошо – если я ничего не делаю сам, пользователь все равно может помещать </script> , убивая мой код и вставляя вредоносные код. Но здесь есть еще один аргумент. Так как в любом случае только исходный автор может видеть текст в поле ввода, должен ли я даже беспокоиться? В основном единственные люди, с которыми они могли бы атаковать XSS, – это сами.

Related of "Безопасное извлечение вывода для обоих полей html и ввода"

Извините, но я не могу воспроизвести описанное вами поведение. Я всегда использовал htmlspecialchars() (который выполняет по существу ту же задачу, что и htmlentities() ), и он никогда не приводит к какому-либо двойному кодированию. Источник страницы показывает d&eacute;j&agrave; vu d&eacute;j&agrave; vu в обоих местах (конечно же, это точка!), но на отображаемой странице отображаются соответствующие значения, и это то, что отправлено обратно на сервер.

Можете ли вы опубликовать полный самодостаточный фрагмент кода, демонстрирующий такое поведение?

Обновление : некоторый тестовый код:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title></title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <?php $default_value = 'déjà vu <script> ¿foo?'; if( !isset($_GET['foo']) ){ $_GET['foo'] = $default_value; } ?> <form action="" method="get"> <p><?php echo htmlentities($_GET['foo']); ?></p> <input type="text" name="foo" value="<?php echo htmlentities($_GET['foo']); ?>"> <input type="submit" value="Submit"> </form> </body> </html> 

Ответ на обновленный вопрос

Функция htmlentities() , как следует из ее названия, используется при генерации вывода HTML. Вот почему в вашем втором примере это малоприменимо: JavaScript не является HTML. Это собственный язык с собственным синтаксисом.

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

  1. Это допустимая строка в JavaScript.
  2. Его можно безопасно внедрить в HTML-документ.

Ближайшая функция PHP для # 1, о которой я знаю, это json_encode () . Поскольку синтаксис JSON является подмножеством JavaScript, если вы кормите его строкой PHP, он выведет строку JavaScript.

Как и в случае с № 2, когда браузер входит в блок JavaScript, он ожидает, что </script> покинет его. Функция json_encode () позаботится об этом и ускользнет от него ( <\/script> ).

Мой пересмотренный тестовый код:

 <?php $default_value = 'déjà vu </script> ¿foo?'; if( !isset($_GET['foo']) ){ $_GET['foo'] = $default_value; } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title></title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"><!-- $(function(){ $("input[type=text]").val(<?php echo json_encode(utf8_encode($_GET['foo'])); ?>); }); //--></script> </head> <body> <form action="" method="get"> <p><?php echo htmlentities($_GET['foo']); ?></p> <input type="text" name="foo" value="(to be replaced)"> <input type="submit" value="Submit"> </form> </body> </html> 

Примечание: utf8_encode() преобразуется из ISO-8859-1 в UTF-8, и это не требуется, если ваши данные уже находятся в UTF-8 (рекомендуется).

Если вам просто нужно отменить кодировку, вы можете использовать html_entity_decode – http://www.php.net/manual/en/function.html-entity-decode.php .

Другая возможность – запустить только htmlentities в то время, когда контент будет отображаться как часть веб-страницы. В противном случае сохраните незашифрованный текст, отправленный или загруженный из вашего хранилища данных.

Я считаю, что это проблема с тем, как вы применяете значение к вводу. Он отображается как закодированный, что имеет смысл, потому что это Javascript, а не HTML. Итак, я бы предложил написать свой закодированный текст как часть разметки, чтобы он разбирался естественным образом (вместо того, чтобы вводить клиентский скрипт). Поскольку ваши текстовые поля не всегда доступны, когда сервер отвечает, вы можете использовать временное скрытое поле …

 <input type="hidden" id="hidEncoded" value="<?=htmlentities("déjà vu");?>" /> 

Затем он будет анализироваться как старый добрый HTML, и когда вы попытаетесь получить доступ к значению с помощью Javascript, он должен быть декодирован …

 // Give your textbox an ID! $("#txtInput").val($("#hidEncoded").val());