Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Security Vulnerabilities in Heroku (stephensclafani.com)
64 points by ssclafani on Jan 9, 2013 | hide | past | favorite | 19 comments


Hi, our response can be found at...

http://blog.heroku.com/archives/2013/1/9/password_hijacking_...

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

-Tom Maher, Heroku Security Team


Wow. Those are pretty nasty vulnerabilities.

Way to responsibly disclose them after working with Heroku!


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.


"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.


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


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.


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.


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.


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.


Thank you for being open about that issue. All the reading about vulnerabilities definitely made me more aware when writing critical parts of my applications.


Presumably though the where clause would be there if you are taking the user id from the request vars in order for the code to work at all?


If you build the query at runtime based on whichever arguments are available, it is quite easy for missing arguments to slip through to the inner query generator and end up with a blank where clause.


a blank where clause throws an error (in mySQL at least) as it should do. Or will the query generator respond to missing arguments by removing the where clause altogether? In which case that's some pretty nasty behaviour.


Depends on the flavor of SQL. But also, might not be a totally missing where clause, but just an incomplete one.


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.


Heroku will be publishing a blog post sometime today.



I wish that Heroku would just use a third party open source auth system like Persona. This stuff is difficult and complicated to implement correctly. Sure, Persona could have had this same bug, but I'd rather trust someone who's job all day long is to implement auth systems (and which I can get the source to).


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




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: