How to restrict API endpoint access to certain clients? - api

I'm building an API using the Django Rest Framework.
I've looked at a whole bunch of documentation, however I can't seem to answer this:
How can I restrict my API such that only my iOS client can register users / log them in?
I understand that I can use OAuth2 or Token Authentication for additional endpoints. But for unauthenticated requests, is there any way of restricting them?

There's no truly secure way to guarantee requests are coming from a specific device. Checking headers seems like the best way, as mentioned by #dukebody, but should be considered as a "good enough" solution for most users.
I'd also question why you want to do this. APIs generally shouldn't be restricted to certain devices because it makes them less extensible. Moreover, REST/HTTP services should return the same result regardless of the client device; otherwise, you will cause headaches when dealing with caches and proxies between clients and your service.
If you are trying to format content specifically for iOS, you'd be better off adding a specific parameter like ?format=ios without checking headers, then just make sure your iOS client uses that param. That would be more in the spirit of REST and make things easier to cache as well as test.

I also encounter this issue.I would like to provide some of my thought.
My team would need to support some APIs with heavy operation and it would be open to unauthenticated users which is design by business logic.
That's why we need to restrict api requests to our app clients.
The API call is stateless and irrelative with caching and proxies.
In the other hand, some malicious attack like CSRF, you should also provide some additional protection on you API to prevent request sending from untrusted way.
There are several mechanism we considered.
Using HTTP header
This is untrusted and very easy to crack.
Use one static random generated API Key
Very common and easy-implementation way. Server generated one static random string as key and client must carry when sending request.
If you have to support web, this would be leak by web console.But if you only support app client and restrict your API connection with HTTPs. This should be safe enough.
Dynamic change API key with AES crypto algorithm
To prevent MITM or static API key is leak, I proposed to use AES crypto algorithm and encrypt current timestamp.
When server receive, decrypt and check whether the request is valid or not.
You can also append some string as salt to make the mechanism harder to brute force attack.
You can do as much effort to make it harder to crack, but it would never be absolutely 100% safe.
Hackers can still reverse engineer your app to see how the encryption works.
All you can do is making it harder.
This is my propose and hope it could inspire you.
If you have any other better solutions or find some bug in my proposal, please let me know.

Restrict the views to the user agent of the iOS client, checking the headers. See https://stackoverflow.com/a/4617648/356729

Related

Finding out authentication method of web API (websocket) to login with my own script (I have the login data)

My parents own a wallbox for charging a electric car. The wallbox is controllable with an app which uses an authenticated API. I already did a MITM attack to get that traffic. I also have the login data, as it is the wallbox of my parents and they agreed that I do this. (If you are interested: I try to automate that the car is always charging when there is enough power from the photovoltaic but at the same time the car should never run low if there is not enough sun.)
I want to write a small Python script which controls the wallbox, but the only problem is, that I don‘t know how the authentication works.
Is there any way to find that out, without decompiling the app (which I found hard because it apparently uses React Native with the Hermes engine from Facebook which can‘t be decompiled as nicely as other Android apps)?
Is it realistic to find the used authentication method by just looking at the example I show below?
Or is the only way to understand the authentication with the decompiled app? I pasted an example of what I sniffed below.
If there is an easy solution to my problem, I am happy to take that, but if you say that I should look more into these and that, then I am also good with that, as I am kinda stuck at the moment.
Thank you very much!
Two messages from the API
They come automatically after opening the websocket connection.
{
"type":"hello",
"message":"Hello app",
"serial":"3215XXXX",
"devicetype":"deviceName",
"manufacturer":"companyName",
"protocol":2
}
The first token stays the same for multiple hours, even if you make multiple requests to the API.
{
"type":"authRequired",
"token1":"0dtOJ1LkCrMgaz5ri8MZmgHBcXXXXXXX",
"token2":"Ij10ETYSo2GJSVMJlDNzMGW9TXXXXXXX"
}
From the app
{
"type":"auth",
"token3":"b4eb9e8baae62429c577216aaXXXXXXX",
"hash":"cbc3d99391db59e59174ddb01073157581afb2ad1e392433c9107477eXXXXXXX"
}
Answer from the API
{
"type":"authSuccess",
"message":"Successfully authenticated"
}
It's not super-realistic to assess the auth method from that data, however, you can get some idea.
There could be multiple reasons why the server provides two tokens (rather than just one), but I'm going to give a "best estimation" example scenario. The auth method is possibly something fairly similar to this. It's possible that one of the two tokens is authenticating the server to the client.
One of the two tokens the server provides is likely some sort of challenge for the client: it may be a hash of current time or day, or a hash of a client-specific identifier, or just some random data used to prevent replay attacks.
The client response to the server is probably some hashed or encrypted combination of one of the tokens from the server and the client secret (your password, or username:password, or username:password:productID or something like that.)
The hash may be a protection against replay attacks by hashing the current time along with the client secret info, or possibly an authentication sequence number along with client secret info.
So as you can probably tell there are many, many possibilities here. It's possible the whole protocol is custom designed by the charging station manufacturer.
You might try sniffing some data again, and within the first token timeframe try to replay what your client sent. It will most likely not auth you, but It's possible you'll be presented with some error information that is useful and can give you more clues about what's going on.
Otherwise, the disassembler is probably going to be the way to go, and may be tedious, but should give you a much clearer picture of the correct auth protocol.

