用PHP清理用户输入的最佳方法是什么?

Bre*_*ent 1069 php security xss user-input sql-injection

是否有一个catchall函数适用于清理SQL注入和XSS攻击的用户输入,同时仍允许某些类型的html标记?

tro*_*skn 1149

这是一种常见的误解,即用户输入可以被过滤.PHP甚至还有一个(现已弃用的)"功能",称为魔术引号,它建立在这个想法的基础之上.这是胡说八道.忘记过滤(或清洁,或任何人称之为).

为了避免出现问题,你应该做的很简单:每当你在外国代码中嵌入一个字符串时,你必须根据该语言的规则来逃避它.例如,如果在某些SQL目标MySql中嵌入字符串,则必须为此目的使用MySql函数转义字符串(mysqli_real_escape_string).(或者,对于数据库,如果可能,使用预处理语句是更好的方法)

另一个例子是HTML:如果在HTML标记中嵌入字符串,则必须使用它进行转义htmlspecialchars.这意味着每个单词echoprint语句都应该使用htmlspecialchars.

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

等等等等 ...

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

  • "这意味着每个echo或print语句应该使用htmlspecialchars" - 当然,你的意思是"每个...语句输出用户输入"; htmlspecialchars() - ifying"echo'Hello,world!';" 会很疯狂;) (235认同)
  • 有一种情况我认为过滤是正确的解决方案:UTF-8.您不希望在整个应用程序中使用无效的UTF-8序列(根据代码路径,您可能会获得不同的错误恢复),并且可以轻松地过滤(或拒绝)UTF-8. (10认同)
  • @jbyrd - 不,LIKE使用专门的正则表达式语言.您必须两次转义输入字符串 - 一次用于regexp,一次用于mysql字符串编码.它是代码中代码中的代码. (6认同)
  • 此时,不推荐使用`mysql_real_escape_string`.现在使用[预备语句](http://bobby-tables.com/php.html)来防止SQL注入是一种很好的做法.所以切换到MySQLi或PDO. (5认同)
  • 因为你限制了攻击面.如果您提前清理(输入时),则必须确保应用程序中没有其他漏洞可以输入错误数据.如果你做得很晚,那么你的输出功能就不必"信任"给它安全的数据 - 它只是假设一切都是不安全的. (4认同)
  • @porneL:是的,此时过滤掉换行以外的控制字符也是值得的.然而,鉴于大多数PHP应用程序甚至无法获得HTML转义,但我不打算推​​出过长的UTF-8序列问题(它们只是IE6 pre-Service-Pack-2和旧版本中的一个问题.歌剧). (3认同)
  • 当我做出这个答案时,@david 5.2.0 已经出来了。 (3认同)
  • 嗨特罗尔斯 - 感谢您的回答。我每天使用的大多数框架和语言,包括 PHP、Javascript 和 Apache Web 服务器,过去在“清理”输入方面都表现得非常失败(神奇的引号天哪!),如果他们不能正确处理,那又如何呢?我有机会吗?目前,我对我编写的所有 SQL 都使用准备好的语句,对于 html,我使用 htmlspecialchars 的变体,坦率地说,我仍然不能 100% 确定我没有遗漏一些东西。安全很难。 (3认同)
  • 我意识到这是一个老问题,但是从PHP 5.2.0开始,PHP引入了Filters(http://www.php.net/manual/en/book.filter.php)和函数filter_var(),它们在传递时值和适当的过滤器将清除或验证提供的用户输入。 (2认同)
  • @Jens Roland - 你说得对; 安全很难.试图将其委托给一个框架可能不是一个好策略.更好地理解我们正在处理的事情.听起来你有最常见的基础. (2认同)
  • 我已经很久没有接触PHP了;回到它并看到这个关于弃用魔术引号的答案让我很高兴。 (2认同)
  • 虽然有用,但不能回答实际问题。他们想在输入中允许一些HTML标记。关于如何执行此操作的唯一建议是考虑使用htmlspecialchars不允许它们。支持它们可能是某种客户需求。我已经看到许多网站在输入上支持某些HTML标记(例如slashdot.org),因此我只能假设这是可能的。 (2认同)
  • @tastro不,您不会在输入数据时进行清理-在使用数据时会进行清理。例如越晚越好。这将为您提供最佳的安全级别。 (2认同)
  • @troelskn 你能告诉我“为什么”如果我尽可能晚地这样做,它会给我最好的安全级别吗?谢谢! (2认同)
  • @troelskn“如果你尽早清理,你必须确保应用程序中没有其他漏洞可以让坏数据进入”你在晚些时候进行清理时也会遇到同样的问题:你必须确保应用程序中没有其他漏洞您正在使用数据的应用程序。直觉上,我似乎更容易错过数据使用而不是数据输入。 (2认同)
  • @YourCommonSense 感谢您的反馈,尽管它给人的感觉是“一点点”对抗性,特别是对于这个网站!不过,我不会否认这个评论。我不认为“echo 'hello world';” 应该写成“echo htmlspecialchars('hello world');”。显然,我同意你的观点,但我认为这将防御性编程推向了极致。不过,如果您有的话,我很想在重要的代码库中看到这种方法的示例。 (2认同)

And*_*ter 209

不要试图通过清理输入数据来阻止SQL注入.

相反,不要在创建SQL代码时使用数据.使用使用绑定变量的Prepared Statements(即使用模板查询中的参数).这是防止SQL注入的唯一方法.

有关阻止SQL注入的更多信息,请访问我的网站http://bobby-tables.com/.

  • 或者访问[官方文档](http://php.net/manual/en/pdo.prepared-statements.php)并学习PDO和准备好的声明.微小的学习曲线,但如果你很熟悉SQL,你就可以轻松适应. (16认同)
  • 请注意,预准备语句不会添加任何安全性,参数化查询会这样做.它们碰巧在PHP中很容易一起使用. (4认同)
  • 对于SQL注入的具体情况,*this*是正确的答案! (2认同)

Dan*_*ian 77

不可以.如果没有任何上下文,您无法对数据进行一般过滤.有时您想要将SQL查询作为输入,有时您希望将HTML作为输入.

您需要过滤白名单上的输入 - 确保数据符合您期望的某些规格.然后,您需要在使用它之前将其转义,具体取决于您使用它的上下文.

转义SQL数据的过程 - 防止SQL注入 - 与转换(X)HTML数据的过程非常不同,以防止XSS.


Sch*_*kie 48

PHP现在具有新的漂亮的filter_input函数,例如,现在有一个内置的FILTER_VALIDATE_EMAIL类型可以让你找到"最终的电子邮件正则表达式"

我自己的过滤器类(使用javascript来突出显示错误的字段)可以由ajax请求或普通表单发布.(见下面的例子)

/**
 *  Pork.FormValidator
 *  Validates arrays or properties by setting up simple arrays. 
 *  Note that some of the regexes are for dutch input!
 *  Example:
 * 
 *  $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
 *  $required = array('name', 'email', 'alias', 'pwd');
 *  $sanitize = array('alias');
 *
 *  $validator = new FormValidator($validations, $required, $sanitize);
 *                  
 *  if($validator->validate($_POST))
 *  {
 *      $_POST = $validator->sanitize($_POST);
 *      // now do your saving, $_POST has been sanitized.
 *      die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
 *  }
 *  else
 *  {
 *      die($validator->getScript());
 *  }   
 *  
 * To validate just one element:
 * $validated = new FormValidator()->validate('blah@bla.', 'email');
 * 
 * To sanitize just one element:
 * $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
 * 
 * @package pork
 * @author SchizoDuckie
 * @copyright SchizoDuckie 2008
 * @version 1.0
 * @access public
 */
class FormValidator
{
    public static $regexes = Array(
            'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}\$",
            'amount' => "^[-]?[0-9]+\$",
            'number' => "^[-]?[0-9,]+\$",
            'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$",
            'not_empty' => "[a-z0-9A-Z]+",
            'words' => "^[A-Za-z]+[A-Za-z \\s]*\$",
            'phone' => "^[0-9]{10,11}\$",
            'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$",
            'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$",
            'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$",
            '2digitopt' => "^\d+(\,\d{2})?\$",
            '2digitforce' => "^\d+\,\d\d\$",
            'anything' => "^[\d\D]{1,}\$"
    );
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
    {
        $this->validations = $validations;
        $this->sanitations = $sanitations;
        $this->mandatories = $mandatories;
        $this->errors = array();
        $this->corrects = array();
    }

    /**
     * Validates an array of items (if needed) and returns true or false
     *
     */
    public function validate($items)
    {
        $this->fields = $items;
        $havefailures = false;
        foreach($items as $key=>$val)
        {
            if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
            {
                $this->corrects[] = $key;
                continue;
            }
            $result = self::validateItem($val, $this->validations[$key]);
            if($result === false) {
                $havefailures = true;
                $this->addError($key, $this->validations[$key]);
            }
            else
            {
                $this->corrects[] = $key;
            }
        }

        return(!$havefailures);
    }

    /**
     *
     *  Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
     */
    public function getScript() {
        if(!empty($this->errors))
        {
            $errors = array();
            foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; }

            $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
            $output .= "new FormValidator().showMessage();";
        }
        if(!empty($this->corrects))
        {
            $corrects = array();
            foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; }
            $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';   
        }
        $output = "<script type='text/javascript'>{$output} </script>";
        return($output);
    }


    /**
     *
     * Sanitizes an array of items according to the $this->sanitations
     * sanitations will be standard of type string, but can also be specified.
     * For ease of use, this syntax is accepted:
     * $sanitations = array('fieldname', 'otherfieldname'=>'float');
     */
    public function sanitize($items)
    {
        foreach($items as $key=>$val)
        {
            if(array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
            $items[$key] = self::sanitizeItem($val, $this->validations[$key]);
        }
        return($items);
    }


    /**
     *
     * Adds an error to the errors array.
     */ 
    private function addError($field, $type='string')
    {
        $this->errors[$field] = $type;
    }

    /**
     *
     * Sanitize a single var according to $type.
     * Allows for static calling to allow simple sanitization
     */
    public static function sanitizeItem($var, $type)
    {
        $flags = NULL;
        switch($type)
        {
            case 'url':
                $filter = FILTER_SANITIZE_URL;
            break;
            case 'int':
                $filter = FILTER_SANITIZE_NUMBER_INT;
            break;
            case 'float':
                $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
            break;
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_SANITIZE_EMAIL;
            break;
            case 'string':
            default:
                $filter = FILTER_SANITIZE_STRING;
                $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
            break;

        }
        $output = filter_var($var, $filter, $flags);        
        return($output);
    }

    /** 
     *
     * Validates a single var according to $type.
     * Allows for static calling to allow simple validation.
     *
     */
    public static function validateItem($var, $type)
    {
        if(array_key_exists($type, self::$regexes))
        {
            $returnval =  filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
            return($returnval);
        }
        $filter = false;
        switch($type)
        {
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_VALIDATE_EMAIL;    
            break;
            case 'int':
                $filter = FILTER_VALIDATE_INT;
            break;
            case 'boolean':
                $filter = FILTER_VALIDATE_BOOLEAN;
            break;
            case 'ip':
                $filter = FILTER_VALIDATE_IP;
            break;
            case 'url':
                $filter = FILTER_VALIDATE_URL;
            break;
        }
        return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
    }       



}
Run Code Online (Sandbox Code Playgroud)

当然,请记住,您需要进行sql查询转义,具体取决于您使用的数据库类型(例如,mysql_real_escape_string()对于SQL Server无用).您可能希望在适当的应用程序层(如ORM)自动处理此问题.另外,如上所述:输出到html使用其他php专用函数,如htmlspecialchars;)

对于真正允许带有类似剥离类和/或标记的HTML输入,取决于其中一个专用的xss验证包.不要将自己的注册内容写入PARSE HTML!

  • 这看起来可能是一个用于验证输入的方便脚本,但它与问题完全*无关. (15认同)
  • @Reham Fahmy:此代码来自 2008 年。现在是 2022 年。不要使用这个。使用框架。 (2认同)

Pet*_*ley 44

不,那里没有.

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

基本的经验法则

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

  • 如果您的用户数据将进入数据库并稍后显示在网页上,那么它通常不会比编写的更多地阅读吗?对我来说,在存储它之前过滤它一次(作为输入)更有意义,而不是每次显示它时都必须过滤它.我是否遗漏了一些东西,或者是否有很多人投票支持这个和接受的答案中的不必要的性能开销? (2认同)
  • 对我来说最好的答案.它很简短,如果你问我,我会很好地解决这个问题.是否有可能通过$ _POST或$ _GET以某种方式攻击PHP,或者这是不可能的? (2认同)

jas*_*bar 22

要解决XSS问题,请查看HTML Purifier.它相当可配置,并具有良好的跟踪记录.

至于SQL注入攻击,请确保检查用户输入,然后通过mysql_real_escape_string()运行它.但是,该函数不会破坏所有注入攻击,因此在将数据转储到查询字符串之前检查数据非常重要.

更好的解决方案是使用预准备语句.该PDO库和mysqli扩展支持这些.


dan*_*gel 20

PHP 5.2引入了filter_var函数.

它支持大量的SANITIZE,VALIDATE过滤器.

http://php.net/manual/en/function.filter-var.php


Ham*_*ner 16

在你有一个页面的特定情况下可以帮助的一个技巧,/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
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我使用$ id = intval($ id)代替:) (10认同)

