The Open Redirect That Made the Phishing Link Look Legitimate
The login page accepted a return address and sent the user there without checking it, so the attacker's link started with the real domain, passed the user's…
I have chased this from the open redirect end and from the worked end, and the truth was in the hand-off, as it usually is.
Strip the open redirect down and one property makes it dangerous rather than merely sloppy: the attacker's URL begins with the legitimate domain, so the user's check passes, and the check is the domain, and the domain is the real one, and the real one is the trust the attacker borrowed.
I have since met the same mechanics in plenty of endpoint that redirects to a user-supplied address.
Why the redirect existed
The login needed the return, and the return was the next, and the next was the parameter, and the parameter was the user's original page, and the page was the experience, and the experience was the clean, and the clean was the reason the parameter exists, and the exists is the legitimate, and the legitimate is the requirement, and the requirement is the redirect, and the redirect is the feature.
The feature was the redirect to the parameter, and the parameter was the unchecked, and the unchecked was the any value, and the any value was the attacker's URL, and the URL was the external, and the external was the redirect's target, and the target was the phishing, and the phishing was the incident, and the incident is the reason the parameter needs the validation, because the feature is legitimate and the implementation is not.
The redirect is the useful feature and the open redirect is the missing check, and the check is the allowlist, and the allowlist is the internal only, and the internal is the safe, and the safe is the fix, and the fix is the one condition, and the condition is the prevention.
Why the user's check failed
The user checks the domain, and the domain is the beginning, and the beginning is the real one, and the real one is the trust, and the trust is the click, and the click is the redirect, and the redirect is the arrival, and the arrival is the attacker's, and the attacker's is the after, and the after is the too late, because the user's check was the before, and the before was the real domain.
The phishing page looked like the login, and the looked was the copy, and the copy was the credential form, and the form was the password, and the password was the theft, and the theft was the incident, and the incident was the trust's cost, and the cost is the reason the open redirect is a real vulnerability rather than a cosmetic one, because it lends the domain's reputation to the attacker.
This is the same borrowed trust as the session cookie that rode along cross site, and the shared property is the one worth fixing.
The fix, in order
Allowlist the redirect targets. The parameter is checked against the known internal paths, and the checked is the allowed, and the allowed is the internal, and the internal is the fix, and the fix is the list, and the list is the explicit, and the explicit is the discipline, because the unchecked is the any, and the any is the attacker's.
Use relative paths only. The redirect accepts the path rather than the URL, and the path is the internal, and the internal is the safe, and the safe is the fix, and the fix is the rejection of the absolute, and the absolute is the external, and the external is the attack, and the attack is the blocked.
Beware the protocol-relative URL. The two slashes is the external, and the external is the bypass, and the bypass is the check's failure, and the failure is the parse, and the parse is the fix, and the fix is the proper URL parsing, and the parsing is the library's, and the library's is the correct, because the string check misses the slash form.
Show an interstitial for external links. The external link is the warning page, and the warning is the user's second look, and the second look is the catch, and the catch is the prevention, and the prevention is the interstitial, and the interstitial is the discipline, because the borrowed trust is broken by the visible departure.
Log the redirect targets. The logged is the pattern, and the pattern is the attacker's use, and the use is the detection, and the detection is the fix, and the fix is the monitoring, and the monitoring is the discipline, because the open redirect in the wild shows up as the external targets in the log.
What I now do
A redirect to a user-supplied address without an allowlist lets an attacker build a link that starts with your domain and ends on theirs, borrowing your reputation. Allowlist the targets, accept relative paths only, parse URLs properly to catch the protocol-relative form, show an interstitial for external links, and log the redirect targets.
The phishing email contained a link to the real login page with a next parameter pointing at the attacker's copy of the sign-in form, and the users checked the domain, saw the real one, and typed their passwords. The lesson I keep is the property, not the incident.