Authenticating Requests From A Single Server

I'm working on a project which contains data belonging to multiple clients, and I'm trying to find a secure way to notify their servers of certain sensitive changes to their data.
The issue is that the most secure method I found for this is OAuth, but since my server will be pushing the updates to them, that would mean that each client would have to implement an OAuth provider solely to authenticate my server, and it feels like a bit of an overkill.
My question is: Keeping in mind that not all clients will use HTTPS, would it be enough to simply use a shared secret, a timestamp, and some form of encryption for their servers to safely receive and validate my updates or will that leave them vulnerable to attacks?
Yes, that would be secure. For simple messages I think JTW would be a very good choice. You could use it for just authentication or the actual notification itself. A few reasons you might want to use it:
It's signed, so you know the message hasn't been tampered with.
You can encrypt with public/private key pairs.
You can add any data you like.
It's very simple to implement and doesn't require back-and forth exchange between servers like OAuth often does.

How exactly to implement challenge-response for REST API authentication?

I want my REST API server to be able to communicate only with my iOS app. The user base is going to be no more than 1000 people, and the market is pretty small and unpopular in general. That's why I think anything beyond a simple challenge-response authentication (HTTP, OAuth 2.0, SSL) would be an overkill. But I'm not sure exactly how this auth should flow. Here is what I have in mind:
Client app (user) sends a request: api.example.com/auth?username=john
Server responds with a randomly generated string: "somerandomlygeneratedstring"
Client takes the string, appends it to the username and then appends a secret string, hard coded in the app and uses MD5 to hash the entire string.
Client passes the string to the server: api.example.com/auth?username=john&response=thenewMD5hashstring
Server generates the same MD5 hash string and if they match, marks this user as authenticated in the database and all API requests from this user will be handled from now on.
Do I have the right idea? Or am I totally wrong? Please have in mind, I want basic security, anything too fancy would be an overkill for such a small project.
Also, I'm not keeping any sensitive data on my database like personal information.
You should simply use HTTP Basic auth for every request, through the Authorization header, and have all your interactions over SSL. If you want basic security, there's no need to go beyond that.
There are several problems with the scheme you have in mind.
Your last step is essentially a server-side session, which isn't acceptable in REST.
MD5 is effectively broken and shouldn't be used for anything but integrity checking.
In REST, you should use the standardized authentication method provided by the protocol if it fits your needs. Reinventing it to use URI parameters like you have in mind is unnecessary.
The hashing scheme you have in mind only makes sense when you want to sign the request, guaranteeing it wasn't tampered with.

Do I need to secure my API?

