I've written a web application that interfaces to an API, in a different domain.
This API requests a username and password for certain calls (involving POST, e.g. to upload a photo to the API). For these calls the API uses https.
Is there a way I can store the username and password within the web app, so the user doesn't have to log in repeatedly each time they upload a photo?
Here's what I can think of:
The obvious way is to stick both in a cookie, but clearly that's a security hole, whether plaintext or hashed.
If it were a secure website, I could use a session ID: could I persuade the API owners to allow session IDs, or would that be impossible across domains?
Perhaps I simply have to ask the user to re-enter their username and password each time they make an API call.
Thanks!
If I understand your architecture correctly, your users are sending the API calls to a service running in a different domain. You are not a man-in-the-middle for this request, you are only providing the interface e.g. as a form-field in your web application. The user can send the API calls without you even knowing that he did.
In that case there is no way to implement this without storing some kind of authentication information in the browser (cookie, form-field, etc.) or have your users enter them for each request. They must come from somewhere and your server is not involved in the request.
What you can do is changing the architecture and start playing man-in-the-middle, like a proxy. Instead of just providing the interface, let the users send their requests to your web application instead of communicating with the service directly. Your web application adds the credentials and forwards the request to the service. The answer of the service will be sent to your web application, which can redirect it again to the user.
In this scenario your web application is responsible for authentication. Your web application adds the credentials to a request if the user sending the request was identified and has the required permissions. The credentials for the service are only passed from your web application to the service, they even can be kept hidden from the user himself.
Such a change has several implications of course. The load on your web application will increase and the logic will become more complex. Those trade offs must be considered.
Related
I would like to support this scenario in my app:
User visits standard application URL https://app.example.com/
User logs in and receives a JWT token from server, to maintain a login session
App determines that user's account has a custom domain assigned
App redirects to custom domain https://custom.customer.com/
User remains logged in without having to re-login
Step 5 is the only difficulty. Does anyone have any advice on how this can be achieved securely? I've seen suggestions to pass the JWT as a parameter in the redirect, but this seems exceedingly insecure to me.
I'm thinking of one option, that may be at least more secure... A one-use "transfer" token could be created by the server. This would be passed in the redirect URL, and the (same) app at the new URL could pass this to the server to get the JWT. Thoughts on this?
Thanks.
You should not pass the actual authentication token (jwt) in the url for multiple reasons. Sensitive data should never appear in urls.
Passing a one-time token to be exchanged for the authentication token is somewhat more secure, but you either can make it purely stateless or one-time, but not both, because you will have to remember used tokens. That's fine, just something to consider. Also if you can pass it in the request body or header, you should (eg. a post request would have it in the body instead of the url).
However, if you are doing this, you are reinventing single sign-on. What you need is already available in multiple different forms, most notably OIDC and SAML. In a more best-practice-like architecture, you would have a login endpoint that would act as the authentication provider (say an OIDC provider). That would issue auth tokens that consumers (relying parties in OIDC terms, these are basically your apps) could consume either directly or make their own sessions based on the tokens received from the identity provider.
In case of the authorization code flow, it would look something like
user visits app1, but is not logged in (does not have valid tokens or a session)
user gets redirected to the login server, where he logs in and is redirected back to the app1 with an auth code
app1 in the background could exchange the code for tokens that you could use on your backend to impersonate the user, so every backend component can make sure who the user was, and also in this step app1 can create a plain old session for the user if it wants
in subsequent requests, the user would already have the session (or an id token)
when the user visits app2, depending on what exact flow you choose, the client would either have an id token already that it could send to app2, or would be redirected to the login server, but there the user would be logged in already, so it would all be transparent from a user's perspective and app2 would just work.
A major benefit of the above is it's a standard approach, there are well-tested flows and ready-made components that you can use and with which you can achieve a reasonable assurance that they are secure. Another benefit is that all components are replacable, you can switch to another identity provider relatively easily (you can choose from many, including open source options, or very cheap hosted ones), and relying parties (apps) will also be easy and standard to make.
After spending some time reading about authentication and noticing it is pretty hard to do it well, I have decided to use firebase-authentication to authenticate my users in my vue app.
I'm listing the technologies and flow I use in this app to show each part interaction and clear things up:
I use Vue for my client javascript client
The client log-in users using firebase-authentication.
When user log-in, a call to a node.js rest api is done and a json is retrieved with its user data.
When the data is retrieved by the client, the app shows some parts and hides other depending on user privileges
So, in my Vue application I show a custom login form and use it to authenticate users through firebase. After the user log-in, I retrieve some data from my own server (just a json with different user config values) that defines how the user can interact with the app (For example, what he can or can't do in my app).
How can I retrieve this information and use it in my client app in a secure way?. I mean, as an example, say I have a piece of information in that JSON that defines if the user is a regular or admin user. How can I avoid users to modify the response from the server and elevate privileges?
There isn't anything you can do to prevent client side DOM manipulation. If it's accessible via JavaScript, it's accessible to the user. It's up to you to implement your application in such a way that sensitive information and/or functionality is not dependent on client side security (if such a thing truly exists).
What you can do is prevent unauthorized access on the server. This is the purpose of defining scopes, ACLs, etc. If a savvy user does modify the response data and, say, change their role from user to admin, your response should not contain anything meant for admin users only. Rather, that information should only be accessible after making a successful API call where your server code has authenticated/authorized the request.
Never trust the client when it comes to security. That must be done on the server.
I have an application with the following characteristics:
It's an online service offered to many companies. Each company uses a dedicated Play for Scala (Netty) application server.
Each application server accesses a dedicated MySql database.
In each database users' passwords are stored with MD5.
To login, the user needs to enter on a web page the company code, the user id and the password. Alternatively, the user may go directly to its company web page where they will enter only the user id and the password.
These are my thoughts: I could implement a Node.js application server that will redirect the login to each Play application server where the user password will be validated. Am I too way off?
Here's one way you can do it:
User enters their login info into a form on the Node.js server.
Node.js server receives the POST request and makes an HTTP(S) request to the corresponding Play server.
Play server receives the request and an action verifies the login information, returning a token to the Node.js server.
The Node.js server responds to the original POST with a redirect to the correct Play server, including the token in the redirect URL.
The Play server receives the request, verifies the token and logs the user in.
Disclaimer:
There's a lot of security stuff going on here - the Node.js-Play server communication and passing the token needs to be done securely. Think: nonces, encryption, challenges, etc. I'm not an expert so I haven't made concrete suggestions about how to secure each stage, but I know the design I've given above definitely needs more work to make it properly secure. You'll want to read up on how to do this, perhaps review existing single-sign on architectures, oauth, etc, perhaps ask some specific security-related questions.
Also, using md5s for passwords is not good practice. Use a stronger hashing algorithm with a salt. See http://john.cuppi.net/migrate-from-md5-to-bcrypt-password-hashes/ for how you can migrate without disruption.
How does one handle authentication (local and Facebook, for example) using passport.js, through a RESTful API instead of through a web interface?
Specific concerns are handling the passing of data from callbacks to a RESTful response (JSON) vs using a typical res.send({ data: req.data }), setting up an initial /login endpoint which redirects to Facebook (/login cannot be accessed via AJAX, because it is not a JSON response - it is a redirect to Facebook with a callback).
I've found https://github.com/halrobertson/test-restify-passport-facebook, but I'm having trouble understanding it.
Furthermore, how does passport.js store the auth credentials? The server (or is it service?) is backed by MongoDB, and I'd expect credentials (login & salted hash of pw) to be stored there, but I don't know if passport.js has this type of capability.
There are many questions asked here, and it seems that even though the questions are asked in the context of Node and passport.js the real questions are more about workflow than how to do this with a particular technology.
Let's use #Keith example setup, modified a bit for added security:
Web server at https://example.com serves a single page Javascript client app
RESTful web service at https://example.com/api provides server support to rich client app
Server implemented in Node and passport.js.
Server has a database (any kind) with a "users" table.
Username/password and Facebook Connect are offered as authentication options
Rich client makes REST requests into https://example.com/api
There may be other clients (phone apps, for example) that use the web service at https://example.com/api but do not know about the web server at https://example.com.
Note that I'm using secure HTTP. This is in my opinion a must for any service that is available in the open, since sensitive information like passwords and authorization tokens are passing between client and server.
Username/password authentication
Let's look at how plain old authentication works first.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form.
Many of the sections of this single page app haven't been populated with data due to the user not being logged in. All these sections have an event listener on a "login" event. All this is client side stuff, the server does not know of these events.
User enters his/her login and password and hits the submit button, which triggers a Javascript handler to record the username and password in client side variables. Then this handler triggers the "login" event. Again, this is all client side action, credentials were not sent to the server yet.
The listeners of the "login" event are invoked. Each of these now needs to send one or more requests to the RESTful API at https://example.com/api to obtain the user specific data to render on the page. Every single request they send to the web service will include the username and password, possibly in the form of HTTP Basic authentication, since the service being RESTful isn't allowed to maintain client state from one request to the next. Since the web service is on secure HTTP the password is safely encrypted during transit.
The web service at https://example.com/api receives a bunch of individual requests, each with authentication information. The username and password in each request is checked against the user database and if found correct the requested function executes and data is returned to the client in JSON format. If username and password do not match an error is sent to the client in the form of a 401 HTTP error code.
Instead of forcing clients to send username and password with every request you can have a "get_access_token" function in your RESTful service that takes the username and password and responds with a token, which is some sort of cryptographic hash that is unique and has some expiration date associated with it. These tokens are stored in the database with each user. Then the client sends the access token in subsequent requests. The access token will then be validated against the database instead of the username and password.
Non browser client applications like phone apps do the same as above, they ask user to enter his/her credentials, then send them (or an access token generated from them) with every request to the web service.
The important take away point from this example is that RESTful web services require authentication with every request.
An additional layer of security in this scenario would add client application authorization in addition to the user authentication. For example, if you have the web client, iOS and Android apps all using the web service you may want the server to know which of the three the client of a given request is, regardless of who the authenticated user is. This can enable your web service to restrict certain functions to specific clients. For this you could use API keys and secrets, see this answer for some ideas on that.
Facebook authentication
The workflow above does not work for Facebook connect because the login via Facebook has a third party, Facebook itself. The login procedure requires the user to be redirected to Facebook's website where credentials are entered outside of our control.
So let's see how things change:.
The user connects to https://example.com
The server serves a rich Javascript application which renders the initial page. Somehwere in the page there is a login form that includes a "Login with Facebook" button.
The user clicks the "Login with Facebook" button, which is just a link that redirects to (for example) https://example.com/auth/facebook.
The https://example.com/auth/facebook route is handled by passport.js (see the documentation)
All the user sees is that the page changes and now they are in a Facebook hosted page where they need to login and authorize our web application. This is completely outside of our control.
The user logs in to Facebook and gives permission to our application, so Facebook now redirects back to the callback URL that we configured in the passport.js setup, which following the example in the documentation is https://example.com/auth/facebook/callback
The passport.js handler for the https://example.com/auth/facebook/callback route will invoke the callback function that receives the Facebook access token and some user information from Facebook, including the user's email address.
With the email we can locate the user in our database and store the Facebook access token with it.
The last thing you do in the Facebook callback is to redirect back to the rich client application, but this time we need to pass the username and the access token to the client so that it can use them. This can be done in a number of ways. For example, Javascript variables can be added to the page through a server-side template engine, or else a cookie can be returned with this information. (thanks to #RyanKimber for pointing out the security issues with passing this data in the URL, as I initially suggested).
So now we start the single page app one more time, but the client has the username and the access token.
The client application can trigger the "login" event immediately and let the different parts of the application request the information that they need from the web service.
All the requests sent to https://example.com/api will include the Facebook access token for authentication, or the application's own access token generated from Facebook's token via a "get_access_token" function in the REST API.
The non-browser apps have it a bit more difficult here, because OAuth requires a web browser for logging in. To login from a phone or desktop app you will need to start a browser to do the redirect to Facebook, and even worse, you need a way for the browser to pass the Facebook access token back to the application via some mechanism.
I hope this answers most of the questions. Of course you can replace Facebook with Twitter, Google, or any other OAuth based authentication service.
I'd be interested to know if someone has a simpler way to deal with this.
I greatly appreciate #Miguel's explanation with the complete flow in each cases, but I'd like to add some on the Facebook Authentication part.
Facebook provides a Javascript SDK which you can use to get the access token on client-end directly, which is then passed to the server and used to further pull all the user information from Facebook. So you don't need any re-directs basically.
Moreover, you can use the same API end-point for mobile applications as well. Just use the Android / iOS SDK for Facebook, obtain the Facebook access_token on the client end and pass it to the server.
Regarding the stateless nature as explained, when get_access_token is used to generate a token and passed to the client, this token is also stored on the server. So it's as good as a session token and I believe this makes it stateful ?
Just my 2 cents..
Here is an awesome article I found that can help you authenticate with:
Facebook
Twitter
Google
Local Auth
Easy Node Authentication: Setup and Local
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.