URL跳转漏洞, 也叫开放重定向漏洞(open redirect)。 如果处理不当会导致用户被重定向至钓鱼或恶意网站。我们通常用白名单机制来处理,比如qq登录等接口的回调页面就要求做白名单限制。通常我们会判断跳转url中的域名或者路径是否合法,但是问题往往就出现在这些判断中。
漏洞通常发生在以下几个地方:
用户登录、统一身份认证处,认证完后的跳转;
用户分享、收藏内容过后的跳转;
跨站点认证、授权(第三方登录)后的跳转;
站内点击其它网址链接时的跳转。
出现漏洞的原因大概有以下5个:
写代码时没有考虑过任意URL跳转漏洞,或者根本不知道/不认为这是个漏洞;
写代码时考虑不周,用取子串、取后缀等方法简单判断,代码逻辑可被绕过;
对传入参数做一些特殊的操作(如域名剪切、拼接、重组)和判断,适得其反,反而被绕过;
原始语言自带的解析URL、判断域名的函数库出现逻辑漏洞或者意外特性,可被绕过;
原始语言、服务器/容器特性、浏览器等对标准URL协议解析处理等差异性导致被绕过。
在php中, 常用如下方法进行跳转(以参数名url为例):
$redirect_url = $_GET['url']; header("Location: " . $redirect_url);
后面假设源域名为:www.example.com,我们先设置白名单:
$arr_white_list = ['localhost', 'example.com'];
stripos
检测url字符串中是否存在于白名单中的域名 - 不安全如果使用stripos
检测字符串是否存在于跳转url中,是不可靠的,比如下面的url:
https://www.example.com/redirect.php?url=http://www.example.com.www.evil.com/untrust.html
代码:
$redirect_url = $_GET['url']; $is_redirect_url_valid = false; //跳转url是否验证通过 $arr_white_list = ['localhost', 'example.com']; foreach($arr_white_list AS $white_item){ if(stripos($redirect_url, $white_item) !== false){ $is_redirect_url_valid = true; break; } }
上面这种简单的判断域名是否存在url中是不安全的,不要使用。
使用内置函数parse_url
来判断url格式是否正确,并提取url的各个部分。
这里我们只考虑给定的url是包含protocol的完整的URL。对严重不合格的 URL,parse_url() 可能会返回 FALSE。
$redirect_url = $_GET['url']; $arr = parse_url($redirect_url); //解析 URL,返回其组成部分 $host = ''; //要跳转的URL的域名 if($arr !== null && $arr !== false) { if(array_key_exists('host', $arr)){ $host = $arr['host']; } }else{ echo 'Error: url式不正确'; } $is_redirect_url_valid = false; $arr_white_list = ['localhost', 'example.com']; if($host !== ''){ //判断域名是否在白名单中(包含二级域名) foreach($arr_white_list AS $white_item){ if( ($host === $white_item) || ( //子域名: 长度 > 主域名 strlen($host) > strlen($white_item) && substr($host, strlen($host)-strlen($white_item)-1) === '.'.$white_item ) ){ $is_redirect_url_valid = true; break; } } } var_dump($is_redirect_url_valid); //打印跳转url检查是否通过
上面的代码简单演示了后端PHP如何判断跳转url能否通过验证。
如果白名单下的页面有重定向漏洞,这里就无法处理。我们至少要确保站内没有重定向漏洞。
固定跳转地址,不让用户控制变量。 这种不适合登录后返回原来的页面这种场景,但是我们可以把登录功能作为页面公共部分, 所有页面都可以直接调出登录窗口,登录成功后直接reload页面。
跳转目标地址采用白名单映射机制, 不在白名单内的跳转到固定地址或不做任何动作。
合理充分的校验跳转的目标地址,非己方地址时告知用户跳转风险。
如果觉得博客文章对您有帮助,异或土豪有钱任性,可以通过以下扫码向我捐助。也可以动动手指,帮我分享和传播。您的肯定,是我不懈努力的动力!感谢各位亲~