Mar*_*tin 13

使用PHP清理用户输入的方法:

  • 使用MySQL和PHP的现代版本.

  • 明确设置charset:

    • $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')
      [在PHP 5.5.0中弃用,在PHP 7.0.0中删除].
  • 使用安全字符集:

    • 选择utf8,latin1,ascii ..,不要使用易受攻击的字符集big5,cp932,gb2312,gbk,sjis.
  • 使用空间化功能:

    • MySQLi编写的语句:
      $stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1'); 
      $param = "' OR 1=1 /*";
      $stmt->bind_param('s', $param);
      $stmt->execute();
    • PDO :: quote() - 在输入字符串周围放置引号(如果需要)并使用适合于底层驱动程序的引用样式转义输入字符串中的特殊字符:

      $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准备语句:vs MySQLi预处理语句支持更多数据库驱动程序和命名参数:

      $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 /*"]);

    • mysql_real_escape_string [在PHP 5.5.0中已弃用,在PHP 7.0.0中删除].
    • mysqli_real_escape_string转义字符串中的特殊字符,以便在SQL语句中使用,同时考虑连接的当前字符集.但是建议使用Prepared Statements,因为它们不仅仅是转义字符串,一个语句提出了一个完整的查询执行计划,包括它将使用哪些表和索引,这是一种优化的方式.
    • 在查询中的变量周围使用单引号('').
  • 检查变量包含您期望的内容:

    • 如果您期望一个整数,请使用:
      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

      使用过滤器函数 filter_var() - 使用指定的过滤器过滤变量:
      $email = filter_var($email, FILTER_SANITIZE_EMAIL);
      $newstr = filter_var($str, FILTER_SANITIZE_STRING);
      预定义过滤器
    • filter_input() - 按名称获取特定的外部变量,并可选择对其进行过滤:
      $search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
    • preg_match() - 执行正则表达式匹配;
    • 编写自己的验证功能.


And*_*rew 11

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

  1. 消除/过滤用户输入数据.
  2. 逃避输出.

1)应始终假定用户输入不良.

使用预准备语句,或/和使用mysql_real_escape_string进行过滤绝对是必须的.PHP还内置了filter_input,这是一个很好的起点.

2)这是一个很大的主题,它取决于输出数据的上下文.对于HTML,有像htmlpurifier这样的解决方案.根据经验,总是逃避你输出的任何东西.

这两个问题都太大了,无法在一篇文章中介绍,但有很多帖子更详细:

方法PHP输出

更安全的PHP输出


web*_*lik 10

没有包罗万象的功能,因为有多个问题需要解决。

  1. SQL 注入- 今天,通常每个 PHP 项目都应该通过 PHP 数据对象 (PDO)使用准备好的语句作为最佳实践,以防止错误引用以及针对注入的全功能解决方案。这也是访问数据库的最灵活和最安全的方式。

查看(唯一合适的)PDO 教程,了解您需要了解的有关 PDO 的几乎所有内容。(衷心感谢顶级 SO 贡献者 @YourCommonSense 提供了有关该主题的重要资源。)

  1. XSS - 在途中清理数据...
  • HTML Purifier已经存在很长时间了,并且仍在积极更新中。您可以使用它来清理恶意输入,同时仍然允许大量且可配置的标签白名单。适用于许多 WYSIWYG 编辑器,但对于某些用例来说可能很繁重。

  • 在其他情况下,我们根本不想接受 HTML/Javascript,我发现这个简单的函数很有用(并且已经通过了针对 XSS 的多次审核):

    /* Prevent XSS input */
    function sanitizeXSS () {
        $_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
        $_POST  = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
        $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  1. XSS - 在输出时清理数据...除非您保证在将数据添加到数据库之前已正确清理数据,否则您需要在将其显示给用户之前对其进行清理,我们可以利用这些有用的 PHP 函数:
  • 当您调用echoprint显示用户提供的值时,htmlspecialchars除非数据经过适当的安全处理并允许显示 HTML ,否则请使用。
  • json_encode 是一种将用户提供的值从 PHP 提供到 Javascript 的安全方式
  1. 您是使用exec()system()函数还是向backtick操作员调用外部 shell 命令?如果是这样,除了 SQL 注入和 XSS 之外,您可能还有一个需要解决的问题,即用户在您的服务器上运行恶意命令escapeshellcmd如果您想转义整个命令或escapeshellarg转义单个参数,则需要使用。


Ale*_*lva 8

如果您正在使用PostgreSQL,可以使用pg_escape_string()转义PHP的输入

 $username = pg_escape_string($_POST['username']);
Run Code Online (Sandbox Code Playgroud)

从文档(http://php.net/manual/es/function.pg-escape-string.php):

pg_escape_string()转义用于查询数据库的字符串.它返回PostgreSQL格式的转义字符串,不带引号.

  • **[pg_escape_literal()](https://php.net/manual/es/function.pg-escape-literal.php)** 是 PostgreSQL 推荐使用的函数。 (2认同)

sym*_*ean 6

你永远不会清理输入。

您总是清理输出。

您为使其安全地包含在 SQL 语句中而对数据应用的转换与您申请包含在 HTML 中的转换完全不同,与您申请包含在 Javascript 中的转换完全不同,与您申请包含在 LDIF 中的转换完全不同:与您应用于包含在 CSS 中的内容完全不同 与您应用于包含在电子邮件中的内容完全不同......

无论如何都要验证输入- 决定是否应该接受它以进行进一步处理或告诉用户这是不可接受的。但是,在数据即将离开 PHP 之前,不要对数据的表示进行任何更改。

很久以前,有人试图发明一种万能的转义数据机制,我们最终得到了“ magic_quotes ”,它没有正确转义所有输出目标的数据,并导致不同的安装需要不同的代码才能工作。


Ond*_*tek 5

避免清理输入和转义数据时出错的最简单方法是使用像Symfony,Nette等PHP框架或该框架的一部分(模板引擎,数据库层,ORM).

Twig或Latte 这样的模板引擎默认情况下输出转义 - 如果您根据上下文(网页的HTML或Javascript部分)正确转义输出,则无需手动解决.

框架自动清理输入,你不应该直接使用$ _POST,$ _GET或$ _SESSION变量,而是通过路由,会话处理等机制.

对于数据库(模型)层,有像Doctrine这样的ORM框架或者像Nette Database这样的PDO包装器.

您可以在此处阅读更多相关信息 - 什么是软件框架?