本节内容:
php后门URL的防范
所谓后门URL,是指虽然无需直接调用的资源,却可以直接通过URL访问。
例如,web应用程序可能向登入用户显示敏感信息:
$authenticated = FALSE;
$authenticated = check_auth();
if ($authenticated)
{
include './sensitive.php';
}
?>
风险分析:
由于sensitive.php位于网站主目录下,用浏览器能跳过验证机制直接访问到该文件。
这是由于在网站主目录下的所有文件都有一个相应的URL地址。在某些情况下,这些脚本可能执行一个重要的操作,这就增大了风险。
解决方法:
为了防止后门URL,需要确认把所有包含文件保存在网站主目录以外。
所有保存在网站主目录下的文件,必须通过URL直接访问的。
本节内容:
php session劫持
session 劫持
它是所有攻击者可以用来访问其它人的会话的手段的总称。所有这些手段的第一步都是取得一个合法的会话标识来伪装成合法用户,因此保证会话标识不被泄露非常重要。前面关于会话暴露和固定的知识能帮助你保证会话标识只有服务器及合法用户才能知道。
深度防范原则可以用在会话上,当会话标识不幸被攻击者知道的情况下,一些不起眼的安全措施也会提供一些保护。作为一个关心安全的开发者,你的目标应该是使前述的伪装过程变得更复杂。记住无论多小的障碍,都会以你的应用提供保护。
把伪装过程变得更复杂的关键是加强验证。会话标识是验证的首要方法,同时可以用其它数据来补充它。
可以用的所有数据只是在每个HTTP请求中的数据:
Host: example.org
User-Agent: Firefox/1.0
Accept: text/html, image/png, image/jpeg, image/gif, */*
Cookie: PHPSESSID=1234
请注意请求的一致性,并把不一致的行为认为是可疑行为。
例如,虽然User-Agent(发出本请求的浏览器类型)头部是可选的,但是只要是发出该头部的浏览器通常都不会变化它的值。
如果一个拥有1234的会话标识的用户在登录后一直用Mozilla Firfox浏览器,突然转换成了IE,这就比较可疑了。
例如,此时可以用要求输入密码方式来减轻风险,同时在误报时,这也对合法用户产生的冲击也比较小。
可以使用如下的代码来检测User-Agent的一致性:
<?php
session_start();
if (isset()($_SESSION['HTTP_USER_AGENT']))
{
if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))
{
/* Prompt for password */
exit;
}
}
else
{
$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
}
?>
在某些版本的IE浏览器中,用户正常访问一个网页和刷新一个网页时发出的Accept头部信息不同,因此Accept头部不能用来判断一致性。
确保User-Agent头部信息一致的确是有效的,但如果会话标识通过cookie传递(推荐方式),有道理认为,如果攻击者能取得会话标识,他同时也能取得其它HTTP头部。由于cookie暴露与浏览器漏洞或跨站脚本漏洞相关,受害者需要访问攻击者的网站并暴露所有头部信息。所有攻击者要做的只是重建头部以防止任何对头部信息一致性的检查。
比较好的方法是产生在URL中传递一个标记,可以认为这是第二种验证的形式(虽然更弱)。使用这个方法需要进行一些编程工作,PHP中没有相应的功能。例如,假设标记保存在$token中,需要把它包含在所有你的应用的内部链接中:
<?php
$url = array();
$html = array();
$url['token'] = rawurlencode($token);
$html['token'] = htmlentities($url['token'], ENT_QUOTES, 'UTF-8');
?>
<a href="/blog_article/index/token/lt;php echo $html[.html'token']; ?>">Click Here</a>
为了更方便地管理这个传递过程,你可能会把整个请求串放在一个变量中。你可以把这个变量附加到所有链接后面,这样即便你一开始没有使用该技巧,今后还是可以很方便地对你的代码作出变化。
该标记需要包含不可预测的内容,即便是在攻击者知道了受害者浏览器发出的HTTP头部的全部信息也不行。
一种方法是生成一个随机串作为标记:
$string = $_SERVER['HTTP_USER_AGENT'];
$string .= 'SHIFLETT';
$token = md5($string); // www.
$_SESSION['token'] = $token;
?>
当使用随机串时(如SHIFLETT),对它进行预测是不现实的。
此时,捕获标记将比预测标记更为方便,通过在URL中传递标记和在cookie中传递会话标识,攻击时需要同时抓取它们二者。这样除非攻击者能够察看受害者发往你的应用所有的HTTP请求原始信息才可以,因为在这种情况下所有内容都暴露了。这种攻击方式实现起来非常困难(所以很罕见),要防止它需要使用SSL。
有专家警告不要依赖于检查User-Agent的一致性。
这是因为服务器群集中的HTTP代理服务器会对User-Agent进行编辑,而本群集中的多个代理服务器在编辑该值时可能会不一致。
如果不希望依赖于检查User-Agent的一致性,可以生成一个随机的标记:
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
?>
此方法的安全性虽然是弱一些,但它更可靠。
以上的两个方法都对防止会话劫持提供了强有力的手段。
请在安全性和可靠性之间作出平衡。
本节内容:
PHP获取访问者IP地址
方法一:$_SERVER['HTTP_X_FORWARDED_FOR']来获取相应的地址
function get_onlineip() {
$onlineip = '';
if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$onlineip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$onlineip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$onlineip = getenv('REMOTE_ADDR');
} elseif(isset()($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$onlineip = $_SERVER['REMOTE_ADDR'];
} // www.
return $onlineip;
}
方法二:利用curl依靠第三方来获取,如http://www.ip138.com/ip2city.asp
function get_onlineip() {
$ch = curl_init('http://www.ip138.com/ip2city.asp');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$a = curl_exec($ch);
preg_match('/\[(.*)\]/', $a, $ip);
return $ip[1];
}