php安全 - PHP如何安全地使用$_GET
PHPz
PHPz 2017-04-10 15:49:52
0
16
1536

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

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

PHPz
PHPz

学习是最好的投资!

reply all (16)
伊谢尔伦

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

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

    阿神
    纯数字的参数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

    乌云白帽子路过...

      伊谢尔伦

      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,应该早就废了吧。

        左手右手慢动作

        现在市面上这些书真的害人不浅,随便下结论或者是楼主没有仔细读。为什么直接使用 $_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也一定要关闭它。

          Peter_Zhu

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

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

            黄舟

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

              左手右手慢动作

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

                迷茫

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

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

                purify($html);

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

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

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

                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观察到.

                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

                  Ty80

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

                  PDO是否可以防住SQL注入。

                    PHPzhong

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

                      Latest Downloads
                      More>
                      Web Effects
                      Website Source Code
                      Website Materials
                      Front End Template
                      About us Disclaimer Sitemap
                      php.cn:Public welfare online PHP training,Help PHP learners grow quickly!