I'm trying to put some security on my Flask web app. As a first step I'm going to make my session cookie secure by setting SESSION_COOKIE_SECURE to true.
But after I get my session cookie from "inspect element" I can decode session cookie easily and there is no difference whether I add SESSION_COOKIE_SECURE or not.
Here is my code:
from flask import Flask, request, app, render_template, session, send_file, redirect
MyApp = Flask(__name__)
MyApp.secret_key = "something"
application = MyApp
if __name__ == "__main__":
MyApp.debug = False
MyApp.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
MyApp.config["SESSION_PERMANENT"] = True
MyApp.run()
I also tried to add this attribute using the following syntax but this made no difference:
MyApp.config['SESSION_COOKIE_SECURE'] = True
When I try to print SESSION_COOKIE_SECURE I get this error
Traceback (most recent call last):
File "...", line ..., in <module>
print(MyApp.session_cookie_secure)
AttributeError: 'Flask' object has no attribute 'session_cookie_secure'
My Flask version is 1.0.2, and I'm on HTTPS.
Setting SESSION_COOKIE_SECURE does not encrypt the cookie value, no. When set, this causes Flask to create cookies with the "Secure" flag set. This means that a browser can only return the cookie to the server over an encrypted connection, nothing more. The setting doesn't change anything about the cookie value itself.
Flask produces cookies that are cryptographically signed, by default. That means that the cookie contents can be decoded but not altered, because a third party without access to the server secret can't create a valid signature for the cookie.
You generally don't need to encrypt your session cookie if you a) use HTTPS (which encrypts the data from outsiders) and b) protect your web app from XSS attacks. Without an XSS attack vector, attackers can't get access to your cookie contents at all anyway.
You certainly don't need to do so here, as SESSION_COOKIE_HTTPONLY means that the browser will never expose the cookie to JavaScript, and only someone with full access to the browser can see the cookie value.
Flask doesn't have a 'encrypt cookie' setting, because it is not deemed necessary when you can secure the cookie in other ways. You should not store information in a session cookie so sensitive that it should be protected from the end-user with access to the browser storage; keep such data on the server and only store a unique identifier in the session to retrieve that secret data later on.
If for some reason you can't keep such secrets out of the session cookie and are unwilling to accept that the end-user can read this data, then you'll have to encrypt the cookie yourself or use an alternative session provider for Flask, such as EncryptedSession.
As for the attribute error: only a few configuration settings are accessible as attributes on the Flask object. To print arbitrary configuration settings, use the app.config object:
print(MyApp.config['SESSION_COOKIE_SECURE'])
Related
I have a server-side session file created and I am new to web applications. I don't understand why the session files when opened with text file has plain content inside it. I have a secret key setup and all but why is it not encrypted?
from flask import Flask, render_template, request, redirect, url_for, session, flash
from flask_sessions import Session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'keykeykey'
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
app.config['SESSION_USE_SIGNER'] = True
server_session = Session(app)
And on login the file route is
app.route('/login', methods=['GET', 'POST'])
def login_page():
session['email'] = email
return redirect(url_for('home_page'))
And on logout the route is
#app.route("/logout")
def logout():
session.pop('email', None)
return redirect(url_for("home_page"))
WHen the session is started a file is created in dir/flask-sessions/2029240f6d1128be89ddc32729463129, there are two files generated for each time and when I open it with notepad I can see the email id in plain text that is
Mø`.€•i }”(Œ
_permanent”ˆŒ
csrf_token”Œ(fb90d22be1adc1237c52730fadf95d1e07936cdd9e”Œemail”Œemail#email.com”u.
the ending email#email.com is the input from the form.
My questions are
Why is the content not encrypted even though it is stored in my server?
When I do session.pop() why is the file not deleted?
EDIT:
I guess the issue is because I use from cachelib import FileSystemCache instead of from werkzeug.contrib.cache import FileSystemCache?? Is that the issue? How can I overcome this as latest version of werkzeug doesn't have .contrib?
Trying to answer it to the best of my knowledge.
1) Why is the content not encrypted?
You do not really need to worry about the session stored in your server as long as your server is secured. The vulnerability is the session stored as cookies in the browser. To bypass that, the 'SECRET_KEY' is used to let the server sign the session variables before storing them in the browser. That is the reason why you might still see the session in plain text on the server. It will be signed in the browser cookie-data though.
2) When I do session.pop() why is the file not deleted?
To understand what the session.pop does, I did a little exercise.
At first, my flask session looked like this:
Session is: <SecureCookieSession {'id': '27260b14-405d-440a-9e38-daa32d9a7797', 'loggedin': True, 'username': 'Rajat Yadav'}>
When I pop all the keys in the session dict mapping, I am left with this:
New Session is: <SecureCookieSession {}>
The clarity is that the key:value pair gets deleted as we pop the session. One thing for sure is that pop does not delete the complete dictinary object but just the key:value pair inside.
To your question of the file not getting deleted, I believe deleting the dictionary object should do the trick.
Try:
del session
Let me know if this deletes the file.
I have a question about flasks session logic. First of all as I know there are two ways to store session data, one is on client side and the second is server side. Flask, as I know, is using the former one (client side) where the session is encrypted and stored on the browser of the client.
Let's us say we want to make a login on a flask-backend
User does a login, flask generates a session and through set-cookie the client stores the session
User makes another request to the backend and sends its cookies where also the session is stored and flask validates the session with the key which it used to encrypt the session
When the session is valid, flask loads the session, thus that means the user is logged in
And JWT works the following as I know. It generates a token and the client stores the token and sends it in each request to the server, where the token is validated.
As I know, both flask and JWT uses a secret to encrypt the data.
So can we say, that flask-session and JWT are somehow similar?
Both jwt and flask session work on client, but the key difference is that flask session stores the signed session data at the client cookie, but in jwt you have the independence to store the token anywhere you want, say localstorage, cookie etc.
And jwt will be base64 encoded by default while in flask session it has to be done manually for security. But yes the difference between traditional sessions (say php) and flask-sessions is that the session data is stored in the client rather than as a file at the server (while the client cookie has session id in traditional sessions).
I am trying to set a cookie with Flask after login and redirect on the front end in Javascript.
#app.route("/login")
#auth.login_required
def get_auth_token():
token = g.user.generate_auth_token()
request = make_response()
token = str(token.decode("ascii"))
request.set_cookie("token", value = token)
return request, 200
No matter if I have the redirect in or not, the cookie never sets. I've tried commenting out my redirect on the front end, I've tried setting my cookie with secure = false but none of that seems to work. What am I missing? If needed, I can provide the generate_suth_token function, but I know that is working properly. I am serving on localhost:5000 and using Flask 0.12.2, and received no cookie warnings in the server log.
If Flask service and client service are being hosted on different domains (e. g Flask uses 127.0.0.1:8080 and a client uses 127.0.0.1:3000) in this case, cookies should be set with domain parameter otherwise they will not be available.
resp.set_cookie('cookie_key', value="cookie_value", domain='127.0.0.1')
Find more info about domain parameter here
I am using Django's signed cookie engine for storing session data. My settings are:
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_NAME = 'sessionid'
And it works as it should. Even after closing browser and web server when I visit the website, I am still logged in. I can see the sessionid being set but I can't seem to find where session data is stored. I am storing entire user object in session.
The data is stored in the sessionid itself. Here's the relevant source code from the signed cookie backend:
def _get_session_key(self):
"""
Instead of generating a random string, generate a secure url-safe
base64-encoded string of data as our session key.
"""
return signing.dumps(
self._session, compress=True,
salt='django.contrib.sessions.backends.signed_cookies',
serializer=self.serializer,
)
I am running a Flask app using uWSGI and Nginx. I want make it compliant with PCI DSS. Running the scan gives the error Cookie Does Not Contain The "secure" Attribute. How do I set the secure attribute for cookies in Flask?
I have added the following line in my Nginx file but it didn't work.
proxy_cookie_path / "/; secure;";
The secure flag for Flask's session cookie can be enabled in the Flask configuration.
SESSION_COOKIE_SECURE = True
To set it for other cookies, pass the secure flag to response.set_cookie.
response = app.make_response('<p>Hello, World!</p>')
response.set_cookie('name', 'World', secure=True)