I'm working on an API service for my website. I have read a lot on this topic, though can't decide which the best solution would be for me.
My API is simple. Each user gets an API key for each app that connects to my site.
There are only 2 different calls atm:
send_data
get_data
The get_data is quiet harmless, with send_data you can end new entries to your mini app. Possible security problems could occur there, though calls are limited. None of the data is useful if it would fall in the wrong hands. Server side I am protected for sql injection etc.
The calls are something like this:
http://example.com/api/?call=send_data&data=DATAXYZ&api_key=KEY
The pro:
It's super easy to use
The con:
It's not secure
I read a lot of similar questions here and elsewhere and OAuth pops up as a possible answer on almost all of them. I know OAuth, and i think it's a lot of overhead for something I want to be easy to use for my users.
As explained in this article It's not always needed to use authorization:
http://blog.apigee.com/detail/do_you_need_api_keys_api_identity_vs._authorization/
Is this all true for my case too though or would you still recommend authentication with or without OAuth?
Don't send the API key as a GET parameter: it would be logged at the very least in the browser's history (and probably also in the proxy, if there's one), which isn't very secure. POST it instead.
I don't think it would be unsecure, in fact the widely used Basic Access Authentication sends the username and the password as plain text (base64 encoded), and in fact when using a form to log into any web service you are sending the password as plain text too. Of course this works on the assumption that the communications between the client and server are secure, so you probably want to use HTTPS.
I'm personally using similar API authentication methods in multiple commercial projects.
So far I've never had an issue with security but I use a slightly different approach.
What I do different:
a) API calls use a user-id/login plus an API key.
b) the API key is a salted md5 hash of the users password (you can add the userid and something else as salt)
That means people are less likely trying to "guess" an API key, you can also more easily see who is using your API in your logs (without looking up the API key).
And users can change their API key by changing their password, so if they think the API credentials might have been leaked then they can just change it.
Regarding GET/POST : If your users do not use the API themself (for example by including it in own tools/scripts/code) then I'd use POST as serans suggested.
But POST has several drawbacks, it's not as "easy" to use. It just requires a bit more work to be implemented.
So I'd offer GET as well as POST and just add a note about possible security issues.

Creating an API for mobile applications - Authentication and Authorization

