I have a json API for some resources owned by users. I have protected API access using an API access key as described in this railscast: http://railscasts.com/episodes/352-securing-an-api
This works fine, I have a unique key for each user that they have to submit when they want to add/update/delete a resource. The problem I'm having is, aside from the API, users should be able to edit the resources from a Web form. This does not work though, since the form does not submit the API key in the header and so access is denied.
Is there a way to get the form to send the access key for the user since they are logged in already? Or perhaps I am going about it wrong? Perhaps I should check if there is a active session and in that case use that as authentication instead of the API Key?
Is there a way to get the form to send the access key for the user
since they are logged in already?
The API access key can be sent for the user by including it as a hidden field in the form. Once you receive it, you can compare it with the assigned access key for the logged-in user.
But think about your customers and your business. Including the API key in a clear-text within the form is like giving the hackers, literally, access to alter anything they want, especially if HTTPS is not configured.
Perhaps I should check if there is a active session and in that case use that as authentication instead of the API Key?
Yes, this is one of the secure methods to do it. The first method you mentioned is not secure at all. Don't put any thing related to authenticating in a place where it can be easily altered (form, cookie).
If you wish, you can use both session-based authentication with API access Key. How? Lets say you generate an API access key with expiry date for each modification request. Each modification is required to be submitted within x minutes after it is triggered. Once submitted, you authenticate the user against session and the modification against API. This is just an example.
Related
I currently have a backend running on AWS Lambda and I'm using DynamoDB as a database. In Dynamo, there is a list of users and each user has specific permissions as to what routes they have access to through the API. There is no issue here.
I have not built the front end yet, but I will be logging in users using Google Auth, more specifically with the react-google-login component.
My question is: Once a user is logged in to the site, should I trust the JWT from Google (after verifying its legitimacy
here with the Google API) which returns the user information (Name, Email), lookup the user item inside of Dynamo to retrieve their permissions, and then serve their request?
This seems like the logical thing to do but I was looking for some confirmation. My one worry is that someone could use a supervisors name & email to authorize a request but if the lambda must accept a JWT created by Google as entry, I believe this problem is solved correct?
I have API Keys as well for every user for some external functionality, but I have that covered since it's just a Dynamo call away. My only concern is with the front end requests to Lambda since I do not want to roll my own auth/jwt.
Here is what I was envisioning.
Thank you!
Normally you should use access tokens for that purpose. The ID token should be meant only to authenticate the user, and the access token should be used to authorize access.
The best scenario would be to have a separate Authorization Server which could issue access tokens, and there are some open source solutions out there which you can use.
If you really don't want to setup your own AS then you could follow the scenario you outlined - the part with verifying JWT from Google and checking permissions in the DynamoDB is what the Authorization Server would normally do to issue an access token.
Just remember to thoroughly validate the incoming JWT - not only the signature with Google, but also check if that is a token created for your client / audience, etc. Otherwise someone could take a Google ID token JWT from their client and gain access to your API. This article lists best security practices when working with JWTs.
Also remember that ID tokens might have short expiration times and there are no means of automatically refreshing them (like you can do it with a refresh token in case of an access token), so you might end up having to reauthenticate quite often.
I am building an API for my rails app. Through that API I will log users in and allow them to interact with their data.
On top of that users authentication, I will also like to make sure only my iOS app has access to the API, and eventually my own web app.
I want to make sure no one else will be using the API, so on top of the user authentication, I will like to protect my API with a token for each of my apps.
How do you usually solve this problem? Would I have to pass that token over on each call in order to authenticate that the call is coming from a valid client and identify which client it is (web vs iOS).
I will very much appreciate any pointers or if you know of an article explaining how to deal with this.
As you are already using jwt's to authenticate your user, why not just use the functionality of jwt to include additional information in the token, in this instance some form of hashed string that you can verify server side if it is a valid "client id".
On each request you could refresh the string.
Kind of dual authentication in each request. the user and the client.
I use gem 'rack-oauth2-server'. Currently I need add access to API by email/password from mobile app.
About problem:
Gem provide access token from 'oauth/access_token' endpoint. This require next parameters: 'email', 'password', 'client_id', 'secret'.
'client_id' and 'secret' - fields of oauth client from mongodb collection. Client have setting to scope access. I have few user types. For each user type be different access scope(different oauth clients).
So, a problem: I want allow get access to api from mobile app for any user type, but, before login, i don't know which type have user. So, mobile app can't know which client_id and sercret should be passwed to 'oauth/access_token' request.
Maybe exist some pre-hook for rails requests or another method for add params to request on fly(server side)? Note: before_filter not can be used, because 'rack-oauth2-server' called before callbacks.
P.S. Excuse me for my bad English.
Maybe exist some pre-hook for rails requests or another method for add params to request on fly(server side)? Note: before_filter not can be used, because 'rack-oauth2-server' called before callbacks.
Rails app is a stack of Rack middleware. So, you can write a new one that identifies and adds/sets/updates request variables that you need. The link above explains the concept and how to add/manage custom middlewares.
So, a problem: I want allow get access to api from mobile app for any user type, but, before login, i don't know which type have user. So, mobile app can't know which client_id and sercret should be passwed to 'oauth/access_token' request.
Having said that, it seems like you are confusing the meaning of client_id in oAuth context. A client is the application, in your case the mobile app, that is registered and connects to your oAuth endpoint. So, the same mobile application (ideally) should not be connecting using different client_ids. Just have a different forms or a dropdown that would allow your users to select how they want to login and set the appropriate scope param.
PS. Since you are using Client Credentials grant type, make sure you are using secure connection.
I am working with an Arduino that I want to send data to a remote or local Rails RESTful API of mine. When building its front-end, I can login with devise and authenticate. But I am wondering what happens when you want a third party device to POST data to the backend ?
One choice could be to use random generated long hashes as keys, as Twitter does (a client key for example and an API key) which of course is not secure but decreases the chances someone will POST data easily to another account.
However, If I am right, the data will be sent over an http connection so they could be easily sniffed. There is no problem sending temperature data, but If someone decides to send RFID IDs and names etc. it could be a vulnerability.
How could I send data with a POST request to a RESTful Rails backend API:
authenticated?
secured?
authenticaed?
You will need an endpoint that the 3rd party can call (let's call him Zed). Zed sends a request (POST) to that endpoint with his email address. Devise then sends an email to Zed, with a confirmation link that contains a confirm_token. Zed clicks the link, which opens a page where he can enter a password. Once entered, he is logged in and an auth_token is stored against his user id. Subsequently he can use that auth_token to make further requests by passing the token in an Authorization header. The 'confirm_token' is throw away (you can set it to auto-expire after a given time period).
Obviously this requires Zed to manually create his account and login. Even if you setup a 3rd party 'developer program' you still need those developers to sign-up and generate tokens for them that they can pass in requests to your api. All of this should of course be done over https. Devise provides almost all of this capability out of the box.
secured?
HTTPS helps with the 'sniffing' aspect. The method above is secure, since only people who provide an email account they have access to can create accounts and get tokens that they can then user for later requests. However, you could use mobile phone number/sms as a second factor (google 2-factor authentication).
Without authenticaion - well, sort of
The only other option I can think of is that you issue known users a 'signing key'. They sign (encrypt) their request with this key. Since the key should only be known to them and can only be decrypted by the server using the matching public key, the data can be sent over HTTP. If anyone sniffs it, they almost certainly cannot crack the key to see what the real data is. All they can really do is mimic the request and keep sending that same request to the server repeatedly in a DOS attack.
But you still have to solve the problem of how do you verify WHO you are giving keys to - ie you still need to verify who Zed is somehow. Do you plan to do that offline and then email that 'verified' individual their private key? Using RoR, I still recommend sticking with Devise as most of the grunt work is done for you already.
Creating an angularjs single page application trying to use a RESTful API and I came across a problem that I can't seem to find an answer for. I was trying to prevent session hoping, one user logged in watching the requests figures out his account ID is 13. So he performs the same request but this time alters the request to get info for account ID 14.
So after the user logged in I was setting a session variable to his account ID and was going to strip the account ID out of the ajax requests. I then tried to access the Session from a class inheriting from ApiController. After looking around I realize that storing session information is not very RESTful.
So how would I go about ensuring that one account cannot access another account's information just because they watched the ajax requests and figured out how to manipulate the ajax request?
Is restful not meant to be used with users that need to authenticated and authorized? I was thinking of maybe hashing the IDs or something but I am not sure that is the right approach.
UPDATE:
I have token based authentication working now. But I am still in the dark as to how to prevent someone from fiddling with HTTP request and getting information that doesn't belong to him. For Example, I want to retrieve all the users for account with ID 14.
HTTP Get /users/14
I have a token so I know that the person trying to use the web API at some point authenticated themselves. I can lock it down to roles. But there is nothing stopping this authenticated person form fiddling/hacking with the request and doing the following
HTTP Get /users/58
Now the person has got all of account with ID 58's information. This is information does not belong to account 14 but now he can browse through other people's information.
I need someone of knowing that the request that comes from the browser and says it is for account with ID 14 that it really is account 14. I can put that information in the token but how do I check it in a handler or check it in the ApiController?
The problem you have described is not something unique to REST-based services. In fact, this is one of the top 10 OWASP vulnerabilities (Insecure Direct Object References). You will need to first identify the user and then authenticate the user. For identification, an ID is used, such as user ID. The identifier can be anything you want. After identification, you need to authenticate the user. This is done by authenticating the credential presented to the app, such as password. The identifier and the credential can be any thing, say the good old user name/password, or may be a token or may be an API key. It actually does not matter to the problem on hand. Once authenticated, you authorize the requests based on what the user can do in your app. The authz part is a must regardless of whether you use a token, certificate or what not. Hashing user ID or using some method to hide things is security by obscurity and is not a good practice.
Say, you are using a message handler to authenticate the credential submitted by a user. Once authentication is done you can store the account number associated with the authenticated user in the properties collection of HttpRequestMessage. This is done in the server side and no user can make the system store some random account number. Only the account number associated with the authenticated user is stored in the properties collection. With that, you can now authorize requests. Say, you can write an authorization filter that pulls this account number and compare it against the account number in the URI to determine if the request is allowed or not. By applying this filter against a GET action method, you can ensure only right folks can see right data.
For example, a user with user ID 'abc' and password 'pwd1' makes a GET request to /users/14. First step is, you will authenticate the user ID. If there is a user with ID 'abc' and password 'pwd1' in your store, you will consider the user authentic. As part of this authentication, you can pull the account number associated with the user 'abc'. Say it is 15. You will store 15 in request.properties. From your authorization filter, you can get the account number from URI, which is 14 and compare it against the one in the request, which is 15. Obviously the numbers do not match and you reject the request in the OnActionExecuting method of your filter with a 401.
What I described above is a simple approach. Better one (in terms of extensibility) will be to use claims but it will not be possible to explain all that here. You can get good amount of information related to claims-based identity from Dominick's blog.
Every request should be authenticated. If the credentials provided do not allow the user with account 13 to access data from account 14 then the request will be denied. The trick is to find a way to do authZ quickly.
You seem to be missing the information on how you want to implement authentication. As you correctly noted, using session to keep authentication information is not very restful. Here are the alternatives
Implement your own OAuth provider or use third party (for example
Azure ACS)
Implement STS provider (this is only for soap though)
Implement a custom token system, if you don't want to deal with
the above two. Basic system would take user id, salt it and encrypt with private key - but don't quote me on how secure that would be...
In all the cases, the authentication information is stored in the cookie, similar to session cookie. But it is still stateless.
The standard way on the web seems to be the oauth way, in fact the standard VS MVC template even comes with OAuth consumer implemented out of the box. So the question is, how do you link the oauth token to your internal user ID. That's really pretty simple, as you implement the "registration" step after the new user is authenticated - you keep user ID and oauth token in the database table, to link the two.
That link is quick to retrieve, and can be cached for speed. I have heard some people implement that type of credentials caching for some very big systems (google docs).