Checking/Reading/Writing cookies in .NET, please help me understand - c#

So I have never had to use cookies before but now I am making a Shopping Cart that they can keep coming back to and leaving but I want it to store what they added.
What I am wondering:
How do check if a cookie exists and then create or update it, is that the best way to think about using a cookie?
How exactly would I store the data, in particular I want to store a list of IDs like "5,6,7,8", should I just use one string for this or is there a faster/better way than reading/parsing/writing something like that? I mean I suppose I would just keep adding new_value + ',' to the end, is there an append for cookie variables?
Does the cookie have some unique identifier that I would use to be sure I don't write duplicates or something?
Note: It's easy to look up 'HOW' like for seeing the syntax but I'm really trying to grasp the 'BEST WAY' or most ideal, how it was meant to be used, or how all you programmers found is the most fruitful way to utilize them in this type of scenario.

The winning answer to this similar question suggests that you only store the user ID in the cookie. The rest goes in the database.
If you can consider other approaches besides cookies, many folks prefer using session over using cookies. For one thing, you don't always have a lot of room in a cookie.
Storing the shopping cart in a cookie means that you will have no record of what people were shopping for but didn't purchase.
OTOH, using the cookie is using the shoppers' storage space and preserving your own. That could be significant over time and a lot of shoppers.

I solved this in the past by creating a class to manage the cookies (e.g.CookieManager) with static methods I passed an HttpRequest object to.
I was trying to solve a very similar problem, so I created a Count cookie and then a cookie which stored the information I wanted to save (in your case an ID number). I only wanted to save the last 5 items a user viewed, so I would manage this in my CookieManager class, dequeuing the oldest cookie and queuing up latest. The Count cookie kept track of how many cookies I had. Obviously, this isn't very high tech or secure, but for this project that was completely unnecessary. Anything you want to be robust should be saved on a database, or elsewhere server-side.

I want to further explain why you only store a guid that maps to a userid in a cookie. There are two main reasons:
Performance. As slow as it may seem to pull data from a database, you have to remember that cookie data is not free. It has to be uploaded from the user's browser to your web server, and even high-speed broadband connections tend to have much slower upload speeds. By contrast, your database likely has a gigabit link (sometimes even faster) directly to the web server. So what you really want in your cookie for best performance is a guid that maps directly to the primary key of your database table.
Security. Data in cookies is stored in a plain text file on the user's computer. You never know where a user will access your site from; it could be a very public place that's not appropriate to keep such data.
So is there any data you can use cookies for directly? As it happens, there is. Cookies have the nice property of sticking with a particular machine and browser. These days a lot of people will access the web from more than one place. Perhaps a work computer, a home computer, a smart phone, a netbook... all of which may have different screen sizes and other peculiarities. So what you can do with a cookie is store information specific to that combination of user+location.

Related

Saving values server side vs. using Sessions and Request.QueryString in ASP.net

