Charles Miller's article, "Persistent Login Cookie Best Practice,"[1] describes a relatively secure approach to implementing the familiar "Remember Me" option for web sites. In this article, I propose an improvement that retains all the benefits of that approach but also makes it possible to detect when a persistent login cookie has been stolen and used by an attacker.
Review
To summarize Miller's design:
The Problem
Miller correctly describes the many advantages of this approach. One disadvantage, however, is that if an attacker successfully steals a victim's login cookie and uses it before the victim next accesses the site, the cookie will work and the site will issue a new valid login cookie to the attacker (this disadvantage is far from unique to Miller's design). The attacker will be able to continue accessing the site as the victim until the remembered login session expires. When the victim next accesses the site his remembered login will not work (because each token can only be used one time) but he's much more likely to think that "something broke" and just log in again than to realize that his credentials were stolen. Displaying a "last login time" may help the user notice the problem but, frequently, it will go undetected.
One possible solution to this problem is to treat the presentation of an invalid login cookie as evidence of a previously successful attack. The site could then present an impossible to miss security warning and automatically invalidate all of the user's remembered login sessions. This approach would create a denial of service attack: since usernames are easy to come by or guess, an attacker could submit invalid login cookies for every user and thus disable the entire system.
The Solution
My solution to this problem is based on the observation that since each token can only be used once, a remembered login session actually consists of a series of such tokens. When an attacker successfully steals and uses T_0 he is issued T_1, but the victim is still holding T_0. The database no longer has a copy of T_0 and thus cannot differentiate it from an arbitrary invalid token.
However, if the series of tokens is itself given an identity that must be presented along with the current token, the system can notice that the victim is presenting a valid series identifier along with an invalid token. Assuming that the series identifiers are as hard to guess as tokens, the only way a user could present a valid series identifier with an invalid token is if some other user previously presented the same valid series identifier with a valid token. This requires that two different users held the same series and token pair at the same time and therefore indicates that a theft has occurred.
The implementation is no more difficult and requires no more resources than Miller's design. From the summary above, only items 2 and 3 change:
It is critical that the series identifier be reused for each token in a series. If the series identifier were instead simply another one time use random number, the system could not differentiate between a series/token pair that had been stolen and one that, for example, had simply expired and been erased from the database.
Conclusion
This system has all the advantages of Miller's original approach. Additionally:
This system is used by the Persistent Login module for the Drupal content management system.
Notes
[1] Miller, Charles. Persistent Login Cookie Best Practice, http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice. January 2004.
[2] For the most secure result, the standard session management cookie should be a "session" cookie that expires as soon as the Web browser is closed. Furthermore, the server should enforce a fairly short maximum lifetime on sessions even if the browser remains open.
[转自:http://jaspan.com/improved_persistent_login_cookie_best_practice]