I need to track unregistered users in my Django website. This is for conversion optimization purposes (e.g. registration funnel, etc).
A method I've used so far is using IP address as a proxy for user_id. For various well-known reasons, this has led to fudged/unreliable results.
Can I sufficiently solve my problem via setting a session variable at server-side? An illustrative example would be great.
For example, currently I have a couple of ways in my head. One is doing request.session["temp_id"] = random.randint(1,1000000), and then tracking based on temp_id.
Another is setting a session variable every time an unauthorized user hits my web app's landing page, like so:
if not request.session.exists(request.session.session_key):
request.session.create()
From here on, I'll simply track them via request.session.session_key. Would this be a sound strategy? What major edge-cases (if any) do I need to be aware of?
Cookies are the simplest approach, but take into consideration that some users can have cookies turned off in their browsers.
So for those users you can use javascript local storage to set some data. This information will get deleted once you close the browser, but it's ok for funneling purposes. Still others can have javascript turned off.
Another approach would be to put custom data(key) in every link of the page when generating the template. in other words you would have the session_id stored in html page and send through url parameters at click. Something similar happens with csrf token. Look into that.
Related
I am building a Django application where people can register for events. Everyone can register, there's no user account or login, i.e. no authentication. Verification is done through an an email with a link that has to be clicked in order to activate the registration.
I'm unsure whether I need to enable CSRF-protection for these forms. It boils down to the following question:
Is CSRF-protection necessary for every POST-request (which doesn't leave the domain) or only for POST-requests by logged-in users?
What could be done with a CSRF-attack? I know you can use it to circumvent the same origin policy and post whatever you want in the name of the user, but can you also use it to alter a real post by the user or steal their data? If a malicious site could learn the data the user posted or silently alter their request that would be a reason for me to use it. If it just means that another website can create additional registrations then no, because so can everyone else.
(I know that it doesn't cost much to just use it everywhere and I might in fact do that, but I'm trying to understand the principle better)
Contrary to the other answer, CSRF fundamentally is not about sending cookies. CSRF is about another website being able to have a user visiting it send a request to your application. If there is a session, it needs to be via something like cookies for this to be successful, because cookies for example will be sent automatically. But there are other forms of authentication that will be sent automatically, for example client certificates.
Also if there is no authentication, even easier, requests can be made. And that sounds like a problem in your case too.
What another website can do is if a user visit them, they can have that user perform actions in your application. For example they can have them register for an event, without them even noticing it. Or the malicious website can deregister people from events if that's possible. They can do whatever in the name of the victim user that is possible on your website, without the victim knowing about it, just by having them visiting the malicious website.
So to put it another way, the probelm is not that another website can perform actions in your application - they could do it with CSRF enabled too if there is no authentication. But without CSRF protection, they can have your users perform actions inadvertently in your application, just by having them visit the malicious website.
Only you can tell, whether this is a problem in your case. Without more info, I think you should have CSRF protection enabled.
CSRF attacks rely on the fact that the browser will send the information that you gave it to identify your users (cookies, typically) along with requests to your site, even ones triggered by a third party (like a malicious script).
If you don't have users, and aren't sending any such information to the browser, your application isn't in danger from CSRF.
I am creating a saas, software as a service site with django.
Due to the project requirements the users are inside schemas/tenants, for that im using the fantastic django-tenant-schemas app, one user can have accounts inside different schemas (they share username and password) ... i want to let the user move throught the different schemas they are in more or less freely ... for that i have created a view where the user can select on what schema he wants to be on.
When i use an application wide cookie session that is when i have the cookie setting as ".domain.ext" (django documentation) that works fine but its NOT the behaviour we really want for our application.
What we really need is to be able to have different versions of the app on different browser tabs.
So we have to set the cookie configuration to "domain.ext", then everything breaks because the original view is on one tenant and the next view (where the just logged user really belongs) is inside other tenant then the old cookie is deleted.
So the question is how can i programmatically set the cookie correctly on the new view so the user that really belongs to that tenat is still authenticated.
Or is there any alternative approach we could use for that? Any examples?
EDIT TO CLARIFY as demanded:
Person A belongs to 2 schemas SH1 and SH2 on both of them he has the same username and password.
On every password change the password hash is replicated on all the schemas they belong to so they dont have to remember specific passwords or usernames.
When the person is logged on SH1 the url will be sh1.domain.com when he is logged on SH2 the url will be sh2.domain.com
So lets say the person is now logged on schema SH1, he decides to switch to schema SH2, to be able to do that i need the user to still been authenticated so that view has to be on the SH1 schema, but then its redirected to the new schema force authenticating the user but since the cookie is set as domain specific (default django behaviour) when the user lands on the next url sh1.domain.com/whatever the previous cookie is deleted and thus he has to log in again to be able to access.
If I'm understanding correctly, you want the ability to have the behavior of a cross-domain cookie, but without actually using a cross-domain cookie.
The immediate answer that comes to mind is "well, use a cross-domain cookie". This is pretty much the vanilla example of a situation where you'd want to use use a cross-domain cookie. Engineering a complex solution so that you can avoid using the simple solution never ends well :-) Unless there's some other constraint in play that you haven't revealed, I'd start by questioning whether you shouldn't just be doing this the easy way.
However, assuming there is a good reason (and, frankly, I'd be interested to know what that is), the problem you're going to face is that browser security is essentially trying to stop you doing exactly what you're proposing. You want to know, from domain SH2, whether something has happened to a cookie set on domain SH1. That's exactly the situation that cookie security policies are designed to prevent.
The only way you're going to be able to work around this is to have a third party that can share knowledge. When user A logs into SH1, you do password authentication as normal - but you also post a flag somewhere that says "User A is now on SH1". When A logs into SH2, you post the corresponding flag. If A goes back to SH1, you check against the central source of truth, discover that they're currently on SH2, and force a login.
You probably could do this by manipulating cookies and session keys, but I suspect an easier way would be to use an Authentication backend. What you'll be writing is an authentication backend that is very similar to Django's own backend - except that it will be making checks of cross-domain login status against the central source of truth.
How you implement that "source of truth" is up to you - an in memory cache, database table, or any other source of data will do. The key idea is that you're not trying to rewrite cookies so that the same cookie works on every site - you're keeping each site's cookies independent, but using Django's authentication infrastructure to keep the cookies synchronised as a user moves between domains.
I would like Akamai not to cache certain URLs if a specified cookie exist (i.e) If user logged in on specific pages. Is there anyway we can do with Akamai?
The good news, is that I have done exactly this in the past for the Top Gear site (www.topgear.com/uk). The logic goes that if a cookie is present (in this case "TGCACHEKEY") then the Akamai cache is to be bypassed for certain url paths. This basically turns off Akamai caching of html pages when logged in.
The bad news is that you require an Akamai consultant to make this change for you.
If this isn't an option for you, then Peter's suggestions are all good ones. I considered all of these before implementing the cookie based approach for Top Gear, but in the end none were feasible.
Remember also that Akamai strips cookies for cached resources by default. That may or may not effect you in your situation.
The Edge Server doesn't check for a cookie before it does the request to your origin server and I have never seen anything like that in any of their menus, conf screens or documentation.
However, there are a few ways I can think of that you can get the effect that I think you're looking for.
You can specify in the configuration settings for the respective digital property what path(s) or URL(s) you don't want it to cache. If you're talking about a logged on user, you might have a path that only they would get to or you could set up such a thing server side. E.g. for an online course you would have www.course.com/php.html that anybody could get to whereas you might use www.course.com/student/php-lesson-1.html for the actual logged on lessons content. Specifying that /student/* would not be cached would solve that.
If you are serving the same pages to both logged on and not-logged on users and can't do it that way, you could check server-side if they're logged on and if so add a cache-breaker to the links so when they follow a link a cache-breaker is automatically added. You could also do this client side if you want, but it would be more secure and faster to do it server-side. As a note on this, this could be userid-random#. That would keep it unique enough when combined with the page that nobody else would request it and get the earlier 'cache-broken' page.
If neither of the above are workable, there is one other way I can think of, which is a bit unconventional to say the least, but it would work. Create symbolically linked directory in your document root with another name so that you can apply the first option and exempt it from cacheing. Then you check if the guy is logged on and if so prepend the extra directory to the links. From akamai's point of view www.mysite.com/logged-on/page.html can be exempt from cache where www.mysite.com/content/page.html is cached. On your server if /logged-on/ symbolically links over to /content/ then you're all set.
When they login you could send them to a subdomain which is set up as a ServerAlias, so on your side it's the same, but on Akamai has differnt cache handling rules.
Following the same answer than #llevera, you can use the cookies on CloudFlare without intervention of engineers to make the change for you.
Having that sort of cookies to bypass content is a technique that its becoming more popular with the time, and even bug companies like Magento are using it for Magento 2 platform.
But solutions from above still valid, Maybe Akamai supports that that already now, we are in 2017!
I have a internal website that users log into. This data is saved as a cookie. From there the users go on their merry way. Every so often the application(s) will query the authentication record to determine what permissions the user has.
My question is this: Is it more efficent to just query the cookie for the user data when it is needed or to save the user information in viewstate?
[Edit] As mentioned below, Session is also an option.
Viewstate is specific to the page they are viewing, so its gone once they go along thier merry way. Not a good way to persist data.
Your best bet is to use Forms Authentication, its built in to ASP.NET and you can also shove any user-specific information into the Forms Authentication Ticket's Value. You can get 4000 bytes in (after encrypting) there that should hold whatever you need. It will also take care of allowing and denying users access to pages on the site, and you can set it to expire whenever you need.
Storing in the session is a no-no because it scales VERY poorly (eats up resources on the server), and it can be annoying to users with multiple browser connections to the same server. It is sometimes unavoidable, but you should take great pains to avoid it if you can.
Personally, I prefer using a session to store things, although the other developers here seem to think that's a no-no.
There is one caveat: You may want to store the user's IP in the session and compare it to the user's current IP to help avoid session hijacking. Possibly someone else here has a better idea on how to prevent session hijacking.
You can use session data - that way you know that once you have stored it there, users can't fool around with it by changing the query string.
I would use the cookie method. Session is okay but gets disposed by asp.net on recompile, and you have to use a non session cookie if you want to persist it after session anyway. Also if you ever use a stateserver its essentially doing the same thing (stores session in the db). Session is like a quick and dirty fix, real men use cookies.
You're building a web application. You need to store the state for a shopping cart like object during a user's session.
Some notes:
This is not exactly a shopping cart, but more like an itinerary that the user is building... but we'll use the word cart for now b/c ppl relate to it.
You do not care about "abandoned" carts
Once a cart is completed we will persist it to some server-side data store for later retrieval.
Where do you store that stateful object? And how?
server (session, db, etc?)
client (cookie key-vals, cookie JSON object, hidden form-field, etc?)
other...
Update: It was suggested that I list the platform we're targeting - tho I'm not sure its totally necessary... but lets say the front-end is built w/ASP.NET MVC.
It's been my experience with the Commerce Starter Kit and MVC Storefront (and other sites I've built) that no matter what you think now, information about user interactions with your "products" is paramount to the business guys. There's so many metrics to capture - it's nuts.
I'll save you all the stuff I've been through - what's by far been the most successful for me is just creating an Order object with "NotCheckedOut" status and then adding items to it and the user adds items. This lets users have more than one cart and allows you to mine the tar out of the Orders table. It also is quite easy to transact the order - just change the status.
Persisting "as they go" also allows the user to come back and finish the cart off if they can't, for some reason. Forgiveness is massive with eCommerce.
Cookies suck, session sucks, Profile is attached to the notion of a user and it hits the DB so you might as well use the DB.
You might think you don't want to do this - but you need to trust me and know that you WILL indeed need to feed the stats wonks some data later. I promise you.
I have considered what you are suggesting but have not had a client project yet to try it. The closest actually is a shopping list that you can find here...
http://www.scottcommonsense.com/toolbox.aspx
Click on Grocery Checklist to open the window. It does use ASPX, but only to manage the JS references placed on the page. The rest is done via AJAX using web services.
Previously I built an ASP.NET 2.0 site for a commerce site which used anon/auth cookies automatically. Each provides you with a GUID value which you can use to identify a user which is then associated with data in your database. I wanted the auth cookies so a user could move to different computers; work, home, etc. I avoided using the Profile fields to hold onto a complex ShoppingBasket object which was popular during the time in all the ASP.NET 2.0 books. I did not want to deal with "magic" serialization issues as the data structure changed over time. I prefer to manage db schema changes with update/alter scripts synced with software changes.
With the anon/auth cookies identifying the user on the client you can use the ASP.NET AJAX client-side to call the authentication web services using the JS proxies that are provided for you as a part of ASP.NET. You need to implement the Membership API to at least authenticate the user. The rest of the provider implementation can throw a NotImplementedException safely. You can then use your own custom ASMX web services via AJAX (see ScriptReference attribute) and update the pages with server-side data. You can completely do away with ASPX pages and just use static HTML/CSS/JS if you like.
The one big caveat is memory leaks in JS. Staying on the same page a long time increases your potential issue with memory leaks. It is a risk you can minimize by testing for long sessions and using tools like Firebug and others to look for memory leaks. Use the JS Lint tool as well as it will help identify major problems as you go.
I'd be inclined to store it as a session object. This is because you're not concerned with abandoned carts, and can therefore remove the overhead of storing it in the database as it's not necessary (not to mention that you'd also need some kind of cleanup routine to remove abandoned carts from the database).
However, if you'd like users to be able to persist their carts, then the database option is better. This way, a user who is logged in will have their cart saved across sessions (so when they come back to the site and login, their cart will be restored).
You could also use a combination of the two. Users who come to the site use the session-based cart by default. When they log in, all items are moved from the session-based cart to a database-based cart, and any subsequent cart activity is applied directly to the database.
In the DB tied to whatever you're using for sessions (db/memcache sessions, signed cookies) or to an authenticated user.
Store it in the database.
Do you envision folks needing to be able to start on one machine (e.g. their work PC) but continue/finsih from a different machine (e.g. home PC)? If so, the answer is obvious.
If you don't care about abandoned carts and have things in place for someone messing with the data on the client side... I think a cookie would be good -- especially if it's just a cookie of JSON data.
I'd use an (encrypted) cookie on the client which holds the ID of the users basket. Unless it's a really busy site then abandoned baskets won't fill up the database by too much, and you can run a regular admin task to clear the abandoned orders down if you care that much. Also doing it this way the user will keep their order if they close their browser and go away, a basket in the session would be cleared at this point..
Finally this means that you don't have to worry about writing code to deal with de/serialising the data from a client-side cookie, while later worrying about actually putting that data into the database when it gets converted into an order (too many points of failure for my liking)..
Without knowing the platform I can't give a direct answer. However, since you don't care about abandoned carts, then I would differ from my colleagues here and suggest storing it on the client. Why store it in the database if you don't care if it's abandoned?
Then again, it does depend on the size of the object you're storing -- cookies have their limits after all.
Edit: Ahh, asp.net MVC? Why not use the profile system? You can enable an anonymous profile if you don't want to bother making them log in
I'd say store the state somewhere on the server and correlate it to the user's session. While a cookie could ostensibly be an equal place to store things, if you consider security and data size, keeping as much data on the server as possible becomes a good thing.
For example, in a public terminal setting, would it be OK for someone to look at the contents of the cookie and see the list? If so, cookie's fine; if not, you'll just want an ID that links the user to the data. Doing that would also allow you to ensure the user is authenticated to the site in order to get to that data rather than storing everything on the machine - they'd need some form of credentials as well as the session identifier.
From a size perspective, sure, you're not going to be too concerned about a 4K cookie or something for a browser/broadband user, but if one of your targets is to allow a mobile phone or BlackBerry (not on 3G) to connect and have a snappy experience (and not get billed for the data), minimizing the amount of data getting passed to the client will be key.
The server storage also gives you some flexibility mentioned in some of the other answers - the user can save their cart on one machine and resume working with it on another; you can tie the cart to some form of credentials (rather than a transient session) and persist the cart long after the user has cleared their cookies; you get a little more in the way of fault tolerance - if the user's browser crashes, the site still has the data safe and sound.
If fault tolerance is important, you'll need some sort of persistent store like a database. If not, in application memory is probably fine, but you'll lose data if the app restarts. If you're in a farm environment, the store has to be centrally accessible, so you're again looking at a database.
Whether you choose to key by transient session or by credentials is going to depend on whether the users can save their data and come back later to get it. Transient session will eventually get cleaned up as "abandoned," and maybe that's OK. Tying to a user profile will let the user keep their data and explicitly abandon it. Either way, I'd make use of some sort of backing store like a database for fault tolerance and central accessibility. (Or maybe I'm overengineering the solution?)
If you care about supporting users without Javascript enabled, then the server side sessions will let you use URL rewriting.
If a relatively short time-out (around 2 hours, depending on your server config) is OK for the cart, then I'd say the server-side session. It's faster and more efficient than accessing the DB.
If you need a longer persistence (say some users like to leave and come back the next day), then store it in a cookie that is tamper-evident (use encryption or hashes).