Keeping securly API tokens in the database - php

I have multiple companies utilising my GET endpoint, each company needs to have their own API key which they will provide as a url parameter.
I need to keep generating these token whenever new company will join in (there is a table reflecting this).
Is it safe to just:
- create company_token pivot table
- generate token as str_random(32) (because GET request might have maximum url length)
? Or is there a safer, better method?

The best solution I guess would be to use JWT.
You can generate token for each company and distribute them.
Instead of sending the token in the URL as a query parameter, use the HTTP request authorization header and send the token as bearer token.

Database
The simpler and most secure way of keeping a company-level API token would be what you are already doing - using a secure PRNG to get a HTTP-safe token, which is what str_random() does, and having a UNIQUE constraint on the API token table to be sure you don't get duplicates.
UX
You could also supply a way of changing the API token by the company, after a suitable login, in order to allow them to get rid of obsolete or leaked tokens. Since you would update the API row and not keep old values, keeping track of obsolete tokens would not be a concern.
Security (as much as possible)
To avoid sending the token visibly in the URL, you could also receive them from a custom HTTP Header, as #AbdurRahman suggested.
Finally, you could use the token only once per session and per client: the API token can be consumed only by a /nonce API, which will reply with a longer token in the form of "IP:DATE:HASH" (e.g. "192.168.168.192:2020.02.16.15.35:ee2998d477ee4a1b50e886590d228239"), which would be around 64 bytes. The hash would be produced by MD5("IP:DATE:SECRET"), which guarantees that the information has not been tampered with. All subsequent APIs just verify that this token is untampered with, the IP matches and the date is not too far in the past (or the future).
The advantage is that the token being sent is now different for each client and changes every time, so even if it gets intercepted, little damage would be done. The "real" token that would be harmful if intercepted is sent only once per session; there are more secure schemes than this, but this would already be an improvement.

Related

Is my Access Token strategy a good practice or vulnerable?

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,
user_id to fetch corresponding user data.
timestamp to check if Token is expired or not.
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.

Security PHP RESTful API

I'm starting to develop a simple PHP RESTful API. After reading some tutorials, one of the features about REST is that the
"... statelessness is key. Essentially, what this means is that the
necessary state to handle the request is contained within the request
itself, whether as part of the URI, query-string parameters, body, or
headers"
Therefore, it means that my PHP server won't need to have $_SESSION ? What kind of approach do you recommend ? Using a token (valid for a short limit of time) in the URL doesn't seem a bit unsecure?
For example www.myapi.com/1233asdd123/get_user/12.
Many thanks.
If you're a web developer of any sort, you'll have heard this sentence probably 1,000 times: "HTTP is a stateless protocol". This means that every session works with a token exchanged between the server and the client.
When you use PHP's built-in sessions, the server is actually doing exactly that, even if you don't realize it: it generates a session_id and passes it to the client. The client passes the session_id token back normally on a cookie; PHP allows including the session token also on the URL, as a GET parameter, but I personally recommend disabling that feature (disabled by default on PHP 5.3+).
In your case, yes, you won't be using PHP's sessions.
You create a table in your database storing all session tokens and the associated session.
Tokens should have a short lifespan (for example, 30 minutes) and should be refreshed frequently. Refreshes are important not only to extend the life of the session (every refresh gives you an extra 30 minutes or so), but also help fighting against thefts of the session key. In some REST servers we created, the session token lives for 30 minutes and users are given a new token on the first request made after 10 minutes the session started. When clients are sent a new token, the old one is invalidated immediately.
You could pass the token to the server in any way, but adding it as a GET parameter is not an ideal solution for two reasons: 1. GET parameters are often written in the access logs of the servers and 2. users often copy/paste URLs and share them, and that can expose their session token.
For API servers, the best approach is to include the session token in one of the headers of the HTTP request. For example, you could set your Authorization header: Authorization: SessionToken 123123123 where 123123123 is your token and SessionToken is a string to tell the server to use your authorization method (you're free to choose your own name, as long as it's not one of the default methods like Basic; be consistent, though!).
Security on API servers is normally obtained by using SSL. Basically, if you have an API server, you must protect it with HTTPS (SSL).
There are methods to achieve security also without using SSL, but they require signing each request and are really complicate to implement and to use - and the overhead they add is probably bigger than the one of SSL.
A very common practice is to use a key value inside the URL:
www.myapi.com?key=ABCD1234
It is not less/more secure than POSTing the string. SSL encryption ensures that the whole payload cannot be intercepted by a man-in-the-middle.
More info :
You also mentioned a temporary access (session token). It is common in systems to log in using credentials (like the solution above) and obtain a temporary session token in the response. The session token is then used instead of the login details to query the service. It reduces the exposition of credentials in case of interception, and if someone manages to steal the session token, it will be working only for a few minutes. Good to have although not a necessity.

