我的访问令牌策略是一种好的做法还是易受攻击的?

  • I am developing API for my real-time Web Application to make it work with Mobile App.
  • I want make my user's data available to access/modify with Mobile App.
  • To avoid sending user credentials to server every time to access user data, I am going to implement Access tokens.

So what?.. Instead of storing generated Access token details like user_id, expiry_time, user_ip, etc., in database, I am going to store them in Access token itself. so, I can avoid database queries every time user requests for update.

I am thinking of following API strategy:

  • Initially Mobile App asks User Email and Password from user and sends request to API Server to get Access Token.
  • API server checks user credentials against the database table.
  • If user exists,
    • gather user_id, timestamp, user_ip, etc.,
    • format a comma delimited string with above data.(or url_encode?)
    • encrypt the comma delimited string with encryption key (I keep it safe) using Mcrypt Library.
    • base64_encode the encrypted data and return it as Access Token.
  • Mobile App stores this returned Token for later use.
  • Further requests from App are sent with the Token.
  • When access request with Token is received by API Server,
    • decrypts the Token with same encryption key. (So, we will get the same comma delimited string)
    • Parse the decrypted delimited string. we will get user_id, timestamp, user_ip.
    • directly use,
      1. user_id to fetch corresponding user data.
      2. timestamp to check if Token is expired or not.
      3. user_ip to decide allow/deny if user IP Address change.

If encryption is failed, we can conclude it as invalid Access Token.

Advantages: No database queries required every time when user request for fresh data. so, time and resources are saved.

I didn't find any vulnerabilities / problems with this approach. that's I am here! please provide your valuable feedback!

Note: I don't know whether this is the common way in which access tokens works or not. sorry, if it is.

Do not hand reversible encryption to a user. You will need to use the same encryption key for all users, which means you have one very very secret key which you must ensure stays secret. If this key ever leaks, any user can embody any other user by recreating your token scheme and choosing arbitrary user ids. Since you're handing the cypher data to the user, they can easily mount an offline attack on it (e.g., just try any and all combinations of keys on the data until it successfully decrypts). Once the key has been discovered this way, you have no recourse besides changing the key.

Instead, use a hash which is specifically designed to slow down such brute force attacks to such a degree that they become impossible in practice. Implement this using a signed token. That means, you use the same information (user id, ip, timestamp), you add a randomly generated value, you hash all this with your secret key, and you send all these pieces except the secret key to the user.

// user_id,ip,timestamp,random_token,hash
42,127.0.0.1,12345678,oiawd8juht4mp9384,q209c8yqc23n09rhcq823n9t87q432hnq9493q784gth

The information can all be in plaintext, because it's meaningless by itself, and it's authenticated by the hash, which cannot be faked without the secret key. Use an expensive HMAC hash for this purpose.