
Security Vulnerabilities in Heroku - ssclafani
http://stephensclafani.com/2013/01/09/vulnerabilities-in-heroku/
======
tmaher
Hi, our response can be found at...

[http://blog.heroku.com/archives/2013/1/9/password_hijacking_...](http://blog.heroku.com/archives/2013/1/9/password_hijacking_security_incident_and_response/)

Thanks again to Stephen for giving us ample time to fix this.

-Tom Maher, Heroku Security Team

------
darkarmani
Wow. Those are pretty nasty vulnerabilities.

Way to responsibly disclose them after working with Heroku!

------
angkec
from the article: "Initial fixes were in place within 24 hours." So it's all
fixed? Great! I'll stick with Heroku as my hosting provider like the author
does.

------
jiggy2011
"If the POST was made with ID removed from both the URL and body, the password
of a random account would be reset and the account automatically logged in
to:"

That seems like a very strange bug to occur.

~~~
scriby
This kind of bug can happen when you have code like this in SQL:

SELECT @id = id FROM table --Oops, forgot where clause. This selects a
"random" row

DELETE FROM table_2 WHERE id = @id

~~~
tmaher
It was actually slightly more dumb than that.

Like most sites, after you register your account, we generate a nonce and
email it to the provided address. You click the link with the nonce, we prompt
you to set your password, and your account is ready. Our bug was that for
already-verified users, the nonce column in the database is empty (it's a
nonce, you see, so we only use it once...). This was the root cause for both
bugs Mr. Sclafani describes.

~~~
bgentry
The ActiveRecord query that caused this was along the lines of:

    
    
        User.find_by_email_and_token(params[:email], params[:token])
    

If the token is nil, it basically turns into a `find_by_email`.

I'll also add that while we had tests that were intended to avoid this bad
behavior, these tests were unfortunately broken and were instead verifying the
incorrect behavior.

~~~
wulczer
It's interesting how differently Django handles password resets - no nonce is
generated.

Instead, the user is emailed a token that's just her user ID, HMAC-signed with
the last login date and a secret site key.

You can't generate valid reset links without knowing the secret key and you
can't tamper with the one you got because it's HMAC-signed. By adding the last
login date to the HMAC you make sure the link can be used only once. After a
user resets her password, the last login date is updated to _now_ so the link
is no longer valid due to broken HMAC.

I like this solution because it doesn't rely on storing any state anywhere
between requesting the reset and completing it.

~~~
mikey_p
This is pretty much exactly what Drupal does as well, with the exception of
using the user's password hash instead of the ID as input before hashing and
it also stores the timestamp of the reset request as part of the URL (and the
token) to allow for expiring password resets.

------
danielpal
WOW this was critical bug, you could basically change anyone password without
authenticating and then authenticate as them.

I wish heroku would disclose this issues.

~~~
ssclafani
Heroku will be publishing a blog post sometime today.

~~~
willlll
[http://blog.heroku.com/archives/2013/1/9/password_hijacking_...](http://blog.heroku.com/archives/2013/1/9/password_hijacking_security_incident_and_response/)

------
jlkinsel
Always like to see transparent and timely responses to issues like this. Well
done.

