URL重定向及跳轉漏洞

URL跳轉漏洞php

   URL 跳轉漏洞是指後臺服務器在告知瀏覽器跳轉時,未對客戶端傳入的重定向地址進行合法性校驗,致使用戶瀏覽器跳轉到釣魚頁面的一種漏洞。瀏覽器

使用場景服務器

   如今 Web 登陸不少都接入了QQ、微信、新浪等第三方登陸,以 QQ 第三方受權登陸爲例說明,在咱們調用 QQ 受權服務器進行受權時,會在參微信

數中傳入redirect_url(重定向)地址,告知 QQ 受權服務器,受權成功以後頁面跳轉到這個地址,而後進行站點登陸操做。可是若是你的重定向地址在dom

傳輸過程當中被篡改爲了一個釣魚網址,那麼就是致使用戶的受權信息被非法獲取。固然,QQ 第三方登陸,也會有本身的策略,就是接入 QQ 第三方url

登陸的應用,會在開發者平臺,配置相關的跳轉白名單,只有屬於白名單中的域名、子域名或 url ,QQ受權服務器才跳轉,若是發現 redirect_url 不code

合法,則跳轉到非法頁面。blog

防護策略ip

   根據上面的場景分析,咱們知道,之因此會出現跳轉 URL 漏洞,就是由於服務端沒有對客戶端傳遞的跳轉地址進行合法性校驗,因此,預防這種攻ci

擊的方式,就是對客戶端傳遞過來的跳轉 URL 進行校驗。

 

經常使用的方式:

服務端配置跳轉白名單或域名白名單,只對合法的 URL 作跳轉

 

下面是關於PHP服務端對客戶端傳遞過來的跳轉 URL 進行校驗的代碼:

<?php

// $allowedDomains 表示容許跳轉的url白名單
$allowedDomains = array(
		"aaaa.com"
		"bbbb.com"
		.......	
	);
function encodeUrl($urlInfo)
    {/*{{{*/
        $path = isset($urlInfo['path']) ? $urlInfo['path'] : '';
        if(!empty($path))
        {
        	$t = explode("/", $path);
        	
        	for($i = 0; $i < count($t); $i++)
        	{
        		$t[$i] = rawurlencode($t[$i]);        		
        	}
        	$path = implode("/", $t);
        }
    	$query = isset($urlInfo['query']) ? $urlInfo['query'] : '';
        if(!empty($query))
        {
        	$t = explode("&", $query);
        	
        	for($i = 0; $i < count($t); $i++)
        	{
        		$tt = explode("=", $t[$i]);
        		$tt[1] = rawurlencode($tt[1]);
        		$t[$i] = implode("=", $tt);        		
        	}
        	$query = implode("&", $t);
        }
        if(!isset($urlInfo['host']) || empty($urlInfo['host']))
        {
        	return $path. "?". $query;
        }
        $scheme = isset($urlInfo['scheme']) ? $urlInfo['scheme'] : 'http';
        $port = isset($urlInfo['port']) ? $urlInfo['port'] : 80;

        
        $request = $scheme . '://'. $urlInfo['host'];
        $request .= ($port == 80) ? '' : ':'.$port;
        $request .= $path;
        $request .= (empty($query)) ? '' : '?'.$query;
        return $request;
    }/*}}}*/
	
function checkUrl($url,$domainArr=array())
	{/*{{{*/
		$res = array('isTrustedDomain' => false,'url' => '','domain' => '');
		if(empty($url))		return $res;
		$domainArr = empty($domainArr) || !is_array($domainArr) ? $allowedDomains : $domainArr;
		$url	  = filterUrl($url);//先過濾特殊字符
		$p      = parse_url($url);
		$scheme = $p['scheme'];
		if(!in_array(strtolower($scheme),array('http','https'))){
			return $res;
		}
		
		$host   = $p['host'];
		if(!isValidHost($host)){
			return $res;
		}
		$hostLen = strlen($host);
		foreach($domainArr as $domain){
			$firstPos = strpos($host, $domain);
			if($firstPos !== false && ($firstPos + strlen($domain)) == $hostLen){
				
				if($firstPos == 0 || $domain[0] == '.' || $host[$firstPos-1] == '.'){
					$res['isTrustedDomain'] = true;
					$res['url'] 		  				= $url;
					$res['domain'] 				= $domain;
					break;
				}
			}
		}
		return $res;
	}/*}}}*/

function filterUrl( $url )
	{/*{{{*/
		if(empty($url)) return $url;
		// Strip all of the Javascript in script tags out...
		$url = preg_replace('/<SCRIPT.*?<\/SCRIPT>/ims',"",$url);
		// Strip all blank character
		$url = preg_replace('/[\s\v\0]+/',"",$url);
		//Strip special characters(',",<,>,\)
		$url = str_replace(array("'","\"","<",">","\\"),'',$url);
		return $url;
	}/*}}}*/

function isValidHost($host)
	{/*{{{*/
		$p = "/^[0-9a-zA-Z\-\.]+$/";
		return preg_match($p,$host) ? true : false;
	}/*}}}*/
	
$url = "https://www.baidu.com";
$call_back_url = trim($url);
$call_back_url = encodeUrl(parse_url(urldecode($call_back_url)));
$res = checkUrl($call_back_url, $domainArr);

var_dump($res);
相關文章
相關標籤/搜索