当前位置:  编程技术>php

PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等)

    来源: 互联网  发布时间:2014-08-26

    本文导语:  浅谈Php安全和防Sql注入,防止Xss攻击,防盗链,防CSRF 前言: 首先,笔者不是web安全的专家,所以这不是web安全方面专家级文章,而是学习笔记、细心总结文章,里面有些是我们phper不易发现或者说不重视的东西。所以笔者写...

浅谈Php安全和防Sql注入,防止Xss攻击,防盗链,防CSRF

前言:

首先,笔者不是web安全的专家,所以这不是web安全方面专家级文章,而是学习笔记、细心总结文章,里面有些是我们phper不易发现或者说不重视的东西。所以笔者写下来方便以后查阅。在大公司肯定有专门的web安全测试员,安全方面不是phper考虑的范围。但是作为一个phper对于安全知识是:“知道有这么一回事,编程时自然有所注意”。

目录:

1、php一些安全配置
(1)关闭php提示错误功能
(2)关闭一些“坏功能”
(3)严格配置文件权限。
2、严格的数据验证,你的用户不全是“好”人
2.1为了确保程序的安全性,健壮性,数据验证应该包括内容。
2.2程序员容易漏掉point或者说需要注意的事项
3、防注入
   3.1简单判断是否有注入漏洞以及原理
   3.2常见的mysql注入语句
       (1)不用用户名和密码
       (2)在不输入密码的情况下,利用某用户
       (3)猜解某用户密码
(4)插入数据时提权
(5)更新提权和插入提权同理
(6)恶意更新和删除
(7)union、join等
(8)通配符号%、_
(9)还有很多猜测表信息的注入sql
   33防注入的一些方法
       2.3.1 php可用于防注入的一些函数和注意事项。
       2.3.2防注入字符优先级。
2.3.3防注入代码
    (1)参数是数字直接用intval()函数
    (2)对于非文本参数的过滤
(3)文本数据防注入代码。
(4)当然还有其他与addslashes、mysql_escape_string结合的代码。
4、防止xss攻击
4.1Xss攻击过程
4.2常见xss攻击地方
4.3防XSS方法
5、CSRF
5.1简单说明CSRF原理
5.2防范方法
6、防盗链
7、防拒CC攻击

1、php一些安全配置


(1)关闭php提示错误功能

在php.ini 中把display_errors改成

代码如下:
display_errors = OFF

或在php文件前加入
代码如下:
error_reporting(0)

1)使用error_reporting(0);失败的例子:

A文件代码:

代码如下:

错误:
代码如下:
Parse error: parse error, expecting `','' or `';'' in E:webphp2.php on line 4

2)使用error_reporting(0);成功的例子:
a文件代码:
代码如下:


b文件代码:
代码如下:


这是很多phper说用error_reporting(0)不起作用。第一个例子A.php里面有致命错误,导致不能执行,不能执行服务器则不知有这个功能,所以一样报错。

第二个例子中a.php成功执行,那么服务器知道有抑制错误功能,所以就算b.php有错误也抑制了。

ps:抑制不了mysql错误。

(2)关闭一些“坏功能”

1)关闭magic quotes功能

在php.ini 把magic_quotes_gpc = OFF
避免和addslashes等重复转义

2)关闭register_globals = Off

在php.ini 把register_globals = OFF

在register_globals = ON的情况下

地址栏目:http://www.?bloger=benwin

代码如下:


这种情况下会导致一些未初始化的变量很容易被修改,这也许是致命的。所以把register_globals = OFF关掉

(3)严格配置文件权限。

为相应文件夹分配权限,比如包含上传图片的文件不能有执行权限,只能读取

2、严格的数据验证,你的用户不全是“好”人。

记得笔者和一个朋友在讨论数据验证的时候,他说了一句话:你不要把你用户个个都想得那么坏!但笔者想说的这个问题不该出现在我们开发情景中,我们要做的是严格验证控制数据流,哪怕10000万用户中有一个是坏用户也足以致命,再说好的用户也有时在数据input框无意输入中文的时,他已经不经意变“坏”了。

2.1为了确保程序的安全性,健壮性,数据验证应该包括

(1)     关键数据是否存在。如删除数据id是否存在
(2)     数据类型是否正确。如删除数据id是否是整数
(3)     数据长度。如字段是char(10)类型则要strlen判断数据长度
(4)     数据是否有危险字符