I'm making a simple asp.net app that displays data which can be filtered based on a few different parameters. As such, the different filters that are currently selected need to be saved somewhere. I'm fairly new to .NET, and am wondering the best way to save this information. I noticed a coworker used Request.QueryString in conjunction with the Sessions dictionary. Something like this on page load:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["Category"] != null &&
Request.QueryString["Value"] != null)
{
string Category = Request.QueryString["Category"];
string CategoryValue = Request.QueryString["Value"];
// selectedFacets is the server side dictionary
selectedFacets.Add(Category, CategoryValue);
}
}
The QueryString here is changed when the user presses a button on the webpage, updating the URL.
My question is why even bother with the QueryString at all when all we're using it for is saving a value server side anyway? Wouldn't just making the button an asp controller be easier, something like:
protected void exampleCatexampleVal_Button_onClick(object sender, EventArgs e)
{
selectedFacets.Add(exampleCat, exampleVal);
}
Similar business goes on the with the Sessions dictionary: it's just used to save a bunch of values to variables on the server, so why use it in the first place? I'm sure there's a good reason, but right now they just seems overly complicated for what they do. Thank you!
Based on your code examples, I understand that you're talking about ASP.NET WebForms.
Your use case is not complete, but I'll show here some alternatives to achieve your goal. If you give further information, I'll gladly update my answer.
Before we get to it, let me just put things clear: HTTP is stateless. Understanding this basic rule is very important. It means that your server will receive a request, send it to your app (and the .NET process), get the resulting page (and assets) and send it back to the client (mostly, a browser). End of story.
(Almost) Everything that you've created to respond to the request will be lost. And that's why we have options on where to store objects/values across requests.
Server-side Session
This is one of the easiest options. You simply call this.Session.Add("key", object) and it's done. Let's dig into it:
It will use server resources. That is, the most you use the session, the most memory (and other resources, as needed) your app will consume.
It will be harder to scale, because data will be on your server memory. Vertical scale may be an option, according to your hardware, but horizontal scale will be limited. You can use a session-server or store session on a SQL Server database, but it won't be so efficient anymore.
It's attached to your client session. It will be lost if the user opens another browser or sends a link to his friend.
It's relatively safe. I say relatively because of the options below. At least it's server side.
GET arguments (AKA QueryString)
That's another option, and you know it already. You can send data back and forth using the querystring (?that=stuff&on=the&URL=youKnow).
It's limited to 2000 characters and that must be serializable. That's why you probably won't put a DataGrid there.
The user may change it. Be aware! Always sanitize data from the QueryString.
User is free to bookmark the link or send it to a friend and stuff will be the same. That's nice, mind you.
ViewState
You may have heard about it, it's the engine that makes WebForms so lovely (and so hateful). By default, each controller on your page will have its state serialized to the viewstate, which is a huge hidden field with encrypted data on your page. Go on, click "View source" and look for it. Don't scream, please. You may add arbitrary data to the ViewState just like the Session.
It's on the client side. Don't trust it.
It will be send back and forth on each request, so it will consume extra bandwidth.
It will take time to be deserialized/serialized on each request/response.
Data must be serializable (you know what I mean).
So, by now I hope that you have enough information to make your own decision.
If I missed anything, please let me know.
Have a look at this MSDN Article first. I read through it, and it may answer your question for you.
http://msdn.microsoft.com/en-us/magazine/cc300437.aspx
What you're missing, is how the asp.net page lifecycle works:
http://msdn.microsoft.com/en-us/library/ms178472(v=vs.100).aspx
The thing is, that 'server variable' won't persist between postbacks (AFAIK). It's only useful inside that page, right then. As soon as the page is disposed at the end of the cycle, that dictionary is gone. So you have to store it somewhere if you want to use it later. The article I referenced shows you all the places that you can store information to persist it and where you store it depends on how long you need it to persist, and how many users should have access to it.
Now, certainly, if you DON'T want to persist that dictionary, then sure, just store it the page variable. That's just fine. There's no reason to persist data that you never need again.
It's always good to keep in mind that there is a slight performance hit when storing and retrieving session state from database or from separate process service (StateServer). If session state is stored in-memory, you cannot scale your application to a web farm and this wastes valueable memory in the web server.
On the other hand, using query string values won't waste your memory and resources, it is fast and you don't have to think about managing session state. It gives SEO benefit and allows bookmarks/favorites.
However, you can store only limited amount of data using query string (WWW FAQs: What is the maximum length of a URL). It can also pose a security risk, if sensitive data is exposed or a malicious user tries to find a bug in your code that mishandles URL values. SQL injection attack is one scenario. What you can do is encrypt sensitive values.
Overall there are many aspects to consider here.
One of the benefits of using query string values is if you need bookmarks/favorites stored in your application that would allow a user to directly navigate to a page and have certain values be passed into the page without the assistance of an in-memory cache. Take the following for example:
I have a product page that displays a grid view of products that can be filtered by a category name. If I use the categoryId value in the query string, then I can make a bookmark to this page and then later click on the bookmark and the page will work as I left it earlier. Depending upon in-memory cache, that may or may not be there, would not guarantee that my bookmark would work every time.

