Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用PHP清理用户输入?_Php_Security_Xss_Sql Injection_User Input - Fatal编程技术网

如何使用PHP清理用户输入?

如何使用PHP清理用户输入?,php,security,xss,sql-injection,user-input,Php,Security,Xss,Sql Injection,User Input,是否有一个catchall函数可以很好地清除SQL注入和XSS攻击的用户输入,同时仍然允许某些类型的HTML标记?否。如果没有任何数据的上下文,您无法对数据进行常规筛选。有时您希望将SQL查询作为输入,有时您希望将HTML作为输入 您需要过滤白名单上的输入——确保数据符合您期望的某些规范。然后,您需要在使用它之前转义它,这取决于您使用它的上下文 为SQL转义数据的过程(防止SQL注入)与为(X)HTML转义数据的过程(防止XSS)非常不同。有过滤器扩展(,),它可以很好地处理所有GPC变量。虽然

是否有一个catchall函数可以很好地清除SQL注入和XSS攻击的用户输入,同时仍然允许某些类型的HTML标记?

否。如果没有任何数据的上下文,您无法对数据进行常规筛选。有时您希望将SQL查询作为输入,有时您希望将HTML作为输入

您需要过滤白名单上的输入——确保数据符合您期望的某些规范。然后,您需要在使用它之前转义它,这取决于您使用它的上下文


为SQL转义数据的过程(防止SQL注入)与为(X)HTML转义数据的过程(防止XSS)非常不同。

有过滤器扩展(,),它可以很好地处理所有GPC变量。虽然这不是一个神奇的“一劳永逸”的东西,但您仍然需要使用它。

要解决XSS问题,请查看。它是相当可配置的,并且有良好的业绩记录

至于SQL注入攻击,请确保检查用户输入,然后通过mysql\u real\u escape\u string()运行它。不过,该函数无法抵抗所有注入攻击,因此在将数据转储到查询字符串中之前检查数据非常重要

更好的解决方案是使用事先准备好的语句。和mysqli扩展支持这些功能。

不,没有

首先,SQL注入是一个输入过滤问题,XSS是一个输出转义问题——因此您甚至不会在代码生命周期中同时执行这两个操作

基本经验法则

  • 对于SQL查询,绑定参数(与PDO一样)或对查询变量(例如)使用驱动程序本机转义函数
  • 用于过滤掉不需要的HTML
  • 使用转义所有其他输出,并注意此处的第2和第3个参数

    • 用户输入可以过滤是一种常见的误解。PHP甚至有一个(现在已弃用的)“特性”,名为,它建立在这个想法之上。这是胡说八道。忘记过滤(或清洁,或其他人们称之为过滤的东西)

      为了避免出现问题,您应该做的很简单:每当您在外部代码中嵌入一段数据时,您必须根据该代码的格式规则来处理它。但您必须了解,这些规则可能太复杂,无法手动执行。例如,在SQL中,字符串、数字和标识符的规则都是不同的。为了您的方便,在大多数情况下,有一个专用的工具用于这种嵌入。例如,当您需要在SQL查询中使用PHP变量时,您必须使用一个准备好的语句,该语句将负责所有正确的格式/处理

      另一个例子是HTML:如果在HTML标记中嵌入字符串,则必须使用转义。这意味着每个
      echo
      print
      语句都应该使用
      htmlspecialchars

      第三个例子可能是shell命令:如果要将字符串(如参数)嵌入到外部命令中,并用调用它们,则必须使用and

      另外,一个非常引人注目的例子是JSON。规则是如此之多和复杂,你永远无法手动遵守它们。这就是为什么您永远不应该手动创建JSON字符串,而应该始终使用一个专用函数,该函数将正确格式化每一位数据

      诸如此类

      您需要主动筛选数据的唯一情况是,您正在接受预格式化的输入。例如,如果您允许用户发布您计划在网站上显示的HTML标记。但是,您应该明智地不惜一切代价避免这种情况,因为无论您如何过滤它,它始终是一个潜在的安全漏洞。

      PHP现在有了新的nice函数,例如,现在有了一个内置的
      过滤器\u验证\u电子邮件
      类型,您就可以从查找“终极电子邮件正则表达式”中解放出来


      我自己的过滤器类(使用JavaScript突出显示错误字段)可以通过ajax请求或普通表单post启动。(参见下面的示例)
      不要试图通过清理输入数据来阻止SQL注入

      相反,不允许在创建SQL代码时使用数据。使用使用绑定变量的准备语句(即在模板查询中使用参数)。这是防止SQL注入的唯一方法


      有关防止SQL注入的更多信息,请访问我的网站。

      在特定情况下,有一个技巧可以帮助您使用类似于
      /mypage?id=53的页面,并且您在where子句中使用id是为了确保id绝对是整数,如下所示:

      if (isset($_GET['id'])) {
        $id = $_GET['id'];
        settype($id, 'integer');
        $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
        # now use the result
      }
      

      当然,这只会减少一个特定的攻击,所以请阅读所有其他答案。(是的,我知道上面的代码不是很好,但它显示了具体的防御。)

      您在这里描述的是两个不同的问题:

    • 清理/过滤用户输入数据
    • 转义输出
    • 1) 应始终假定用户输入是错误的

      使用预先准备好的语句,或/或使用mysql\u real\u escape\u字符串进行过滤绝对是必须的。 PHP还内置了filter_输入,这是一个很好的起点

      2) 这是一个很大的主题,它取决于输出数据的上下文。对于HTML,有一些解决方案,比如htmlpurifier。 根据经验法则,输出的任何内容都要转义

      这两个问题都太大,无法在一篇文章中讨论,但有许多文章更详细:

      PHP5.2引入了该函数


      它支持大量的
      SANITIZE
      VALIDATE
      过滤器。

      只是想在输出转义的主题上添加这些,如果使用php DOMDocument生成html输出,它将在正确的上下文中自动转义。属性(值=“”)和的内部文本不相等。 成为
      if (isset($_GET['id'])) {
        $id = $_GET['id'];
        settype($id, 'integer');
        $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
        # now use the result
      }
      
      $mysqli->set_charset("utf8"); $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password); $pdo->exec("set names utf8"); $pdo = new PDO( "mysql:host=$host;dbname=$db", $user, $pass, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) ); mysql_set_charset('utf8') $stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
      $param = "' OR 1=1 /*";
      $stmt->bind_param('s', $param);
      $stmt->execute(); $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
      $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection)
      $var = $pdo->quote("' OR 1=1 /*");not only escapes the literal, but also quotes it (in single-quote ' characters) $stmt = $pdo->query("SELECT * FROM test WHERE name = $var LIMIT 1"); $pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
      $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); $stmt->execute(["' OR 1=1 /*"]); ctype_digit — Check for numeric character(s);
      $value = (int) $value;
      $value = intval($value);
      $var = filter_var('0755', FILTER_VALIDATE_INT, $options); is_string() — Find whether the type of a variable is string $email = filter_var($email, FILTER_SANITIZE_EMAIL);
      $newstr = filter_var($str, FILTER_SANITIZE_STRING); $search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
      function clean_input($data) {
        $data = trim($data);
        $data = stripslashes($data);
        $data = htmlspecialchars($data);
        return $data;
      }
      
      & (ampersand) becomes &
      " (double quote) becomes "
      ' (single quote) becomes '
      < (less than) becomes &lt;
      > (greater than) becomes &gt;