数据验证有些人主张是把功能完成后再慢慢去写安全验证,也有些是边开发边写验证。笔者偏向后者,这两种笔者都试过,然后发现后者写的验证相对健壮些,主要原因是刚开发时想到的安全问题比较齐全,等开发完功能再写时有两个问题,一个phper急于完成指标草草完事,二是确实漏掉某些point。
2.2程序员容易漏掉point或者说需要注意的事项:

(1)     进库数据一定要安全验证,笔者在广州某家公司参与一个公司内部系统开发的时候,见过直接把$_POST数据传给类函数classFunctionName($_POST),理由竟然是公司内部使用的,不用那么严格。暂且不说逻辑操作与数据操控耦合高低问题,连判断都没判断的操作是致命的。安全验证必须,没任何理由推脱。
(2)     数据长度问题,如数据库建表字段char(25),大多phper考虑到是否为空、数据类型是否正确,却忽略字符长度,忽略还好更多是懒于再去判断长度。(这个更多出现在新手当中,笔者曾经也有这样的思想)
(3)     以为前端用js判断验证过了,后台不需要判断验证。这也是致命,要知道伪造一个表单就几分钟的事,js判断只是为了减少用户提交次数从而提高用户体验、减少http请求减少服务器压力,在安全情况下不能防“小人”,当然如果合法用户在js验证控制下是完美的,但作为phper我们不能只有js验证而抛弃再一次安全验证。
(4)     缺少对表单某些属性比如select、checkbox、radio、button等的验证,这些属性在web页面上开发者已经设置定其值和值域(白名单值),这些属性值在js验证方面一般不会验证,因为合法用户只有选择权没修改权,然后phper就在后端接受数据处理验证数据的时候不会验证这些数据,这是一个惯性思维,安全问题也就有了,小人一个伪表单。
(5)     表单相应元素name和数据表的字段名一致,如用户表用户名的字段是user_name,然后表单中的用户名输入框也是user_name,这和暴库没什么区别。
(6)     过滤危险字符方面如防注入下面会独立讲解。

3、防注入

3.1简单判断是否有注入漏洞以及原理。

网址:http://www./benwin.php?id=1 运行正常,sql语句如:select  *  from phpben where id = 1

(1) 网址:http://www./benwin.php?id=1'   sql语句如:select  *  from phpben where id = 1'  然后运行异常 这能说明benwin.php文件没有对id的值进行“'” 过滤和intval()整形转换,当然想知道有没有对其他字符如“%”,“/*”等都可以用类似的方法穷举测试(很多测试软件使用)
(2)网址:http://www./benwin.php?id=1 and 1=1  则sql语句可能是 select  *  from phpben where id = 1 and 1=1,运行正常且结果和http://www./benwin.php?id=1结果一样,则说明benwin.php可能没有对空格“ ”、和“and”过滤(这里是可能,所以要看下一点)
(3)网址:http://www./benwin.php?id=1 and 1=2则sql语句可能是 select  *  from phpben where id = 1 and 1=2 如果运行结果异常说明sql语句中“and 1=2”起作用,所以能3个条件都满足都则很确定的benwin.php存在注入漏洞。

ps:这里用get方法验证,post也可以,只要把值按上面的输入,可以一一验证。

3.2常见的mysql注入语句。

(1)不用用户名和密码

代码如下:

//正常语句 
$sql ="select * from phpben where user_name='admin' and pwd ='123'"; 
//在用户名框输入'or'='or'或 'or 1='1 然后sql如下 
$sql ="select * from phpben where user_name=' 'or'='or'' and pwd ='' "; 
$sql ="select * from phpben where user_name=' 'or 1='1' and pwd ='' ";

这样不用输入密码。话说笔者见到登录框都有尝试的冲动。

(2)在不输入密码的情况下,利用某用户。

代码如下:

//正常语句 
$sql ="select * from phpben where user_name='$username' and pwd ='$pwd'"; 
//利用的用户名是benwin 则用户名框输入benwin'#  密码有无都可,则$sql变成 
$sql ="select * from phpben where user_name=' benwin'#' and pwd ='$pwd'";

