如何保护 cookie 免受攻击
我想在会话期间使用 cookie 来存储 userId,这样可以避免不必要的数据库往返。该userId用于访问一些用户特定信息。由于 cookie 可以轻松编辑,我现在担心安全问题。
为了禁止登录用户编辑其 userId 并访问其他用户的信息,我使用了一种非常简单的方法。我在 userId cookie 创建时刻添加了一个 cookie,它为其存储哈希值。在散列时,我使用硬编码的 64 字节密钥。从 cookie 检索 userId 时,始终会检查它是否与其散列值匹配。
这基本上是我的代码:
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;
}
return userId;
}
所以我的问题是:
可以考虑这种方法吗 在这种情况下足够可靠吗?
如果不是,我应该修改它以及如何修改或 我应该寻找不同的东西吗 (例如通过加密/解密 系统.安全.密码学作为 推荐此处)?
还有一个问题:考虑到用户也可以轻松修改 cookie,设置 HttpCookie.HttpOnly = true 来阻止 javascript 访问 cookie 真的有意义吗?
更新
非常感谢 Kerrek SB 和 Darin Dimitrov 的回答,他们都同意,考虑到已经内置了存储 cookie 的受保护机制,尝试自己保护 cookie 是没有意义的。回发之间的此类信息。
建议的选项是:
- 使用 ASP.NET
cache
(但我相信它通常应该 存储应该在用户之间共享的信息,所以我看看 其他两个选项)。 - 将带有 userId 的自定义字符串添加到 UserData 部分
FormsAuthenticationTicket
。 - 使用
会话状态
。
所以目前我正在后两者之间做出决定。
更改 FormsAuthenticationTicket 并不简单。此外,它不适用于无 Cookie 表单身份验证(如所述 此处)。
使用会话状态要容易得多,但它会影响性能,因为它将值存储在服务器内存中。然而,在我的例子中,情况可能并没有那么引人注目,因为我们只存储 int 类型的 userId。
所以现在最后一个选择对我来说看起来更好。然而,如果其他人能够评论、支持或批评所讨论的任何选项,我将不胜感激。
提前致谢!
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;
}
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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你似乎在这里重新发明了一些轮子。虽然在执行某些标准代码时这可能是可以接受的,但当涉及安全时,这几乎总是会导致灾难性的后果。
要跟踪主动登录的用户,我建议您使用表单身份验证(和这是另一个有用的教程)。它使用身份验证 cookie 来跟踪用户。这些 cookie 由框架安全加密,因此无法使用服务器
machine.config
文件的
部分修改它们。在您的代码中,访问当前登录的用户名所需要做的全部工作如下:
您确实不应该手动处理所有这些内容,尤其是当 ASP.NET 框架具有内置机制时。
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 servermachine.config
file.Form your code all you need to do to access the currently logged in user name is the following:
You really shouldn't be handling all this stuff manually especially when the ASP.NET framework has a built-in mechanism for it.
这是非常迂回和晦涩的。如果您已经有一个活动会话,为什么不将此类数据(请注意,客户端永远不需要知道)存储在服务器端会话数据中?
实际上,您需要与客户端交换的只是会话 ID。
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.
您还可以使用安全套接字层加密 cookie
<代码>
HttpCookie cookie = new HttpCookie();
cookie.安全 = true;
you can also encrypt the cookies with Secure Socket Layer
HttpCookie cookie = new HttpCookie();
cookie.Secure = true;