REST API authentication: how to prevent man-in-the-middle replays?

I am writing a REST API and would like to implement an authentication system similar to AWS.
http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
Basicly, on AWS the client encrypts the Authorization header with some request data using a secret key that is shared between client and server. (Authorization: AWS user: )
The server uses the key to decrypt the header using the shared key and compare to the request data. If successful, this means the client is legit (or at least is in possession of a legitimate key).
The next step can be to execute the request or, preferrably, send the client a unique, time-based token (ex.: 30 minutes) that will be used on the actual request (added to a Token header, for example). This token cannot be decrypted by the client (uses a server-only key).
On next requests, the server checks the token (not Authorization anymore) and authorizes the request to be executed.
However, is it possible to have a man-in-the-middle, even on SSL-encrypted connections, that replays these token-authenticated requests? Even if the MITM does not know what's inside the message, he/she could cause damage for example by ordering a product many times. If the server receives a replayed message and the token is still within the valid timestamp, the server will assume this is a valid request and execute it.
AWS tries to solve this with a timestamp requirement:
A valid time stamp (using either the HTTP Date header or an x-amz-date
alternative) is mandatory for authenticated requests. Furthermore, the
client timestamp included with an authenticated request must be within
15 minutes of the Amazon S3 system time when the request is received.
If not, the request will fail with the RequestTimeTooSkewed error
code. The intention of these restrictions is to limit the possibility
that intercepted requests could be replayed by an adversary. For
stronger protection against eavesdropping, use the HTTPS transport for
authenticated requests.
However, 15 minutes is still enough for requests to be replayed, isn't it? What can be done to prevent replay attacks in this scenario? Or am I overthinking and a certain degree of uncertainty is acceptable if you provide enough mechanisms?
I am thinking about requiring the client to add a unique string on each request body. This string will be transport-encrypted and unavailable to MITM for modification. On first receipt, the server will record this string and reject any new requests that contain the same string in the same context (example: two POSTS are rejected, but a POST and a DELETE are OK).
EDIT
Thanks for the info. It seems the cnonce is what I need. On the wikipedia diagram it seems the cnonce is only sent once, and then a token is generated, leaving it open to reuse. I guess it is necessary to send a new cnonce on every call with the same token. The cnonce should be included on the body (transport-protected) or shared-key-protected and included on a header. Body-protection seems the best (with obvious SSL) since it avoids some extra processing on both sides, but it could be shared-key-encrypted and included on a header (most likely prepended to the temp token). The server would be able to read it directly on the body or decrypt it from the header (extra processing).
A Cryptographic nonce, the unique string you mention, is indeed a good security practice. It will prevent requests to be reused. It should be unique for each petition, independently of their nature.
Including a timestamp and discarding all petitions made past a certain expiration date is also a good practice. Keeps the used nonce registry short and helps preventing collisions.
The nonce registry should be associated to a user, to also prevent collisions. And consumers should use cryptographically secure pseudorandom number generators.
If a predictable seed for the pseudorandom number generator is used, such as microtime, two nasty things can happen.
The nonces may become predictable. Though if the
communication is encrypted this is less of an issue, as they will
not be able to modify the request and thus not be able to tamper the nonce.
Legitimate requests by the same user might be discarded. For
instance, if two servers sharing the authentication key try to do
two different "post" actions concurrently, nonces may collide.

