为了账号安全,请及时绑定邮箱和手机立即绑定

php程序的安全要素

标签:
PHP

前段时间写了一个 “PHP开发的一些漏洞安全知识” 。内容比较好有实例,但不全。于是我决定收集一些PHP程序安全要素,用于以后分析和提醒。个人技术有限如有不当之处还请指正。

漏洞都源于与客户会话,接收客户提交数据。可以说“一切提交的数据都是不安全的”。虽然现在程序安全不断的被重视与升级,但是没有“绝对的安全”。也只有这样我们才可以不断的提升,找到程序的乐趣和奥妙。本文参考了 https://code.google.com/p/pasc2at/wiki/SimplifiedChinese

现在有很多的开源系统都存在有漏洞,虽然他们都在努力解决这些问题,实际也现体出了“道高一尺魔高一丈”的局面,以至于写的代码还得通过一些安全审计人员检测与分析。当然这些审计基本只是通过查找有没有一些关键词(容易出现漏洞的语句),现在都有好多的工具来查找。即使查找出来的不全有漏洞,但可以看的出来程序员中有很多的人“只看重功能不看重安全”,因为在外界来看功能是最直接的,而安全只是囗头话。我也相信很多的项目为了赶时间也会暂时放弃这一问题,但我认为程序员的安全功底能直接限制其的程序是否安全。所以学习程序漏洞知识是每一个好程序员必上的一课。


mysql_connect('localhost','root','');

mysql_select_db('test');

mysql_query('set names utf8');

$sql="select password from user where name='{$_POST['name']}'";

$re=mysql_query($sql);

$arr=mysql_fetch_assoc($re);

if(mepty($arr['password'])&&$arr['password']==md5($_POST['password'])){

echo '登录成功';

}else{

echo '登录失败';

}

