Back to Blog
SecurityJuly 3, 20264 min read

Open redirection and SSRF prevention in Node.js and PHP

Open redirection and SSRF risks are common in dynamic redirects. Learn how to secure your Node.js and PHP apps using strict URL validation and whitelisting.

securitynodejsphpweb-securitybest-practicesssrfopen-redirectWebBackend

During a recent refactor of a legacy Node.js authentication service, I found a classic "redirect_to" parameter being passed directly into a res.redirect() call. It seemed harmless until I realized an attacker could swap that URL for a malicious site, turning our trusted domain into a vehicle for phishing.

Open redirection is a deceptively simple vulnerability. It happens when your application accepts a user-controlled input to decide where to send the browser, without verifying the destination. While I’ve touched on preventing open redirect vulnerabilities before, the intersection of these redirects with Server-Side Request Forgery (SSRF) makes the stakes much higher.

Why URL validation is harder than it looks

My first attempt at a fix was a simple startsWith('https://myapp.com') check. That failed immediately when I realized an attacker could use https://myapp.com.attacker.com. The string matched, but the destination was entirely external.

When you're handling dynamic redirects, you aren't just protecting the browser; you're often protecting your server's outbound network. If your backend follows a redirect to fetch metadata or a profile image, an unvalidated URL allows an attacker to force your server to probe internal network services, leading to SSRF.

Implementing secure URL validation

To secure your application, you need to stop relying on regex hacks and start using proper URL parsing. In Node.js, the URL constructor is your best friend. In PHP, use parse_url().

Here is the strategy I use to prevent both open redirection and SSRF:

  1. Whitelisting: Never use a blacklist. Maintain a list of allowed hostnames or domains.
  2. Strict Parsing: Break the URL into components and validate the host explicitly.
  3. Internal-only check: If the redirect is intended for internal use, ensure it doesn't contain a protocol or host that points outside your infrastructure.

Node.js Example

Using the native URL API, we can safely decompose the input:

JAVASCRIPT
const { URL } = require(CE9178">'url');

function isSafeRedirect(targetUrl, allowedHosts) {
  try {
    const parsed = new URL(targetUrl, CE9178">'https://myapp.com'); // Base URL handles relative paths
    return allowedHosts.includes(parsed.hostname);
  } catch (e) {
    return false;
  }
}

PHP Example

PHP’s parse_url() is great, but watch out for edge cases where the host might be missing or malformed.

PHP
function isSafeRedirect($targetUrl, $allowedHosts) {
    $parsed = parse_url($targetUrl);
    if (!$parsed || !isset($parsed['host'])) {
        return true; #6A9955">// Likely a relative path, handle accordingly
    }
    return in_array($parsed['host'], $allowedHosts);
}

Comparing mitigation strategies

When securing your traffic, the approach you take depends on whether you are handling user-facing redirects or server-side requests.

StrategyEffectivenessComplexityBest Use Case
Regex MatchingLowLowNever recommended
Domain WhitelistingHighMediumUser-facing redirects
Proxy/Gateway RoutingVery HighHighComplex microservices
Allow-list + HardcodingAbsoluteLowFixed internal paths

SSRF: The hidden danger of redirects

If your code fetches data from the URL provided by the user, you are at risk of SSRF. I’ve seen developers fall into this trap while building "link preview" features. Even if you validate the URL, a request might be redirected again by the target server.

I always recommend setting a strict timeout on your HTTP client (like axios or Guzzle) and disabling automatic follow-redirects. If you must follow them, inspect the new URL against your whitelist at every hop. This is similar to how we manage preventing arbitrary file write vulnerabilities by strictly controlling the destination of data streams.

Frequently Asked Questions

Is it enough to just check if the URL starts with /?

No. An attacker can use //evil.com, which browsers interpret as a protocol-relative URL, effectively redirecting to an external site. Always use a proper parser.

How do I handle relative paths safely?

If you only want to allow relative paths, ensure the parsed URL’s host property is null or empty before allowing the redirect.

Should I use a library for URL validation?

Native tools like URL in Node and parse_url in PHP are usually sufficient if used correctly. Avoid heavy dependencies unless you need complex validation logic.

Final thoughts

Securing redirects is less about perfect code and more about defensive configuration. I usually prefer a "hardcoded lookup" approach whenever possible—if the user needs to return to a page, provide an ID or a token in the URL instead of the full destination path.

I'm still refining how we handle these redirects in highly distributed systems where services share hostnames. The best advice I can give is to treat every URL input as untrusted, regardless of where it originates in your application.

Similar Posts