坚持不懈的学习才能有所成长,学习之第二篇,请各位大佬指导。。。。
1、定义解释:
filter_var() 函数通过指定的过滤器过滤变量。如果成功,则返回已过滤的数据,如果失败,则返回 false。
2、语法:
filter_var(variable, filter, options)
参数 描述
variable 必需。规定要过滤的变量。
filter 可选。规定要使用的过滤器的 ID。
options 规定包含标志/选项的数组。检查每个过滤器可能的标志和选项。
例:
`<?php
if(!filter_var("1@qq.com",FILTER_VALIDTE_EMAIL)){
echo ("Email is not valid");
}else{
echo ("Email is valid");
}
?>
输出结果:EMAIL is not valid`
3、针对anchor 0.9.2版本实例分析:漏洞入口在themes/404.php:
`<?php theme_include('header'); ?>
<section class="content wrap">
<h1>Page not found</h1>
<p>Unfortunately, the page <code>/<?php echo current_url(); ?></code> could not be found. Your best bet is either to try the <a href="<?php echo base_url(); ?>">homepage</a>, try <a href="#search">searching</a>, or go and cry in a corner (although I don’t recommend the latter).</p>
</section>
<?php theme_include('footer'); ?>`
在上述代码里面,有个“echo current_url()”,执行了一个current_url函数,我们跟踪这个函数看一下里面的内容,如下:
`<?php
/**
- Theme helpers functions
*/
function full_url($url = '') {
return Uri::full($url);
}
function base_url($url = '') {
return Uri::to($url);
}
function theme_url($file = '') {
$theme_folder = Config::meta('theme');
$base = 'themes' . '/' . $theme_folder . '/';
return asset($base . ltrim($file, '/'));
}
function theme_include($file) {
$theme_folder = Config::meta('theme');
$base = PATH . 'themes' . DS . $theme_folder . DS;
if(is_readable($path = $base . ltrim($file, DS) . EXT)) {
return require $path;
}
}
function asset_url($extra = '') {
return asset('anchor/views/assets/' . ltrim($extra, '/'));
}
function current_url() {
return Uri::current();
}
function rss_url() {
return base_url('feeds/rss');
}
// Custom function helpers
function bind($page, $fn) {
Events::bind($page, $fn);
}
function receive($name = '') {
return Events::call($name);
}
function body_class() {
$classes = array();
// Get the URL slug
$parts = explode('/', Uri::current());
$classes[] = count($parts) ? trim(current($parts)) : 'index';
// Is it a posts page?
if(is_postspage()) {
$classes[] = 'posts';
}
// Is it the homepage?
if(is_homepage()) {
$classes[] = 'home';
}
return implode(' ', array_unique($classes));
}
// page type helpers
function is_homepage() {
return Registry::prop('page', 'id') == Config::meta('home_page');
}
function is_postspage() {
return Registry::prop('page', 'id') == Config::meta('posts_page');
}
function is_article() {
return Registry::get('article') !== null;
}
function is_page() {
return Registry::get('page') !== null;
}`
4、可以看到函数在第34~36行,调用了内置的一个Uri类(说实话Uri::current()这种写法,我也是第一次见,不知道是啥意思,如果有大佬可以帮忙解释一下),跟踪一下这个类,在system/下的uri.php;
`<?php namespace System;
/**
use ErrorException;
use OverflowException;
use System\Request\Server;
class Uri {
/**
* The current uri
*
* @var string
*/
public static $current;
/**
* Get a path relative to the application
*
* @param string
* @return string
*/
public static function to($uri) {
if(strpos($uri, '://')) return $uri;
$base = Config::app('url', '');
if($index = Config::app('index', '')) {
$index .= '/';
}
return rtrim($base, '/') . '/' . $index . ltrim($uri, '/');
}
/**
* Get full uri relative to the application
*
* @param string
* @return string
*/
public static function full($uri, $secure = null) {
if(strpos($uri, '://')) return $uri;
// create a server object from global
$server = new Server($_SERVER);
if( ! is_null($secure)) {
$scheme = $secure ? 'https://' : 'http://';
}
else {
$scheme = ($server->has('HTTPS') and $server->get('HTTPS')) !== '' ? 'http://' : 'https://';
}
return $scheme . $server->get('HTTP_HOST') . static::to($uri);
}
/**
* Get full secure uri relative to the application
*
* @param string
* @return string
*/
public static function secure($uri) {
return static::full($uri, true);
}
/**
* Get the current uri string
*
* @return string
*/
**public static function current()** {
if(is_null(static::$current)) static::$current = static::detect();
return static::$current;
}
/**
* Try and detect the current uri
*
* @return string
*/
**public static function detect()** {
// create a server object from global
$server = new Server($_SERVER);
$try = array('REQUEST_URI', 'PATH_INFO', 'ORIG_PATH_INFO');
foreach($try as $method) {
// make sure the server var exists and is not empty
if($server->has($method) and $uri = $server->get($method)) {
// apply a string filter and make sure we still have somthing left
if($uri = filter_var($uri, FILTER_SANITIZE_URL)) {
// make sure the uri is not malformed and return the pathname
if($uri = parse_url($uri, PHP_URL_PATH)) {
return static::format($uri, $server);
}
// woah jackie, we found a bad'n
throw new ErrorException('Malformed URI');
}
}
}
throw new OverflowException('Uri was not detected. Make sure the REQUEST_URI is set.');
}
/**
* Format the uri string remove any malicious
* characters and relative paths
*
* @param string
* @return string
*/
public static function format($uri, $server) {
// Remove all characters except letters,
// digits and $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=.
$uri = filter_var(rawurldecode($uri), FILTER_SANITIZE_URL);
// remove script path/name
$uri = static::remove_script_name($uri, $server);
// remove the relative uri
$uri = static::remove_relative_uri($uri);
// return argument if not empty or return a single slash
return trim($uri, '/') ?: '/';
}
/**
* Remove a value from the start of a string
* in this case the passed uri string
*
* @param string
* @param string
* @return string
*/
public static function remove($value, $uri) {
// make sure our search value is a non-empty string
if(is_string($value) and strlen($value)) {
// if the search value is at the start sub it out
if(strpos($uri, $value) === 0) {
$uri = substr($uri, strlen($value));
}
}
return $uri;
}
/**
* Remove the SCRIPT_NAME from the uri path
*
* @param string
* @return string
*/
public static function remove_script_name($uri, $server) {
return static::remove($server->get('SCRIPT_NAME'), $uri);
}
/**
* Remove the relative path from the uri set in the application config
*
* @param string
* @return string
*/
public static function remove_relative_uri($uri) {
// remove base url
if($base = Config::app('url')) {
$uri = static::remove(rtrim($base, '/'), $uri);
}
// remove index
if($index = Config::app('index')) {
$uri = static::remove('/' . $index, $uri);
}
return $uri;
}
}`
5、在第81~85行可以看出,对detect方法进行了调用,而此方法就在下方,通过查看detect方法可以看到,该方法会执行如下几步:
1)定义了一个$server对象,该对象包含服务器和执行环境信息,且对象内包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组;
2)定义了一个含有'REQUEST_URI', 'PATH_INFO', 'ORIG_PATH_INFO'字符串数组;
3)通过循环$SERVER对象,通过if($server->has($method) and $uri = $server->get($method))语句并进行与定义的数组中的字符串进行比较,如果条件成立,将$uri进行了赋值操作,最后进入下一个条件语句;
4)if($uri = filter_var($uri, FILTER_SANITIZE_URL)语句中,对$uri进行过滤,并返回过滤后的结果,如果有则返回,如果没有则返回false;
5)通过if($uri = parse_url($uri, PHP_URL_PATH))语句解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。本函数不是用来验证给定 URL 的合法性的,只是将其分解为PHP_URL_SCHEME、 PHP_URL_HOST、 PHP_URL_PORT、 PHP_URL_USER、 PHP_URL_PASS、 PHP_URL_PATH、 PHP_URL_QUERY 或 PHP_URL_FRAGMENT 的其中一个来获取 URL 中指定的部分的 string。 (除了指定为 PHP_URL_PORT 后,将返回一个 integer 的值)。不完整的 URL 也被接受,parse_url() 会尝试尽量正确地将其解析。
6)最后将结果完整的URL结果进行返回给current_url()函数进行执行,但此处并没有对URL中存在的XSS代码进行过滤,因此漏洞产生;
注:filter_var函数在实际使用过程中,过滤了URL中空格。特意验证了以下,如果是事先定义的URL中存在空格,则不会进行过滤,如果是采用前端页面输入的空格则会进行过滤。