I am going to be storing a significant amount of information inside Django's session cookie. I want this data to persist for the entire time the user is on the website. When he leaves, the data should be deleted, but the session MUST persist. I do not want to user to need to log in every time he returns to the website.
I found ways to purge the entire session cookie every time a user leaves the website, but ideally I would like to only delete select pieces of the cookie which I explicitly set. Does anyone know how to do this?
You're confusing things a bit.
The only thing stored inside "Django's session cookie" is an ID. That ID refers to the data which is stored inside the session backend: this is usually a database table, but could be a file or cache location depending on your Django configuration.
Now the only time that data is updated is when it is modified by Django. You can't expire data automatically, except by either the cookie itself expiring (in which case the entire set of data persists in the session store, but is no longer associated with the client) or by running a process on the server that modifies sessions programmatically.
There's no way of telling from the server end when a user leaves a website or closes his browser. So the only way of managing this would be to run a cron job on your server that gets sessions that were last modified (say) two hours ago, and iterate through them deleting the data you want to remove.
Related
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.
How do I delete session when the browser is refreshed by the user? I do know, the following deletes the session key.
del request.session['session_key']
Edit:
I am trying to propagate user entered value across multiple forms in different views, and for that I am using session variable. However, when the user manually refreshed the page, I want to clear the session keys.
There is no way in Django (I can think of) to know if a page has been refreshed or just starting a new session, page etc. You could do something with the request and Javascript.
If after a page has finished loading you want to just remove all sessions dependant where you want this to happen, look at Signals or just removing the sessions after the request has finished in your view.
Re: deleting all sessions...
flush() Deletes the current session data from the session and deletes the session cookie. The user will remain logged in. https://docs.djangoproject.com/en/1.8/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.flush
If you just want to delete each session key (and keep the user logged in) then do:
for key in request.session.keys():
del request.session[key]
This deletes each session in request.session.
I have a Django app with a MySQL database which allows answering of questions on an HTML page. The answers get sent to the server via AJAX calls. These calls are initiated by various JavaScript events and can often be fired multiple times for one answer. When this happens, multiple save requests for one answer get sent to the server.
In order to avoid duplicate answers, each answer has a client-side ID generated the first time it gets saved - client_id. Before creating a new answer server-side, the Django app first checks the DB to see if an answer with such a client_id exists. If one does, the second save requests updates the answer instead of creating a new one.
In Chrome, when a text input field is focused, and the user clicks outside of the Chrome window, two save requests get fired one after the other. The server receives them both. Let's say that for the sake of the example the client_id is 71.
The first request checks the DB and sees that no answers with a client_id 71 exist. It creates a new answer and saves in the the DB. I am debugging with breakpoints and at this time, I see in my external MySQL database viewer that indeed the answer is saved. In my IDE, when I execute Answer.objects.filter(client_id=71) I get the answer as well. I let the debugger continue.
Immediately my second breakpoint fires for the second AJAX save answer request. Now a curious thing happens. In my IDE, when I execute Answer.objects.filter(client_id=71) I see no answers! My external tool confirms that the answer is there. So my code creates a new answer and saves it. Now if in my IDE I execute Answer.objects.filter(client_id=71) I see two answers with that client_id.
I am guessing that the DB connection or MySQL uses some kind of time-based method of keeping views constant, but it is causing me problems here. I would like a live insight into the state of the DB.
I am not using any transaction management, so Django should be doing auto_commit.
How can I instruct the DB connect to "refresh" or "reset" itself to take into consideration data which is actually in the DB?
I have solved this issue by wrapping my view in the #transaction.autocommit decorator and executing transaction.commit() immediately before checking in the database if an answer with a particular client_id exists. This accomplishes the "refresh" I was aiming for.
I have a problem and can't solve it. Maybe I'm making it too hard or complex or I'm just going in the wrong direction and thinking of things that don't make sense. Below is a description of what happens. (Multiple tabs opened in a browser or a page that requests some other pages at the same time for example.)
I have a situation where 3 requests are received by the web application simultaneously and new user session has to be created. This session is used to store notification, XSRF token and login information when the user logs in. The application uses threads to handle requests (CherryPy under Bottle.py).
The 3 threads (or processes in case or multiple application instances) start handling the 3 requests. They check the cookie, no session exists, and create a new unique token that is stored in a cookie and in Redis. This will all happen at the same time and they don't know if a session already has been created by another thread, because all 3 tokens are unique.
These unused sessions will expire eventually, but it's not neat. It means everytime a client simultaneously does N requests and a new session needs to be created, N-1 session are useless.
If there is a property that can be used to identify a client, like an IP address, it would be a lot easier, but an IP address is not safe to use in this case. This property can be used to atomically store a session in Redis and other requests would just pick up that session.
If this is through a browser and is using cookies then this shouldn't be an issue at all. The cookie will, from what I can tell, the last session value that it is set to. If the client you are using does not use cookies then of course it will open a new session for each connection.
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.