Validate redirects against an allowlist. Treat every input as potentially malicious and use accept-known-good validation covering the expected type, length, syntax, complete value range, missing or extra data, consistency, and business rules. Approve only specifically allowed URLs or domains, rather than relying exclusively on a denylist.
Replace user-supplied URLs with fixed mappings. When the permitted destinations are limited or known, accept fixed identifiers and map them to the corresponding URLs, rejecting all other values.
Use an intermediate warning page. Clearly warn users that they are leaving the current site, require an explicit click, or apply a long delay before redirecting. Avoid introducing cross-site scripting when generating that page.
Require an unpredictable application nonce. Require every externally supplied redirect request to include a unique nonce generated by the application, and ensure that the nonce is not predictable. This measure can be bypassed through cross-site scripting.
Reduce the attack surface. Identify every possible source of untrusted data, including parameters, cookies, hidden fields, network data, environment variables, reverse DNS results, query results, request headers, URL components, files, databases, email, APIs, and external systems. Do not assume that cookies or hidden fields cannot be modified.
Use an application firewall as defense in depth. This can provide emergency protection when the code cannot immediately be fixed, but it may miss input vectors, be bypassed by malformed inputs, or reject or alter legitimate requests. Customization may also be necessary.