我如何能找到100%确定HTML标签内的JS
How i can find 100% sure a JS inside of HTML tag?
我需要用一些HTML标签保存一些数据,所以我不能为所有文本使用strip_tags
,我不能使用htmlentities
,因为文本必须由标签修改。为了保护其他用户不受XSS的攻击,我必须从标签内部删除任何JavaScript。
最好的方法是什么?
如果您需要在数据库中保存HTML标记,然后希望将其打印回浏览器,那么使用内置的PHP函数实现此目的没有100%安全的方法。当没有html标签时,这很容易,当你只有文本时,你可以使用内置的PHP函数来清除文本。
有一些函数可以从文本中清除XSS,但它们不是100%安全,并且总是有一种方法可以让XSS不被注意到。你的regex的例子是好的,但如果我使用,让我们说< script>alert('xss')</script>
,或一些其他的组合,regex可能错过和浏览器将执行。
最好的方法是使用HTML净化器
还要注意,有两个级别的安全性,第一级是在数据进入数据库时,第二级是在数据离开数据库时。
希望这对你有帮助!
如果你想允许特定的标签,你必须解析HTML。
已经有一个很好的库用于此目的:HTML净化器(LGPL下的开源)
我建议您使用DOMDocument
(与loadHTML
)来加载所述HTML,删除您不想看到的每种标记和每个属性,并保存回HTML(使用saveXML
或saveHTML
)。可以通过递归地遍历文档根节点的子节点,并用它们的内部内容替换不需要的标记来实现这一点。由于loadHTML
以与浏览器类似的方式加载代码,因此它比使用正则表达式更安全。
EDIT这是我做的一个"净化"函数:
<?php
function purifyNode($node, $whitelist)
{
$children = array();
// copy childNodes since we're going to iterate over it and modify the collection
foreach ($node->childNodes as $child)
$children[] = $child;
foreach ($children as $child)
{
if ($child->nodeType == XML_ELEMENT_NODE)
{
purifyNode($child, $whitelist);
if (!isset($whitelist[strtolower($child->nodeName)]))
{
while ($child->childNodes->length > 0)
$node->insertBefore($child->firstChild, $child);
$node->removeChild($child);
}
else
{
$attributes = $whitelist[strtolower($child->nodeName)];
// copy attributes since we're going to iterate over it and modify the collection
$childAttributes = array();
foreach ($child->attributes as $attribute)
$childAttributes[] = $attribute;
foreach ($childAttributes as $attribute)
{
if (!isset($attributes[$attribute->name]) || !preg_match($attributes[$attribute->name], $attribute->value))
$child->removeAttribute($attribute->name);
}
}
}
}
}
function purifyHTML($html, $whitelist)
{
$doc = new DOMDocument();
$doc->loadHTML($html);
// make sure <html> doesn't have any attributes
while ($doc->documentElement->hasAttributes())
$doc->documentElement->removeAttributeNode($doc->documentElement->attributes->item(0));
purifyNode($doc->documentElement, $whitelist);
$html = $doc->saveHTML();
$fragmentStart = strpos($html, '<html>') + 6; // 6 is the length of <html>
return substr($html, $fragmentStart, -8); // 8 is the length of </html> + 1
}
?>
您将使用不安全的HTML字符串和预定义的标记和属性白名单调用purifyHTML
。白名单格式为'tag' => array('attribute' => 'regex')。白名单中不存在的标记被剥离,其内容内联在父标记中。白名单中给定标签不存在的属性也会被删除;白名单中存在但与正则表达式不匹配的属性也会被删除。
下面是一个例子:
<?php
$html = <<<HTML
<p>This is a paragraph.</p>
<p onclick="alert('xss')">This is an evil paragraph.</p>
<p><a href="javascript:evil()">Evil link</a></p>
<p><script>evil()</script></p>
<p>This is an evil image: <img src="error.png" onerror="evil()"/></p>
<p>This is nice <b>bold text</b>.</p>
<p>This is a nice image: <img src="http://example.org/image.png" alt="Nice image"></p>
HTML;
// whitelist format: tag => array(attribute => regex)
$whitelist = array(
'b' => array(),
'i' => array(),
'u' => array(),
'p' => array(),
'img' => array('src' => '@'Ahttp://.+'Z@', 'alt' => '@.*@'),
'a' => array('href' => '@'Ahttp://.+'Z@')
);
$purified = purifyHTML($html, $whitelist);
echo $purified;
?>
结果是:
<p>This is a paragraph.</p>
<p>This is an evil paragraph.</p>
<p><a>Evil link</a></p>
<p>evil()</p>
<p>This is an evil image: <img></p>
<p>This is nice <b>bold text</b>.</p>
<p>This is a nice image: <img src="http://example.org/image.png" alt="Nice image"></p>
显然,您不希望允许任何on*
属性,并且我会建议不要使用style
,因为behavior
等奇怪的专有属性。确保所有URL属性都用一个体面的正则表达式进行验证,匹配完整的字符串 ('Aregex'Z
)。
我写了这段代码,你可以设置一个列表的标签和属性来删除
function RemoveTagAttribute($Dom,$Name){
$finder = new DomXPath($Dom);
if(!is_array($Name))$Name=array($Name);
foreach($Name as $Attribute){
$Attribute=strtolower($Attribute);
do{
$tag=$finder->query("//*[@".$Attribute."]");
//print_r($tag);
foreach($tag as $T){
if($T->hasAttribute($Attribute)){
$T->removeAttribute($Attribute);
}
}
}while($tag->length>0);
}
return $Dom;
}
function RemoveTag($Dom,$Name){
if(!is_array($Name))$Name=array($Name);
foreach($Name as $tagName){
$tagName=strtolower($tagName);
do{
$tag=$Dom->getElementsByTagName($tagName);
//print_r($tag);
foreach($tag as $T){
//
$T->parentNode->removeChild($T);
}
}while($tag->length>0);
}
return $Dom;
}
的例子:
$dom= new DOMDocument;
$HTML = str_replace("&", "&", $HTML); // disguise &s going IN to loadXML()
// $dom->substituteEntities = true; // collapse &s going OUT to transformToXML()
$dom->recover = TRUE;
@$dom->loadHTML('<?xml encoding="UTF-8">' .$HTML);
// dirty fix
foreach ($dom->childNodes as $item)
if ($item->nodeType == XML_PI_NODE)
$dom->removeChild($item); // remove hack
$dom->encoding = 'UTF-8'; // insert proper
$dom=RemoveTag($dom,"script");
$dom=RemoveTagAttribute($dom,array("onmousedown","onclick"));
echo $dom->saveHTML();
- Morris.js折线图x轴标签在调整大小后消失
- Knockout.JS标签在foreach内部不起作用
- Chart.js条形图:网格颜色和隐藏标签
- 如何在标签上输出Chart.js雷达图的正确值
- 是否可以使用Chart.js缩短雷达图上的外部标签,而不影响其他标签
- 如何将具有相同功能的两个select html标签的两个JS组合在一起
- d3.js:如何为图上的散点添加标签
- 如何在chart.js中显示圆环图上的标签
- d3.js散点图中的刻度标签在Firefox 13.0.1中被截断
- Chart.js条形图标签在悬停时被隐藏
- 如何在Chart.js v2.0中的标签上添加OnClick事件
- Meteor.js:<脚本>标签不't在<身体>
- Highlight.js为每个<代码>标签
- D3.js-单击节点后无法设置节点标签
- d3.js轴标签-颜色不变
- 如何在angular js的ng应用程序中以普通的htm显示标签
- 如何将attr(id)添加到特定值的<文本>标签-Js/Jquery
- <a>超文本电子邮件链接的标签.JS搞砸了我的下拉列表,因为它是基于<a>标签
- 如何在HTML脚本标签JS上运行Gulp ESLint
- 这个标签JS有什么问题