How to clear cookies for old SESSION_COOKIE_DOMAIN in Django - django

We recently changed our cookie domain (settings.SESSION_COOKIE_DOMAIN) from domain.com to .domain.com and this is now preventing Safari users from logging in unless they clear their cookies. The problem seeds to the fact that there's sessionid cookies set for both domains.
Is there a way to clear or ignore the original domain or is the only way to advice users to clear cookies?

This can occur when the SESSION_COOKIE_DOMAIN setting is modified. (You stated that SESSION_COOKE_PATH was changed).
The documentation for SESSION_COOKIE_DOMAIN comes with this warning:
SESSION_COOKIE_DOMAIN
Be cautious when updating this setting on a production site. If you
update this setting to enable cross-domain cookies on a site that
previously used standard domain cookies, existing user cookies will be
set to the old domain. This may result in them being unable to log in
as long as these cookies persist.
This would occur if you went from:
SESSION_COOKIE_DOMAIN = None
to
SESSION_COOKIE_DOMAIN = '.domain.com'
As you've stated, there are now two cookies on the client end which will be sent to the server during a request, with both cookies named sessionid. When Django looks at the cookies, it only has access to a Python dictionary, so it only every sees one sessionid cookie rather than both that were sent.
I haven't tested this, but some ideas for fixing the problem may be:
Ask the user to delete the appropriate cookies. Depending on the number of users and their skill level, this may not be an reasonable option. Asking them to delete ALL their cookies may be out of the question.
Wait for the old cookies to expire. By default, it appears as though the sessionid cookie has a 14 day expiry. Once the old session cookies expire, they will no longer be sent with each request, allowing the new sessionid cookie to take effect.
Change the name of the sessionid cookie and write a custom Django middleware to handle both old and new sessionid cookies.
I haven't tested the last point, but it should be possible to change the SESSION_COOKIE_NAME to something other than sessionid. Now, this will prevent existing logged in users from using their existing sessionid cookies, so you'd need to write a custom middleware which was capable of handling both sessionid cookies (for old cookies) and sessionidnew cookies for current logons.
Something like this will work:
from django.utils.importlib import import_module
from django.contrib.sessions import middleware
from django.conf import settings
class MySessionMiddleware(middleware.SessionMiddleware):
def process_request(self, request):
engine = import_module(settings.SESSION_ENGINE)
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
if session_key is None:
# Look for old cookie in request for auth purposes.
session_key = request.COOKIES.get('sessionid', None)
request.session = engine.SessionStore(session_key)
You'd have to replace the SessionMiddleware in settings.py under MIDDLEWARE_CLASSES with this new middleware. Eg: Change 'django.contrib.sessions.middleware.SessionMiddleware' to 'custommiddleware.MySessionMiddleware' where custommiddleware.py is the file with above code and is present in your project root folder (where manage.py file is present)
Once enough time has passed and you're satisfied that all of the old sessionid cookies have expired, you could do the reverse and change back to using sessionid as the preferred cookie name for sessions, eventually removing the specialist code which can handle two different types of sessionid cookie.

Related

Django, setting cookie

