I'm using Flask and it's occurred to me it could be a rather elegant solution to redirect back to the user's last page after login/logout by simply placing a session['next'] = request.url
at each endpoint of my application and to just have my login/logout functions redirect right to session.get('next')
. This is even similar to an option in the Flask-Login extension if you enable USE_SESSION_FOR_NEXT.
I would like to confirm this is a safe workflow but am not security-savvy to recognize if there are any ways to spoof the request.url or if I should still be validating the next url prior to redirecting, as is specified here:
http://flask.pocoo.org/snippets/62/
Is there a reason this method is not more commonly deployed? It seems like a nice, clean, easy solution that keeps URL's clean, minimizes for fields/processing, and removes a vulnerability to open redirect attacks if you are not taking the extra steps to validate the next url. What's the catch?
URL Redirection is a vulnerability which allows an attacker to force users of your application to an untrusted external site. The attack is most often performed by delivering a link to the victim, who then clicks the link and is unknowingly redirected to the malicious website.
Permanent (301): redirect one page URL to another URL. This is the default selection for new redirects. Temporary (302): temporarily redirect one page to another URL. This type of redirect is often used to temporarily redirect traffic for website maintenance or a website redesign.
The most common ways to implement redirection logic after login are: using HTTP Referer header. saving the original request in the session. appending original URL to the redirected login URL.
TL;DR
This is a safe workflow, assuming your server authenticates incoming requests to all secure resources.
When you ask "if I should still be validating the next url prior to redirecting", the answer to that is no, but you need to validate all requests to that url (after redirecting) to make sure they are logged in.
In your question, it sounds like you are trying to keep the url hidden from the user until they are logged in. That shouldn't be necessary.
For example, let's say you have two urls:
url 1: "/login" # anyone can access this
url 2: "/secure_page" # only a logged in user can access this
Let's say a user is not logged in, and tries to navigate to yoursite.com/secure_page
. They should be redirected to your login page every time. If they know the secure_page
url, that shouldn't compromise your security at all. In fact, they must already know that url because they navigated to that page in the first place, so either they typed it in, clicked a link, or it was saved in a bookmark or a browsing history. The important thing is that when you handle requests to secure_page
, you require them to be logged in.
You ask if they can "spoof" the url that they are redirected to. They cannot, when you save it in the session like that. However, they can hit any url they want after they log in, so it doesn't matter if they "spoof" that url.
So since they already know that url and they can hit any url they want after they log in, you don't need to keep that url secret from the user. The only advantage of doing that is an aesthetically cleaner url. This is why you see many login pages that look like this:
http://yoursite.com/login?next=secure_page
What is happening there is they are saving that next url as an HTTP GET parameter. While it is less "clean", it is more explicit, so it has its pros and cons. And if they were to revisit the login page later, that redirect would no longer occur, which may be your desired behavior. With your current code, once that redirect is on the session, this next login after that will follow the redirect until the session expires, which could be after the user walks away and someone else uses that web browser.
Many sites do it the way I showed above. Django does it that way. In this case, a malicious link could provide the "next" url and have it redirect to some phishing site, but that could be easily prevented by ensuring the "next" url doesn't navigate away from your domain.
Here is a basic cheat sheet for redirect/forward security (you are redirecting, but others landing here may be considering forwarding requests).
To be honest, I can't think of any practical way to exploit this. Rather, I can't think of any practical way to exploit this, assuming you are properly validating incoming requests on other pages, and have properly implemented authentication and access control. That being said, I know nothing about your application, and there are certainly attackers out there a lot brighter than me, so take that with a grain of salt.
That being said, I don't see any reason why you shouldn't validate the URL, at the very least to make sure you're redirecting to a page on the same domain. The performance cost is trivial, and I'm of the opinion that anything related to the login/logout flow deserves an extra level of scrutiny. I would also make sure that you have an acceptable default case for when you receive a request without this field in the cookie.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With