В моем приложении php у меня есть поле textarea, которое получает уценку от пользователей (например, stackoverflow’s), а затем отображается на веб-сайте. Я использую Laravel Framework и использую parsedown-Laravel пакет.
Я могу сделать:
{!! Markdown::parse('__Hello__ Markdown!'); !!}
Оно работает.
{!! Markdown::parse('<h1>Hello</h1> Markdown!'); !!}
Это все еще работает. И я в порядке с этим.
Теперь, если я сделаю:
{!! Markdown::parse('<script>alert("XSS Attack!!!")</script> Markdown!'); !!}
Это все еще работает !!!
Как я могу предотвратить использование тегов сценариев в моем приложении, используя Laravel и этот пакет?
Если вы посмотрите на спецификацию Markdown (либо оригинальный синтаксис Джона Грубера или же CommonMark), вы обнаружите, что Markdown не должен заменять HTML. Его единственная цель — облегчить чтение написанного вами текста. Поскольку Markdown охватывает только небольшое подмножество HTML-тегов, вы все равно можете использовать встроенный HTML-код, чтобы создать именно то, что вам нужно. На самом деле Джон Грубер говорит следующее:
Для любой разметки, на которую не распространяется синтаксис Markdown, вы просто используете сам HTML. Нет необходимости вводить предисловие или разделять его, чтобы указать, что вы переходите с Markdown на HTML; вы просто используете теги.
Так что, по сути, именно так должен работать Markdown. Очевидно, что это не должно иметь место, если вы анализируете ввод пользователя. Поскольку анализатор Markdown выводит HTML-код, вы не можете использовать htmlentities
функция или аналогичное решение.
Самый простой способ решить вашу проблему — использовать библиотеку фильтрации HTML, например Очиститель HTML. Это удалит вредоносный код из вывода Markdown и попытается остановить XSS-атаки. По сути, вы должны сначала вызвать ваш анализатор Markdown и с этим выводом вызвать библиотеку HTML Purifier.
Оригинал Parsedown В библиотеке есть опция экранирования html:
echo Parsedown::instance()
->setMarkupEscaped(true) # escapes markup (HTML)
->text("<div><strong>*Some text*</strong></div>");
# Output:
# <p><div><strong><em>Some text</em></strong></div></p>
От Учебник Parsedown: Начало работы
Предположительно, так как parsedown-Laravel это просто оболочка, вы должны иметь доступ к этой опции.
Очевидно, что это отключает все теги, а не конкретные.
Пользователь GitHub moldcraft на проблема 229 — отключить анализ определенных элементов на Parsedown bugtracker обеспечивает следующий код, это может проложить путь к решению:
Moldcraft прокомментировал 24 фев • 2015-02-24 18:41:31 +0100
Может быть полезно для кого-то: я также использую Parsedown для комментариев пользователей, и я хотел заменить все h1, h2, h3 на h4 для предотвращения SEO-предупреждений (например, на странице должен быть только один h1), вот мой сервис Symfony2
<?php
namespace App\MainBundle\Service;
use Parsedown;
use HTMLPurifier;
use Emojione\Emojione;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Markdown extends Parsedown
{
/**
* @var HTMLPurifier
*/
private $purifier;
public function __construct(ContainerInterface $container)
{
$this->setMarkupEscaped(true);
{
$purifierConfig = array(
'HTML.ForbiddenElements' => array('h1', 'h2', 'h3'),
'HTML.ForbiddenAttributes' => array('style', 'onclick',),
'HTML.TargetBlank' => true,
);
$this->purifier = new HTMLPurifier($purifierConfig);
}
{
Emojione::$imageType = 'svg';
Emojione::$sprites = true;
Emojione::$imagePathSVGSprites = $container->get('templating.helper.assets')->getUrl(
'bundles/appmain/emojione/sprites/emojione.sprites.svg'
);
Emojione::$ascii = true;
}
}
function text($raw)
{
return Emojione::shortnameToImage(
$this->purifier->purify(
parent::text($raw)
)
);
}
private function safeHeader($Block)
{
if ($Block && isset($Block['element'])) {
/**
* Change h1, h2, h3 to h4
*/
if (in_array($Block['element']['name'], array('h1', 'h2', 'h3'))) {
$Block['element']['name'] = 'h4';
}
}
return $Block;
}
protected function blockHeader($Line)
{
return $this->safeHeader(
parent::blockHeader($Line)
);
}
protected function blockSetextHeader($Line, array $Block = null)
{
return $this->safeHeader(
parent::blockSetextHeader($Line, $Block)
);
}
}
Принятие пользовательского ввода и его интеграция с кодом приложений никогда не может быть безопасным. Это не идти.
Если это просто отображение кода, то вы можете сделать это, используя <textinput>
тег для примера. Вы можете стилизовать его так, чтобы он не выглядел как вход. Или вы просто используете функцию как htmlescape()
в сочетании с <pre>
тег.