从php角度分析预防xss和Sql注入

引言 从php角度分析预防xss和Sql注入,是因为php对这方面做了很好的支持。

XSS

概念: Xss即跨站脚本攻击,指攻击者在网页中嵌入恶意脚本程序(一般由html,css,js组成),当用户打开网页的时候脚本程序便在客户端执行而产生若干危害的情况。XSS的重点不在于跨站点,而是在于恶意脚本的执行。
一般是攻击者利用网站对用户提交数据没有过滤或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码。

分类 部分参考百度百科
XSS漏洞按照攻击利用手法的不同,暂且分为三类: 反射型XSS(非持久型)、存储型XSS(持久型)和DOM XSS。

类型A:利用本地漏洞,这种漏洞存在于页面中客户端脚本自身。其攻击过程如下所示:

-Charly给Alice发送一个恶意构造的Web URL。

  • Alice点击并查看了这个URL。
  • 恶意页面中的JavaScript打开一个具有漏洞的HTML页面并将其下载到Bob电脑上。
  • 具有漏洞的HTML页面包含了在Alice电脑本地域执行的JavaScript。
  • Charly的恶意脚本可以在Alice的电脑上执行Alice所持有的权限下的命令。

类型B:反射式漏洞,这种漏洞和类型A有些类似,不同的是Web客户端使用Server端脚本生成页面为用户提供数据时,如果未经验证的用户数据被包含在页面中而未经HTML实体编码,客户端代码便能够注入到动态页面中,具体实例参考文章,其攻击过程如下:

  • Alice经常浏览某个网站,此网站为Bob所拥有。Bob的站点运行Alice使用用户名/密码进行登录,并存储敏感信息(比如银行帐户信息)。
  • Charly发现Bob的站点存在反射性的XSS漏洞。
  • Charly编写一个利用漏洞的URL,并将其冒充为来自Bob的邮件发送给Alice。
  • Alice在登录到Bob的站点后,浏览Charly提供的URL,即点击邮件。
  • 嵌入到URL中的恶意脚本在Alice的浏览器中执行,就像它直接来自Bob的服务器一样。此脚本盗窃敏感信息(授权、信用卡、帐号信息等),然后在Alice完全不知情的情况下将这些信息发送到Charly的Web站点。

反射式XSS 一般是攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。
对于访问者而言是一次性的,具体表现在我们把我们的恶意脚本通过 URL 的方式传递给了服务器,而服务器则只是不加处理的把脚本“反射”回访问者的浏览器而使访问者的浏览器执行相应的脚本。反射型 XSS 的触发有后端的参与,要避免反射性 XSS,必须需要后端的协调,后端解析前端的数据时首先做相关的字串检测和转义处理。

类型C:存储式漏洞,该类型是应用最为广泛而且有可能影响到Web服务器自身安全的漏洞,骇客将攻击脚本上传到Web服务器上,使得所有访问该页面的用户都面临信息泄漏的可能,其中也包括了Web服务器的管理员,具体实例参考文章。其攻击过程如下

  • Bob拥有一个Web站点,该站点允许用户发布信息/浏览已发布的信息。
  • Charly注意到Bob的站点具有类型C的XSS漏洞。
  • Charly发布一个热点信息到留言板,吸引其它用户纷纷阅读。
  • Bob或者是任何的其他人如Alice浏览该信息,其会话cookies或者其它信息将被Charly盗走。

存储型 XSS一般是攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。

类型D:DOM XSS和反射型XSS、存储型XSS的差别在于DOM XSS的代码并不需要服务器参与,触发XSS靠的是浏览器端的DOM解析,完全是客户端的事情,简单地说就是通过修改页面的DOM节点形成的XSS,产生的根源是因为不安全的引用和通过服务器提供的页面使用不受约束的DOM对象,具体参考文章1文章2。其过程如下:

  • Bob拥有一个Web站点,并且站点有很多用户,如Alice。
  • Charly注意到Bob的站点具有DOM XSS,构造一个该站点具有DOM XSS的正常URL并发送给Alice等用户。
  • Alice点击该URL发生XSS。

DOM XSS发生的前提是易受攻击的网站有一个HTML页面采用不安全的方式(没有经过过滤)从document.location 或document.URL 或 document.referrer获取数据(或者任何其他攻击者可以修改的对象),即客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从 URL 中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的 JavaScript 脚本,而这些脚本没有经过适当的过滤和消毒,那么应用程序就可能受到 DOM-based XSS 攻击。需要特别注意以下的用户输入源document.location、 document.URL、 location.hash、 location.search、 document.referrer 等。