ASP.NET cookie-based sessions, is there SessionStateModule for it?

I am looking for a way to do fully cookie-based sessions in ASP.NET. I don't intend to store complex objects in them, just string key-value pairs.
I am looking for something similar to how the Play! framework handles sessions, it basically encodes all the session data in a cookie and takes care of encrypting/decrypting it on each request.
I don't want to have to write my own SessionStateModule for this if I can avoid it, does one exist?
Thanks
EDIT: I don't need to store more data than a cookie can handle (just a few identifiers) and I still need the key-value pairs to be specific to each session. I would like to use cookies so that no server state has to be maintained (either in process or in a database) which allows me to add more servers quite easily and also depend less on external applications (no state server/memcached/redis etc)
You won't be able to store that much data in a cookie unless you are going to create lots of them.
Given you want to work with key value pairs have considered using a cache such as memcached or redis. Or even the server cache if you are not in a web farm?
I don't think one exists: it would be too fragile because of the restrictions inherent in using cookies (notably the maximum size).
And I know this isn't answering your question, but I wouldn't implement a SessionStateModule for this. Doing so would mean that any 3rd party components that use Session, or any future maintenance programmers who use Session would possibly be storing inappropriate data (e.g. too large) in the cookie.
I'd suggest you write your own API oriented round storing key-value pairs with only primitive values (string, Int32, DateTime,...) in your cookie.
You can also make the API "cookie-aware" - e.g. set HttpCookie.Path which gives you the possibility to:
avoid sending cookies for requests that don't need them (javascript, images, ...)
have different cookies (same name but different Path) for different Areas of your application. This can help keep the cookie size down.

Guids, QueryStrings and Authentication

