[OpenID] Nonces generated by the server?

Martin Atkins mart at degeneration.co.uk
Wed Apr 1 16:17:13 UTC 2009


Thanks for sharing your experiences and advice. Hopefully this 
information can be included in some kind of best practices or 
implementors guide document at some point.

Andrew Arnott wrote:
> Martin,
> I didn't realize you were the author of the Perl library.  I probably 
> would have been more gentle with my words. :(  Sorry.  It's often a 
> thankless job as a library author (I know) and it's a very big job to 
> get it done right and well.
> Further discussion inline below, including the nonce discussion you 
> asked for...  Good luck with your Perl implementation of the feature!
> 2009/3/31 Martin Atkins <mart at degeneration.co.uk 
> <mailto:mart at degeneration.co.uk>>
>     Andrew Arnott wrote:
>            I'm also somewhat curious about how many OpenID consumers
>         actually
>            do nonce checking. Net::OpenID::Consumer for Perl actually
>         ignores
>            the nonce altogether and implements its own timestamp
>         checking due
>            to legacy code for OpenID 1.1, and seems to be vulnerable to
>         replay
>            for up to 30 seconds after a positive assertion.
>         The author of the Perl library ought to be ashamed. This kind of
>         thing reduces my confidence in using OpenID at any site other
>         than one that I wrote the library for myself.
>         Although this is what OSIS testing is all about.  Hopefully
>         there is a test to catch RPs and OPs that don't check the nonce
>         for replays.
>     Yes. As the maintainer of that library (though not its original
>     author), I am ashamed, which is what prompted the question in the
>     first place.
>     I'd love to have a test in the test suite for this.
>     RPs only need to do this checking when they're running in stateful
>     mode, right? Since stateless RPs have nowhere to store state they
>     can't retain a history of nonces.
>     Can you share some high-level details about your nonce-checking
>     implementation? Specifically how you persist the previous nonces,
>     when you expire them, etc?
> Sure.  
> *Relying Party side of things*
> DNOI (dotnetopenid) generate nonces and add a "dnoi.request_nonce" 
> parameter to the return_to url if discovery on the user supplied 
> identifier suggests that the OP is a 1.x version of OpenID.  The RP does 
> not store nonces it generates.  In stateless mode in never stores them 
> at all, relying on the OP to check for unique nonces.  In stateful mode, 
> the RP only stores nonces that are included in positive assertions it 
> receives, whether those nonces are dnoi.request_nonce or 
> openid.response_nonce values.  It uses a 'blacklist' style instead of a 
> whitelist style for these reasons:
>    1. Causing an RP to generate an authentication request is cheap.  In
>       a DoS attack, an RP could quickly fill its memory with nonces by
>       just asking the RP to start an auth request without ever following
>       up on it.  By waiting until there's a positive assertion carrying
>       a nonce, it becomes more expensive to run such a DoS attack and
>       thus mitigates the risk to the RP.  But it also means you will
>       have a record of the claimed_id of each of the logins involved in
>       the DoS, so you can block that OP endpoint later if it ever became
>       a problem.
>    2. Since the RP sometimes generates the nonce (for openid 1.x) and
>       sometimes does not (openid 2.0), it provides a single place to
>       store and check the nonce in the code to only do so upon receipt
>       of the assertion.
>    3. The OP generates nonces that it never will store or check for
>       openid 2.0, so again, it made sense for the nonce generation code
>       to not store, and for the consumer of the nonce (whether RP or OP)
>       to just add the nonce to a store and check for a conflict at that
>       time and have cleaner code.
> Sure there are reasons to argue the other way, but the above is why I 
> chose this way of doing it.
> Oh, and here's a detail to be mindful of that DNOI had a bug regarding 
> for a lot of versions: the nonce should be combined with the OP endpoint 
> (in a secure way) to make a unique nonce that you store and check for 
> collisions with.  The reason for this is to avoid an RP falsely 
> detecting a replay attack when one OP endpoint happens to generate the 
> same nonce as another OP endpoint.  An OP endpoint can legally just 
> increment an integer (1, 2, 3) to be its nonce and be unique for itself. 
>  If two OPs do this, you can imagine how likely a collision would be. 
>  Nonces out there are typically more random than that, but it's still a 
> slight concern.
> Provider side of things
> On the OP side it gets much more interesting.  I have a blog post on it 
> already.
> http://blog.nerdbank.net/2009/03/replay-protection-for-openid-1x-relying.html
> Basically, OpenID 1.1 Providers provide no replay protection for their 
> customers. That wasn't good enough for me, so with DotNetOpenAuth 3.0 
> (DNOA, previously known as DNOI), I added replay protection from the 
> Provider side even for customers logging into 1.1 RPs.  My blog post 
> discusses how this is done.  
> The basic 2.0 scenario though is that the OP generates nonces, and only 
> stores the ones that come back in check_authentication messages.  
> The advanced 1.1 scenario is that the OP always forces private 
> associations for positive assertions (read: RPs are forced into dumb 
> mode) and thus the check_auth comes back to the OP, and the OP can check 
> its proprietary dnoi.response_nonce value.
> *Clearing of expired nonces*
> Since most web sites don't have associated services that run constantly 
> or periodically (yes, there are cron jobs, but not on Windows as much as 
> on Linux, and I'm targeting Windows), I just had a simple algorithm that 
> was roughly this: every 20th nonce check should also cause an expired 
> nonce sweep to occur, where expired nonces are removed from the database.
> *
> *
> *Web farm considerations*
> It's vitally important that if your library is used by a site that is 
> hosted by a web farm, that the nonce store is shared by all servers 
> (including multiple processes on the same server, I think called a web 
> garden) in a transaction supporting database.  Even if your web farm has 
> a sense of affinity so the same user tends to be directed to the same 
> server in the farm, a hacker will have a different IP address and 
> therefore be directed to any random server, and if the nonce store is 
> not shared, he will succeed at replaying a message and spoofing a user's 
> identity!
> *
> *
>     I'm wondering if it would instead be simpler to use a
>     client-generated nonce in the return_to URL, as you note that
>     DotNetOpenID is doing for 1.1 requests, thus allowing the nonce
>     checking to be a whitelist rather than a blacklist and the nonces to
>     be in a known format that I can optimize for.
>     _______________________________________________
>     general mailing list
>     general at openid.net <mailto:general at openid.net>
>     http://openid.net/mailman/listinfo/general
> ------------------------------------------------------------------------
> _______________________________________________
> general mailing list
> general at openid.net
> http://openid.net/mailman/listinfo/general

More information about the general mailing list