危害:
1、恶作剧,即单纯使客户端显示异常信息;

2、盗取用户信息,简单的如用户cookie,还可以获取用户各类信息,如机器登录帐号、用户网银帐号、各类管理员帐号,比如2011年6月新浪微博XSS受攻击事件。

3、获取各类账号后就可以控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力,盗窃企业重要的具有商业价值的资料,非法转账等;

4、强制用户账号做不愿做的事情,如发送电子邮件,转发消息等;

5、控制受害者机器向其它网站发起攻击,即DDos攻击,比如3DM(一个游戏网站)也曾经被植入script代码对另一个游戏网站进行了惨无人道的DDOS攻击;

6、诱惑用户访问钓鱼网站等;

7、网页挂马,即使用户本地下载执行病毒及木马程序。

解决方案 究其发生根本,是网站对用户输入数据过滤不足,因此网站开发者要始终把Web安全放在心上,简单点,就是认为用户提价的数据都是不可信的,对其进行合适的过滤处理,使用php过滤函数就可以达到很好的目的。
在说解决方法前,还要了解HTML字符实体的概念,具体参考文章
前面讲到对用户数据进行过滤,过滤也分很多种,比如转义、删除关键字(词)等。

过滤方针:

1、将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了;

2、表单数据规定值的类型,进行正则等验证,例如:年龄应为只能为int、密码只能为n位的字母数字组合等;

4、对数据进行Html Encode 处理;

5、过滤或移除特殊的Html标签, 例如: <script>、 <iframe> 、<p>、<input>;

6、过滤JavaScript 事件的标签。例如 “οnclick=”, “onfocus” 等等。

【特别注意】
在有些应用中是允许html标签出现的,甚至是javascript代码出现。因此我们在过滤数据的时候需要仔细分析哪些数据是有特殊要求(例如输出需要html代码、javascript代码拼接、或者此表单直接允许使用等等),然后区别处理!

Sql注入

概念: 如果说Xss是用户输入的恶意脚本在客户端执行,那SQL注入,就是用户把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。所以再次强调我们永远不要信任用户的输入,我们必须认定用户输入的数据都是不安全的,我们都需要对用户输入的数据进行过滤处理。
SQL注入之所以存在,主要是因为工程师将外部的输入直接嵌入到将要执行的SQL语句中了。黑客可以利用这一点执行SQL指令来达到自己目的。
幸运的是,如果你在使用MySQL 的话,mysql_query() 函数不允许查询堆积(query stacking),或者说在一次函数调用中执行多次 SQL 查询。如果你试图进行堆积式查询的话,函数调用将会失败。
然而,其他的 PHP 数据库扩展,例如 SQLite 和 PostgreSQL 会愉快地接受堆积式查询,执行字符串中所有的查询,并由此产生严重的安全问题。,具体参考PHP官方文档Sql注入,这里主要讲Mysql。

例如:

$db = new \PDO('mysql:host=localhost;port=3306;dbname=**', 'root', '***');  
$pdostatement=$db->query('select * from fpf_user where id ='.$id );	       	
$list=$pdostatement->fetchall();
dump($list);

这里用用户输入的变量$id来拼接SQL语句,存在安全隐患。如果$id = ‘2 or 1=1’,这里就能轻松的获取到user表的所有信息。
利用SQL注入漏洞,我们能够获取想要的信息,同时可以通过猜测和报错获取到数据库其它表的结构和信息,如果数据库、服务器权限设置不当,甚至有可能能获取到整个服务器的控制权限。 这些攻击总是建立在发掘安全意识不强的代码上的。所以,永远不要信任外界输入的数据,特别是来自于客户端的,包括选择框、表单隐藏域和 cookie。

解决方案
从产生sql注入的原因说起,就是攻击者嵌入的恶意sql语句被服务器执行了,所以要解决它,就是防止任何可能的恶意sql被服务器执行。

1.永远不要使用超级用户或所有者帐号去连接数据库。要用权限被严格限制的帐号。
2.写一个ORM(Object Relational Mapping,实现面向对象编程语言里不同类型系统的数据之间的转换),这样可以避免直接拼接SQL 语句,相对安全而且能大大提高开发效率.补充 ORM并不能防止sql注入,而是为防止sql注入提供了便利的方法,当下的php框架都在ORM中做了防止sql注入的处理,如TP,Laravel;

