Make a securityScheme expect two parameters for authentication - php

I have this authentication guard called apiKey which expects two headers to be sent in order to authenticate a user to access the microservices (x-header-apikey, x-header-prodId).
While doing the API documentation with darkaonline/l5-swagger: 8.1, I saw that I can't define two parameters in the same security scheme, is there any way that makes a security scheme expect 2 parameters in order to authenticate? Something like this pic:
Except adding the prodId as header on each API.
I tried searching on every forum to at least tell that it is not possible to do that, but there aren't nor articles or comments which deny that this can be handled in that way.

Related

How to implement an API Referrer list restriction?

I'm developing an API service and I would like to allow the users to restrict access of their tokens by domain, so an API key can only be used from one site/domain/host (it could be a server calling the API, not necessarily a browser), like Google Maps API allows you to do.
Now my question is, how do I check which host/domain the request comes from - in PHP (Laravel) - so I can compare it to the allowed domain(s) or pattern?
Is $_SERVER['REMOTE_HOST'] the right variable to check? Or should I look at a request header? Like $_SERVER['HTTP_ORIGIN'] though that seems to be browser related and, if I'm not mistaken, another client (a server or Postman for instance) would not necessarily have the Origin header, while $_SERVER['HTTP_HOST'] is not required and can be faked.
Edit: just to be more specific, I don't think this additional check on the requesting domain is supposed to replace the access token for auth, but it is an additional layer of protection and helps with token management and misuse - a user might have multiple tokens for different clients/apps calling your API so this way you can discriminate the traffic.
If Google can do it I assume there is a way for implementing it. Could it be not possible in PHP? I don't know, but I was hoping somebody here could suggest a way to implement this check/restriction, maybe underlying the limitations of the proposed solution. Even if the solution is not 100% reliable (again it is not suppose to authenticate the client) it would still help improving protection - in fact Google considers it best practice to "protect" the API keys this way.

Query string JWT JSON Web Token Authentication in PHP Slim API

This is a question about the best way of implementing JWT in a Slim PHP API - I'm looking for some guidance from senior/experienced developers as to how to proceed.
I currently have an open API, where users can perform get requests with query parameters such as device and date-time range to pull data. I also have devices which are POSTing data, with no authentication. We're not in production yet, but obviously this is bad.
To tackle this, I've been looking at implementing stateless authentication on the GET requests in the first case, specifically using JWT. I initially thought about passing the JWT through as a query string, with options for resetting a token performed through the web front-end after a user has logged in. However, I can see this being bad for man-in-the-middle attacks and my token being exposed (if using plain http). If I was to make sure all get/post requests were performed as https requests, will this be sufficiently secure?
What seems to be the more secure way would be to pass the token through the header. But from what I understand about this, you'd need something like Postman to be able to send requests, which isn't really an option since my users want to access the data using their browser only.
It's pointless using http, https is a must otherwise everyone in between the user and your server will see the password the responses can even be cached.
The token can be stored in a secure cookie which the browser will automatically include with each request. (The Slim Middleware for JWT has this functionality built in). Check out many available libraries at https://jwt.io/
Adding the token to the query string isn't needed if you use cookies, I would not recommend adding tokens to the query string as they are to easily leaked.
(Users love copy&pasting URLs to each other, this would also leak the token)
Note: If you're not sure if JWT is right for you, check out: http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/

PHP - Securely sending request/response between 2 servers?

