API Key in path - rest

We have some IoT sensors that POST json payloads to an endpoint. They are configured with only a HTTPS URL to send to, no ability to setup authentication etc.
We need basic ability to see which sensor is sending data, and loosely prevent anyone from sending payloads. Full authentication will not be possible.
It was suggested we could put a token in the path and use it as a super basic API Key. I was wondering what the best format for the route should be...
/api/events/_ingest/api-key
/api/producer/api-key/events/_ingest

I was wondering what the best format for the route should be: /api/events/_ingest/api-key or /api/producer/api-key/events/_ingest
There's no best approach here, both are really bad. The API key does not belong to the URL. It should be sent in the standard Authorization HTTP header.
Once you mentioned in the comments that it will be something temporary, you could try a query parameter. It's still bad though. But you will be able to reuse this same route later, just moving the API key to a HTTP header, when your clients support it:
/api/events/_ingest?api-key=somecoolhashgoeshere

Related

API Design; action endpoints

Let's say I have a devices which will connect to a server and register/transfer data through an API.
I understand that you would have things like:
GET: api/devices
GET: api/devices/:id
POST api/devices
DELETE: api/devices/:id
Those are examples of typical CRUD endpoints.
But where would I add endpoints for checking if this device is allowed to connect with it's factory ID?
I was thinking of always passing a post field with an API key in the form of a device ID, but that would mess with the HTTP verbs.
So I think the best way is to add a parameter like this:
GET: api/devices/:id?id=something
But that would become redundant with this endpoint.
So the question is; how would I successfully identify my own devices?
It sounds like you're simply looking for a way to do authentication. Take a look at the Authorization header and the various authentication schemes for it. If existing authentication schemes don't fit your needs, you can also extend it with your own. Common ones are Basic, Digest and Bearer. An example of a vendor-extension is AWS.

Sending passwords over HTTPS: GET vs POST

I'm creating a headless API that's going to drive an Angular front end. I'm having a bit of trouble figuring out how I should handle user authentication though.
Obviously the API should run over SSL, but the question that's coming up is how should I send the request that contains the user's password: over GET or POST. It's a RESTFUL API, so what I'm doing is retrieving information meaning it should get a GET request. But sending the password over get means it's part of the URI, right? I know even a GET request is encrypted over HTTPS, but is that still the correct way? Or is this a case to break from RESTFUL and have the data in the body or something (can a GET request have data in the body?).
If you pass the credentials in a request header, you will be fine with either a GET or POST request. You have the option of using the established Authorization header with your choice of authentication scheme, or you can create custom headers that are specific to your API.
When using header fields as a means of communicating credentials, you do not need to fear the credentials being written to the access log as headers are not included in that log. Using header fields also conforms to REST standards, and should actually be utilized to communicate any meta-data relevant to the resource request/response. Such meta-data can include, but is not limited to, information like: collection size, pagination details, or locations of related resources.
In summary, always use header fields as a means of authentication/authorization.
mostly GET request will bind data in URL itself... so it is more redable than POST..
so if it is GET, there is a possibility to alive HISTORY LOG
Using ?user=myUsername&pass=MyPasswort is exactly like using a GET based form and, while the Referer issue can be contained, the problems regarding logs and history remain.
Sending any kind of sensitive data over GET is dangerous, even if it is HTTPS. These data might end up in log files at the server and will be included in the Referer header in links to or includes from other sides. They will also be saved in the history of the browser so an attacker might try to guess and verify the original contents of the link with an attack against the history.
You could send a data body with a get request too but this isn't supported by all libraries I guess.
Better to use POST or request headers. Look at other APIs and how they are handling it.
But you could still use GET with basic authentication like here: http://restcookbook.com/Basics/loggingin/

REST : Correct HTTP verb to check a password

I read many posts about passing sensible data in a GET request but didn't find an answer that would suit my needs.
I have to expose a RESTful resource that will check the password strength.
GET http://api.domain.com/security/password/P#55w0rd
I find the GET HTTP verb suitable since I only want if the password is secure enough.
The problem is that the client will be forced to pass it in the resource (i.e. URL).
Some colleagues told me to use POST and then pass it in the data body but I'm not sure how RESTful is it.
The REST standard just says to use HTTP Verbs. It doesn't actually mandate that you use particular ones. However some conventions have arisen about which verb to use, POST to create & GET to retrieve data, however this should not be followed religiously if it will cause an issue.
As per the following article you should not use GET for password, and yes you can use POST or pass something in the HTTP headers instead.
REST Security Cheat Sheet
Session management
RESTful web services should use session-based authentication, either by establishing a session token via a POST or by using an API key as a POST body argument or as a cookie. Usernames, passwords, session tokens, and API keys should not appear in the URL, as this can be captured in web server logs, which makes them intrinsically valuable.
I went with this:
GET /api/public/check-password
Authorization: Basic <base64(test:<password>)>
The username must literally be either '' (empty string) or 'test'.
I chose to use
test because it's obviously not a real user
GET because no modifications are made
The Authorization header because the security middleware in (most?) application stacks already removes that from logging - so no special care is needed.
/api/public because it doesn't require authentication to do the check
I'm not in love with check-password - that sounds more RPC-ish than REST-ish... but what can you do? At least it's obvious. I'm open to other suggestions.

REST API GET with sensitive data

I'm designing api with method that should be an idempotent, and should not modify any data on the server. It should be method that process request and return response for given parameters.
One of the parameters is sensitive data. It's not an option to use additional encryption. Data is already encrypted, but security requirements are very demanding and even encrypted data should be treated very carefully.
According to REST spec, idempotent query method should be implemented as a GET HTTP method. Problem in this case is sensitive data that shouldn't be pass as a GET parameter in URL. Only option in HTTP standard is to pass sensitive data in a body part of HTTP request.
My question is what is better? Broke rest api design, and send query request as a POST, or pass encrypted data in URL? Maybe is there better solution I don't see?
According to REST spec, idempotent query method should be implemented
as a GET HTTP method.
2016
As far as I can tell with my limited English SHOULD != MUST. You won't break REST API design by sending a POST in this case. You can send your sensitive data in a HTTP header if that is possible. And ofc. you should use HTTPS if you want to send sensitive data to anywhere.
2019
I checked the HTTP 1.1 standard meanwhile. They don't explicitly use the MUST or SHOULD words in the specs for idempotency, but I got the impression they mean SHOULD. Another HTTP related thing here, that we use GET mostly because we can cache response with it. You don't necessarily want to cache sensitive data, so it might not make sense to insist on using GET on retrieval when security is more important by the parameters. You can find some tips about how to set cache-control headers here, but you can read the HTTP standard for that too.
From security perspective my non-expert opinion is the following:
Normally query parameters are not that sensitive, usually they are just random ids or keywords. So maybe the problem is with your design and you should hide these sensitive parameters (e.g. social security number) behind random ids instead of querying them explicitly. Another thought here, that user credentials must be in the Authorization header for example, not in the query string, so if the sensitive data is that kind, then you are doing it wrong.
As far as I understand the issue about sending sensitive data in URLs is that it can show up in browser history, cache, address bar and in server logs unencrypted. Even though many people call REST webservices directly from browser via AJAX (or the fetch API), that is not the intended way they should be used. Webservices are mostly for server side usage to scale out your application to multiple threads, cores or servers. So if you use a server side HTTP client which does not have history or cache to call the REST webservice programmatically, then all you need to do is encrypting your logs. If the client has cache, then you can encrypt that too if you feel it necessary. I think it is possible to filter these params from logs and store the cached content based on the salted hash of the URL, but I don't have much experience with that.
If you have a 3rd party client or a browser where you don't have that kind of control, then you can still assume that it follows the HTTP standard. So you can use the cache-control headers to disable cache for sensitive content. The address bar and history is not a problem by single page applications unless they move the sensitive data to there with the history API, but that can happen no matter what you do. It is possible to disable the Referrer header too. Only if you serve HTML with your webservice will you have a problem with browsers, because that assumes that javascript is disabled (so you cannot use location.replace to override browser history along with the sensitive querystring) and that the browser is your REST client. I think that is a very unlikely scenario, though it is possible to do it relative well with XML+XSL reusing most of the code or nowadays maybe with nodejs or some sort of transpiler on different languages.
So I think this can be solved even without POST if you do everything right. But this is just an opinion, I wait for security expert to correct me...

Consuming wcfRest service from android/iphone

I need some good suggestions and ideas.
I have wcfRest service and the client is iPhone and Android. The client will GET and POST data.
I also made an API key which is a GUID, for the client.
BUT, do the client need to supply the api key with every method they request?? Or is there any way that I can store in the session or something??
for example:
json/getUserDetails/{userID}/{apikey}
json/saveUser/{apikey}
You could try checking out OAuth, that's the security method Twitter, Facebook, Google and others use. Since sending the API key to the server could lead you to someone getting it and doing stuff you might not like.
OAuth
An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications. It also works with mobile.
http://oauth.net/
Also check out the different languages http://oauth.net/code/
You'll have to send something on each request - whether it's the API key or an authenticated header, you need a way to authenticate the caller. So the easiest way would be to send the api key with each request, although using the header is a better idea.