1

我不久前发布了这个问题,它非常适合从用户生成的帖子中查找和“链接”链接。 Linkify 正则表达式函数 PHP 大胆火球法

   <?php
if (!function_exists("html")) {
function html($string){
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
}

if ( false === function_exists('linkify') ):   
  function linkify($str) {
$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';
return preg_replace_callback("#$pattern#i", function($matches) {
    $input = $matches[0];
    $url = $matches[2] == 'http' ? $input : "http://$input";
    return '<a href="' . $url . '" rel="nofollow" target="_blank">' . "$input</a>";
}, $str); 
}
endif;

echo "<div>" . linkify(html($row_rsgetpost['userinput'])) . "</div>";

?>

我担心我可能会通过将用户生成的内容插入链接来引入安全风险。htmlspecialchars($string, ENT_QUOTES, 'UTF-8')在通过 linkify 函数运行它并回显到页面之前,我已经在转义来自我的数据库的用户内容,但是我在 OWASP 上读到需要对链接属性进行特殊处理以缓解 XSS。我认为这个功能没问题,因为它将用户生成的内容放在双引号内并且已经用 转义了htmlspecialchars($string, ENT_QUOTES, 'UTF-8'),但非常感谢具有 xss 专业知识的人来确认这一点。谢谢!

4

4 回答 4

1

首先数据在进入数据库之前一定不能被转义,这是非常严重的错误这不仅不安全,而且会破坏功能。链接字符串的值会导致数据损坏并影响字符串比较。这种方法是不安全的,因为XSS 是一个输出问题。当您将数据插入数据库时​​,您不知道它出现在页面上的什么位置。例如,即使您使用此函数,以下代码仍然容易受到 XSS 攻击:

例如:

<a href="javascript:alert(1)" \>

就您的正则表达式而言。我最初的反应是,这是一个可怕的想法。没有评论它应该如何工作以及大量使用 NOT 运算符,黑名单总是比白名单更糟糕。

所以我加载了Regex Buddy大约 3 分钟后,我用这个输入绕过了你的 regex:

https://test.com/test'onclick='alert(1);//

没有开发人员愿意编写易受攻击的代码,因此他们是由程序员认为他的应用程序如何工作以及它实际上如何工作的故障引起的。在这种情况下,我会假设您从未测试过这个正则表达式,并且它对问题的过度简化。

HTMLPurifer是一个旨在清理 HTML 的 php 库,它由数千个正则表达式组成。它非常慢,并且经常被绕过。所以如果你走这条路,一定要定期更新。

在修复这个缺陷方面,我认为你最好使用htmlspecialchars($string, ENT_QUOTES, 'UTF-8'),然后强制字符串以“http”开头。HTML 编码是一种转义形式,值会自动解码,从而使 URL 不受干扰。

于 2012-04-26T05:39:57.607 回答
1

因为数据进入一个属性,它应该是 url(或百分比)编码:

return '<a href="' . urlencode($url) . '" rel="nofollow" target="_blank">' . "$input</a>";

从技术上讲,它也应该是 html 编码的

return '<a href="' . htmlspecialchars(urlencode($url)) . '" rel="nofollow" target="_blank">' . "$input</a>";

但没有浏览器我知道关心,因此没有人这样做,听起来你可能已经在做这一步,你不想这样做两次

于 2012-04-26T05:52:21.060 回答
0

首先,正如 PHP 文档所述,htmlspecialchars 仅在未设置ENT_NOQUOTES时转义“'&'(与号)变为'&''”'(双引号)变为'"'。"'"(单引号)变为'''(或 ') 仅当设置了 ENT_QUOTES 时。'<'(小于)变为 '<' '>'(大于)变为 '>'"。javascript: 仍在常规编程中使用,所以为什么 : 没有转义超出了我的范围。

其次,如果 !html 只期望您认为将被输入的字符,而不是那些可以输入并被视为有效的字符的表示。utf -8 字符集,以及所有其他字符集都支持同一字符的多种表示形式。此外,您的错误陈述允许 0-9 和 az,因此您仍然需要担心base64 characters。我认为你的代码是一个很好的尝试,但它需要大量的改进。那或者你可以只使用htmlpurifier,人们仍然可以绕过它。我确实认为在 htmlspecialchars 中设置字符集真是太棒了,因为大多数程序员不明白他们为什么要这样做。

于 2014-01-05T23:38:39.480 回答
0

您的正则表达式正在寻找 http 或 https 的 url。该表达式似乎相对安全,因为 in 不会检测到任何不是 url 的内容。

XSS 漏洞来自将 url 转义为 html 参数。这意味着确保 url 不能过早地转义 url 字符串,然后向@Rook 提到的 html 标记添加额外的属性。

所以我真的想不出如何按照@tobyodavies 的建议执行 XSS 攻击,但没有 urlencode,它会做其他事情:

$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';
return preg_replace_callback("#$pattern#i", function($matches) {
    $input = $matches[0];
    $url = $matches[2] == 'http' ? $input : "http://$input";
    return '<a href="' . htmlspecialchars($url) . '" rel="nofollow" target="_blank">' . "$input</a>";
}, $str); 

请注意,我还添加了一个小快捷方式来检查 http 前缀。

现在您生成的锚链接是安全的。

但是,您还应该清理文本的其余部分。我想您根本不想允许任何 html 并将所有 html 显示为明文。

于 2012-04-26T13:55:50.420 回答