Created
May 14, 2021 11:06
-
-
Save meglio/cd93e4963f96c69e2ed7c7746f182cba to your computer and use it in GitHub Desktop.
Sanitizes relative URL to use for redirects through HTTP response headers - when the URL comes from an insecure input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
public static function sanitizeRelativeRedirectUrl($url): ?string | |
{ | |
$res = parse_url($url); | |
// On seriously malformed URLs, parse_url() may return FALSE | |
if (!is_array($res)) { | |
return null; | |
} | |
// If a scheme and/or a host is specified, ignore the whole URL | |
$scheme = array_key_exists('scheme', $res)? trim($res['scheme']) : ''; | |
if ($scheme !== '') { | |
return null; | |
} | |
// If no path specified, or it is insanely long, then the URL is not valid | |
$path = array_key_exists('path', $res)? trim($res['path']) : ''; | |
if ($path === '' || mb_strlen($path) > 10000) { | |
return null; | |
} | |
$query = array_key_exists('query', $res)? trim($res['query']) : ''; | |
// Make sure the query is not insanely long | |
if (mb_strlen($query) > 1000000) { | |
return null; | |
} | |
// Fragment is what comes after the hashmark # | |
$fragment = array_key_exists('fragment', $res)? trim($res['fragment']) : ''; | |
// Make sure the fragment is not insanely long | |
if (mb_strlen($fragment) > 1000) { | |
return null; | |
} | |
// Sanitize path | |
$path = explode("/", $path); | |
foreach ($path as &$part) { | |
$part = urldecode($part); | |
$part = str_replace(["\n", "\r", "\\", "/"], '', $part); | |
} | |
$path = implode("/", $path); | |
$path = preg_replace("/\/+/", "/", $path); | |
return $path . ($query !== ''? '?'.$query : '') . ($fragment !== ''? '#'.$fragment : ''); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment