2

I'm reviewing a website a friend developed, and was looking for general errors and concerns. In reviewing I noticed he is very heavy on ajax calls using JSON to a RESTful API that he maintains on a different server.

While some calls are simply things that return content, some are more sensitive to get attributes of a user that is authenticated. To determine authentication, he is passing a userid (stored as a GUID) in the call to the API. The code on that server then validates that this userID exists, and acts accordingly.

I went home later and took that same call with his GUID and was able to do all sorts of nasty things based on that GUID. He said "well who would get the GUID? The chances of guessing it are not likely, and all my calls are made over https".

Based on this, would you say the chances of someone stealing a GUID are low and he is fine? Or should he be handling this better? Perhaps generating a nonce [from the server the API is on] and then passing that along as well in the ajax calls to avoid replaying like how I did.

Perhaps i'm wrong on a few areas so go easy on me but would love some opinion :)

Thanks!

  • GUIDs are not designed to be unpredictable in most implementations. So I'd recommend a 128 bit value from a CSPRNG instead. – CodesInChaos Mar 10 '14 at 19:38
  • so if the uniqueID being passed along was a 128 bit value you'd say it's ok? Or did you mean IN ADDITION to the guid userid? – NullHypothesis Mar 10 '14 at 19:48
  • It's bad style but for different reasons. You should be able to identify a user without being authorized to be that user. You should be able to revoke tokens (e.g. to log out). The replay attack by itself shouldn't matter much, SSL already has nonces which prevent it. – CodesInChaos Mar 10 '14 at 19:53
  • Thanks for your reply - Just touching on the fact that I took my friend's userid, and then used his API to update his preferences later that night (and other aspects of his account) would you say b/c these requests are made with SSL it's not too likely someone could get a user's unique ID (userid/GUID)? In my case I cheated b/c he was logged in as himself already. But if I didn't have that luxuy, then it would be different? – NullHypothesis Mar 10 '14 at 19:56
  • A userID should not act as a bearer token. Bearer tokens for web api access should have an expiration, different each time they log in, and different for each user. A bearer token shouldn't contain the User id directly in it, however the server should know how to determine the userID from a given token. – goodguys_activate Mar 10 '14 at 20:07
3

This is a broken design because a GUID is not supposed to be secret, yet from what I understand it provides access identical to entering your username and password on the website.

In theory the design is solid. Protect the GUID as if it were the user's password and case closed.

In practice this introduces a lot of problems.

Example: I start working at your company today. I'm told to write a search feature so that you can find other users by email address. I would probably code the search results as a page showing a list of links to profiles, which contains something like <a href="/user/${user.id}">${user.name}</a>. Upon checking which columns to use I discover that the id field is called guid and the name field is called fullName. I test this. It works. I push the code.

Without realizing it, I just leaked the user's GUID which basically provides full account access. Now you can hijack any account of whom I know the email address.

Right now the programmer may constantly have in the back of his mind that knowing the GUID provides full account access, but in a few months it won't be something you think about a lot anymore. Since it is, I assume, the only unique way to point to an account, you need to use it in a lot of places. Especially for user interaction this might be a problem (perhaps users can form companies or groups, share folders, you name it).

A better way would be to separate identification and authentication. The GUID identifies a user whereas a security token authenticates a user. This completes the Identification, Authentication and Authorization (IAA) parts of a security system: the system decides the Authorization based on the Identification after verifying the Authentication. This is why, in addition to passwords, we also need to fill out a username on websites. Using only one or the other is generally a bad idea.

All places where the GUID is currently used should be replaced with the newly generated security tokens. For example a request might look like this: /API/2.0/doAction?GUID=${user.guid}&token=${some_security_token}. Note that these tokens must be fully randomized (odds of guessing it must be around 1 in 2^128).

There are many ways of generating these security tokens. Many websites generate sessions, but you could also use an extra database field. Whenever API calls are made, the user is authenticated by this random field. The field should be called something that makes it clear it's not supposed to be known to others.

Again, in theory it doesn't really make a huge difference in the system's design whether you use a random GUID or another randomly generated field for authentication, but in practice I think it does prevent a lot of big security errors, especially when the site has any kind of user interaction (but also if it doesn't, e.g. a password reset feature might accidentally expose the GUID after entering a username or email address). It simply reduces the number of attack possibilities.

  • Thank you for such an in-depth response! Apparently he is not showing the GUID anywhere whatsoever in the application, but if he ever does then clearly that would be a problem. I have a feeling he's going to simply say "they can't get the ID, so no point in making it any more secure or proper". I'll pass on your better recommendations, of course. It seems much more proper. One final question is: is the token you're referring to randomly generated each time by the server? – NullHypothesis Mar 10 '14 at 20:41
  • @user3379785 It could be, but it's probably much more practical to generate it only once and put it in a database column. Or generate it upon logging in and put it in a session file (or session table). Depends on the implementation. – Luc Mar 10 '14 at 21:40
  • Hey Luc, another question if you don't mind: If the guid is retrieved upon login, and is saved in session and then checked before each API call, would that be sufficient? What would be some problems that remain with this? The fact that the guid couldn't be invalidated still? – NullHypothesis Mar 11 '14 at 18:05
  • @user3379785 The crux of the problem is that the GUID is both the unique way of referring to an account and it provides full access. So as long as the GUID can be used instead of username+password, I think the design could be improved (even if it's not directly broken, like I said in the post). You say the GUID is checked before API calls, but how is it checked? You mean the server checks whether the GUID matches the session's owner? So the GUID is not enough, you now also need to send the session id with API requests to control an account? In that case I think it's much more solid now :) – Luc Mar 11 '14 at 22:18
  • @user3379785 Note that comments aren't really meant for chatty back-and-forth stuff. The chat is usually recommended instead, but for some reason you need 20 reputation point to participate in the chat... If you have more questions on this topic you could email me or something. See https://lucb1e.com/!about for contact details. If you have a more general question (something that would be of use to others), you can always start a new question on this site. – Luc Mar 11 '14 at 22:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.