PHP防注入攻击

纯数字的参数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配置废弃

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

================================================================================

防止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观察到.
225047_UF1o_561214.png

<?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


============================================================================================

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

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

例如:

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

如果用户提交的username 为

" 0 or true or username ="

那么就会变成这样:

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

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

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

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

=========================================================================================

1.对用户输入进行安全过滤
2.关闭PHP危险函数
3.关闭PHP错误提示
4.关闭PHP超全局变量
5.注意XSS攻击
6.避免SQL注入
7.上传验证


==============================================================================

1.打死也不要手工拼接sql语句,全改成参数化查询(如果用了只能一个一个找,把用户能影响到的那部分给转义了).

2.关于xss是进库之前过滤好还是出库时过滤好,我也没个准确的答案,个人是倾向进库前过滤的,毕竟团队不是每个人都有安全意识,在出库时再过滤的话,有可能有人员会疏忽,后果你懂的,安全出问题往往是最薄弱的那一环节.

只要是不应该出现html标签的地方,都记得要过滤,哪怕是上传图片后的图片地址,友情连接的a标签.

htmlpurifier是一个很好的xss过滤库,不过也挺占资源的,要在出库时过滤的话,就得配合缓存.

做到这里,应该就只剩界面劫持的漏洞了吧?这个就比较难防御了,因为没有过滤css,在发布文章等富文本时,我发一个高仿登录框的html代码,搞成在屏幕居中且悬浮在最上层,有多少用户看到这个登陆框会手贱输入帐号信息然后点击登陆?那form标签要过滤吗?要是用户想发个投票帖怎么办?....这个就得看设计思路了...

3.csrf这玩意很多人会忽略的,只要在能对数据进行修改的地方,我都觉得得加一个token避免,token的话我觉得生成一次放在cookie里并设置http-only就够了,凡是有表单是修改的,或者有个地址加个id就可以删除的,都要带上这个token,并且在php里验证是否一致.

4.能删除文件的地方,得记得过滤啊,要是人家传个../../之类的文件名,你什么都不判断就删了,文件任意删除漏洞就出来了,读取的话同理.

5.接口安全啊,提供给客户端的接口,记得多多判断啊,比如一个给app用的登陆接口,没验证码的话,就容易被爆破了;获取用户信息的接口,没有校验来源的身份的话,那用户信息泄漏就出来了.

6.图片不防盗链真的好吗?我去各大论坛想办法挤到最热帖子的第一页,发n个图片,图片连接全是你的图,你网站的速度和流量...不忍直视啊.

7.上传漏洞就懒得说了,反正有文件上传的地方都得判断,免得别人直接传个shell...

8.调用系统命令时候,如果有能被用户影响部分的也要记得过滤再过滤,想想最近的bash漏洞就懂了...

9.业务逻辑漏洞,像商品价格,数量负数这个应该都科普了吧,像身份认证这种只要cookie里有个flag=1这种就能进后台现在也少了吧?逻辑漏洞还是去乌云看看各大厂商的比较好

10.人员的安全意识也很重要啊,要是人家密码硬是用了个弱密码,或者跟个人信息密切相关的密码,然后被社工到也是没办法的是吧.你要是给个复杂的密码,人家把密码保存在txt里,然后电脑中毒了你也没办法的是吧.要是随便来个人对管理员说:你们网站是我做的,现在要升级了,没有帐号进不去,麻烦你给我下,管理员就傻乎乎地给了,你也是没办法的是吧...到最后基本都是人员的安全问题了.

11.切记一定要把用户当成大恶人啊,用户提交的数据都是不可信的啊...php层一定要判断再判断,过滤再过滤啊...到这里应该web层的都走了个遍吧?遗漏的就等小伙伴们帮补充了,服务器安全性的我是个渣,就不多说了

============================================================================================================

安全问题要细心,业务安全靠经验,中几次枪就知道了。代码层面上要考虑的主要有五项

1、SQL注入。用PDO、mysqli_*的参数化查询来查询数据库,使用数据库预处理;
2、XSS攻击。正常情况下不存在特殊字符的使用htmlspecialchars转义,反之过滤特殊字符;
3、CSRF。严格来说非幂等操作都加上token,但实际上比较重要的接口验证一下就行了;
4、权限控制。比如登录状态、操作权限之类的,用session/cookie加密后维护登录状态,用RBAC之类的方案验证权限;
5、文件验证。上传、删除、修改文件都要严加验证


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值