Set a Cookie in flask Redirect to external URL - session

I want to redirect a user from my flask application to the client application with a header (encoded session object) that the browser can store as a cookie for further requests.
I'm authenticating a user using a different server and on a successful sign-in, he is redirected to my flask application where I set the user in the database and the session object. And, right after this is done, I need the request to be redirected to my client application. So, I use flask.redirect to redirect the user to my client application. Now, for the browser to store the user information, I want to send the session object to the browser as a cookie.
TLDR;
This is what I'm trying to do:
Client reaches content server.
Client does not have an active session, is redirected to authentication server with a callback to content server.
Content server creates session and redirects back to Client with session cookie.
Client reaches Content server.
Content server verifies session cookie and allows access to client.
Authentication is on a separate server, but the content server and client both need to keep track of the session via a cookie. The part I'm unable to do is make the Client (localhost:3000) keep track of the session.
The following is what I tried:
resp = flask.make_response()
resp.set_cookie('Set-Cookie', 'this is the session cookie I want the browser to set for further requests')
return flask.redirect('http://localhost:3000/', Response=resp)
This gives me the error:
File "/home/shaily/.virtualenvs/venv/lib/python3.6/site-packages/werkzeug/utils.py", line 507, in redirect
mimetype="text/html",
TypeError: __call__() got an unexpected keyword argument 'mimetype'
Is there an alternative or a way I can fix this?

"redirect functionality" can refactored in the following way.
resp = redirect("http://localhost:5001")
resp.set_cookie('a', 'x')
return resp
Referring a comment on this question, we can't pass 'Response' objects to redirect. Response has to be another Class
(useful when a wrapper class of werkzeug.Response) as written here.

According to how sessions are implemented in flask, on making any changes to the session object during the lifecycle of an http request, the encoded session object is sent as a cookie in the http response to this request. So, I no longer need to explicitly send it.
I was unable to read the cookie in my client application using document.cookie since by default, session cookies are httpOnly, i.e., they cannot be accessed via javascript applications, for security reasons. What httpOnly does let you do is let your browser store the cookie for further http requests to the server. If for some reason, you still want to read the session cookie in javascript, you cant set SESSION_COOKIE_HTTPONLY to False in your server config.
To send a cookie with an http response, this solution worked well for me: In Flask, set a cookie and then re-direct user

Related

Does Laravel CSRF protection provide 100% safety?

Laravel documentation says:
Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the person actually making the requests to the application. Since this token is stored in the user's session and changes each time the session is regenerated, a malicious application is unable to access it.
Laravel config session.php file guarantees session cookie lifetime is 120 minutes by default:
'lifetime' => env('SESSION_LIFETIME', 120)
So let's imagine, for example, I authenticate into the Laravel app and receive session cookies. What will happen if within 120 minutes after authentication I will go to a malicious website and get exposed to CSRF attack? Of course, considering the fact cors.php config is set to allow accept any (*) origin ('allowed_origins' => ['*']).
In my current understanding within these 120 minutes after authentication browser has the session cookie, so if I go to a malicious website and get exposed to CSRF attack, the attack will be successful.
Please correct me if my current understanding is wrong?
So the problem with my understanding was that I was not aware of the fact you can't access a cookie of the origin that differs from website you are trying to access it. So in case of csrf, origin of malicious website differs from the origin of CSRF-TOKEN cookie which is provided by Laravel server, therefore attacks fails. So yeah laravel csrf protection works.
Full explanation of CSRF protection to the beginners as myself:
What is csrf attack?
Imagine, you authenticated into website with domain A, and received the session cookie from server that serves the site A. Annother malicious website with domain B contains a script which produce a request to the server which serves domain A as you enter the site B. As long your browser contains the session cookie of website A, the script attempting to attack from website B will be successful.
So how does csrf token help to cover this vulnerability?
Now laravel server sends you response with XSRF-TOKEN cookie, when you try to send axios request with script from domain A, axios automatically places value of XSRF-TOKEN to X-XSRF-TOKEN header in case of same-origin request (when website A has domain of the same origin as the server). In case of malicious website with non same-origin request, script can't access the XSRF-TOKEN cookie because it is not possible to accesss a cookie of another origin. So axios can't place a value of XSRF-TOKEN to a requst header or a request parameter. Server examines incoming request for X-XSRF-TOKEN or csrf token parameter, server is not able to find it, and so therefore server doesn't validate the request.