Overview
I'm looking to create a (REST) API for my application. The initial/primary purpose will be for consumption by mobile apps (iPhone, Android, Symbian, etc). I've been looking into different mechanisms for authentication and authorization for web-based APIs (by studying other implementations). I've got my head wrapped around most of the fundamental concepts but am still looking for guidance in a few areas. The last thing I want to do is reinvent the wheel, but I'm not finding any standard solutions that fits my criteria (however my criteria my be misguided so feel free to critique that as well). Additionally, I want the API to be the same for all platforms/applications consuming it.
oAuth
I'll go ahead and throw out my objection to oAuth since I know that will likely be the first solution offered. For mobile applications (or more specifically non-web applications), it just seems wrong to leave the application (to go to a web-browser) for the authentication. Additionally, there is no way (I am aware of) for the browser to return the callback to the application (especially cross-platform). I know a couple of apps that do that, but it just feels wrong and gives a break in the application UX.
Requirements
User enters username/password into application.
Every API call is identified by the calling application.
Overhead is kept to a minimum and the auth aspect is intuitive for developers.
The mechanism is secure for both the end user (their login credentials are not exposed) as well as the developer (their application credentials are not exposed).
If possible, not require https (by no means a hard requirement).
My Current Thoughts on Implementation
An external developer will request an API account. They will receive an apikey and apisecret. Every request will require at minimum three parameters.
apikey - given to developer at regisration
timestamp - doubles as a unique identifier for each message for a given apikey
hash - a hash of the timestamp + the apisecret
The apikey is required to identify the application issuing the request. The timestamp acts similarly to the oauth_nonce and avoids/mitigates replay attacks. The hash ensures that request was actually issued from the owner of the given apikey.
For authenticated requests (ones done on the behalf of a user), I'm still undecided between going with an access_token route or a username and password hash combo. Either way, at some point a username/password combo will be required. So when it does, a hash of several pieces of information (apikey, apisecret, timestamp) + the password would be used. I'd love feedback on this aspect. FYI, they would have to hash the password first, since I don't store the passwords in my system without hashing.
Conclusion
FYI, this isn't a request for how to build/structure the API in general only how to handle the authentication and authorization from solely within an application.
Random Thoughts/Bonus Questions
For APIs that only require an apikey as part of the request, how do you prevent someone other than the apikey owner from being able to see the apikey (since sent in the clear) and make excessive requests to push them over usage limits? Maybe I'm just over thinking this, but shouldn't there be something to authenticate that a request was verified to the apikey owner? In my case, that was the purpose of the apisecret, it is never shown/transmitted without being hashed.
Speaking of hashes, what about md5 vs hmac-sha1? Does it really matter when all of the values are hashed with with sufficiently long data (ie. apisecret)?
I had been previously considering adding a per user/row salt to my users password hash. If I were to do that, how could the application be able to create a matching hash without knowing the salt used?
The way I'm thinking about doing the login part of this in my projects is:
before login the user requests a login_token from the server. These are generated and stored on the server on request, and probably have a limited lifetime.
to login the application calculates the hash of the users password, then hashes the password with the login_token to get a value, they then return both the login_token and the combined hash.
The server checks the login_token is one that it has generated, removing it from its list of valid login_tokens. The server then combines its stored hash of the user's password with the login_token and ensures that it matches the submitted combined token. If it matches you have authenticated your user.
Advantages of this are that you never store the user's password on the server, the password is never passed in the clear, the password hash is only passed in the clear on account creation (though there may be ways around this), and it should be safe from replay attacks as the login_token is removed from the DB on use.
That's a whole lot of questions in one, I guess quite a few people didn't manage to read all the way to the end :)
My experience of web service authentication is that people usually overengineer it, and the problems are only the same as you would encounter on a web page. Possible very simple options would include https for the login step, return a token, require it to be included with future requests. You could also use http basic authentication, and just pass stuff in the header. For added security, rotate/expire the tokens frequently, check the requests are coming from the same IP block (this could get messy though as mobile users move between cells), combine with API key or similar. Alternatively, do the "request key" step of oauth (someone suggested this in a previous answer already and it's a good idea) before authenticating the user, and use that as a required key to generate the access token.
An alternative which I haven't used yet but I've heard a lot about as a device-friendly alternative to oAuth is xAuth. Have a look at it and if you use it then I'd be really interested to hear what your impressions are.
For hashing, sha1 is a bit better but don't get hung up about it - whatever the devices can easily (and quickly in a performance sense) implement is probably fine.
Hope that helps, good luck :)
So what you're after is some kind of server side authentication mechanism that will handle the authentication and authorisation aspects of a mobile application?
Assuming this is the case, then I would approach it as follows (but only 'cos I'm a Java developer so a C# guy would do it differently):
The RESTful authentication and authorisation service
This will work only over HTTPS to prevent eavesdropping.
It will be based on a combination of RESTEasy, Spring Security and CAS (for single sign on across multiple applications).
It will work with both browsers and web-enabled client applications
There will be a web-based account management interface to allow users to edit their details, and admins (for particular applications) to change authorisation levels
The client side security library/application
For each supported platform (e.g.
Symbian, Android, iOS etc) create a
suitable implementation of the
security library in the native
language of the platform (e.g. Java,
ObjectiveC, C etc)
The library
should manage the HTTPS request
formation using the available APIs
for the given platform (e.g. Java
uses URLConnection etc)
Consumers of the general authentication and
authorisation library ('cos that's
all it is) will code to a specific
interface and won't be happy if it
ever changes so make sure it's very
flexible. Follow existing design
choices such as Spring Security.
So now that the view from 30,000ft is complete how do you go about doing it? Well, it's not that hard to create an authentication and authorisation system based on the listed technologies on the server side with a browser client. In combination with HTTPS, the frameworks will provide a secure process based on a shared token (usually presented as a cookie) generated by the authentication process and used whenever the user wishes to do something. This token is presented by the client to the server whenever any request takes place.
In the case of the local mobile application, it seems that you're after a solution that does the following:
Client application has a defined Access Control List (ACL) controlling runtime access to method calls. For example, a given user can read a collection from a method, but their ACL only permits access to objects that have a Q in their name so some data in the collection is quiety pulled by the security interceptor. In Java this is straightforward, you just use the Spring Security annotations on the calling code and implement a suitable ACL response process. In other languages, you're on your own and will probably need to provide boilerplate security code that calls into your security library. If the language supports AOP (Aspect Oriented Programming) then use it to the fullest for this situation.
The security library caches the complete list of authorisations into it's private memory for the current application so that it doesn't have to remain connected. Depending on the length of the login session, this could be a one-off operation that never gets repeated.
Whatever you do, don't try to invent your own security protocol, or use security by obscurity. You'll never be able to write a better algorithm for this than those that are currently available and free. Also, people trust well known algorithms. So if you say that your security library provides authorisation and authentication for local mobile applications using a combination of SSL, HTTPS, SpringSecurity and AES encrypted tokens then you'll immediately have creditibility in the marketplace.
Hope this helps, and good luck with your venture. If you would like more info, let me know - I've written quite a few web applications based on Spring Security, ACLs and the like.
Twitter addressed the external application issue in oAuth by supporting a variant they call xAuth. Unfortunately there's already a plethora of other schemes with this name so it can be confusing to sort out.
The protocol is oAuth, except it skips the request token phase and simply immediately issues an access token pair upon receipt of a username and password. (Starting at step E here.) This initial request and response must be secured - it's sending the username and password in plaintext and receiving back the access token and secret token. Once the access token pair has been configured, whether the initial token exchange was via the oAuth model or the xAuth model is irrelevant to both the client and server for the rest of the session. This has the advantage that you can leverage existing oAuth infrastructure and have very nearly the same implementation for mobile/web/desktop applications. The main disadvantage is that the application is granted access to the client's user name and password, but it appears like your requirements mandate this approach.
In any case, I'd like to agree with your intuition and that of several other answerers here: don't try to build something new from scratch. Security protocols can be easy to start but are always hard to do well, and the more convoluted they become the less likely your third-party developers are to be able to implement against them. Your hypothetical protocol is very similar to o(x)Auth - api_key/api_secret, nonce, sha1 hashing - but instead of being able to use one of the many existing libraries your developers are going to need to roll their own.
Super late to the party but I wanted to throw in some additional points to consider for anyone interested in this issue. I work for a company doing mobile API security solutions (approov) so this whole area is definitely relevant to my interests.
To start with, the most important thing to consider when trying to secure a mobile API is how much it is worth to you. The right solution for a bank is different to the right solution for someone just doing things for fun.
In the proposed solution you mention that a minimum of three parameters will be required:
apikey - given to developer at registration
timestamp - doubles as a unique identifier for each message for a given apikey
hash - a hash of the timestamp + the apisecret
The implication of this is that for some API calls no username/password is required. This can be useful for applications where you don't want to force a login (browsing in online shops for example).
This is a slightly different problem to the one of user authentication and is more like authentication or attestation of the software. There is no user, but you still want to ensure that there is no malicious access to your API. So you use your API secret to sign the traffic and identify the code accessing the API as genuine. The potential problem with this solution is that you then have to give away the secret inside every version of the app. If someone can extract the secret they can use your API, impersonating your software but doing whatever they like.
To counter that threat there are a bunch of things you can do depending on how valuable the data is. Obfuscation is a simple way to make it harder to extract the secret. There are tools that will do that for you, more so for Android, but you still have to have code that generates your hash and a sufficiently skilled individual can always just call the function that does the hashing directly.
Another way to mitigate against excessive use of an API that doesn't require a login is to throttle the traffic and potentially identify and block suspect IP addresses. The amount of effort you want to go to will largely depend upon how valuble your data is.
Beyond that you can easily start getting into the domain of my day job. Anyway, it's another aspect of securing APIs that I think is important and wanted to flag up.