How to prevent cookie poisoning
I save data in a cookie to authenticate users for the next login (remember me option). This data is encrypted and hashed.
But here's the problem:
Anyone can take this cookie and put it on another machine and it will work.
I heard that is called开发者_C百科 cookie poisoning
How do I overcome this?
Store the computer's IP address and/or hostname in the cookie (hashed) as well as your current scheme and validate that as well.
You really can't stop it, but there are things you can do to make it harder and thereby less-attractive
Require the user to use https (443) the entire session. This will prevent any man-in-the-middle attacks from sniffing the cookie
Only allow one session to be active at a time. Once the second session shows up, the first session is invalidated.
Require the user to provide his old password when changing the password (edit: or email address or anything else that could allow the account to be stolen once the attacker is logged in); this will prevent someone from hijacking the account and easily changing the password.
Have a very limited life for the session cookie - maybe a few hours.
That being said, since you have an open door into your system, you might want to ensure you're not storing any sensitive information that can be easily read by a user. So, for example, if a credit card or SSN is in the system, do not display it to the user.
The threat you're describing is that an adversary will steal a user's cookie and use it to access that user's session. One way to prevent against this is to store IP addresses or Hostnames as Daniel A White mentions, although if that's not possible there is no 100% secure way to negotiate this.
Here are a couple other options that can secure against this kind of attack:
- Use HTTPS for all session-based site traffic, and set your cookies to only transmit via HTTPS. If this is an option for you, this will prevent man-in-the-middle attacks.
- Set an additional cookie with a random value that changes on every request. If the random value is used more than once, you know a hijacker has gained access, and you can destroy the session for safety.
Even an identifier could be used to hijack a session (which is used anyway to identify a unique session). The tip about asking for old password before assigning a new one is ok but if you support kind of "Lost my password" feature you need to ask for password everytime critical information is changed in the account (such as email).
What Google did: they allow you to browse the "places" (or computer) that logged onto your account (because you may use it at home, at work, etc.) and to "close" those connections. In the event a connection is unknown to you, you can "close" it (close the session) and change you password immediately to make sure the hijacker doesn't use the your old password (if password was known of it).
Cookie poisoning is not only a problem for PHP.. this addresses .net
The only way to stop cookie poisoning is to know the cookies and to stop the poisoning of the web application by halting the response before permanent damage is done.
The Web application firewall I helped develop (https://www.nuget.org/packages/Walter.Web.FireWall) does that, the community edition is free and you get alerted when poisoning is detected and allows you to deal with it via its OnCookiePoisoningIncident event.
/// <summary>
/// If this creates a incident the firewall will queue the incident in the reporting workflows, if
/// the email workflow is enabled an email to the firewall administrators will be send informing them about the incident
/// </summary>
private void MyFireWall_OnCookiePoisoningIncident(object sender, FireWallCookieIncidentEventArgs e)
{
/* create a incident and block all access based on the firewall rules for cookie poisoning
* you can not create an incident based on your own logic here
* like:
e.AllowRaiseIncident = e.CookiePoisoning.CookieManipulations > 2;
* or when a non- served cookie was injected by checking for common attack patterns like "userId", "card" or "admin"
e.AllowRaiseIncident = e.CookiePoisoning.PhishingForCookies.ContainsKey("admin");
*
* or when the firewall knows the user is a bot, but not a search engine
e.AllowRaiseIncident = user.UserType.HasFlag(UserTypes.IsBot) && !user.UserType.HasFlag(UserTypes.IsSearchEngine);
*/
e.AllowRaiseIncident = true;
var user = e.Page.User.AsFirewallUser();
//what ever the firewall detected the user was, add the fact that the user is malicious
user.UserType |= UserTypes.IsMalicious;
//you can do this in the logger but as we are going to block the response making it a ms slower will not "harm user experience"
var InterNetProviderAbuseContact = e.Page.GetAbuseContact();
var ipAddressFromCountry = Walter.BOM.Geo.GeoLocationMapping.GetCountryName(e.Page.Country ?? InterNetProviderAbuseContact.Country);
//loop over all poisoned cookies and log them
foreach (var cookie in e.PoisonedCookies)
{
if (e.Page.User.IsSearchEngine == SearchEngine.NotSure)
{
_logger.LogWarning("Cookie {name} was poisoned with {value} when {original} was send to by {IP} via {ISP_Name} contact {ISP_Email} in {country}"
, cookie.Name
, cookie.PoisonedValue
, cookie.OriginalValue
, user.IPAddress
, InterNetProviderAbuseContact.Name
, InterNetProviderAbuseContact.EMail
, ipAddressFromCountry
);
}
else
{
_logger.LogWarning("Cookie {name} was poisoned with {value} when {original} was send to site by search engine {searchEngine}"
, cookie.Name
, cookie.PoisonedValue
, cookie.OriginalValue
, e.Page.User.IsSearchEngine
);
}
}
}
精彩评论