我目前正在从事一个项目,该项目要求用户输入可能已设置格式或可能未设置格式的文本(如果有帮助,即使它不太准确,也可以将其视为Stack Exchange克隆。我认为,与其选择某种类型的BB代码或其他标记语言来允许用户设置其文本格式,不如让用户仅使用HTML子集可能会减轻压力。我的用户通常都是经验丰富的计算机用户,因此我认为这不会成为问题。

我的计划是将标签和属性列入白名单。与白名单不符的所有内容都将被删除。我认为,只要我不偶然允许使用危险的属性或元素并且很好地实现了代码,就不会有任何问题。

我认为我通常都很好地实现了代码,但是我对安全问题的了解充其量是不稳定的,因此为什么我要在此处发布代码。

public function set($value){
    /*
        First, I want to make sure that we're dealing with a string, so I cast it to a string. Should I throw an error if it's not a string instead?

        Next, I transform \n to <br>, so that whitespace appears correctly. I think it might be better to skip this step and use a CSS rule to allow whitespace.
    */
    $value    =    (string) $value;
    $value    =    nl2br(trim($value));

    /*
        Here is my whitelist. Notice the multiple br elements.
    */
    $value    =    strip_tags($value, "<a><img><table><tr><td><th><h2><h3><h4><blockquote><ul><ol><li><br><br/><br />");

    /*
        This caused some issues in my tests, where it'd unnecessarily escape certain things, so I commented it out. Are shell command injections something I need to worry about?
    */
    //$value    =    escapeshellcmd($value);

    $dom = new DOMDocument;
    if($value === ""){
        return false;
    }
    $dom->loadHTML($value);

    $nodes = $dom->getElementsByTagName('*');
    foreach($nodes as $node){
        if($node->hasAttributes()){
            foreach($node->attributes as $attr){
                $name    =    $attr->name;
                $value    =    $attr->value;
                switch($name){
                    /*
                        These elements are generally safe. Worst case scenario, someone just creates some weird looking HTML, which I'm not too worried about.
                    */
                    case "id":        break;
                    case "style":    break;
                    case "src":        break;
                    case "alt":        break;
                    case "class":    break;
                    /*
                        This is my biggest concern. You can embed inline javascript with <a href="javascript:foo();"></a>, so I want to prevent this. However, links are important so I don't want to completely strip this attribute.
                    */
                    case "href": 
                        if(strpos($value, "javascript") !== false){
                            $node->removeAttribute($name);
                        }
                        break;
                    default:
                        $node->removeAttribute($name);
                        break;
                }
            }
        }
    }

    $value    =    $dom->saveXML($dom->documentElement->firstChild);

    /*
        PHP is weird and adds a bunch of extra elements around the HTML, and it's easiest to just strip the tags again. It's a little hacky, but it works every time (I think).
    */
    $value    =    strip_tags($value, "<a><img><table><tr><td><th><h2><h3><h4><blockquote><ul><ol><li><br><br/><br />");

    /*
        I don't exactly remember why this is here. I think it ensures that all br elements are in the same format, but it probably doesn't do a very good job at it.
    */
    $value    =    str_replace("br/", "br", $value);

    /*
        This ensures that our input is the right length. I chose to do this after we removed all the junk just as a little present for the user.
    */
    if(strlen($value) > $this->length){
        $this->text    =    substr($value, 0, $this->length);
    }else{
        $this->text    =    $value;
    }
    return $this;
}


我不太担心SQL注入,所以我最大的担心是是XSS,我猜想我不熟悉的任何形式的注入。正在执行:


在检查“ javascript:”的URL时使用不区分大小写的搜索。
从白名单中删除样式属性(现在,我需要一种使用户加粗/斜体化他们的文本,我可能会允许<b><i>,我想)我目前有什么

评论

strip_tags可能有点过多。您会在Stack Overflow上遇到类似“我尝试(换行)没有用”之类的问题,因为HTML示例是隐藏的,因此没有意义。

我认为strip_tags是合适的。我的用户不会发布代码段,因此我不必担心。

您可以通过说“嗨,我的名字是
来自我介绍。
嗯...好点。您有什么建议吗?

在查看JavaScript是否嵌入在href属性中时,应该使用不区分大小写的搜索。

#1 楼

按照我的看法,您必须保护自己免受以下类型的攻击:


XSS(在浏览器上运行Javascript注入)
PHP注入
信息披露

允许<img src="whatever"/>违反了#3,因此恶意用户可以嵌入透明像素并看到查看给定页面的所有人。我相信style属性可以完成相同的攻击。<​​br />
如果您不小心将用户生成的内容嵌入到网页中,则可能会受到PHP注入的攻击。这可能非常严重,因为PHP在服务器上运行。它将公开所有SQL数据库,甚至可能公开整个系统和整个网络。您必须检查HTML4和HTML5的每个属性中可以嵌入的内容。 XSS攻击很严重,因为该脚本可以使用当前用户会话访问您的网站。通常,XSS攻击可以窃取Cookie,发布新帖子以将XSS攻击传播给其他用户,并尝试更改用户帐户设置。

我认为,允许用户嵌入HTML很危险,最好做功课。使用一些替代标记(例如StackExchange用途)会更好。

评论


\ $ \ begingroup \ $
我修复了样式属性问题(最新版本位于我的问题的底部)。我认为我将针对白名单(imgur,puush等)运行图像src,因此无法使用跟踪图像。您可以扩展PHP注入吗?
\ $ \ endgroup \ $
– Meredith
2014年6月10日19:48



\ $ \ begingroup \ $
我认为PHP注入不是很普遍,但是如果您将用户输入传递给eval(),system(),passthru(),deserialize()或类似函数,那么您将面临风险。
\ $ \ endgroup \ $
–苏菲特
2014年6月10日20:56

\ $ \ begingroup \ $
好吧,我什么都不做,所以我应该很安全
\ $ \ endgroup \ $
– Meredith
2014年6月10日21:15

#2 楼

PHP strip_tags文档

您还应该查看文档以及人们对函数的评价,以便您确切了解所使用的代码正在发生什么。


我还将针对HTML5元素对此进行大量测试,或者如果您也希望将其列入白名单,请添加这些元素,从文档中看,您似乎已受到PHP标记的保护。您应该找到最新的HTML / XHTML标记列表并测试所有标记的用法。


注释中已经提到的是hrefsrc您说过要将其列入白名单,但问题并不总是它们所注入的信息是否对您有害。

举例来说,有人发布了一个普通链接,例如<a href="http://www.not-a-real-site-but-a-virus-injection-point.com>Click here</a>,它通过了您的白名单,因此它在您的留言板或聊天室中可见,但是当有人单击链接时,它将在客户端浏览器中的该网页上运行脚本。

这种攻击可能会使他们(您网站上)的帐户容易受到攻击,您将永远不会知道,他们也不会。

那里大量的XSS漏洞每天都在增加,这意味着您唯一可以做的就是继续阅读Internet上的安全问题并相应地测试应用程序。


链接

XSS Wiki页面

OWASP跨站点脚本(XSS)

OWASP是我所阅读内容的安全信息的很好来源

这是OWASP的备忘单,用于XSS漏洞保护

XSS(跨站点脚本)预防备忘单

评论


\ $ \ begingroup \ $
这不是评论,而是答案,似乎错过了问题的全部内容。
\ $ \ endgroup \ $
– Meredith
2014年6月6日17:31

\ $ \ begingroup \ $
@Meredith,如何?我的意思是说HTML5元素,因为它具有新的HTML元素,您还应该检查以确保XHTML元素也被剥离,尽管您可以创建所需的内容,但这可能会更加困难。
\ $ \ endgroup \ $
–马拉奇♦
2014年6月6日18:03

\ $ \ begingroup \ $
该问题询问如何强制用户输入是HTML的安全子集。只说“ HTML5引入了新元素”并不是一个主题答案。
\ $ \ endgroup \ $
– Meredith
2014年6月6日18:12

\ $ \ begingroup \ $
您已经在使用旧的PHP函数将安全子集列入白名单,我是说我将对其进行测试以确保它首先起作用,然后您可以从那里开始。
\ $ \ endgroup \ $
–马拉奇♦
2014年6月6日18:15

\ $ \ begingroup \ $
关于本文标签: php html security validation