I'm creating a client-side application (i.e. HTML/CSS/JS in a web browser) that retrieves survey information from a SurveyMonkey account and generates an appropriate form to submit it. The application itself works fine, but it relies on knowing the API key to call get_survey_list and get_survey_details. The problem is that anyone could easily extract the key (e.g. by inspecting the network requests using the browser's debug tools) and perform more privileged operations like get_responses which is private information and thus should not be publicly accessible in this way.
Is there a way to create a "limited access API token" of some kind? For example, I would like to create one that is only authorized to perform certain types of API calls.
This is not possible, the only authorization token you can generate is a full access one as documented here.
Your best bet in this case is to have a proxy web app you can call, which then makes the API calls on the client's behalf.
Related
For the last few months i've been working on a Rest API for a web app for the company I work for. The endpoints supply data such as transaction history, user data, and data for support tickets. However, I keep running into one issue that always seems to set me back to some extent.
The issue I seem to keep running into is how do I handle user authentication for the Rest API securely? All data is going to be sent over a SSL connection, but there's a part of me that's paranoid about potential security problems that could arise. As it currently stands when a client attempts to login the client must provide a username or email address, and a password to a login endpoint (E.G "/api/login"). Along with with this information, a browser fingerprint must be supplied through header of the request that's sending the login credentials. The API then validates whether or not the specified user exists, checks whether or not the password supplied is correct, and stores the fingerprint in a database model. To access any other endpoints in the API a valid token from logging in, and a valid browser fingerprint are required.
I've been using browser fingerprints as a means to prevent token-hijacking, and as a way make sure that the same device used to login is being used to make the requests. However, I have noticed a scenario where this practice backfires on me. The client-side library i'm using to generate browser fingerprints isn't always accurate. Sometimes the library spits out a different fingerprint entirely. Which causes some client requests to fail as the different fingerprint isn't recognized by the API as being valid. I would like to keep track of what devices are used to make requests to the API. Is there a more consistent way of doing so, while still protecting tokens from being hijacked?
When thinking of the previous question, there is another one that also comes to mind. How do I store auth tokens on client-side securely, or in a way that makes it difficult for someone to obtain the tokens through malicious means such as a xss-attack? I understand setting a strict Content-Security Policy on browser based clients can be effective in defending against xss-attacks. However, I still get paranoid about storing tokens as cookies or in local storage.
I understand oauth2 is usually a good solution to user authentication, and I have considered using it before to deal with this problem. Although, i'm writing the API using Flask, and i'm also using JSON Web tokens. As it currently stands, Flask's implementation of oauth2 has no way to use JWTs as access tokens when using oauth for authentication.
This is my first large-scale project where I have had to deal with this issue and i am not sure what to do. Any help, advice, or critiques are appreciated. I'm in need of the help right now.
Put an API Gateway in front of your API , your API Gateway is publicly ( i.e in the DMZ ) exposed while the actual API are internal.
You can look into Kong..
Let's say I have Instagram connector inside my Logic App workflow, authenticated and authorized to perform actions on my behalf.
I can see this connection stored in "$connections": sections but there is no access token or anything that really makes this connection work with instagram API.
The problem here is that available Logic App actions for Instagram are way from complete and for some API calls I have to use plain HTTP action and inject my access token manually.
My question - where is in general this information is stored by Logic App (OAuth tokens and so on) and how to access it inside workflow?
This is not available. I see what you want to do - if Instagram introduced a new API Logic Apps doesn't support, it would be cool to use a generic HTTP action, but use the token Logic Apps already retrieved for auth.
This is not possible because, it would be a violation of the terms of use for third party services to make token available so end users can make any arbitrary call, since it may be abused. And this would risk all Logic Apps user lossing the ability to communicate with said service when our API key is revoked.
I'm developing the restful web app that using some popular web framework on the backend, say (rails, sinatra, flask, express.js). Ideally, I want to develop client side with Backbone.js. How do I let only my javascript client side interact with those API calls? I don't want those API calls to be public and be called by curl or simply by entering the link on browser.
As a first principle, if your API is consumed by your JS client, you have to assume, that it is public: A simple JS debugger puts an attacker into a position, where he can send a byte-for-byte identical request from a tool of his choice.
That said, if I read your question correctly, this is not, what you want to avoid: What you really don't want to happen is, that your API is consumed (on a regular basis) without your JS client being involved. Here are some ideas on how to if not enforce, then at least encourage using your client:
I am sure, your API has some sort of authentication field (e.g. Hash computed on the client). If not, take a look at This SO question. Make sure you use a salt (or even API key) that is given to your JS client on a session basis (a.o.t. hardcoded). This way, an unauthorized consumer of your API is forced into much more work.
On loading the JS client, remember some HTTP headers (user agent comes to mind) and the IP address and ask for reauthentication if they change, employing blacklists for the usual suspects. This forces an attacker to do his homework more thoroughly again.
On the server side, remember the last few API calls, and before allowing another one, check if business logic allows for the new one right now: This denies an attacker the ability to concentrate many of his sessions into one session with your server: In combination with the other measures, this will make an abuser easy detectable.
I might not have said that with the necessary clarity: I consider it impossible to make it completely impossible for an abuser to consume your service, but you can make it so hard, it might not be worth the hassle.
You should implement some sort of authentication system. One good way to handle this is to define some expected header variables. For example, you can have an auth/login API call that returns a session token. Subsequent calls to your API will expect a session token to be set in an HTTP header variable with a specific name like 'your-api-token'.
Alternatively many systems create access tokens or keys that are expected (like youtube, facebook or twitter) using some sort of api account system. In those cases, your client would have to store these in some manner in the client.
Then it's simply a matter of adding a check for the session into your REST framework and throwing an exception. If at all possible the status code (to be restful) would be a 401 error.
There's an open standard now called "JSON Web Token",
see https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token
JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for
creating tokens that assert some number of claims. For example, a
server could generate a token that has the claim "logged in as admin"
and provide that to a client. The client could then use that token to
prove that they are logged in as admin. The tokens are signed by the
server's key, so the server is able to verify that the token is
legitimate. The tokens are designed to be compact, URL-safe and usable
especially in web browser single sign-on (SSO) context. JWT claims can
be typically used to pass identity of authenticated users between an
identity provider and a service provider, or any other type of claims
as required by business processes.[1][2] The tokens can also be
authenticated and encrypted.[3][4]
Set a SESSION var on the server when the client first loads your index.html (or backbone.js etc.)
Check this var on the server-side on every API call.
P.S. this is not a "security" solution!!! This is just to ease the load on your server so people don't abuse it or "hotlink" your API from other websites and apps.
Excuse me #MarkAmery and Eugene, but that is incorrect.
Your js+html (client) app running in the browser CAN be set up to exclude unauthorized direct calls to the API as follows:
First step: Set up the API to require authentication. The client must first authenticate itself via the server (or some other security server) for example asking the human user to provide the correct password.
Before authentication the calls to the API are not accepted.
During authentication a "token" is returned.
After authentication only API calls with the authentication "token" will be accepted.
Of course at this stage only authorized users who have the password can access the API, although if they are programmers debugging the app, they can access it directly for testing purposes.
Second step: Now set up an extra security API, that is to be called within a short limit of time after the client js+html app was initially requested from the server. This "callback" will tell the server that the client was downloaded successfully. Restrict your REST API calls to work only if the client was requested recently and successfully.
Now in order to use your API they must first download the client and actually run it in a browser. Only after successfully receiving the callback, and then user entry within a short frame of time, will the API accept calls.
So you do not have to worry that this may be an unauthorized user without credentials.
(The title of the question, 'How do I secure REST API calls', and from most of what you say, that is your major concern, and not the literal question of HOW your API is called, but rather BY WHOM, correct?)
Here's what I do:
Secure the API with an HTTP Header with calls such as X-APITOKEN:
Use session variables in PHP. Have a login system in place and save the user token in session variables.
Call JS code with Ajax to PHP and use the session variable with curl to call the API. That way, if the session variable is not set, it won't call and the PHP code contains the Access Token to the API.
I figured this has been answered before, but a quick SO search didn't yield anything.
I have a private API that is locked down by an APIKey. This key needs to be passed for each request. With this key you can access any part of the API. Obviously that's pretty open. For the most part this is acceptable. However, there are cases where I want to ensure that the request is sent by the owner of the data.
For example, consider an update or delete request. You shouldn't be able to make this request for someone else's data. So in addition to the APIKey, I'd like to have something else to ensure that this user making the request is authorized to perform that action.
I could require that an ownerID be passed with such request. But that's quickly forged. So what have I gained.
I am interested to hear what other members of SO have implemented in these situations. Individual APIKeys? Dual-authorization?
If it matters, my API follows the REST architecture and is developed with PHP/Apache.
API keys should be unique per user. This will verify the user and that they should have access to the data.
If you want to be even more secure you can have that api secret be used as a refresh token that can be used to retrieve an access token with an automated expiration.
SSL for all requests is also suggested.
Each API user has a unique API key. This key identifies them as a single user of the system. When dealing with more sensitive data, I've used client side certificates for auth, however Basic Auth + requiring SSL is usually sufficient.
When the request comes in, map the API key to the user and then determine if that user "owns" the resource they are trying to interact with.
The whole "determine the owner" part is a separate issue that can be tricky to do nicely in an API depending on how well the system was built. I can share how we've done that in the past as well, but figured that's a bit off topic.
Suggest you should consider using Oauth. In summary this is how it should work.
Each application making the API calls will need the respective application level APIkey for authorization through the Oauth process. Apikey here would just represent the application (client) identity.
Each end-user associated with the usage must authenticate themselves separately (independent of the apikey) during the Oauth authorization process. The users identity, associated context such as scope of authorization is then encoded into a token called access token.
Once the application obtains this access token, all subsequent API calls to access resources should use the access token, until expiry.
On the API implementation side, the access token validation should reveal the end-user context (including the scope of access that is granted during the Oauth process) and hence the access/authorization to use a specific resource can be managed by the resource server.
Reading on some of the answers on here, people suggest doing userless access by calling Foursquare by:
https://api.foursquare.com/v2/venues/search?ll=40.7,-74&client_id=XXXXXXXXXXXXXXXX&client_secret=YYYYYYYYYYYYYYYYY&v=20111109
This means I have to include my client_secret key? Is this safe?
Clarification, I'm working on an iOS app using Foursquare search without the user logging in.
You should probably route the search requests via your server, which can add the client_id/client_secret information before passing it to foursquare. This will also be useful if you ever need to change your id/secret information, want to add caching, etc.
(That being said, it's perfectly common to put your client id / secret into your iOS app, but I would avoid explicitly publishing it anywhere, e.g. in any public source code)
Yes, it means that you need to include the client_id and client_secret.
Define safe :)
For facebook server-side application access, you include the app id and app secret as well (id|secret constructs the access token)
I think that the main idea behind this kind of access is to allow server-side access from the application and if the api access is done via a server script/code/web-service (and not via client-side javascript), this information remains a secret.
I guess it would be true to say that leaving this information somehow in the javascript code is not the best idea (= not safe!).