代码之家  ›  专栏  ›  技术社区  ›  Tesserex

安全地转义HTML和输入字段的输出

  •  5
  • Tesserex  · 技术社区  · 15 年前

    在我的Web应用程序中,用户可以输入文本数据。这些数据可以显示给其他用户,原始作者也可以返回并编辑他们的数据。我正在寻找正确的方法来安全地避开这些数据。

    我只是在进入的过程中进行SQL清理,所以所有内容都在读取时存储。假设我在数据库中有“d_)j_vu”。或者更极端的是, <script> 标签。这可能是有效的,甚至不是恶意的输入。

    我在用 htmlentities() 在出去的路上确保一切都安全。问题是HTML和输入字段对待事物的方式不同。我想确保它在HTML中是安全的,但是作者在编辑文本时,可以准确地看到他们在输入字段中键入的内容。我还使用jquery动态地用数据填充表单字段。

    如果我这样做:

     <p><?=htmlentities("déjà vu");?></p>
     <input type=text value="<?=htmlentities("déjà vu");?>">
    

    页面源放置 d&eacute;j&agrave; vu 在这两个地方(我不得不在上面打勾,否则你会看到“D_J_VU”!)问题在于 <p> 是正确的,但输入仅显示转义文本。如果用户重新提交表单,则会重复转义并破坏输入。

    我知道我仍然需要清理字段中的文本,否则您可以结束值引用并做坏事。我找到的唯一解决办法就是这个。同样,我在使用jquery。

    var temp = $("<div></div>").html("<?=htmlentities("déjà vu");?>");
    $("input").val(temp.html());
    

    这是有效的,因为它使DIV将转义文本作为编码字符读取,然后jquery将这些编码字符复制到输入标记中,并正确地保留这些字符。

    所以我的问题是:这是否仍然安全,或者在某个地方有安全漏洞?更重要的是,这是唯一/正确的方法吗?我是否遗漏了一些关于HTML和字符编码如何工作的信息,从而使这个问题变得微不足道?

    编辑

    事实上,这是错误的,我把我的例子过于简单化,以至于它不起作用。问题实际上是因为我使用jquery的val()将文本插入到字段中。

    <input>
    <script>$("input").val("<?=htmlentities("déjà vu");?>");</script>
    

    这样做的原因是表单是动态的-用户可以随意添加或删除字段,因此它们是在页面加载后生成的。

    因此,jquery似乎正在转义数据以进入输入,但这还不够好-如果我自己不做任何事情,用户仍然可以将 </script> 标记,杀死我的代码并插入恶意代码。但这里还有另一个争论。既然只有原始作者才能看到输入框中的文本,我还需要麻烦吗?基本上,他们唯一能执行XSS攻击的人就是他们自己。

    3 回复  |  直到 8 年前
        1
  •  5
  •   Álvaro González    8 年前

    对不起,我不能复制你描述的行为。我总是用 htmlspecialchars() (基本上与 htmlentities() )它不会导致任何形式的双重编码。页面源显示 d&eacute;j&agrave; vu 在这两个地方(当然!这就是重点!)但呈现的页面显示了适当的值,这就是发送回服务器的值。

    你能发布一个完整的展示这种行为的独立代码片段吗?

    更新 :一些测试代码:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    </head>
    <body>
    
    <?php
    
    $default_value = 'déjà vu <script> ¿foo?';
    
    if( !isset($_GET['foo']) ){
        $_GET['foo'] = $default_value;
    }
    
    ?>
    
    <form action="" method="get">
        <p><?php echo htmlentities($_GET['foo']); ?></p>
        <input type="text" name="foo" value="<?php echo htmlentities($_GET['foo']); ?>">
        <input type="submit" value="Submit">
    </form>
    
    </body>
    </html>
    

    更新问题的答案

    这个 HTMLN() 函数,顾名思义,是在生成HTML输出时使用的。这就是为什么它在第二个示例中很少使用:javascript是 HTML。它是一种有自己语法的语言。

    现在,您要解决的问题是如何生成遵循以下两个规则的输出:

    1. 它是javascript中的有效字符串。
    2. 它可以安全地嵌入到HTML文档中。

    我所知道的1最接近的PHP函数是 json_encode() . 因为JSON语法是JavaScript的一个子集,所以如果向它提供一个PHP字符串,它将输出一个JavaScript字符串。

    关于2,一旦浏览器进入一个javascript块,它期望 </script> 留下标签。json_encode()函数负责处理这个问题并正确地进行转义。( <\/script> )

    我修订的测试代码:

    <?php
    
    $default_value = 'déjà vu </script> ¿foo?';
    
    if( !isset($_GET['foo']) ){
        $_GET['foo'] = $default_value;
    }
    
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript"><!--
    $(function(){
        $("input[type=text]").val(<?php echo json_encode(utf8_encode($_GET['foo'])); ?>);
    });
    //--></script>
    </head>
    <body>
    
    
    <form action="" method="get">
        <p><?php echo htmlentities($_GET['foo']); ?></p>
        <input type="text" name="foo" value="(to be replaced)">
        <input type="submit" value="Submit">
    </form>
    
    </body>
    </html>
    

    注: utf8_encode() 从ISO-8859-1转换为UTF-8,如果数据已经是UTF-8格式,则不需要转换(推荐)。

        2
  •  1
  •   Frank    15 年前

    如果您只需要反转编码,那么可以使用HTML实体解码- http://www.php.net/manual/en/function.html-entity-decode.php .

    另一种可能是只在内容显示为网页的一部分时运行htmlentities。否则,将未编码的文本保留为从数据存储中提交或加载的文本。

        3
  •  0
  •   Josh Stodola    15 年前

    我相信这是一个问题,你是如何应用价值的输入。它被显示为编码的,这是有意义的,因为它是JavaScript,而不是HTML。所以,我建议将您的编码文本作为标记的一部分写入,以便自然地解析它(而不是注入客户机脚本)。由于服务器响应时文本框不可用,因此可以使用临时隐藏字段…

    <input type="hidden" id="hidEncoded" value="<?=htmlentities("déjà vu");?>" />
    

    然后它将被解析为好的旧HTML,当您试图用JavaScript访问该值时,它应该被解码…

    // Give your textbox an ID!
    $("#txtInput").val($("#hidEncoded").val());