Saturday, March 07, 2009

OpenID association poisoning







  1. Step 7 is not possible? I'd guess the RP stores associations per OP, so an OP cannot overwrite any other OP's associations

    I don't know how step 3 would be possible. The Web browser will never be able to read the handle established between RP and GoodOP, isn't the association created in a HTTP connection directly between the RP and GoodOP.

    Even if the Hacker could read the association between RP and GoodOP, this association wouldn't be the same as the one between the victim and GoodOP, because GoodOP probably derive the handle from a signed hash of the username & random number & timestamp, or something like that? So the handle that EvilOP gets, would be different from the one between RP and GoodOP.

  2. Step 7 mentions that the RP must be vulnerable to this attack. As you say, the RP shouldn't be vulnerable, but it *may* be.

    Step 3 is always possible, as the browser (and thus the attacker) can see the association handle after the RP and OP establish it by their privat echannel, because during the checkid_setup redirect one of the user-visible parameters is the association handle.

    Shared association handles are not per-user at all, as the point of shared associations is to reuse across many logins between an RP and OP. The secret of the association need not be the same between the good and evil OPs (in fact the point is they are not) but the assoc_handle is contrived to be the same, as evilOP can be configured to target a known assoc_handle.

  3. Andrew, I realize this is several years later, so you may not remember. What exactly *is* the preferred solution here? Flipping through Janrain's code, I'm hard pressed to pin down where they solve the problem. How can the return_to script be sure that the assoc_handle it receives is not hijacked - when it passes the very same assoc_handle in outbound requests, which are easily viewed by anyone with a local proxy?

  4. The solution is simply that the RP stores the associations by both the association handle *and* OP endpoint that the association is with. That way, any association handle "collisions" between OP endpoints don't occur.

    Protecting the return_to script or the fact that the assoc_handle is visible to eavesdroppers is irrelevant to the fix.

  5. I'm still missing some subtlety. The return_to script will receive an HTTP request from some source, containing an association handle that may or may not be hijacked. The source of the HTTP request may say that it is a particular GoodOP returning the result of a authorization request - in my case Google, using federated login - but I don't think I can rely on the HTTP request to establish the identity of the OP, because that can be faked as well.

    In the OpenID docs, I see that they require that the openid_sig be validated, as well as the openid_response_nonce. Since that code is annoying, I'd rather not write it, and just use something like Janrain instead. But your solution sounds simpler, and like something I'd be willing to deal with myself. Please illuminate further?

  6. When you say "return_to script" are you referring to Javascript? OpenID isn't a security protocol for javascript clients -- it's for web servers. This blog post and my earlier comment is only around securing against one possible exploit of the protocol. response nonces, signatures, etc. all play very important parts in other security concerns of the protocol. And I agree, you should *not* implement it yourself. Janrain is a good option. If your web site is based on .NET then DotNetOpenAuth is another option that I personally invest a lot of time in developing. With DotNetOpenAuth (and I believe Janrain as well) you should be well protected from this and many other security vulnerabilities with little or no additional effort on your part.

  7. I'm referring to a PHP script, not Javascript. The PHP (or ASP.NET, or whatever) script doesn't have any way to know that the sender of the HTTP request purporting to be the last stage of an authorization actually emerged from a legit OP.

    I think I went off in a different direction than you did, though. I see that your sequence describes a scenario where the Evil OP is a legitimate, but evil, provider, that is sending back a hijacked association handle and then creating a new association handle, overwriting the Good OP's handle. I was imagining a scenario in which the bad guy hijacks the original association handle and then simply sends back an id_res HTTP request purporting to be the Good OP. But, on closer examination and with your comments, I see that the nonce and signature verification should account for that scenario.

    It's largely academic for me at this point, since my own efforts have led more to understanding the technology than to a workable solution; I'll replace the guts of my solution with Janrain's PHP library. Thanks for sharing your thoughts.