Skip to content

Instantly share code, notes, and snippets.

@meglio
Created May 14, 2021 11:06
Show Gist options
  • Save meglio/cd93e4963f96c69e2ed7c7746f182cba to your computer and use it in GitHub Desktop.
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
<?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