这是因为mysql中其中的一个注悉是“#”,上面语句中#已经把后面的内容给注悉掉,所以密码可以不输入或任意输入。网上有些人介绍说用“/*”来注悉,笔者想提的是只有开始注悉没结束注悉“*/”时,mysql会报错,也不是说“/**/”不能注悉,而是这里很难添加上“*/”来结束注悉,还有“– ”也是可以注悉mysql 但要注意“–”后至少有一个空格也就是“– ”,当然防注入代码要把三种都考虑进来,值得一提的是很多防注入代码中没把“– ”考虑进防注入范围。

(3)猜解某用户密码

代码如下:

//正常语句 
$sql ="select * from phpben.com where user_name='$username' and pwd ='$pwd'"; 
//在密码输入框中输入“benwin' and left(pwd,1)='p'#”,则$sql是 
$sql ="select * from phpben.com where user_name=' benwin' and left(pwd,1)='p'#' and pwd ='$pwd'";

如果运行正常则密码的密码第一个字符是p,同理猜解剩下字符。

(4)插入数据时提权

代码如下:

//正常语句,等级为1 
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',1) "; 
//通过修改密码字符串把语句变成 
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)#',1) "; 
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)--  ',1) ";这样就把一个权限为1的用户提权到等级5


(5)更新提权和插入提权同理
代码如下:

//正常语句 
$sql = "update phpben set  `user_name` ='benwin', level=1"; 
//通过输入用户名值最终得到的$sql 
$sql = "update phpben set  `user_name` ='benwin',level=5#', level=1"; 
$sql = "update phpben set  `user_name` ='benwin',level=5--  ', level=1";


(6)恶意更新和删除
代码如下:

//正常语句 
$sql = "update phpben set `user_name` = ‘benwin' where id =1"; 
//注入后,恶意代码是“1 or id>0” 
$sql = "update phpben set `user_name` = ‘benwin' where id =1 or id>0"; 
//正常语句 
$sql = "update phpben set  `user_name` ='benwin' where id=1"; 
//注入后 
$sql = "update phpben set  `user_name` ='benwin' where id>0#' where id=1"; 
$sql = "update phpben set  `user_name` ='benwin' where id>0-- ' where id=1";


(7)union、join等
代码如下:

//正常语句 
$sql ="select * from phpben1 where `user_name`='benwin' "; 
//注入后 
$sql ="select * from phpben1 where`user_name`='benwin' uninon select * from phpben2#' "; 
$sql ="select * from phpben1 where`user_name`='benwin' left join……#' ";


(8)通配符号%、_
代码如下:

//正常语句 
$sql ="select * from phpben where `user_name`='benwin' "; 
//注入通配符号%匹配多个字符,而一个_匹配一个字符,如__则匹配两个字符 
$sql ="select * from phpben where `user_name` like '%b' "; 
$sql ="select * from phpben where `user_name` like '_b_' ";

这样只要有一个用户名字是b开头的都能正常运行,“ _b_”是匹配三个字符,且这三个字符中间一个字符时b。这也是为什么有关addslashes()函数介绍时提示注意没有转义%和_(其实这个是很多phper不知问什么要过滤%和_下划线,只是一味的跟着网上代码走)

(9)还有很多猜测表信息的注入sql

代码如下:

//正常语句 
$sql ="select * from phpben1 where`user_name`='benwin'"; 
//猜表名,运行正常则说明存在phpben2表 
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(*) from phpben2 )>0#' "; 
//猜表字段,运行正常则说明phpben2表中有字段colum1 
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(colum1) from phpben2 )>0#'"; 
//猜字段值 
$sql ="select * from phpben1 where`user_name`='benwin' and left(pwd,1)='p'#''";

当然还有很多,笔者也没研究到专业人士那种水平,这里提出这些都是比较常见的,也是phper应该知道并掌握的,而不是一味的在网上复制粘贴一些防注入代码,知然而不解其然。

下面一些防注入方法回看可能更容易理解。

3.3防注入的一些方法

3.3.1 php可用于防注入的一些函数和注意事项。

(1)addslashes 和stripslashes。

Addslashes给这些 “'”、“””、“”,“NULL” 添加斜杆“'”、“””、“\”,“NULL”, stripslashes则相反,这里要注意的是php.ini是否开启了magic_quotes_gpc=ON,开启若使用addslashes会出现重复。所以使用的时候要先get_magic_quotes_gpc()检查

