Maison  >  Questions et réponses  >  le corps du texte

php安全 - PHP如何安全地使用$_GET

本人新手,在《PHP安全编码》中提到“不要直接使用$_GET”,同时又提到“可以尝试在php.ini中开启magic_quotes_gpc,这样对于所有由用户GET、POST、COOKIE中传入的特殊字符都会转义”,我很纠结,是否开启magic_quotes_gpc就可以直接使用$_GET?

如下面例子中的代码本人感觉很不安全,因为没有做验证,但又不知道如何改进,希望大神能帮忙,谢谢。

<?php
    $name = $_GET["name"];
    $user = $_GET["user"];
    mysql_query("SELECT $name FROM $user");
PHPzPHPz2772 Il y a quelques jours1609

répondre à tous(16)je répondrai

  • 伊谢尔伦

    伊谢尔伦2017-04-10 15:51:52

    你是想要filter_input函数,多看手册:

    http://www.w3school.com.cn/php/func_filter_input.asp

    répondre
    0
  • 阿神

    阿神2017-04-10 15:51:52

    纯数字的参数intval强制取整
    其他参数值进行过滤或者转义
    
        protected function zaddslashes($string, $force = 0, $strip = FALSE)
        {   
            if (!defined('MAGIC_QUOTES_GPC'))
            {   
             define('MAGIC_QUOTES_GPC', '');
            }   
            if (!MAGIC_QUOTES_GPC || $force)
            {   
             if (is_array($string)) {
                 foreach ($string as $key => $val)
                 {   
                     $string[$key] = $this->zaddslashes($val, $force, $strip);
                 }   
             }   
             else
             {   
                 $string = ($strip ? stripslashes($string) : $string);
                 $string = htmlspecialchars($string);
             }   
            }   
            return $string;
         }
    
    

    我一般都对$_POST $_GET都使用zaddslashes,然后整数的参数值进行取整,防止XSS和SQL注入

    HTTP头信息:IP、浏览器信息、等也进行转义过滤防止HTTP头注入

    magic_quotes_gpc开启后会影响图片上传等,自动将内容引号转义

    注意PHP5.5包括之后已经将magic_quotes_gpc配置废弃

    除此之外,最好在服务器方面也做关键词过滤,Mysql为业务使用到的库创建用户和赋权

    可以把自己应用放服务器上,装个sqlmap注入下自己试试,以上几点做到一般情况下不会被搞,至少不会被getshell

    乌云白帽子路过...

    répondre
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 15:51:52

    1. 像用户名这种有格式的东西,应该取到之后马上用正则表达式验证,比如preg_match('/\A\w{6,14}\z/', $user)就验证了它是不是6~14位的数字字母下划线。不要使用系统自带的filter,那个管不了什么用。

    2. 不要使用mysql开头的函数,要使用mysqli,而且最好进行参数化查询而不是addslashes,后者会有编码问题。

    3. 输出html的时候,默认使用htmlspecialchars,这个函数可以指定编码。或者你可以用现成的模板引擎。

    4. 比较字符串的时候,强制使用strcmp,不要使用双等号。

    5. 不要使用$_REQUEST

    这样可以防掉95%。至于magic_quotes_gpc,应该早就废了吧。

    répondre
    0
  • ringa_lee

    ringa_lee2017-04-10 15:51:52

    现在市面上这些书真的害人不浅,随便下结论或者是楼主没有仔细读。为什么直接使用 $_GET $_POST 不安全?

    看了楼主的例子,应该是直接将$_GET 用在拼接SQL上,这样肯定是不安全的,所以核心信息应该是:直接将 $_GET/$_POST等用户输入的内容用于SQL拼接是不安全的,如何避免?

    例如:

    sqlselect * from user where username= "$_GET['username']"
    

    如果用户提交的username 为

    sql" 0 or true or username ="
    

    那么就会变成这样:

    sqlselect * from user where username = "0" or true  or username=""
    

    那么会返回所有的用户记录。当然这里只是粗暴的举了一个例子。实际上要做XSS要熟知代码或者猜测到运行的逻辑等了解很多东西。

    最简单的过滤方法是使用 mysql_real_escape_string 函数

    至于 magic_quotes,是php最失败的一个改进,现已废弃,就算是低版本的PHP也一定要关闭它。

    répondre
    0
  • 天蓬老师

    天蓬老师2017-04-10 15:51:52

    如果 $_GET
    首先判断是否为空
    然后对值进行判断
    举个例子:
    只接受数字 那就使用 php自带函数 is_numeric

    一般 GET 也只是传递某个标识
    总之在数据库或其他操作之前 先验证 传过来的变量 是否为自己预期的值

    répondre
    0
  • 黄舟

    黄舟2017-04-10 15:51:52

    可以先对post或者get请求过滤,php有内置函数进行过滤,然后在使用

    répondre
    0
  • ringa_lee

    ringa_lee2017-04-10 15:51:52

    同意二楼的要有一个过滤,不过只是系统自带的肯定不行,最好自己再根据情况做一个过滤等之类的处理。

    répondre
    0
  • 迷茫

    迷茫2017-04-10 15:51:52

    防止XSS攻击,最简单粗暴的做法就是用htmlspecialchars把特殊字符(&,",',<,>)转换为HTML实体(&amp;&quot;&#039;&lt;&gt;)后输出.

    <?php
    echo htmlspecialchars($html, ENT_QUOTES, 'UTF-8');
    

    防止XSS攻击,最复杂的就是自己写正则过滤,不过还好有HTMLPurifier库,除了能过滤XSS代码,还能把不完整的标签补全或者去掉.Yii框架也用到了这个XSS过滤库.
    http://htmlpurifier.org/download

    <?php
    require dirname(__FILE__).'/htmlpurifier/library/HTMLPurifier.auto.php';
    $purifier = new HTMLPurifier();
    echo $purifier->purify($html);
    

    上面说的是防御XSS,下面说防御SQL注入:
    PDO和MySQLi等都提供有绑定参数查询的功能,而绑定参数的目的就是防止SQL注入.
    http://php.net/manual/zh/pdo.prepared-statements.php

    很多更成熟的数据库都支持预处理语句的概念.
    什么是预处理语句?可以把它看作是想要运行的SQL的一种编译过的模板,它可以使用变量参数进行定制.
    预处理语句可以带来两大好处:
    1.查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次.
    当查询准备好后,数据库将分析/编译/优化执行该查询的计划.
    对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度.
    通过使用预处理语句,可以避免重复分析/编译/优化周期.
    简言之,预处理语句占用更少的资源,因而运行得更快.
    2.提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理.
    如果应用程序只使用预处理语句,可以确保不会发生SQL注入.
    然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在SQL注入的风险.

    预处理语句如此有用,以至于它们唯一的特性是在驱动程序不支持的时候,PDO将模拟处理.
    这样可以确保不管数据库是否具有这样的功能,都可以确保应用程序可以用相同的数据访问模式.

    <?php
    $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour');
    $sth->bindParam(':calories', $calories, PDO::PARAM_INT);
    $sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
    $sth->execute();
    

    上面参与查询的变量$calories被绑定为整型,$colour被绑定为长度为12个字符的字符串型.
    MySQLi里同样提供有像PDO bindParam一样的bind_param,这时就不需要用addslashes,mysqli_real_escape_string之类的函数了,也不需要依赖magic_quotes_gpc配置了(该配置从PHP5.4开始已经被移除).
    用PDO操作MySQL时注意禁用模拟预处理,这样才会使用真正的预处理,这样才能确保程序先发送SQL模板给MySQL编译,然后再传参数过去执行,这样可以确保这些参数不被SQL注入.MySQLi扩展的预处理默认就是真正的预处理.

    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    

    这些都可以通过MySQL的general_log日志或者WireShark观察到.

    <?php
    $stmt = $mysqli->prepare('SELECT * FROM users WHERE username = ?');
    $stmt->bind_param('s', $_GET['username']); //s表示用户名被绑定为字符串型,整型用i.
    $stmt->execute();
    

    对于一些要求是整型的参数,其实还可以直接用intval($calories)拿到整型值.

    如果你要验证和过滤一些用户输入的数据,又不想自己写正则表达式,那就可以用filter_input/filter_var函数,比如验证邮箱,IP等:
    http://php.net/manual/zh/filter.filters.php

    répondre
    0
  • PHP中文网

    PHP中文网2017-04-10 15:51:52

    我来回答个无关的:
    Are PDO prepared statements sufficient to prevent SQL injection?

    PDO是否可以防住SQL注入。

    répondre
    0
  • PHPz

    PHPz2017-04-10 15:51:52

    建议你先看看
    joomla-framework的input类库,地址在这里
    或者先把joomla-framework的input类库在你的代码中使用(前期就不要考虑性能之类的问题),先搞明白对于$_GET(包括$_POST、$_FILES、$_COOKIE等)要进行怎样的处理,然后在以后的使用过程中自己选择是否实现简单版本。

    répondre
    0
  • Annulerrépondre