How to protect cookies from an attack
I want to use cookies for storing userId during the session which lets to avoid unnecessary roundtrips to the data base. This userId is used to access some user specific information. As cookies can be easily edited I'm now conserned with the security issue.
In order to forbid an logged in user to edit their userId and so get access to other users' information I use a pretty straightforward method. I add one more cookie at the userId cookie creation moment which stores a hashed value for it. While hashing I use a hard coded 64 byte key. When retrieving the userId from the cookie it is always checked if it matches with its hashed value.
Here is basically my code:
public static int GetUserId(Page page)
{
int userId;
if (page.Request.Cookies["userId"] != null && page.Request.Cookies["userIdHashed"] != null)
{
string userIdHashed = page.Request.Cookies["userIdHashed"].Value;
string userIdCoockie = page.Request.Cookies["userId"].Value;
string coockie = (userIdCoockie + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
if (userIdHashed == coockie)
{
userId = Int32.Parse(userIdCoockie);
}
else
{
throw new Exception("UserId does not match!");
}
}
else
{
userId = ...//here userId is being retrieved from the data base and than:
page.Response.Cookies["userId"].Value = userId.ToString();
page.Response.Cookies["userId"].HttpOnly = true;
string userIdHashed = (userId.ToString() + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
page.Response.Cookies["userIdHashed"].Value = userIdHashed;
page.Response.Cookies["userIdHashed"].HttpOnly = true;
}
开发者_StackOverflow中文版 return userId;
}
So my questions are:
Can such an approach be considered reliable enough in this situation?
If not should I modify it and how or should I look for something different (e.g. encryption/decryption via System.Security.Cryptography as recommended here)?
And additional question: Does it really make sense to set HttpCookie.HttpOnly = true to prevent javascript from accessing the cookie given that it can also easily be modified by the user?
UPDATE
Great thanks for answers to Kerrek SB and Darin Dimitrov who share the opinion that it does not make sense to try to protect cookies on my own taking into account that there are already built in protected mechanisms of storing of such kind of information between postbacks.
Options suggested are:
- Using the ASP.NET
cache
(but I believe it is generally supposed to store information which should be shared between users, so I look at other two options). - Adding a custom string with userId into UserData part of the
FormsAuthenticationTicket
. - Using the
Session State
.
So currently I'm deciding between the latter two.
Changing the FormsAuthenticationTicket is not really straightforward. Additionally it does not work with the Cookieless Forms Authentication (as stated here).
Using the Session State is much easier but it can affect the performance because it stores the values in the server memory. However may be in my case it is not so dramatic because we store only userId of type int.
So for now the last option looks much better for me. However I would greatly appreciate if anybody else could comment and support or criticise any of options discussed.
Thanks in advance!
You seem to be reinventing some wheels here. While this could be acceptable when doing some standard code, when security is involved this almost always leads to catastrophic consequences.
To track actively logged in user I would recommend you using forms authentication (and here's another useful tutorial). It uses authentication cookies to track users. Those cookies are securely encrypted by the framework so that they cannot be modified using the <machineKey>
section of the server machine.config
file.
Form your code all you need to do to access the currently logged in user name is the following:
public static string GetUserId(HttpContextBase context)
{
if (context == null || !context.User.Identity.IsAuthenticated)
{
return null;
}
return context.User.Identity.Name;
}
You really shouldn't be handling all this stuff manually especially when the ASP.NET framework has a built-in mechanism for it.
That's terribly roundabout and obscure. If you already have an active session, why don't you just store this kind of data (which the client never needs to know, mind you) in your server-side session data?
All you should ever need to exchange with the client is the session ID, really.
you can also encrypt the cookies with Secure Socket Layer
HttpCookie cookie = new HttpCookie();
cookie.Secure = true;
精彩评论