Pass Information with URL redirection

We are working on an existing application where web services (tomcat) as well as UI (nginx) applications are hosted on separate containers. One of the service application is used for sending login request (SAML request) to identity provider (ping). Here are the steps for user login to the system:
User loads the application (domain URL: https://ui.domain.com), it loads the UI where it checks for logged in user (JWT token string generated for user/role) on local storage and when not found, it redirects to ping (IDP) for authentication.
Once authenticated with ping, it calls the spring controller which is configured for the success URL on service application (https://api.domain.com/auth-service/auth).
This controller service (/auth), gets the SAML response sent by ping and processes it further to get user details and generates the JWT token for the user and redirects the user to UI (https://ui.domain.com).
Problem Statement:
To pass the token to UI, the JWT token string is added to URL by using
redirectAttributes.addAttribute(“auth-token”, token);
With the above, it shows up in the address bar like: https://ui.domain.com/?auth-token=
This has raised a concern with respect to security as the token is displayed on address bar and exposed which can be decoded to get user information.
Current Approach (tried):
Before redirection from controller to UI, tried to set cookie
Cookie cookie = new Cookie(“auth-token”, token);
cookie.setMaxAge(-1);
cookie.setPath(“https://ui.domain.com”);
response.addCookie(cookie);
However we couldn’t find the cookie from UI.
We tried to set it to response header too.
response.addHeader(“auth-token”, token);
Since it is a redirection, the adding to response doesn’t help.
Further trials:
We are also putting a thought about changing the approach of authentication controls where after ping authentication is done, the success URL can be replaced with UI url rather than service URL, i.e.
Current: saml.sso.default-success-url= https://api.domain.com/auth-service/auth
Proposed: saml.sso.default-success-url= https://ui.domain.com/
With the above, the SAML response supposed to go directly to UI (after ping authentication is successful).
However we couldn’t get the response in UI and it also behaves like ping is doing a redirection to UI and due to the same reason, UI doesn’t get it.
Any ideas and suggestions over this would be great.

how does server recognize client's session cookie without storing it on server

I am trying to understand, how exactly the session management mechanism in a stateless web application works. Currently I am using Play Framework but I think the mechanism should be the same for all of the stateless web frameworks
this is from the documentation of play framework: (link)
It’s important to understand that Session and Flash data are not stored by the server but are added to each subsequent HTTP request, using the cookie mechanism
and
Of course, cookie values are signed with a secret key so the client can’t modify the cookie data (or it will be invalidated).
Now my question is, if the server does not save anything about a session id, how does it authenticate a session coming from a client?!
I did a lot of searching, but I couldn't find out, how the session management on the server side really works.
Now my question is, if the server does not save anything about a
session id, how does it authenticate a session coming from a client?
What play does is it signs your session data through a key say KEY(Its the application.secret that you set in application.conf) and produce a alphanumeric data. Then it attaches both data and encrypted data to cookie and sends it back
ENCRYPTED DATA= 5d9857e8a41f94ecb2e4e957cd3ab4f263cfbdea
DATA = userEmail=sil#st.com&userName=silentprogrammer
If you Inspect the cookie(Right click on browser->Inspect element->Application->Cookie->Your url) in the browser of your running application you can see something like
"5d9857e8a41f94ecb2e4e957cd3ab4f263cfbdea-userEmail=sil#st.com&userName=silentprogrammer"
For each request it gets the data part(userEmail=sil#st.com&userName=silentprogrammer) signs the data again from the KEY and checks it to the alphanumeric data coming from request i.e. 5d9857e8a41f94ecb2e4e957cd3ab4f263cfbdea if the both are equal(if data and encryption key is same) the session is confirmed otherwise session expire. You can confirm this by changing the data part from cookie in browser and sending the request again the session will not exist.
This is what I have observed

Spring Security : restrict other web application access

I am running spring web application in broswer. I logged in to my account and update some value using a url say localhost:80/update/name. On the controller side I check principal==null if not redirect to login page.
Now while login to this application. I open other web application page in the same browser and execute the same update url localhost:80/update/name through ajax call and it is updating the value. How can i avoid this security threat.
How can i make sure that Application1 update url will be executed by application1 request only? Application2 should not be allowed to execute app1's update request no matter whether it is in same browser ?
Why are you surprised ? You are logged, thus the browser has a valid session cookie. You ask the browser to send a request to the host (be it in first window or any other window, it is the same) : it sends the request with all relevant cookies, including session cookie and if appropriate any other security cookie. The server receives a request containing a valid session cookie for a valid logged user and even if it controls IP addressed coming from same address : all is valid and it proceeds with the request.
If you have a different browser on your client machine and if you open the connection from this unrelated browser, the server should reject your request, because the browser would not present a valid cookie.
You are describing a variant of cross-site request forgery, you should enable Spring Security CSRF protection. You can read about it in the reference manual.
Even if the two applications are on the same server, they will get different CSRF tokens, which will protect your case.
You described Cross-Site request forgery attack. Typically when POST method is used hidden token is added to prevent it. I assume You are using GET method - It is good practice to not change any state using GET method.

Session timeout after 15 minutes

In my application I use web services to get required information. To actually use this services you have to login first, you get your token - encrypted password, afterwards this token is attached to SOAP requests to identify current user. The thing is, when you do not use service for 15 minutes, your token changes and when you are trying to obtain another bunch of information from the server it denies old token. As a result app do not get required information and throws a heap of errors.
How to send user (load Login.axm) to Login page when token has been changed?
Thank you, Shay Shmeltzer for your answer.
How I solved this problem:
1) First I read how does sessions work in my particular case. I used stateless session which means -
A new session is opened for an initial request and the session remains
open for subsequent requests. Relogin occurs automatically
(transparent to the user) if the session is closed. UsernameToken and
PasswordText must be included as SOAP headers in the initial request
to open a stateless session.
Stateless session management is the best method to use for high-load
Web service applications. Using Stateless mode, the application
provides the username and password only once, that is for the initial
request. A session is opened on the server and is dedicated for this
user.
In the response Siebel Business Applications return the SessionToken,
which is an encrypted string containing the information about
username, password, and timestamp. For subsequent requests the
application must use the SessionToken to reuse the session.
For security reasons SessionTokens are regenerated for each response.
The application must provide the last received SessionToken for the
next request.
The SessionToken-Siebel session map is maintained in the Siebel Web
Server Extension (SWSE); based on the SessionToken value SWSE sends
the request to the correct Siebel session (task).
Although the session is persistent, authentication happens for each
request (SWSE decrypts the UserName and Password from the
SessionToken).
the main problem was :
NOTE: Reconnecting or automatic logging in again will only happen if
the token has not timed out. If it times out, then the user must
manually log in again. Token timeout must be greater than or equal to
session timeout. For more information on session token timeout, see
Session and Session Token Timeout-Related Parameters.
in my case standard session token live time was 15 minutes.
That is why I included counter in my code and checked it before each request. If counter time > 15 minutes, I sent log in request to the server to get new session token. The reason, I did not change current page to log in page straight away after the counter exceeds 15 minutes is: place in code, where I check counter is already initiated by the bindings to get required value to render it, so if your token has expired you will get a heap of errors. That is why firstly I renew the session sending log in request, get active session token and put it into the last request which is requested by binding. After app renders page without any errors, it shows pop up message "Session has expired" and goes to log in page.
You can programmatically set the soap header being sent to your SOAP service from ADF Mobile - http://docs.oracle.com/cd/E37975_01/doc.111240/e24475/amxwebservices.htm#CHDIBIIE

Resources