一般代码类似:

代码如下:

if(!get_magic_quotes_gpc()) 

         $abc = addslashes($abc); 
}

其实这个稍微学习php一下的人都知道了,只不过笔者想系统点介绍(前面都说不是专家级文章),所以也顺便写上了。addslashes

(2)mysql_escape_string()和mysql_ real _escape_string()

mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string

代码如下:

if (PHP_VERSION >= '4.3') 

$string  =  mysql_real_escape_string($string); 
}else 

$string  =  mysql_escape_string($string ); 
}

mysql_escape_string()和mysql_ real _escape_string()却别在于后者会判断当前数据库连接字符集,换句话说在没有连接数据库的前提下会出现类似错误:
代码如下:

Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'ODBC'@'localhost' (using password: NO) in E:webphptest.php on line 11


(3)字符代替函数和匹配函数
str_replace() 、perg_replace()这些函数之所以也在这里提是因为这些函数可以用于过滤或替代一些敏感、致命的字符。

3.3.2防注入字符优先级。

防注入则要先知道有哪些注入字符或关键字,常见的mysql注入字符有字符界定符号如“'”、“””;逻辑关键字如“and”、“or”;mysql注悉字符如“#”,“– ”,“/**/”;mysql通配符“%”,“_”;mysql关键字“select|insert|update|delete|*|union|join|into|load_file|outfile”

(1)对于一些有规定格式的参数来说,防注入优先级最高的是空格” ”。

如一些银行卡号,身份证号,邮箱,电话号码,,生日,邮政编码等这些有自己规定的格式且格式规定不能有空格符号的参数,在过滤的时候一般最先过滤掉空格(包括一些空格“变种”),因为其他字符界定符号,逻辑关键字,mysql注悉,注意下图可以看出重要的是“'”,“ ”

ps:空格字符的变种有:“%20”,“n”,“r”,“rn”,“nr”,“chr(“32″)” 这也是为什么mysql_escape_string()和mysql_real_escape_string() 两个函数转义“n”,“r”。其实很多phper只知道转义n,r而不知原因,在mysql解析n,r时把它们当成空格处理,笔者测试验证过,这里就不贴代码了。

(2)“and”,“or”,“”,“#”,“– ”

逻辑关键可以组合很多注入代码;mysql注悉则把固有sql代码后面的字符全部给注悉掉从而让注入后的sql语句能正常运行;“”也是能组合很多注入字符x00,x1a。

ps:sql解析“#”,“– ”是大多数mysql防注入代码没有考虑到的,也是很多phper忽略。还有因为一些phper给参数赋值的时候会有用“-”来隔开,所以笔者建议不要这样写参数,当然也可以再过滤参数的时候“– ”(注意有空格的,没空格不解析为注悉)当一个整体过滤而不是过滤“-” ,这样就避免过多过滤参数。

(3)“null”,“%”,“_”

这几个不能独立,都不要在特定情况下,比如通配字符“%,_”都要在mysql like子句的前提下。所以“%”,“_”的过滤一般在搜索相关才过滤,不能把它们纳入通常过滤队列,因为有些如邮箱就可以有”_”字符

(4)关键字“select|insert|update|delete|*|union|join|into|load_file|outfile”

也许你会问怎么这些重要关键字却优先级这么低。笔者想说的是因为这些关键字在没有“'”,“””,“ ”,“and”,“or”等情况下购不成伤害。换句话说这些关键字不够“独立”,“依赖性”特别大。当然优先级低,不代表不要过滤。


3.3.3防注入代码。

(1)参数是数字直接用intval()函数

注意:现在很多网上流行的防注入代码都只是只是用addslashes()、mysql_escape_string()、mysql_real_escape_string()或三者任意组合过滤,但phper以为过滤了,一不小心一样有漏洞,那就是在参数为数字的时候:

代码如下:
$id = addslashes($_POST['id']); //正确是$id = intval($_POST['id']); 
$sql =" select * from phpben.com where id =$id"; 
$sql =" select * from phpben.com where id =1 or 1=1";

对比容易发现,post过来的数据通过addslashes过滤后的确很多注入已经不起作用,但是$id并没有intval,导致漏洞的存在,这是个小细节,不小心则导致漏洞。