I have a number of locations in a number of applications I have built where a page accepts a QueryString in the following format: http://localhost/MySite.aspx?ID=ab1cbabe-42e2-4d15-ab11-17534b829381
These pages will then take the query string, attempt to parse it and display the data that matches the guid using a database call with strongly typed values.
Example:
Guid value;
if (Guid.TryParse(Request.QueryString["ID"], out value))
{
SomeControl.Datasource = DatabaseCall(value);
SomeControl.Databind();
}
What this obviously means is that any user (provided they have the guid for the data) can technically access any other users data. Obviously predicting guids is next to an impossibility but I'm still uneasy about it.
How does everyone else deal with this problem? Is there a "correct" way? Is it even worth worrying about?
In various circumstances it absolutely is worth worrying about.
People tend to post or email URIs without stripping away the query strings
Most browsers store the whole uri including the query string in a history
Most browsers even offer autocomplete in the address bar which lets you try through already visited resources
The http request can be intercepted pretty much anywhere on its way from client to server, exposing the query string
I'd recommend some kind of user-based authentication mechanism like asp.net's membership provider.
In case you already are using some authentication, linking resource guids to their respective user ids in an association table might do the trick.
You answered your own question: "Obviously predicting guids is next to an impossibility"
However, the proper way to implement user access, is to build and manage an ACL. You can't simply rely on a unique string for that, because even if users don't guess the string, an attacker can still sniff the traffic and reuse the GUIDs they found.
I agree with #Laurent.
But - it depends on your type of business. For extreme security-related contexts such as banking, money transactions, sensitive personal data etc., I would go to an encrypted cookie, or simple - a unique key that is passed in the query string (as you asked about), but not a guid but something far longer (just make sure it's randomness is fairly hard to predict), along with a background task on the server that invalidates "tokens" that are older than X minutes, to mitigate the risk of stealing URLs.
Consider resorting to some standard mechanism such as ASP.NET Membership.

Asp MVC 2: Obfusicate Entity-IDs

Project type: Asp MVC 2/NHibernate/C#
Problem
If you have an edit page in an web application you will come to the problem that you have to send and then receive the id of the entity you're editing, the IDs of sub-entities, entities that can be selected by dropdownmenus,...
As it is possible to modify a form-post, an evil user could try to send back another ID which maybe would grant him more rights (if i.e. that ID was related to a security entity).
My approach
Create a GUID and associate it with the ID
Save the association in the http session
Wait for the response and extract the real ID out of the received GUID.
Question:
What techniques do you use to obfusicate an entity-ID?
If you're doing that much for GUIDs, why not just use GUIDs for the identity of the entity itself that's actually stored in the database (though I'd advise against it)?
Or you could have a server side encryption scheme that encrypts and then subsequently decrypts the id (this is a long the same lines as what you're doing except you're not storing anything random like this in the session (yuck :) ).
You could even forget trying to do this at all since a lot of sites are "affected" by this issue, and it's obviously not a problem (StackOverflow for example). The overhead is just too much.
Also, if you're worried about security, why don't you have some sort of granular permissions set on the individual action/even entity level. This would solve some problems as well.
EDIT:
Another problem with your solution is inconsistent unique identifiers. If a user says "ID as23423he423fsda has 'invalid' data", how do you know which ID it belongs to if it's changing on every request (assuming you're going to change the id in the URL as well)? You'd be much better of with an encryption algorithm that always hashes to the same value therefore, you can easily perform a lookup (if you need it) and also the user has consistent identifiers.
Your controllers should be immune to modified POST data. Before displaying or modifying records belonging to a user, you should always check whether the records in question belong to the authenticated user.

Storing Language in URL or Session or other

I am developing a multilingual site and was wondering what is the best way to store the language chosen by the user?
Either via QueryString or should it be in Session..or any other options?
Another consideration not mentioned in any of the other answers, is Search Engine Friendliness. If you use a different url for each language like
http://{en|cy}.example.com/subdir/ or http://example.com/{en|cy}/subdir) then search engines can index your site in multiple languages.
I think it very much depends on how your application handles (desires to handle) the user languages. If your users have to log on to your site, then you probably have an account settings page somewhere with an appropriate user profile object or something similar behind. In such a case I guess you would save these settings on the DB, and when the user comes back to your site you get the user-information somehow (i.e. from a cookie), you load your user-profile object from the DB. The information would be kept in a session since I think that would be most suited in this case.
If your users don't have to login, so you basically cannot directly identify them, I would store the language settings in a cookie. This gives your user the value that he will always find the site in his preferred language when he comes back later (given that he doesn't delete the cookies and the cookie's lifetime is long enough).
As a third possibility you could just identify the users language according to his default browser settings (just as "regex" mentioned above).
As I said, it really depends on your application's needs. What you have to keep in mind though is that
objects stored in the session are kept on the server-side, using server memory. So don't keep useless things there in memory if you don't need them. However the session object is suited for storing data related to a user's visit and configurations.
Data stored in cookies, or the Viewstate object are send back and forth between the client browser and web server. So this causes additional traffic and may decrease the performance.
Bye
if you consider this scenario where a user has browsed a series of pages in "en" and the language info is stored in cookie session and pages have been cached (http, browser, app)..
when the language is switched by the user to "cy", a change would happen for the current page, but when the user jumps back to a page they have previously visited (where the header caches expired have not expired) it would load up the page in "en" as the querystring does not state the language - for it to serve content in that language.
unlikely that a user would want to change languages so frequently - but as a developer, its a scenraio that should be handled.
any ideas please feel free to shout.
Profile properties were created specifically to allow you to store user-specific preferences. This would be good place to store this kind of data.
There is a property that is passed when a browser makes a request that you could use. This property is referenced in your code behind by referencing:
Request.UserLanguages // returns an array
Alternatively, you could prompt the user to specify a prefered language, and save it in a cookie.
In your Page.Load handler put something like the following:
string prefLan;
if(Request.Cookies["preferedLanguage"] != null)
prefLan = Server.HtmlEncode(Request.Cookies["preferedLanguage"].Value);
Querystring is not the right place for this, unless it is read initially from the querystring and stored somewhere else.
Store it in a cookie, or if cookies are turned off, store it in session or viewstate.
Kevin's answer "profile properties" is an easy way to let an established library do the heavy lifting for you with minimal effort on your part.

Categories

Resources