CSRF protection and usability

Between most strong CSRF protection, there is the form token protection. The question I have about this method, is about usability: if a user opens multiple page containing a form, which use the token, are generated multiple token, but only the last opened page can successful send the form, all the other will give error.
I thought 2 solutions:
Keep a unique token for all the duration of session.
Store all generated tokens in session.
But:
This is the more realistic solution, but is less safe.
This generate a large resource overhead, because a user could open many pages, and I must store all the generated token.
Therefore, how have you solved this question?
PS The website I'm developing, is practically a ecommerce in PHP and although the money transfer will be managed through an external provider (like paypal), I think right give a good safety to my service.
You don't need to store tokens in the database.
Instead, you should include the same token in a cookie; a cross-site attacker cannot read or set cookies.
As long as the you get the same token in the cookie as the POSTed form, you're safe.
For additional security, you can hash them with a keyed HMAC hash, and verify that hash to make sure that the token came from your server.
You can also make the tokens per-user.

Protect from replay attacks when using request signatures in secure API communication?

I've been reading up on API communication securities and trying to figure out the best way to build a secure API. I know that OAuth and such exist, but I'm also trying to educate myself in the process and not rely on libraries.
Basically I have a Web Service and in that web service users can register for API. They will be provided a Profile ID and secret key which they have to use to build the API request from another web system.
API request is built similarly to the way banks do it, all input data sent to API has to be sorted, hash calculated and then the hash sent to the server, like this:
// Profile data
$apiProfile='api123';
$apiSecret='this-is-a-good-day-to-be-a-secret-key';
// Input
$input=array();
$input['name']='Thomas Moore';
$input['profession']='Baker';
// To ensure that the order of variables checked and received is the same on both ends:
ksort($input);
// Using serialize() for simplifying things
// http_build_query() is another option, or just placing values in order
$input['hash']=sha1(serialize($input).$apiSecret);
// Making a request to URL:
// Using file_get_contents() as an example, would use cURL otherwise
$result=file_get_contents('http://www.example.com/api.php?'.http_build_query($input));
// SERVER CALCULATES COMPARISON HASH BASED ON KNOWN SECRET KEY AND INPUT DATA
This is really good and works. But! My problem is the potential replay attack. If someone snatches this request URL, they can send it to the server again, even though they cannot change the data itself.
Now I've read some things about it that you should also either check the time or add a one-time-use token to the request, but I am unsure how exactly should I do that? Is sending a timestamp with the request really secure enough? (Receiving server would make sure that the request has originated few seconds within the time the request was made, if the clocks are somewhat in sync).
I could also add IP validations to the mix, but these can change and can be spoofed somewhat and are more of a hassle for the user.
I would love this one-time-token type of system, but I am unsure how to do this without exposing token generation to the exact same replay attack problem? (Last thing I need is allowing to give out secure tokens for middle-men).
Opinions and articles would be really welcome, I've been unable to find material that answers my specific concerns. I want to say that my API is secure, without it being just marketing speak.
Thank you!
You need to only allow token exchange via a secure channel (https), and you should have a unique hash per message. Include things like a timestamp and the ip of the client. If you don't use https, you are vulnerable to a firesheep-style attack.
Other than that, you are doing the token generation and exchange correctly.
Sending the time (and including it into the cache) is really an option.
The other option would be 2-phase algorithm when you first request for the session token or a session key, then use it for the session, and its TTL is stored on the server (which can be time or number of requests allowed)
As for the session keys idea look at schemes like http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
Example of 1-time token algorithm:
1) client composes a request for the 1-time token, signs this request with the secret key and sends it to the server.
2) server generates the key, signs it with the same key and sends it to the client (together with the signature)
3) client verifies the token using the secret key
4) client composes the request, including the token, and signs the whole request body with the secret key, then sends to the server
5) server checks whole body integrity and the token validity, then sends the response (again it can be signed with the secret key for integrity and authorship verification)

Categories