4

I am using Facebook login in a mobile native app, and I'm trying to figure out if my approach is secure enough.

This is the flow (all communication is made over SSL):

  1. User logins to Facebook through the mobile app.

  2. The app passes the user's Facebook short term access key to the server.

  3. The server uses the key and makes a request to Facebook to retrieve the user details and to get Facebook long term access key.

  4. If the request to Facebook is successful a user is created in my DB.

  5. An object is then created for that user, which includes his Facebook ID, Facebook Token and creation date. That object is encrypted using Rijndeal (256 bits) and returned to the client. From now on all requests from the client include that token. The token is valid for 48 hours. When the token expires I once again use Facebook's access key and make a request to Facebook. If Facebook's access key is still valid, a new token is generated and returned to the client.

  6. When the user wants his data, the client sends the token, if the decryption of the token is successful I use his Facebook Id (which is also the ID I use for the user), which is part of the token, to retrieve his info and send it back to the client.

I have two questions –

  1. Is that flow secure?
  2. When I encrypt the token, should I use different IV and salt for each token? (My assumption is that it is necessary, but does it mean I should store the IV and Salt in the DB, and actually retrieve it in every call the client makes – seems quite expansive).
Udi Idan
  • 133
  • 1
  • 9

1 Answers1

1

The security of this depends on how exactly you do the encryption. If you are using CBC-mode and no integrity checking, then I see a weakness that could allow one user of your app to impersonate another user:

  1. The attacker gets legitimately issued a token for their own Facebook account. They then wait 48 hours so the token is invalid. If they present this token to your server, they get issues a new token. Crucially, in this request, only the Facebook ID matters - the Facebook token is irrelevant.
  2. If the encryption does not have integrity checking then they can tamper with their token to change their Facebook ID. If the encryption uses CBC-mode, then this is fairly trivial. When they present the tampered token, they then get a legitimate token for the other user's Facebook ID.

You can fix this by using integrity checking as well as encryption. In fact, you may actually want to ditch the encryption and just use integrity checking. You have SSL to encrypt everything on the wire anyway.

Another consideration: how exactly do users login with Facebook? You should use the "Log in with Facebook" button (iOS info) rather than presenting a web page directly within your app.

paj28
  • 32,736
  • 8
  • 92
  • 130
  • I do use CBC-mode. Regarding no. 1 - if the token expires, a new token is issued only after making a request to Facebook using the access_token of that user and get his info. So actually in this scenario you need the user's access_token to get a fake application token. My assumption is that if the user got his hands on that user's facebook token, he can also get my App token. – Udi Idan Mar 30 '14 at 20:25
  • @UdiI - Ok, I see, sounds like you can't get a new token that way. But in point 6 you say a user can retrieve their data based on the decrypted Facebook ID. Which leads me to ask: if a user can tamper with their encrypted Facebook ID, can they retrieve another user's data? – paj28 Mar 30 '14 at 20:44
  • If they can tamper with the token and replace the Facebook ID within the token, and the server successfully decrypts the tampered token and gets the changed Facebook ID - then yes. – Udi Idan Mar 30 '14 at 20:48
  • @UdiI - and you're using CBC with no integrity checking? I'd have to actually test your app to say for sure, but it sounds like you're vulnerable to this kind of tampering. – paj28 Mar 30 '14 at 20:50
  • Yes, CBC-mode. I am not familiar with integrity checking, can you point me to some info about it? – Udi Idan Mar 30 '14 at 21:00
  • Here's a start: http://security.stackexchange.com/questions/9437/does-symmetric-encryption-provide-data-integrity – paj28 Mar 30 '14 at 21:01
  • Thanks, I did some reading on that subject. Do you think the example in the following link would be more appropriate for my scenario? (the first method - Bouncy Castle AES-GCM) http://codereview.stackexchange.com/questions/14892/review-of-simplified-secure-encryption-of-a-string – Udi Idan Mar 30 '14 at 22:23
  • @UdiI - yes, AES-GCM provides integrity checking, so it does what you need. Another option is to ditch encryption and just use HMAC for integrity checking. A third option is to ditch crypto altogether and use a 128-bit random ID that you store in the database. If you use GCM, you must use an IV (http://stackoverflow.com/questions/5690864/source-and-importance-of-nonce-iv-for-protocol-using-aes-gcm) but it can be stored unencrypted with the token on the client. Personally I would go with the HMAC approach. – paj28 Mar 31 '14 at 06:56
  • Thank you for you answers :) Why would you prefer HMAC over AES-GCM? wouldn't AES-GCM provide more security? I also thought about storing a random ID in the DB, but I would like to minimize the calls to the Database. – Udi Idan Mar 31 '14 at 09:35
  • @UdiI - I understand your need to minimise database calls. My thinking with HMAC is that because we don't need encryption it keeps the design as simple as possible to not use it. It also avoids having to use a different IV with each token. But these are only minor reasons; if you feel more comfortable with AES-GCM then go for it. – paj28 Mar 31 '14 at 12:49