使用已使用 filter_input() 过滤的 htmlspecialchars() 从数据库输出数据

output data from database using htmlspecialchars() that has been filtered using filter_input()

我从不同的博客中发现,强烈建议使用 htmlspecialchars() 在屏幕上输出任何数据以免受 XSS Attack 的影响。

我正在使用 filter_input() 在插入 database 之前过滤来自用户的任何数据。 filter_input()' 等特殊字符转换为 ' 并以这种方式保存,例如

 I'm going to shopping with Molly's sister;Dolly

。我的问题是

How can I print(output) apostrope or quotes and specific special characters to users screen using htmlspecialchars so that the output would be user friendly

我曾尝试使用 htmlspecialchars($post,ENT_NOQUOTES);,但它给了我存储在 database.If 中的相同数据副本 我不使用 htmlspecialchars(),只是 $post给了我预期的结果,我认为它容易受到 XSS Attack

感谢您的宝贵时间,期待得到同行的帮助。

编辑

我得到了使用 htmlspecialchars_decode()html_entity_decode() 作为答案的建议,但是 (https://whosebug.com/users/1338292/ja͢ck) 和其他一些人建议不要使用这些 functions 在屏幕上输出数据。

请注意,我正在使用 prepared statementparameterized query。但我不想保留任何安全漏洞,这就是为什么在发送到数据库之前过滤数据。

因为我在发送到数据库之前使用了filter_input()来过滤数据,所以直接从数据库输出数据($post=$posted_data;)而不使用htmlspecialchars是否安全?

如果一定要用htmlspecialchars输出数据,那么这种情况下怎么办呢?

代码示例

 $stmt1=mysqli_stmt_init($connect_dude);

 /*Inserting into database*/

 if(isset($_POST['titlex']) && isset($_POST['pricex'])  && isset($_POST['detailx'])){
  $tit=filter_input(INPUT_POST,'titlex',FILTER_SANITIZE_STRING);
  $pri=preg_replace('#[^0-9]#','',$_POST['pricex']);
  $det=filter_input(INPUT_POST,'detailx',FILTER_SANITIZE_STRING); 

  $query2="INSERT INTO `hotel1`.`dine` (user_id,title,price,detail) VALUES (?,?,?,?)";

    mysqli_stmt_prepare($stmt1,$query2);
    mysqli_stmt_bind_param($stmt1, "isis", $logged_id, $tit, $pri, $det);
    mysqli_stmt_execute($stmt1);    
 }

 /*Get Data from DB*/

 $query1="SELECT id101,title,price,detail FROM `hotel1`.`dine` WHERE user_id=?";

    mysqli_stmt_prepare($stmt1,$query1);
    mysqli_stmt_bind_param($stmt1, "i", $user_idx);
    mysqli_stmt_execute($stmt1);
    mysqli_stmt_store_result($stmt1);
    mysqli_stmt_bind_result($stmt1, $id101, $title,$price, $detail);

    while(mysqli_stmt_fetch($stmt1)){
     $id101=$id101;
     $title=$title;        //htmlspecialchars needed
     $price=$price;       //htmlspecialchars needed
     $detail=$detail;    //htmlspecialchars needed

     ........................
     ........................
     }

你想反过来:) htmlspecialchars_decode()

您不需要,当您对它们进行编码并将它们保存到数据库时,它们将按原样显示在网页上(当您使用 echo $result['message']; 时)。浏览器自动解码它们。

我正在使用这个函数去除输入:

function stripinput($text) {
    if (!is_array($text)) {
        $text = trim($text);
        $text = preg_replace("/(&)+(?=\#([0-9]{2,3});)/i", "&", $text);
        $search = array("&", "\"", "'", "\", '\"', "\'", "<", ">", "&nbsp;");
        $replace = array("&amp;", "&quot;", "&#39;", "&#92;", "&quot;", "&#39;", "&lt;", "&gt;", " ");
        $text = str_replace($search, $replace, $text);
    }else{
        foreach ($text as $key => $value) {
            $text[$key] = stripinput($value);
        }
    }
    return $text;
}

I am using filter_input() to filter any data that comes from user before inserting into database.

这是一种不好的做法。 在将数据插入数据库之前不要破坏它。现在是 2015 年;不要清理,而是使用准备好的语句。

$db = new \PDO(
    'mysql:host=localhost;dbname=mydatabase;charset=UTF-8',
     $username,
     $password
);

// other stuff in between

$statement = $db->prepare(
    "INSERT INTO yourtable (email, username) VALUES (:email, :username);"
);
$success = $statement->execute([
    ':email'    => $_POST['email'],
    ':username' => $_POST['username']
]);

准备好的语句不再需要 filter_input()。这样做并没有增加纵深防御,只会破坏数据完整性并让自己头疼。

渲染输出时,如果要允许 HTML,请使用 HTML Purifier

否则,使用 htmlspecialchars($output, ENT_QUOTES | ENT_HTML5, 'UTF-8') 以获得最佳效果。

推荐阅读:Web Application Security 作者:Taylor Hornby。

我认为你的策略有问题。

您当然需要过滤输入和输出内容,但您正在覆盖它们 - 双重转义。
问题是你的输入过滤器也在做输出过滤器的工作。

As I have used filter_input() to filter data before sending to database,is it safe to output data directly($post=$posted_data;) from database without using htmlspecialchars?

没有。不要相信您的数据库,或者至少不总是如此。这不是第一个 SQL 注入导致巨大 XSS 的案例。

If I must need to use htmlspecialchars to output data,then how can I do it in this case?

正如我上面所说,停止使用输入过滤器进行输出过滤。您的输入过滤器应该确保数据对于内部使用是安全的——以保护您的应用程序免受非缩进操作的影响。因此,您无需在插入到数据库之前转义 HTML,作为奖励,您将节省 space.

另一方面,输出过滤器关心最终用户。您从数据库中获取数据并将其发送给用户。我们谈论的是 htmlspecialchars,这与 ENT_QUOTES 没问题,但在我看来还不够。你还应该转义像 ( ) [ ] = + - \ 这样的字符,因为有一些情况您不需要对 open/end 任何标签或使用引号进行成功的 XSS 攻击。例如当你将数据输出到 onclick

我刚刚看到 htmlspecialchars 有 double_encode 参数,这最终会解决你的问题:

htmlspecialchars($string, ENT_QUOTES, "UTF-8", false);

这样做将始终保持 HTML 特殊字符转义,并且不会转义已经转义的内容。