PHP中移除URL协议部分及修复查询字符串重定向漏洞的方案咨询
Hey there! Let's break down your two PHP technical needs with robust, secure solutions:
To strip any protocol (like http://, https://, ftp://) from a URL, a targeted regular expression is perfect here. It matches the protocol prefix at the start of the string and replaces it with nothing:
function removeUrlProtocol($url) { // Matches any protocol (letters only) followed by :// at the start of the string return preg_replace('/^[a-zA-Z]+:\/\//', '', $url); } // Example usage: $originalUrl = "https://test.dev/contact.php"; $cleanedUrl = removeUrlProtocol($originalUrl); // Output: "test.dev/contact.php" $anotherUrl = "ftp://file.example.com/docs"; $cleanedAnother = removeUrlProtocol($anotherUrl); // Output: "file.example.com/docs"
This regex works because:
^anchors the match to the start of the string (so we don't accidentally replace protocol-like strings in the middle of a URL)[a-zA-Z]+matches any protocol name (HTTP, HTTPS, FTP, etc.):\/\/matches the literal://that follows protocols
Your current str_replace("//", "", $_GET['url']) approach has critical gaps—attackers can easily bypass it with tricks like http:/attack.hack (single slash) or pseudo-protocols like javascript:alert(1) (which could lead to XSS). Here are two far more reliable solutions:
Option 1: Force Internal/Relative Paths Only
This approach ensures the redirect target is always a valid internal path (either relative, like contact.php, or root-based, like /contact.php). Anything that looks like an external URL gets redirected to a safe default (e.g., your homepage):
$returnPage = $_GET['return_page'] ?? '/'; // Default to homepage if parameter is missing // Block any URL that starts with a protocol (e.g., http://, javascript:) or contains double slashes if (preg_match('/^[a-zA-Z]+:\/\//', $returnPage) || strpos($returnPage, '//') !== false) { $returnPage = '/'; } // Optional: Add stricter validation to ensure it's a valid file/path format if (!preg_match('/^(\/|\.\/|\.\.\/)?[a-zA-Z0-9_\-\/\.]+\.?[a-zA-Z]*$/', $returnPage)) { $returnPage = '/'; } // Perform the safe redirect header("Location: " . $returnPage); exit;
Option 2: Validate the Target Domain
If you need to allow redirects to your own domain (including subdomains, if desired), use parse_url() to extract the target host and compare it to your site's host:
$currentHost = $_SERVER['HTTP_HOST']; // Gets your site's domain (e.g., test.dev) $returnPage = $_GET['return_page'] ?? '/'; $parsedTarget = parse_url($returnPage); // If the target has a host (i.e., it's an absolute URL), check if it matches your domain if (isset($parsedTarget['host']) && $parsedTarget['host'] !== $currentHost) { $returnPage = '/'; // Redirect to safe default if domain doesn't match } // Safe redirect header("Location: " . $returnPage); exit;
Why These Are Better Than Your Original Approach
- They block all external URL patterns, not just double slashes
- They prevent pseudo-protocol attacks (like
javascript:ordata:) that could exploit your redirect - They enforce either internal paths or trusted domains, eliminating the open redirect risk entirely
内容的提问来源于stack exchange,提问作者rubo77




