Forum OpenACS Q&A: Response to Ben's scary authentication bug.

Collapse
Posted by Ian Baker on
Sending a secret hash with the link or form, to be returned with the request seems like the best solution. Generation and checking of the hash could be made really simple with a few procs.

What to make the hash from, then. Concatenating the session_id and a secret that's stored on the server (perhaps randomly generated every few hours), and SHA1ing it seems like it'd be a good bet. You wouldn't need to hit the database for it or anything. Code would look something like this:

proc make_hash  { } {
    return [sha1 "[ad_conn session_id][ad_conn server_secret]" ]
}

proc check_hash { input_hash } {
    if { [ string equal $input_hash [sha1 "[ad_conn session_id][ad_conn server_secret]"] } {
        return 1
    } else {
        return 0
    }
}
The value returned by [ad_conn server_secret] would be some random number, generated every few hours (however long a session lasts would be a good number, probably), stored in the database, and memoized. It might be worthwhile to keep the previous server_secret around and check against that one too, but only issue the new one (overlapping the two). Otherwise, when the secret changed, all the links that were just issued would become invalid.

The output of [make_hash] would be included in whatever forms were to be secured, and the scripts accepting those forms would check for it.

In a real implementation, make_hash could be wrapped into ad_conn, and get_hash could be a page_contract filter.

Adding the session_id makes the hash unique for each user, so that the malicious site maintainer can't just go fetch the new hash every hour. The server secret makes it impossible for the malicious user to write javascript to generate a correct hash for the session_id cookie.

Possible vulnerabilities:

  • Since part of the hashed value (the session id) is known, heavy-duty cryptanalysis could possibly be used to determine the second part (the secret). This risk is mitigated by using a fairly long random number for the secret, and refreshing it often.
  • The evil hax0r could write some JavaScript that would go fetch a document from the secure ACS site, extract the current hash for that user, and generate a new request with it. I don't think this is possible with JS (fetching and parsing documents), but if it is, then this whole idea is bunk...

(disclaimer: I don't develop with OpenACS, so I don't know if I'm using the right procedure names here and stuff.)