清除恶意代码,同时允许一些 HTML(在持久化到数据库之前)

Cleanup malicious code while allowing some HTML (before persisting to DB)

我有一个 Symfony 项目,任何用户都可以在其中注册一个帐户,然后使用包含字段 content 的表单创建一个 page。我想允许用户插入一些 html(如粗体文本、编号列表和其他一些元素),这是我使用所见即所得编辑器 CKEditor 完成的。我创建了一个工具栏,它只允许在保存 page 时将我选择的元素解析到数据库中。我可以使用以下方式显示此页面的内容:

{{ page.content | raw }}

这一切都按预期工作。但是,如果用户复制 post-请求,在某些 JS 或其他 HTML 中编辑并使用 cURL 发送它,这将允许他们插入(有害的)代码。 我的问题是:如何防止这种情况发生?

我一直在阅读有关 'sanitation' 或 'purification' 清理用户输入的内容。 HTML Purifier 之类的东西可以清理输出,我也考虑过为我允许的元素创建一种 'whitelist twig filter' 来做到这一点。我最好先清理输入,然后再将其保存到数据库。我想这是一个常见问题,但我只找到有关如何清理输出的解决方案,通常是通过转义所有 HTML,在我的情况下这也不是解决方案,因为我确实想允许一些 HTML.

在用户使用 HTML Purifier Library 和 symfony 表单事件提交表单后,您可以在表单类型中对此进行净化:

use HTMLPurifier;
use HTMLPurifier_Config;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
    $object = $event->getData();

    $config = HTMLPurifier_Config::createDefault();
    $config->set('HTML.AllowedElements', ['a', 'b', 'strong', 'ul', 'li', 'p', 'br']);
    $config->set('Attr.AllowedFrameTargets', ['_blank']);
    $purifier = new HTMLPurifier($config);
    $content = $purifier->purify($object->getContent());

    $object->setContent($content);
});

所以在这个例子中,用户内容被清理了。 HTML.AllowedElements 定义不应删除哪些元素。之后,该实体已准备好保存到您的数据库中,而不会出现不良 html 用户内容。

诀窍是不操纵用户输入。你应该 validate/reject 用户输入(例如:用户上传 10GB 的数据,或者用户开始一个 div 元素,但没有结束它),但不要改变它。它不会去任何地方,也不会通过坐在数据库中来感染任何人。

当您向用户显示页面时,也就是您操作数据时。就像你说的,转义你的角色:<代表<,&代表&,"代表“.

我最近正在为此编程,我所做的是使用 XML 解析器 (luaexpat)。在你的例子中,你有 PHP 有一个 XML 解析器库。

运行 用户通过 XML 解析器输入 HTML。如果出现任何未经授权的元素,您可以在输出时对它们进行转义 (<) 或抛出错误而不是内容。确保内容有效 XML 也很好,这样用户就不会因为不关闭元素而弄乱页面的其余部分。

另一个想法是存储post类型的“版本标识符”。如果您决定添加更多 features/attributes 或切换到另一种编码(如 BBCose),请在数据库中写一条注释,以便更容易解码 post。这也是为什么您不应该更改用户输入,而应该更改用户输出的另一个原因,以防您从拒绝图像开始,然后您决定稍后允许它。

还有白名单属性。不要让别人把JavaScript放在一个属性里(比如<div onclick=“MaliciousCode();”>

一定要注意 SQL 注入攻击和 HTML 注入攻击。