使用哪个正则表达式来确定要为html属性和javascript转义哪些字符?

时间:2012-07-08 16:40:14

标签: php javascript html escaping security

我正在采用Twig的一些代码(一个php模板框架)来转义html和js输出。现在我并不完全理解他们正在使用的正则表达式。

完整的Twig代码:

git clone git://github.com/fabpot/Twig.git
// the code is in Core.php in the function twig_escape_filter

他们使用:

preg_replace_callback( '#[^a-zA-Z0-9,\._]#Su'   , '_twig_escape_js_callback'               , $string ); // for javascript
preg_replace_callback( '#[^a-zA-Z0-9,\.\-_]#Su' , '_twig_escape_html_attr_callback' , $string ); // for html attibutes

回调函数将替换与负字符类对应的所有内容。

据我所知,这是等效的(摆脱一些反斜杠):

'#[^a-zA-Z0-9,._]#Su'
'#[^a-zA-Z0-9,._-]#Su'

现在我们看到,对于javascript,他们允许逗号,我不明白,因为逗号是javascript上下文中的控制字符。以这个逗号漏洞为例:

// say we have a function call to a javascript function like this
function ajax( timeout, onerror, onsuccess ) {...};

// now assume I get the timeout value from somewhere dodgy (in php)
$timeout = escapeJS( '1000, evilCallback, evilCallback2' );

echo "ajax( $timeout, myErrorHandler, mySuccessHandler );"

请注意,javascript会很乐意忽略额外的参数......

在html属性中,想法是阻止关闭属性,因此它们不允许使用空格,因为编写没有引号的属性是常见的,而在html4中它也是合法的。但是,我看到属性中使用的空格,用于为元素提供多个类,如:<tr class="tablerow odd">。因此,不使用空格会阻止此类类属性来自具有模板或其他来源的数据库......

  1. 鉴于在xhtml中禁止使用没有引号的属性而我的网站生成xhtml严格的doctype,我可以承受空格吗?
  2. 我应该禁止javascript的逗号吗?

2 个答案:

答案 0 :(得分:1)

您应该使用htmlspecialchars来转义HTML,使用json_encode来转义Javascript。

$timeout = json_encode('1000, evilCallback, evilCallback2');
echo "ajax( $timeout, myErrorHandler, mySuccessHandler );";

输出:

ajax( "1000, evilCallback, evilCallback2", myErrorHandler, mySuccessHandler );

在您的情况下,您还应该验证$timeout var的实际内容,或者将其转换为int:

$timeout = json_encode((int)'1000, evilCallback, evilCallback2');
echo "ajax( $timeout, myErrorHandler, mySuccessHandler );";

输出:

ajax( 1000, myErrorHandler, mySuccessHandler );

当你转换为int时,并不真正需要json_encode,因为PHP整数也是有效的JS整数,但最好还是为适当的上下文转义所有数据。


更新:关于您尝试调整的Twig代码,似乎它不会生成实际的Javascript文字,但会转义字符串以将包含到 Javascript文字中 - 从\xHH转义码的实际使用中可以看出这一点,它在JS中仅在字符串内部有效(和正则表达式,但不在此处)。它应该用作:

$timeout = escapeJS('1000, evilCallback, evilCallback2');
echo "ajax('$timeout', myErrorHandler, mySuccessHandler);";

请注意$timeoutecho周围的额外引号。这可能是这样做的,允许从多个转义部分组合更长的JS字符串,如'foo $escaped_part1 bar $escaped_part2 baz'

答案 1 :(得分:0)

我在XSS (Cross Site Scripting) Prevention Cheat Sheet上找到的内容:

对于HTML属性:

  

适当引用的属性只能使用相应的引号进行转义。不带引号的属性可以用许多字符来分解,包括[space]%* +, - /; &LT; =&gt; ^和|。

我认为这样看就意味着没有办法让两者都受到不带引号的属性的保护,并且在属性中有空格。我认为转义函数本身可以添加引号,但这样会产生不一致的创建情况,其中引用两次,基本上不引用它们......所以,现在我已经做了两个转义函数,允许用户明确地调用一个知道他们必须放置引号,这允许空间。

考虑javascript:

  

除字母数字字符外,使用\ xHH格式转义所有小于256的字符,以防止将数据值切换到脚本上下文或其他属性中。不要使用任何转义快捷方式,例如\“因为引号字符可能与首先运行的HTML属性解析器匹配。这些转义快捷方式也容易受到攻击者发送的”逃避逃逸“攻击以及易受攻击的代码把它变成“,这使得引用。

     

如果正确引用了事件处理程序,则分解需要相应的引用。但是,我们故意使此规则相当广泛,因为事件处理程序属性通常不加引号。不带引号的属性可以打破多个字符,包括[space]%* +, - /; &LT; =&gt; ^和|。此外,结束标记将关闭脚本块,即使它位于带引号的字符串中,因为HTML解析器在JavaScript解析器之前运行。

这似乎表明我们应该逃避一切。我选择保留下划线,因为它可以是javascript名称和点的一部分,以允许插入带小数点的数值。我希望不会留下任何漏洞。

我认为Twig代码有一个错误,只留下逗号和I will file a report,以便他们可以查看它。