Summary:
I've created an app in PHP. It's lead management system for a call center. I now need to allow a partner to be able to add new leads to the app by integrating our app with their proprietary CRM. In short, I guess I need to build an API for my app.
The easiest approach I can think of is a simple HTML post. Would this be considered too insecure? If so, what would be best approach for this type of situation?
Thanks for any help,
Andrew.
Through your quest to build an API, you'll most likely come across some of these. I'm going to outline the concepts that might come in very handy to actually build an API that is usable, and that follows open standards (which, in turn, makes it trivial for third-party to adapt existing code to interact with it).
API dispositions
The first keyword is: SSL. Don't ever think of not using it. This provides a secure socket layer on which communication can happen in a secure fashion, and consequently makes eavesdropping and MitM attacks significantly more difficult to conceive.
No matter what, do not skip on this. Certificates cost less than $60/year, so it is not exactly costly, and can save you a lot in the long run.
In terms of server techs, use what you want. Your main requirement is a webserver that can handle the four common HTTP verbs: GET, POST, PUT, DELETE. I'll explain why in a moment.
API authorisation
This one is the contentious field, as lots of people "think they have a secure way to do so". The answer is simply not true. The point of your authentication is to allow a client to easily authenticate with their credentials, but to prevent a third-party who is not privileged from doing so.
Simply adding an API key to the feed will just lead to someone eventually getting hold of it. I have seen this specific thing so many times that I strongly advise against it, especially as there are significantly easier options.
I'll go over a couple of things, labelling them as (A) or (S), respectively for Authentication and Signature. Signing is the method used to render your request tamper-proof. Authentication proves who you are.
HMAC-SHA512 signing (A) (S)
This technique is used by Amazon for all their S3/AWS APIs, and is a very lightweight method of signing and authenticating a request. I personally find it relatively ingenious.
The basic idea:
Round up all the GET and POST fields (including your public key)
Sort them alphabetically
Concatenate them using URLEncode or equivalent
Perform a HMAC hashing cipher on the data, with your private key as the key of the HMAC.
Append the result of 4 to your request.
This is simple and ingenious. What it guarantees:
You cannot change the request without knowing the private and public keys
You cannot change the key without changing the request
This neatly wraps both issues using the same HTTP request at the cost of one reserved GET/POST field. Amazon also requires the presence of a Timestamp in the request, which prevents replay attacks. Neat!
(For the reference: HMAC-ALGO = ALGO( (key XOR PAD) concat ALGO(key XOR PAD2) concat message). ALGO can be any hash cipher - SHA256 is preferred for its lightweight nature)
OAuth (A)
You've probably heard of it. the idea is simple: you get given a key and secret. This allows you to queue up for a temporary token. This token is then used to perform requests.
The main advantage of this is that lots of libraries exist to handle it, both client-side and server-side. The other advantage is that OAuth has two modes of operation: two-legged (server->server without client interaction) and three-legged (client->server->server).
The main drawback is 2 HTTP requests to get a token.
Simply sending private keys through (A)
... Leads to replay attacks. don't consider it.
A mixture of methods is a possible things. The HMAC signage is awesome when combined with OAuth, for example!
API conception
API endpoints these days follow two main standards: SOAP (XML-RPC), or REST. If you are building an endpoint to post leads, you may as well build the corresponding API to read leads and to delete them for the future.
Your API would therefore take the form:
/my/endpoint/
- GET: gets a list of leads
- POST: creates a new lead
/my/endpoint/ID/
- GET: get lead info
- PUT: modifies lead
- DELETE: deletes the lead
This allows you to future-proof your API conveniently as well.
A HTML post will suffice, that's not a problem. It would be even better if you're able to use HTTPS to ensure the transferred data is encoded, but this isn't critical.
The most common way of securing this kind of API is to provide a shared 'secret' or 'key', which is used to encode a hash. You'll then be able to verify that the request came from a trusted source, but it's up to the user to ensure that they keep the shared key a secret.
e.g. Users of your API will need to:
// build hash string to be sent with API POST request (use a sensible combination of values)
$string = sprintf('%s.%d.%d.%d', $username, $orderId, $currentTimestamp, $price);
// hash
$encodedString = sha1($string);
// concatenate with shared key
$stringWithKey = sprintf('%s.%s', $encodedString, $sharedKey); // GET KEY FROM SECURE PLACE
// hash again to get hash that will be sent with the POST request
$hash = sha1($stringWithKey);
Then you'll perform the same logic at your end from the POST values provided and verify that their hash matches the hash that you build with the user's shared key.
This is exactly what an API is for. I'd make a unique key per external account and require that API key for each $_GET or $_POST transaction that is sent to your server.
Might want to build an API management console while you're at it. Oh and don't forget the separate DB table for the API keys.
When you're done it'll be something like:
https://api.mysite.com/index.php?key=r328r93fuh3u4h409890fj34klj&other=something&another=somethingelse
You get the idea.

How to build a restful api while being private and members only?