3.如果非得写一些原生的SQL拼接语句,则我们必须对输入的那些变量进行优化过滤;

  • 检查输入的数据是否具有所期望的数据格式。PHP 有很多可以用于检查输入的函数,从简单的变量函数和字符类型函数(比如 is_numeric(),ctype_digit())到复杂的 Perl 兼容正则表达式函数都可以完成这个工作;
  • 如果查询的字段类型是数字等类型,在拼接SQL前先使用 is_numeric() 来检查输入是不是一个合法的数字,不合法则终止程序即可,或者直接使用 settype() 来转换它的类型,也可以用 sprintf() 把它格式化为数字,如$id=intval($_GET[‘id’]);
  • 如果字段类型是字符串,则记得将输入里的的单引号进行转义,如$id=addslashes($_GET[‘id’])。

注意: addslashes()函数将 转换为 \’ 的转义字符使sql语句成功执行,但 \’ 并未作为数据存入数据库,依旧存 ',比如对snow”’‘sun,数据库保存的是snow”’‘sun 而并不是我们想象的snow’’’'sun,所以不需要stripslashes进行反转义,顺便看看PHP防SQL注入不要再用addslashes和mysql_real_escape_string了

另外,php的mysql或mysqli扩展中的mysql_real_escape_string和mysqli_real_escape_string函数对数据库查询字段过滤,即转义一些预定义字符(NUL (ASCII 0),\n,\r,\,’," 和 Control-Z)。不过php的mysql扩展在php5.5.0中已经弃用,并在php7.0.0中删除。

当然,pdo也有其防注入措施,最经典的是quote方法,它为输入的字符串添加引号(如果有需要),并对特殊字符进行转义,且引号的风格和底层驱动适配。如果使用此函数构建 SQL 语句,强烈建议使用 prepare() 配合参数构建,而不是用 PDO::quote() 把用户输入的数据拼接进 SQL 语句。 使用 prepare处理参数,不仅仅可移植性更好,而且更方便、免疫 SQL 注入;相对于拼接 SQL 更快,客户端和服务器都能缓存编译后的 SQL 查询。但不是所有的 PDO 驱动都实现了此功能(例如 PDO_ODBC),此时考虑使用 prepare 代替,可参考文章sql参数化防注入

还有较为重要的一点就是攻击者利用改变注入语句的编码来绕过转义的方法,比如将SQL语句转成 ASCII编码(类似:char(100,58,92,108,111,99,97,108,104,111,115,116…) 这样的格式,或者转成 16进制编码,甚至还有其他形式的编码,这样以来,转义过滤便被绕过去了,具体参考文章

4.like,regexp 困境

要破解 LIKE 困境,必须有一种专门的转义机制,将用户提供的 ‘%’ 和 ‘_’ 转换为字面值。为此你可以使用 addcslashes() 函数,该函数允许指定要进行转义的字符的范围。对于REGEXP 困境,同样如此处理。

$sub = addcslashes("%str_", "%_");  //转义后 $sub == \%str\_
$db = new \PDO('mysql:host=localhost;port=3306;dbname=**', 'root', '***');  
$pdostatement=$db->mysql_query("select * from messages where subject like '{$sub}%'") ;     	

5.也可以用str_replace以及各种php字符替换函数来防注入,不过这种“黑名单”式的防御已经被证明是经不起时间考验的,但也是可以用的。

特别声明:不要为了安全滥用这些转义函数什么的,重复利用反而会出一些问题,因此要谨慎选择

php过滤函数

strip_tags($str, [允许标签]) #从字符串中去除 HTML 和 PHP 标记

htmlentities($str)函数 #转义html实体

html_entity_decode($str)函数 #反转义html实体

htmlspecialchars() #特殊字符转换为HTML实体

htmlspecialchars_decode() #将特殊的 HTML 实体转换回普通字符

addcslashes($str, ‘字符’)函数 #给指定字符加上反斜杠

stripcslashes($str)函数 #去掉反斜杠

addslashes ($str )函数 #给预定义符号(单引号、双引号、反斜线与 NULL)加反斜杠

stripslashes($str)函数 #去掉反斜杠

对于addslashes函数有些文章可能说php开启魔术引号magic_quotes_gpc,参考文章。但是自从php5.4.0后,魔术引号功能已经移除,官方解释如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值