I have been using Flask for some time now and I am really enjoying the framework. One thing that I fail to understand is that in almost all other places they talk about storing the session on the server and the session id on the client, which would then identify the session. However after using flask, I dont feel the need to do so. Saving the session as a cookie on the client cryptographically serves my purpose and seems quite secure too. The only thing being I am unable to encrypt the session keys for eg:
session['life'] = 'the great one'
would appear as
life='gfhjfkjdfa some encryption kj'
in the cookie saved on the client. But how would that matter as it is still encrypted.
I am sure that people here know things much better than I do, so request someone to please clarify :-)
Even if your data is encrypted, the user could still roll back their cookie to a previous state (unless you start encoding one-time IDs etc)
e.g. cookie says the user has 100 credits, user spends 100 credits, they get a new cookie saying they have 0 credits. They could then restore their previous cookie (with 100 credits).
Depending how you encrypt the cookie, the user may also be able to delete keys, insert bogus data etc too.
If the session data is needed at the server, it makes sense to store it at the server. It keeps down the data bulk sent back and forth from the client. Also, cookies have a limit on the amount of data they can store.
In addition to the points already mentioned above
Users can disable cookies using their browser settings.
A lot of antivirus scanners also scan and flag cookies as a risk because of which which can also result in cookies not being allowed on the users computer.
Cookies can be deleted by the user even in the middle of his session. (In fact, i inadvertently did that the other day when one my PC scans listed the tracking cookies...and i just clicked "Clean" and they were all gone). In case the user happens to delete the cookies, the users state will be lost.
If you use cookies to manage the entire state, you are always dependant on the client environment and its settings. In as such, you will probably atleast need a fall back mechanism in case the cookies are deleted / disabled etc in order for your application to work correctly.
The SecureCookie implementation Flask uses does not encrypt the values. The only thing that is being ensured is that the user cannot modify the cookie without knowing the secret used by the application.
Related
(Note: Now, I know a lot of you might jump ahead and be like "Hey. Duplicate." Please read ahead!)
Background:
My goal is to make a Python app for PC that interacts with Spotify using their python API Spotipy. This obviously brings about the need to store the client_secret for purposes of user authentication. Based on my research, storing this as plaintext anywhere is a big no-no. The other solutions involved encrypting that data (but then, where to store that key). The best solution is apparently to have the authentication request handled by the backend in a server (I being a student, obviously have a million servers at my disposal ;) ...) But seriously, to be clear, I do NOT have a server to host this app on. And I do not want to spend money to buy resources from AWS, or others. Also, to clarify, this is not to be a web application. Is it meant to be downloadable, so that a user can install it, login to Spotify, and voila.
Problem:
Basically, without a server, how do I store this key securely? And based on my usage, is there even a need to store the key securely?
Is it meant to be downloadable, so that a user can install it, login to Spotify, and voila. Basically, without a server, how do I store this key securely?
No secret should reside on the user side. Or the user/hacker will be able to find it sooner or later. More about this here How to store a secret API key in an application's binary?
And based on my usage, is there even a need to store the key securely?
If you work without a server, I see 2 options:
(safe but inconvenient) let the user use their own app ID / Secret,
(risky but convenient) decide to publish your app ID / Secret openly. Since everyone can create Spotify apps for free, there isn't really much that's secret about it, apart from the statistics your app will generate. At least, it shouldn't stop your app from working unless someone decided to use their own time and money to reach the rate limits of your app.
Edit: you might be interested by the Implicit Grant Flow that works without any secret. However it's not implemented yet
When using the SignedCookieSessionFactory, the documentation states that the sha512 HMAC digest algorithm is used. As a result of this, once session data is serialised, it is signed and sent to the user's client under the session cookie.
There is no mention in Pyramid's documentation that sessions are also cached server-side (under this SessionFactory).
This presents a contradiction and has also led to authentication confusion when paired with SessionAuthenticationPolicy. If session data cannot be retrieved from the client's session cookie (as it is one-way hashed), how is it that the following is possible?
Authenticate with the application such that reading Request.authenticated_userid does not return None.
Copy the session cookie to the clipboard.
Logout by accessing a view whereby the headers from forget(request) are returned in the Response.
Replace the session cookie with the copied value.
The user is now logged back in.
I understand that simply deleting the cookie client-side is insufficient to completely invalidate the session (without blacklisting), but this then poses the following questions:
How is it possible to remain secure with browser-scoped sessions unless every session cookie the user has recently been issued is somehow remembered and blacklisted/invalidated?
Is the session cookie actually a key/session ID that's being used to lookup a session in memory? As it's one-way signed, surely this is the only explanation?
Is it possible then to invalidate sessions server-side, a little more robust than just the headers=forget(request) pattern?
Ultimately, I imagine the answer is something along the lines of:
"Maintain server-side sessions using an include such as pyramid_redis_sessions"
Any explanation would be appreciated.
The cookie contains all of the data. The session content itself is stored in the cookie, alongside an hmac signature of that content. This means that a client may view the content if they try hard enough, but they cannot change it as they cannot create trusted signatures without the server-side secret.
How is it possible to remain secure with browser-scoped sessions unless every session cookie the user has recently been issued is somehow remembered and blacklisted/invalidated?
It depends what you're using the session for - you need to take these issues into consideration before putting data into a session object.
Is it possible then to invalidate sessions server-side, a little more robust than just the headers=forget(request) pattern?
Not unless you store some sort of id in the session and then a server-side table of blacklisted ids. If you did this then you could write your own wrapper session-factory that opened the session, checked the id, and returned an empty one if it was blacklisted. Of course then you might just want to use a server-side session library like pyramid_redis_sessions or pyramid_beaker with one of its server-side-storage backends.
I'm trying to write a basic Flask app that limits the number of active logins a user can have, a la Netflix. I'm using the following strategy for now:
Using Flask_Security
store a active_login_count field for my User class.
every time a successful login request is completed, the app increases the active_login_count by 1. If doing so makes the count greater than the limit, it calls logout_user() instead.
This is a bad solution, because if the user loses her session (closed the incognito mode without logging out), the app hasn't been able to decrement her login count, and so, future logins are blocked.
One solution is to store the sessions on the server, but I don't know how I would go about authenticating valid sessions. Flask_Sessions is something I'm looking into, but I have no idea how to limit the number of active sessions.
As per my understanding, in the default configuration, Flask generates new session cookies on every request to prevent CSRF attacks. How would I go about doing that?
There could be several ways off the top of my head you approach this, none of them striking a nice balance between simplicity and effectiveness:
One way could be to add a last_seen field to your User. Pick some arbitrary number(s) that could serve as a heuristic to determine whether someone is "active". Any sufficiently long gap in activity could trigger a reset of the active_login_count. This obviously has many apparent loopholes, the biggest I see at the moment being, users could simply coordinate logins and potentially rack up an unlimited number of active sessions without your application being any the wiser. It's a shame humans in general tend to use similar "logical" mechanisms to run their entire lives; but I digress...
You could make this approach more sophisticated by trying to track the user's active ip addresses. Add an active_ips field and populate a list of (n) ips, perhaps with some browser information etc to try and fingerprint users' devices and manage it that way.
Another way is to use an external service, such as a Redis instance or even a database. Create up to (n) session ids that are passed around in the http headers and which are checked every time the api is hit. No active session id, or if the next session id would constitute a breach of contract, no access to the app. Then you simply clear out those session ids at regular intervals to keep them fresh.
Hopefully that gives you some useful ideas.
I'm currently developing a site with Python + Django and making the login I started using the request.session[""] variables for the session the user was currently in, and i recently realized that when i do that it generates a cookie with the "sessionid" in it with a value every time the user logs in, something like this "c1cab412bc71e4xxxx1743344b3edbcc" and if I take that string and paste it in the cookie on other computer in other network and everything, i can have acces to the session without login in.
So what i'm asking here actually is if anyone can give me any tips of how can i add some security on my system or if i'm doing something wrong setting session variables?
Can anyone give me any suggestions please?
Sadly, there is no best way you can prevent this from what I know but you can send the owner of an account an email and set some type of 2fa.
There are a couple of things that can do to help improve the security on session cookies.
You can force a session to expire as soon as the user closes their browser.
In your settings.py file add:
SESSION_EXPIRE_AT_BROWSER_CLOSE=True
You can manually set the number of seconds until a session expires
Using the first argument(request) of any view:
request.session.set_expiry(value) # number of seconds or timedelta object
To address your specific issue, please consider that what you are describing is actually one of the primary features of session security cookies. They are convenience tools that enable users to use the secured parts of site without having to re-authenticate with every page request. Even the cross browser aspect of it is a feature since many apps and browsers provide a sync feature that allows you to share cookies and sessions datas with your mobile and other devices and other web browsers.
If you still feel that this is too significant of a security risk, then probably the safest approach would be to remove the SessionMiddleware
from MIDDLEWARE and django.contrib.sessions both in your settings.py
I have a Pyramid application using Beaker Encrypted cookie sessions. I can log a user in using a RequestWithUserAttribute, pyramid.security.authenticated_userid(), remember() and forget() just fine.
However, the majority of users will never log in, and there is a specific value I'd like to save in a cookie (encrypted if at all possible) that the user has given then site (their location, or any string for that matter).
I cannot discover how to set more than the principal for a session using the remember() function, and I'd prefer not to send my own Set-Cookie headers, let alone deal with the encryption of the data myself.
I have found that you can pass keyword arguments to remember():
remember(request, principal, *kw)
But when I try to send any extra values I continuously run into an error.
Ideally I would expect something like this:
remember(request, 'public', {'location':request.params.get('location')})
Is this even the correct route?
Sessions and Authentication in Pyramid (and in general) are disjoint concepts. There are a lot of people who learn the way to store the authenticated user "is in a session", but in no way is this a requirement. The point of a session is to store arbitrary data for a visitor to your site across requests. That could be the fact that they are logged in or it could be your random strings.
The point is you can store random stuff in the session. It is available in Pyramid (after you've setup the session_factory on the Configurator) directly on the request object via request.session.
request.session['mykey'] = 'some random value'
This does not require you to use authentication, remember/forget, or anything other than a session factory.
https://docs.pylonsproject.org/projects/pyramid/en/1.2-branch/narr/sessions.html