Back from the Symfony Live 2012 in Paris, where I luckily participate to "Designing HTTP Interfaces and RESTful Web Services" conference, I'v much questions on how to build a RESTful API while keeping it private and member only.
Currently I used to generate an API key to make my API private (I mean available to third-party application on my own but end-users).
To make sure signed up users can use the API (through mobile app) I use Cookie, well, I used SESSION.
But afaik, it is not the correct way to do, according to the talk (and other resources I read over the web).
My needs are the following:
Provides a private API which only my mobile app can use
Allows member (of different roles) to do different actions (ie: a Member can post a comment, while an Administrator can edit them all)
As REST constraints are Stateless (amongst others) I can't use Cookie/Session as they need to be initiated by the client and will result in some non-idempotent result.
I read here and there that a way to keep my API RESTful is to provide on each request the credential.
Currently, to authenticate my API key (to keep it private) I use a custom HTTP Authorization scheme, something like Authorization: MyApp SoMeToKeNV3RYPR!V4T3 and then authenticate my member (login) with a POST method (as I would do in any browser web application).
How would you implement such cases? Is it acceptable to use such private scheme and keep using sessions?
After some reading I may think that working with some Signature over each requests can help to solve such problems.
The signature may be generated using the user credential provided in the third-party client while encrypting it with a public/private key (to keep the API private).
On each request, the signature will be checked against a CRC (or something like that) while the credential will be against a database (it doesn't seem worth than checking for a session, does it?)
Any help/advices would be appreciated.
PS: What about OAuth? I don't know much about it, but may it be a solution to such problem?
You're definitely going to want to use OAuth. This will allow you to securely authenticate that your users are who they say they are. No messing with CRCs or anything is needed on your end, once a user is authenticated they have an access token they can use to sign future requests.
You would just need to handle the authentication scheme and handshake and then securely store the access tokens once they have been given out. However, if it were me I would not trust myself to handle all of the secure cases when designing such a system. There are a couple of third party PaaS companies that will do this type of thing for you. I know of the following companies which have some API management tools that will probably help you, and afaik they handle OAuth implementations as well:
Apigee
Layer 7
Ping Identity
If you are so concerned about security though that you don't trust a third party to handle it for you you are going to want to follow the OAuth protocol.

How do I authenticate users with a site API?

I want to build an API for users to build applications that easily interact with a site, and I was wondering what the best way to authenticate users would be.
Taking a look at other API's a lot of them have the user send the username and password as a GET parameter over a HTTPS connection. Is this the best way to go about it? Or are there other methods that I should look into or consider?
I've seen OAuth been tossed around and it looks like a good solution, but just for a simple API is it overkill?
You can use API key's. Generate a unique hash tied to an account upon request. Then check that the key is a valid key. As long as the API doesn't have any major security issues with someone using someone else's key then Authorization isn't needed. If there is a problem with someone using someone else's key then Authentication would be justified.
This is usually achieved with cookies.
The client sends their username and password with a POST request to your API (do not use GET, that's insecure). If the credentials are acceptable, then generate a random, unique session key, store it on your side and send it in a cookie back to the client (see setcookie()).
When the client now makes further requests, they send the session key cookie with the request. Check $_COOKIE for the session key if it matches a stored key on your side; if yes, that means the user authenticated.
Take note that this minimal example is vulnerable to brute-force attacks trying to guess valid session keys. You need to log invalid keys that clients send in their cookies and block their IP address for some period of time to prevent this.
Username / password in a GET isn't a great way to do this because you're potentially exposing the whole user account for hijacking even if the API has more limited functionality than logging into the site. So it's good practice to separate concerns between Web-site login and API access.
I'm not sure which case you're in but:
If the users are business customers of somekind who are embedding some type of widget or code in another website then it's probably best to use an API key which is scoped to the referrer domain (much like Google Maps does).
If they are end-users who won't know anything about the API but are going to be using Apps built by third parties then oAuth is likely to be your best bet, otherwise your users might literally be giving their usernames/passwords to unknown third parties. It's more complex but likely to be worth it in the long run.
To get a bunch of this stuff out of the box you can use something like 3scale (http://www.3scale.net) and it'll handle most of it for you (disclaimer, I work there so adjust for bias!) or there are open source libraries for oAuth in most languages (in PHP Zend-OAuth component might do the job for you).

Categories