Django: Cookie set to expire in 30 seconds is actually expiring in 30 minutes? does
hr = HttpResponse('ok')
hr.set_cookie('user_id', user_id, max_age=30)
while https://stackoverflow.com/a/25179642/433570 does
request.session[user_id] = True
And both says we are setting cookie.
What's the difference between the two?
Can I set the expiration with the request.session method?
In short, cookies are intended to be stored in client side while sessions are stored in server-side (unless you're using cookie based session).
Users can clear http cookies from their browsers but they can't do anything about the sessions on your server. Clearing sessions is up you and your settings. There are some django settings you can use to determine their age like SESSION_COOKIE_AGE. For http cookies it's possible to set attributes like max_age, expires.
Choosing which one to use depends on your requirements; are you going to store sensitive data, is permanence important etc.
References:
Django sessions
Django request-response methods including set_cookie
Wikipedia HTTP cookies

How can a spider bond login cookie, user agent and proxy in its requests process?

I want to crawl a website which has a strong security protocol and want to crawl data as fast as possible. Thus I thought I need a multi-login-cookie, multi-user-agent, and multi-proxy crawler.
I have tens of usernames and passwords and I can login using each one and get all the cookies. To hide the identity of my crawler I thought I should also replace the user-agent setting and my IP. I have found many user agents and proxies.
I learned that the cookie is needed each time I send a request to the server, and that cookie should be of the same identity and contain the information of the previous request and the corresponding response. I've gained the knowledge of how to pass it through requests without logging in from this answer. And I know two ways to login in, one outside the scrapy(by passing the cookie to the cookiesmiddleware in the middleware.py file:
from cookies import cookies # script written to login some accounts and return the cookies
import random
class CookiesMiddleware(object):
def process_request(self, request, spider):
cookie = random.choice(cookies)
request.cookies = cookie
) and another inside it.
What's more in the middleware.py file I passed the user agents randomly in the same as for cookies to the scrapy requests.
My question is: if I pass the cookies randomly as aforementioned, will one spider get the same cookie each time it sends a request? If not the server side will detect me as a bot and block me. What's worse, the same applies to the user-agents and proxies. How to bond each trinity(login cookie, user-agent and proxy) starting from the login, extending the aforesaid answer both in the horizontal and vertical dimension?
To be more precise, should I pass the login cookie in the form of {cookies= user1_cookie} or { meta={'cookiejar': user1_cookie},? And should I pass the user agent and proxy in the meta parameter?
Thanks. Please kindly point me in the right direction, and any suggestions will be highly received and appreciated.
Seems like you are looking for cookiejar. It will allow you to store multiple cookie sessions in single spider session.
Using middleware for random cookies is a bad idea since cookies in most cases store your whole browsing sessions.

Django delete all cookies for all users

I have the django view to set the value in cookies 'no_show_dialog' when a user clicks 'Don't remind me anymore' in the modal dialog.
Now i changed that dialog completely and want to reset that cookie for all users, so they will have to see it again at least once.
I know there is a way to delete the cookie in a view for a particular user:
response.delete_cookie('no_show_dialog')
But how to loop over all users and remove that cookie once?
You can't do that. Cookies are stored on the client; the only time you have access to them is when the particular browser makes a request and receives the response.
The best thing to do here is to simply use a different name for the cookie from now on. This will ensure that no users will have it set initially. Alternatively you might consider using the session for future settings.
As Daniel said you cannot delete all cookies in response as they are stored on client side.
In Django you create a response object for a particular request object in your views. Which means that you can only delete a cookie for that particular request and not for all the requests that was served by your Django server.
What you can do here is set expiry time for a cookie by using max_age as keyword argument in set_cookie method For Example :
response = HttpResponse('your response')
response.set_cookie('user_id', user_id, max_age=30)
return response
This will expire the cookie after the specified time for every client.

Django session authentication and disabled cookies

Does session authentication in django have anaything to do with cookies?Would it work if a user has cookies disabled on his browser? Should django warn users if their browsers have cookies disabled?
No, authentication is cookie-based - session ID stored in cookies!
The Django sessions framework is entirely, and solely, cookie-based.
It does not fall back to putting session IDs in URLs as a last resort,
as PHP does. This is an intentional design decision. Not only does
that behavior make URLs ugly, it makes your site vulnerable to
session-ID theft via the “Referer” header.
There is workarounds, for example you can put the session ID in the query string. Check this article: http://www.stereoplex.com/blog/cookieless-django-sessions-and-authentication-with
Warning from author: don't do what I'm about to describe unless you understand the potential security consequences
Middleware that get session id from request.GET and put it in request.COOKIES (FakeSessionCookie middleware has to be placed before the SessionMiddleware in settings.py):
from django.conf import settings
class FakeSessionCookieMiddleware(object):
def process_request(self, request):
if not request.COOKIES.has_key(settings.SESSION_COOKIE_NAME) \
and request.GET.has_key(settings.SESSION_COOKIE_NAME):
request.COOKIES[settings.SESSION_COOKIE_NAME] = \
request.GET[settings.SESSION_COOKIE_NAME]
After authentication you should include session id as url (GET) parameter in all requests to server.
According to docs:
Django provides full support for anonymous sessions. The session framework lets you store and retrieve arbitrary data on a per-site-visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies contain a session ID – not the data itself...
more here
django uses cookie based sessions, so without cookies authentication won't work.

Secure django session cookies are overriden when a non-secure page is used

Setting SESSION_COOKIE_SECURE = True in Django tells the browser to only send the session cookie over SSL. However, if an authenticated user navigates from a secure page to a non-secure page the session middleware will not know about the secure session (since the cookie won't be sent) and will set a new session cookie. The effect is that the user is then logged out, and needs to log in again.
For example, a user might edit something in the secure admin, click "view on site", is taken to a non-ssl page, then clicks back, only to find that their session has been overwritten, and is no longer authenticated.
I'm just wondering what the preferred approach would be to solve this issue.
As I can see, there are the following solutions:
Use different (sub)domains for the secure / non-secure parts of the site. Force everything on the ssl domain to be ssl. (I know this would probably be the preferred option, but is currently not an option)
Use different django projects (and different session cookie names) for the secure / non-secure parts of the site. Use nginx to proxy to appropriate django project.
Create a custom middleware based on django.contrib.sessions.middleware.SessionMiddleware that manually handles sessions differently depending on secure / non-secure. Perhaps even check whether the url is an admin url, and use a different cookie name and cookie path.
Set SESSION_SAVE_EVERY_REQUEST = False and hope that the user doesn't navigate to pages that use cookies.