(2)对于非文本参数的过滤

文本参数是指标题、留言、内容等可能有“'”,“'”等内容,过滤时不可能全部转义或代替。

但非文本数据可以。

代码如下:

function _str_replace($str ) 

     $str = str_replace(" ","",$str); 
     $str = str_replace("n","",$str); 
     $str = str_replace("r","",$str); 
     $str = str_replace("'","",$str); 
     $str = str_replace('"',"",$str); 
     $str = str_replace("or","",$str); 
     $str = str_replace("and","",$str); 
     $str = str_replace("#","",$str); 
     $str = str_replace("\","",$str); 
     $str = str_replace("-- ","",$str); 
     $str = str_replace("null","",$str); 
     $str = str_replace("%","",$str); 
     //$str = str_replace("_","",$str); 
     $str = str_replace(">","",$str); 
     $str = str_replace("

    
 
 

您可能感兴趣的文章:

  • php session 原理详解,用法介绍以及如何设置过期时间
  • PHP exif扩展方法开启详解
  • PHP正则匹配图片并给图片加链接详解
  • php mail to 配置详解
  • php运行环境配置详解
  • Windows server 2008搭建php运行环境图文详解(php5.3)
  • PHP中替换键名的简易方法示例详解
  • php 获取完整url地址实例详解
  • php实例分享之通过递归实现删除目录下的所有文件详解
  • PHP $_FILES中error返回值详解
  • centos源码编译php5 mcrypt模块步骤详解
  • php事务处理实例详解
  • php数组编码转换示例详解
  • PHP 正则 email语句详解
  • php.ini文件上传功能配置详解
  • PHP5 时区设置方法详解
  • php数组递归转义实例详解,php转义函数
  • 配置PHP服务器环境步骤详解
  • php引用字符串常量方法详解
  • PHP汉字拼音转换、公历农历转换的实例详解
  • php-fpm优化方法详解
  • php防止sql注入代码实例
  • PHP MYSQL注入攻击需要预防7个要点
  • php is_numberic函数产生sql注入漏洞怎么解决
  • php过滤参数特殊字符防注入
  • php防SQL注入代码(360提供)
  • Discuz7.2版的faq.php SQL注入漏洞分析
  • PHP登录环节防止sql注入的方法浅析
  • PHP防范SQL注入的具体方法详解(测试通过)
  • php防范sql注入方法与实例代码
  • PHP5 时区设置方法详解 iis7站长之家
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 有关于PHP中常见数据类型的汇总分享
  • php初学者常见问题总结
  • PHP开源开发框架ZendFramework使用中常见问题说明及解决方案
  • php编译安装常见错误大全和解决方法
  • PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
  • php中的curl使用入门教程和常见用法实例
  • PHP常用函数和常见疑难问题解答
  • PHP编程中的常见漏洞和代码实例
  • 浅析PHP编程中10个最常见的错误
  • 修改配置真正解决php文件上传大小限制问题(nginx+php)
  • IIS7配置PHP图解(IIS7+PHP_5.2.17/PHP_5.3.5)
  • PHP 5.4.19 和 PHP 5.5.3 发布及下载地址
  • php输入流php://input使用示例(php发送图片流到服务器)
  • 修改配置真正解决php文件上传大小限制问题(apache+php)
  • PHP转换器 HipHop for PHP
  • PHP去除html标签,php标记及css样式代码参考
  • PHP 框架 Pop php
  • PHP 'ext/soap/php_xml.c'不完整修复存在多个任意文件泄露漏洞
  • PHP的JavaScript框架 PHP.JS
  • php通过socket_bind()设置IP地址代码示例
  • php服务器探针显示php服务器信息
  • php安装完成后如何添加mysql扩展
  • PHP缓存加速器 Alternative PHP Cache (APC)
  • PHP的substr() 函数用法
  • PHP源文件加密工具 PHP Screw
  • PHP介绍及学习网站推荐
  • PHP自动化测试 PHP-QAT
  • php中操作memcache的类及成员列表及php下如何连接memched服务器
  • PHP 的 HTTP 客户端库 PHP Buzz
  • php中内置的mysql数据库连接驱动mysqlnd简介及mysqlnd的配置安装方式
  • PHP 调试工具 PHP_Dyn




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3