这个是我最初使用的登录基本代码,大部人认为只要把密码与用户名分开操作就可以防止SQL注入,如果在$_POST['name']进入SQL前没有进行添加转义处理那么就可以输入一些你想到没有办法想到的SQL操作,让你的程序执行别人的SQL(比如在用户名框输入:' union select '202cb962ac59075b964b07152d234b70'; -- 密码框输入:202cb962ac59075b964b07152d234b70 那么你还认为这个是安全代码吗?)如果你想说别人不知道我的程序代码结构或我可以多取两个字段等的说法,那你就完全是一个不合格的程序员,不能写出一个严谨程序是一个程序员最大的失败。


if(isset($_COOKIE['cart'])&&!empty($_COOKIE['cart']))

$cart=unserialize($_COOKIE['cart']);

else $cart=array();

froeach($cart as $k=>$v)

{

$sql='select * from goods where id='.$k;

$re=mysql_query($sql);

if(is_resource($re))

{

$arr=mysql_fetch_assoc($re);

echo '商品名:'.$arr['name'].' 数量:'.$v['num'].' 单价:'.$arr['price'];

}

}

这个是我最初使用的购物车功能,购物车是电商平台必须有的功能,虽然实现的方法那是多种多样的。尤其在保存数据上,可写在SESSION,数据库,内存缓存(如memcache),COOKIE,如果你愿意还可以写在文件里,后期可能还会写到HTML5的数据保存机制内,要说哪种最好,各说风云。写在COOKIE里有利于服务性能,但有些牛人说这个不安全;写在SESSION里不利于服务器性能,但有些牛人就认为这种安全;写在数据库里其实还不如写在SEESION里,但使用这种方法有还真有(如ecshop);如果写在memcache里那也只能说这公司很有实力;如果真的要写在文件里,那我只想说你还是写在SESSION里更好更方便。在这里我使用的是写COOKIE,其实数据源只要在客户端都是可以修改的COOKIE也不例外,这也是好多人说购物车数据保存在COOKIE内不安全的原因。不过我不认为写COOKIE不安全(个人观点)。即使一切客户端提交过来的数据都是有害的,但所有的网站都在接收用户提交的数据,并不是都安全了,而是这个功能必须要有,COOKIE能做为一个会话标识,那我相信它也能帮助服务器保存一些浮动性数据(题外话)。上面的代码从提取COOKIE开始只进行了简单的判断处理,如果PHP没有关闭报错,那修改COOKIE为不合理序列串就可以导致页面显示错误内容直接让别人知道你的服务器系统类型和部分目录结构,而在foreach内的SQL更是没有过滤ID值,留下的SQL注入可想而知。

漏洞主要是程序的逻辑不严谨,给攻击都留下了后门。

以下是个人总结的PHP程序安全要素:

一、所有的提交数据在使用前必须转义(换)过滤处理。

用于判断的参数要做好默认值(一切不合理的数据,都可以进入默认处理),其它数据以要求的类型与数据的形式结构进行转义处理或数据类型转换。不要相信任何提交过来的数据尤其是下拉框,隐藏域,复选框,单选框这些看似不能修改内部值的表单元素。数值类型的一定要转换为对应的数值类型。

二、功能模块要么封装在函数内要要封装到类中。

函数或类中的变量(除全局变量外)都是局部的不易被覆盖。而且对外可控性好,安全性高。

三、注意某些函数或PHP语句的参数。

asser(),call_user_func(),call_user_func_array(),create_function(),unserialize(),unset(),session_destroy(),rand(),include,require,file_get_contents(),extract(),parse_str()等。当这些函数的参数受提交参数的影响时一定要注意提交数据的是否达到要求,防止程序注入。(这里的程序只是一些常被攻击的函数,不排除还有一些没有录入,所以只要处理的函数参数受提交数据的影响都应该做好过滤并且判断是否达到理想要求)。有些函数的参数不便验证(unserialize,create_functiont等)要做好防止报错处理(一般服务器端会关闭所有的报错)。删除类的函数的避免直接或间接使用提交数据防止删除错误或核心变量数据或文件。在MVC模式中会大量使用引入文件的操作,有的还会使用call_user_func类的函数,这些函数的参数如果没有处理好会影响整个系统的安全,所以这类函数或语句要使用提交数据时一定要过滤判断严谨。变量操作类的函数最大的问题是会覆盖原有的变量值,所以有使用时引起注意。如果函数自身就存在着安全问题(如溢出漏洞)最好是避免使用。

四、提交参数在进入数据库操作时必须过滤处理。

基本上一个网站都要接收提交数据,提交的数据包含了对数据库增删改查四大基本操作,而这四个基本操作关系到整站的数据安全,所以提交过来的数据过滤是必要的。主要的恶意思想有,获取管理员用户密码或越权获取其它(重要)数据,越权修改别人或自己的数据,越权删除数据,越权增加数据。对于一次查询,不是只做好添加转义就OK了,还得添加必要的where,group,order,having,limit等条件。MYSQL中所有的传值都可以处理转义后添加""把传入的值引起来屏蔽SQL注入,数值类的一定转换为对应的数据类型。越权操作基本是过滤或筛选条件不足,给攻击都留下机会。如修改与会员ID关联的数据时没有添加上会员ID进行筛选(或这个ID保存在客户端)攻击者就可以修改会员ID或修改内容的ID来修改其它会员的数据(所以有关联会员ID的一定要添加到SQL中当然这个会员ID一定不要接收提交过来的数据,可以保存在SESSION中或内存缓存等服务器端)。

五、只要进入数据库的查询的筛选条件内容都必须转义(或转换)处理。

当你认为刚从数据库取出来的内容很安全时,直接进入下一个SQL查询时就可能留下SQL二次(或N次)注入漏洞(如果这个字段内容原本不是接收客户提交的数据相对要安全)。但如果是的那就有必须作转义处理(当然如果字段数据类型是数值类的还可以放心),这是一种习惯必须从认真对待,因为筛选条件使用了转义基本可以解决注入(转义一定要在进入SQL的上一次处理,尽量不要转义后又作其它函数转换或处理,保证数据不会在添加转义后发生变化,比如urldecode(addslashes($_POST['url']))与addslashes(urldecode($_POST['url']))结果就会出现不同)。

六、敏感数据不要保存在客户端。

在实际中除了保存会员(或管理员)的会话凭证外其它关于会员(或管理员)的敏感数据不要保存在客户端,即使带来了很多的方便(如果必须要保存在客户端的也得进行数据匹配、过滤等处理)。尤其是权限值,会员(或管理员)ID,会员(或管理员)密码,会员等级,SQL语句等。只要关系到权限,数据库操作都要避免保存在客户端(COOKIE或GET或POST等形式)。不排除实际中也有一些数据需要保存在客户端,比如浏览产品的ID,购物车数据,分类,分页长度,排序等,这类数据在进入程序前同样要进行匹配过滤处理(不过这类数据在处理上相对简单,存在数据形式少)。

七、所有的过滤功能都封装在一起。

好多的人为了方便经常随意的过滤或处理提交过来的数据,这样很容易出现某处没有过滤处理数据或过滤不到位的现象,只要将过滤封装在一起时就可以方便的管理和升级过滤功能。

八、显示的内容中包含有提交数据内容时作用过滤处理。

这种形式一般叫XSS攻击,就是因为没有处理好提交过来的数据,导致页面中执行了攻击者提交过来的JS操作。这种操作可以获取当前用户(或管理员)的COOKIE信息,如果攻击者了解程序的结构还可以进行更多的恶意操作。所以当我们要显示的内容包含了客户端提交的数据,那就必须要做下过滤处理(根据显示的形式如纯文本只要去掉HTML标签如是邮箱名的那必须就匹配邮件格式,如是标签的属性做好事件名判断等,要记住尽一切可能的防止提交的JS代码被执行)。

九、提交过来的数据做好身份识别处理。

这种主要是针对会批量修改添加数据或修改敏感数据的提交操作。比如注册页面大部分网站都添加了验证码(就是为了防止机器注册等恶意批量提交无效数据),修改找回密码的邮箱名添加验证码(这种主要是防止攻击者恶意利用会员或管理员进入自己制作的恶意页面自动提交修改邮箱名为自己邮箱名然后通过找回密码修改登录密码),登录时设置验证码,就是为了防止暴力破解。所以针对可以大量修改或添加的会员数据,评论数据,订单数据等做好身份识别处理,防止恶意批量提交(一般可以设置提交次数,验证码,提交来源等方式),当修改到会员的重要数据时也一定要做好身份识别处理,防止恶意修改(一般可以要求输入提交次数,密码,验证码,提交来源等方式)。

十、密码加密与长度处理。

网站有登录就会有密码处理,留下的就是密码加密与长度的问题,一般都采用MD5处理,虽然是不可逆,我们在程序中尽量使用附加串连接原密码再MD5来增加密码的强度;其次就是密码的长度也是为防止部分无用浏览者随意注册,同时也是对会员帐户信息负责,长度过短容易被破解,长度过长不易记忆(一般是6 到 16之间)。

十一、避免逻辑漏洞。

这类问题完全是程序员的功底,逻辑问题一般是判断可以避开。比如:if(!empty($_POST['check'])&&$_POST['check']==$_SESSION['check']){die('验证码不正确');} 这段程序看似能完成功能,但是如果没有提交check数据那么就可以避开判断,类似的问题很多,基本上是判断上没有合理的处理好。在做判断时一定要拿出出现情况最少一种形式进入判断,不论是想要的数据或不想要的数据只要找到出现情况最少的一方。对于提交过来的数据最好要先isset后才可以empty,尤其是必须提交的数据,当然如果数据形式比较少如只有0或1时可以直接使用empty。逻辑问题完全是程序员功底的体现,当然逻辑问题不只存在漏洞,还可能会影响程序执行效率和执行结果,危害大。所以当今都在要求写程序要做好层次和注释就是为了更好更快的了解程序的问题和功能。

十二、经常查看一些新漏洞信息或PHP的更新信息。

如果你认为了解了以上的要素就OK了那就错了,漏洞是在不断的被发现,如果你不知道很有可能使用这些认为安全的代码,漏洞来源和出发点也在不断的增加,虽然主要是利用提交数据,但是程序在处理的过程中提交的数据就会进行各种变化,而这些变化很有可能存在着安全问题,如果你不想去研究那就去查看别人的成果。PHP的更新有时也会发出一些PHP的安全问题,而这些问题基本要更新PHP才能得到解决,当然PHP的更新升级不只是安全问题,还有一些更好的特性被修正或添加,可以帮助你写出更新更安全的代码。

最后虽然以上一内容不是很完美,但我完会在日后的工作中不断的添加修正。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消