I have a server where my api is hosted -> http://000.000.0.000:8080/todos
I used apigee for managing my api security. -> http://inscripts-test.apigee.net/v1/api/todos?apikey=myapikeyhere
Those are the two URLs, one from my server and one that apigee generated for me using api key.
Ideally all api requests made to http://000.000.0.000:8080 address should be rejected and calls should be allowed only to http://inscripts-test.apigee.net address.
I am new to the world of APIs, please help me understand how these security things should work.
First things first:
You probably don't want to expose your apikey by posting it to StackOverflow. If you can, you'll want to go into the Developer Apps page and regenerate your key:
Locking down your backend requires changes at the backend, and may also require changes at the Apigee layer. To truly lock down your backend, you'll want to allow access only via https. Otherwise, your traffic and any security measures can be compromised between Apigee and your backend.
Given your change to use https, you have some options:
You can require authentication (username & password) and modify your backend to only allow authenticated users. Then assign the gateway a username and password and include them in communications.
Probably your most secure, and possibly easiest if you only allow https: you can use 2-way SSL (mutual authentication) between Apigee and your backend. Your backend validates that only the Apigee certificate is allowed to connect to your backend. See this doc on setting up Apigee to target SSL.
Related
I am building a system with an ASP.NET Core web app (incidentally, in Blazor), which let's call "Site", and some domain web services (which might someday be used by other sites), one of which let's call "CustomerService".
Following various guides and articles on how to set up authentication with Open ID Connect and Azure Active Directory for this system, I see the following possible different approaches to authentication and authorization, especially with regard to AJAX requests:
Site-only auth, passthrough: Service trusts the site; site authenticates user.
Service-only auth, passthrough: Service authenticates user; site passes through all AJAX requests.
Service-only auth, CORS Service provides site client data via CORS, with authentication; site doesn't handle AJAX requests at all.
Service and site auth, passthrough: Service and site both authenticate user; site passes through some AJAX requests.
These all seem to have significant practical problems. Is there a fifth approach, or a variation I should be considering?
Here's my elaboration of these approaches.
(1) Service trusts the site; site authenticates user:
(1a) Set up Site.Server to use Open ID Connect for users to authenticate, implement all necessary authorization on Site.Server, pass through web API calls to CustomerService, and set up CustomerService to trust requests that come from Site.Server. This looks like a bad idea because then any user can spoof Site.Server and have full access to operations that should be secured on CustomerService. Also, CustomerService would not be able to enforce authorization; we'd be trusting Site.Server to get it right, which seems suboptimal.
(1b) Same as (1a), but Site.Server would know a secret API key that would be passed to CustomerService, either in headers or the API call's querystring or body. This doesn't seem so great because the API key would never change and then could be discovered and spoofed by any user. Still, this could work, as the API key could stay secret, and we could use our secret server for both sides to retrieve it. But still CustomerService would not be able to enforce authorization; we'd be trusting Site.Server to get it right, which seems suboptimal.
(1c) Same as (1b), but we come up with a mechanism for rotating the API key occasionally. This doesn't seem so great because the API key would change and then could be discovered and spoofed by any user. Still, this could work, as the API key could stay secret, and we could use our secret server for both sides to retrieve it. But still CustomerService would not be able to enforce authorization; we'd be trusting Site.Server to get it right, which seems suboptimal.
(2) Service authenticates user; site passes through all AJAX requests: Avoid any authentication on Site.Server and instead enforce authorization/authentication on CustomerService only through Open ID Connect+Azure AD. Site.Server would have to pass through requests including headers to CustomerService. This has the benefit of putting the security in the right place, but it seems unworkable, as the user has no way to authenticate on CustomerService since the user isn't using CustomerService directly; their AJAX requests still go to Site.Server.
(3) Service provides site client data via CORS, with authentication; site doesn't handle AJAX requests at all: Avoid any authentication on Site.Server and instead use CORS to allow the user's browser to connect directly to CustomerService, requiring authentication only through Open ID Connect+Azure AD. This has the benefit of putting the security in the right place, but how can a user authenticate on a AJAX request without having done so in a human-browsable way first? My AJAX request can't redirect to microsoftonline and prompt the user, can it? Plus CORS seems like a bad idea in general--we want to move away from cross-site anything; to the user, it should appear that Site.Server is serving up both AJAX calls and HTML page requests, right?
(4) Service and site both authenticate user; site passes through some AJAX requests. Put authentication on both Site.Server and CustomerService, with the same app ID, making them appear as one and the same site as far as Azure AD knows. Site.Server could do its own authentication and restrict certain service calls from getting to CustomerService, or it could pass through requests, including headers, to CustomerService, which could then deny or grant access as well. This is what we decided to do, but I question it now, as if I add a
second service, now it has to have again the same app ID to keep this approach.
None of these approaches seem to hit the mark. Am I missing another approach that I should be considering? Or is there a variation I am missing?
Here are my thoughts on what an option 5 is:
WEB UI
Code runs in the browser and interacts with the Authorization Server to authenticate the user. A library such as OIDC Client does the security work for you.
Provides best usability and simplest code. The UI uses access tokens to call cross domain APIs. Renewing tokens is tricky though, and browser security requires some due diligence.
WEB BACK END
Is static content only, deployed around the world close to end users - perhaps via Azure CDN. Must execute zero code. Provides best performance.
WEB UI SAME AS MOBILE UI
Your Web UI in effect operates in an identical manner to a mobile UI and is quite a bit simpler, with less need for cookies + double hops.
ENTRY POINT API
The browser UI interacts with an entry point API tailored to UI consumers. This API validates tokens by downloading Azure AD token signing keys. It is also has first say in authorizing requests.
The entry point API orchestrates calls to Core APIs and Azure APIs such as Graph. The Web UI uses a single token scoped to the entry point API and you can strictly control the UI's privileges. Meanwhile the API can use Azure AD's 'on behalf of' feature to get tokens for downstream APIs so that the UI does not need to deal with this.
DOMAIN APIs
These typically run in a locked down private cloud and are not called directly by the outside world. This allows you closer control over which types of caller can invoke which high privilege operations.
BLOG POSTS OF MINE
My blog's index page has further info on these patterns and the goals behind them. Maybe have a browse of the SPA Goals and API Platform Architecture posts.
There are some working code samples on this page. In my case the hosting uses AWS instead of Azure, though concepts are the same.
We are currently analyzing the API gateway for our microservices and Kong is one of the possible candidate. We discovered that Kong support several plugins for authentication but the all based on users stored in Kong database itself. We need to delegate this responsibility to our custom auth HTTP service and don't want to add these users in API gateway database.
It's possible to do this with some code around, instead of using the OpenID connect plugin; in effect you need to implement an Authorization Server which talks to Kong via the Admin (8001) port and authorizes the use of an API with externally given User Ids.
In short, it goes as follows (here for the Authorization Code grant):
Instead of asking Kong directly for tokens, hit the Authorization Server with a request to get a token for a specific API (either hard coded or parameterized, depending on what you need), and include the client ID of the application which needs access in the call (you implement the /authorize end point in fact)
The Authorization Server now needs to authenticate with whatever IdP you need, so that you have the authenticated user inside your Authorization Server
Now get the provision code for your API via the Kong Admin API, and hit the /oauth2/authorize end point of your Kong Gateway (port 8443), including the provision key; note that you may need to look up the client secret for the application client id also via the Admin API to make this work
Include client id, client secret, authenticated user id (from your custom IdP) and optinally scope in the POST to /oauth2/authorize; these values will be added to backend calls to your API using the access token the application can now claim using the authorization code
Kong will give you an Authorization Code back, which you pass back to the application via an 302 redirect (you will need to read the OAuth2 spec for this)
The application uses its client and secret, with the authorization code, to get the access token (and refresh token) from Kong's port 8443, URL /oauth2/token.
It sounds more involved than it is in the end. I did this for wicked.haufe.io, which is based on Kong and node.js, and adds an open source developer portal to Kong. There's a lot of code in the following two projects which show what can be done to integrate with any IdP:
https://github.com/apim-haufe-io/wicked.portal-kong-adapter
https://github.com/Haufe-Lexware/wicked.auth-passport
https://github.com/Haufe-Lexware/wicked.auth-saml
We're currently investigating to see whether we can also add a default authorization server to wicked, but right now you'd have to roll/fork your own.
Maybe this helps, Martin
Check out Kong's OpenID Connect plugin getkong.org/plugins/openid-connect-rp - it connects to external identity and auth systems.
I've read some about authentication and authorization inside of asp.net web api and I've understood that i basically must use ssl in order for not letting people get hold of the authentication tokens. And if i'm not misstaken theese authenticantokens are sent inside of the header? and SSL hides theese headers for the public not to to catch up if they use some tools for internet listening? If thats the case i guess i could create a "custom" authentication by not allowing the api to run unless a specific header is sent with the api call? Which people shouldn't be able to catch up if i use ssl?
I realized I've used alot of questionmarks but it is just to illustrate where my unclear thoughts are, any help or input is highly appreciated, thanks!
Authentication, Authorization and securing the connection over SSL are 3 different parts of a web application.
Authentication
Basically authentication handles who you are. For example with a login you provide a user and a password. The application knows now, who you are.
Authorization
Authorization manages the access rights for the user. It says, on what you have access. For example if you've provided the correct credentials, you are authenticated, but maybe not authorized for everything.
SSL
SSL is securing the connection like you said. You can't sniff (with WireShark or Fiddler) the network traffic if it's over HTTPS. This is a setting on your IIS on which the web api application is running. You don't need to create a "custom" authentication.
I hope this helps.
I have developed a stateless API on a server at api.com. Some API endpoints require authentication.
I have a website on a separate server at website.com. When a user authenticates with the website, the website server needs retrieve some data from an API endpoint which requires authentication (/tweets, for example). This data will be used in the server response (to render the tweets, for example).
The server response will also download some JavaScript in the browser that will subsequently need to retrieve (via XMLHttpRequests (XHR)) some data from an API endpoint which requires authentication (/tweets, for example).
This architecture represents an isomorphic web application. The server renders the whole page when requested, and thereafter the client handles user actions using JavaScript.
--
At a very basic level, I could use HTTP Basic Authentication for both website.com and api.com. However, the browser would prompt the user to enter their credentials when they first login to website.com, and repeatedly when the client makes an XHR to a endpoint requiring authentication.
I want the user to login with their credentials once at website.com. This is similar to the current Twitter website. Once you login to twitter.com, the website server identifies you as authenticated and responds with a HTML page containing JavaScript downloads. The JavaScript app then (presumably) makes authenticated XHRs to the stateless Twitter API.
The API is a separate server by design. Eventually the API could be opened up for third parties, although this is not an initial requirement.
How can I achieve this? I'm looking for:
the simplest secure solution
a solution that uses OAuth (if applicable)
Both would be great!
The situation you describe is exactly what OAuth is designed for: a client authorizes with one server and then obtains access to resources on another server. In your case, website.com is the authorization server and api.com is the resource server. In a nutshell, the authorization server sends an access token to the client, which the client can then pass on to the resource server to prove that they have permission to access the resource. In order for this to work, the resource server (api.com) needs to either check back with the authorization server (website.com) to verify that the token is valid or be informed about the token in advance. So there is a triangle of communication between the client, the authorization server and the resource server in which a shared secret is passed around. Because of this, it is absolutely necessary to use secure connections (HTTPS) in all parts of the chain; otherwise, someone could intercept the token and pretend to be the authorized client. This is kept within reasonable bounds by using limited-access tokens which do not fully authenticate the user, but it is nonetheless a problem that you should try to prevent.
While theoretically secure, OAuth is a complicated system and it is hard to get right. Some people think it is practically impossible to get right (notably Eran Hammer, the original lead author of the OAuth 2.0 specification who decided to withdraw from the working group). However, given that you need to use HTTPS anyway, you could avoid OAuth altogether and instead use a little-known builtin feature of HTTPS (or actually, TLS) called (surprise!) client authentication.
As you probably already know, in the HTTPS protocol, the server (website.com) uses a certificate signed by a trusted authority to authenticate itself. This is a well understood and very secure mechanism (at least by internet standards), provided that the certificate is uncompromised and that the latest version of TLS is used. The client can do the same, i.e. authenticate with a certificate that was signed by a trusted authority. The latter authority can be the server (website.com) for this purpose, because the server can trust itself. So the elegance of TLS client authentication is that the client does not need to contact a third party in order to obtain a certificate; the client and the server can cooperate to provide the client with a certificate that the server can trust. This is potentially even very user-friendly, because the client certificate needs to be transferred and installed only once and can then be used for authentication on subsequent sessions, possibly without the user even needing to enter a password. The same client certificate can also be used for HTTPS connections with other servers (e.g. api.com), provided that those servers know about the certificate and trust the authority that signed it (website.com).
TLS client authentication is likely to be more secure than OAuth, while it might require less interaction from the user overall (depending on the way in which the client certificate is handled in the browser). On the other hand, most users are probably unfamiliar with the particular mechanics of TLS client authentication. If users need to log in from many different devices or need to authenticate to many different servers, this workflow may be confusing or cumbersome because each device needs to have a certificate and the certificate may have to be selected manually by the user when a new server is visited for the first time.
To summarize:
In both cases, website.com provides the client with a means to authorize for access to api.com, which api.com needs to know about. So api.com cannot be 100% stateless; it needs to have some knowledge about the means of authorization that website.com communicated with the client.
Both cases require a secure connection (HTTPS).
In OAuth, the means to authorization is a "shared secret" limited access token (also known as "pseudoauthentication"), while in TLS client authentication, it is a private certificate that fully authenticates the client because it was signed by a trusted authority.
In OAuth, authorization is done on the data layer (applications explicitly communicate the access token) while in TLS client authentication, authentication is done on the transport layer (meaning that your API does not actually need to be aware of authentication or even authorization, if the webserver is configured to allow certain endpoints only to authenticated clients).
TLS client authentication is probably more trustworthy, but OAuth is probably more familiar to users because it works with password logins "as usual".
Some clarifications in response to the comments:
How does website.com know the user is logged in? How does website.com remember the user is logged in (i.e. between browser refreshes)?
By storing the access token in a secure cookie on the client side. On every request from the client to website.com, the access token is included in the request headers. This way, website.com can be assured that every request is either authenticated (if the request contains the access token, i.e. the user is logged in), or the visitor is a guest.
How does the browser make authenticated XHR requests?
By sending the access token in the request header, just like for website.com. Obviously, this requires the cookie to be accessible to the client.
website.com needs to authenticate with api.com when creating the server response
When it does that, it just sends a (HTTPS) request on the user's behalf. It's the same thing where the access token is included in the request headers. website.com always has the access token of the user when it does this, because it either is about to provide it to the user or it just received it from the user.
Further information on Wikipedia:
https://en.wikipedia.org/wiki/Oauth
https://en.wikipedia.org/wiki/HTTP_Secure#Use_as_access_control
https://en.wikipedia.org/wiki/Transport%5FLayer%5FSecurity#Client-authenticated%5FTLS%5Fhandshake
As Julian mentioned OAuth is complicated and hard to get right. I would find a trusted opensource project and use that as your Identity Server.
Also, instead of OAuth, I would look into OpenID Connect. It is a relatively new protocol (Jan 2014), but has been getting a lot of attention. Google+ for example is using it. It combines the authorization framework of OAuth and adds the identity and authentication framework on top. OAuth was never truly designed for that, which is one of the reasons why Eran left the project. This new protocol is the future of Single Sign On and will replace WS-Federation and SAML. http://openid.net/connect/
Here are all the current libraries available: http://openid.net/developers/libraries/
Again, if you're using C#/.NET, here is their project currently in Beta 3 (should be live in Januaray) that provides every possible configurable scenario with examples. If nothing else, it gives you the code to see how you can implement it. https://github.com/thinktecture/Thinktecture.IdentityServer.v3.Samples
See this talk for more details: http://vimeo.com/97344501
Hopefully this gives you some food for thought.
I think something like this can be done
1) User logs in at website.com, website.com will create a temporary token T for future API usage
2) Whenever some data is required from api.com, website will request that data and send token T in the request api.com/getdata/params=...&token=T
This request is better done with SSL to protect the token.
Please also check http://en.wikipedia.org/wiki/Cross-origin_resource_sharing - not all browsers will let you request data from another domain from Javascript.
3) When api.com receives such a request, it will make a separate and secret connection to website.com, something like website.com/checktoken/?token=T and get all necessary information about the user at website.com to send him relevant data
4) User gets all information, not leaving website.com and not having to authenticate at two places
Basically, you need to decide whether you want to authorize website.com domain to use api.com methods, or to authorize users of website.com to use api.com. From your description I understand that your are talking about the second case.
Then some kind of OAuth(OAuth2.0) implementation could be suitable for you with(probably) a single authentication point for the all your sites: it could be the passport.com. When user wants to use api.com or website.com or any other your site, he will be redirected to passport.com and required to authenticate there. After authentication on passport.com, user will be redirected back and provided with authorization code, that is used to request token, that, in turn, could be used by api.com and website.com to get information about the user(roles, permissions etc). On website.com you could use this token to access api.com, because api.com could use this token to validate user against passport.com. Also you could use this token to request info from api.com by AJAX(you need to overcome the Same Origin Policy problem, though, but it's feasible).
UPDATE:
The idea is that user needs to be authenticated on passport.com to use website.com & api.com.
From the OAuth2.0 standpoint you could say that user authorizes website.com & api.com to use his info on passport.com.
So authentication cookie exists only for passport.com domain and
is not sent anywhere else(to website.com or api.com). This is according to the Same Origin Policy.
So more detailed description of OAuth2.0 implementation in your case would be:
User wants(or have to) to be authenticated on website.com. Request to the passport.com is performed(with specified REDIRECT_URL on website.com where to return later): passport.com/auth/?redirectTo=REDIRECT_URL
If user is not authenticated on passport.com(there is no Auth cookie there) then login page of passport.com is displayed to him. When authenticated, new AUTHORIZATION_CODE is saved on passport.com(in database) for that user.
After authentication on passport.com(or if user already was authenticated there) passport.com redirects user back to REDIRECT_URL with AUTHORIZATION_CODE in querystring: {REDIRECT_URL}?code=AUTHORIZATION_CODE
Website.com uses this AUTHORIZATION_CODE to request ACCESS_TOKEN from passport.com:
passport.com/token/?code=AUTHORIZATION_CODE
Having ACCESS_TOKEN, website.com could use it to request information about user from passport.com. Plus you could pass this ACCESS_TOKEN to api.com when requesting something from api.com. api.com could check user's identity against passport.com to check if he has enough permissions. Is it safe to pass ACCESS_TOKEN to api.com? You need to provide some sort of key to api.com anyway(if api.com is not a public api), so using this approach at least ACCESS_TOKEN is not a static one: it has lifetime, and it's user-based.
Again, it's very simplified OAuth2.0 example without secret keys, scopes, access grants and few other details.
Here is a simple way. It adds some overhead/latency, but at least it works and is dead simple:
let website.com act as a proxy and forward all calls to api.com
browser <-> https://website.com/api/url <-> https://api.com/url
You can just reuse the creditentials to make a separate session from website.com to api.com
I've been digging through stackoverflow / security.stackexchange threads and getting no definite answers on providing a universal way for clients to securely consume RESTful services I'm am building through asp.net's web api. In searching for this answer, I see "authorization" and "authentication" used interchangeably, so I want to point out that I am merely wanting to verify both a requests identity and legitimacy. So, at this point, I am not authenticating users.
Amazon's model seems to be the model referenced when "rolling your own," but, in this context, I do understand Amazon has supplied the "papers" per say, so not much reinvention going on here. This post,
Designing a Secure REST (Web) API without OAuth, was super helpful.
What I gather is:
The application must require SSL requests, so a GET at "http://myapi.com/users/1" should be rejected with a bad request response letting the developer know https is required.
An app key / secret must be supplied by the client to verify who they are.
SSL + certificates is a good idea
Require a nonce value
When a client registers their app, require input of URL and IP that they will send requests from to verify upon receiving a request. My concern with this has been the portability of an external app, i.e. app is moved to new server with different IP and now it doesn't work.
I have few problems with 2 that, perhaps, my mind can't wrap itself around. First, isn't an app secret supposed to be secret? So, if a javascript client makes a request doesn't this compromise the app key's secrecy? Why have an app secret then when I can verify the requests identity through a combination of verifying app key, nonce value, and server ip? I do understand that a server side language such as php, ruby, or c#.net wouldn't expose the secret, but I would like this to be universally secure for JS and compiled languages alike.
Finally, Facebook has a developer security checklist telling developers to "Never include your App Secret in client-side or decompilable code," which would suggest an encrypted web.config or the like to me. This solution wouldn't work for exposing the REST service to anyone consuming via javascript.
Other threads I've combed through:
http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
https://developers.facebook.com/docs/facebook-login/security/
Best Practices for securing a REST API / web service
Security of REST authentication schemes
HTTP Basic Authentication instead of TLS client certification
RESTful Authentication
The way I secure my app is with OpenID Connect. For your example, the client you are talking about in #2 would be the RP (resource provider) and an authentication system like Google would be your OP (OpenID provider)
An app key / secret must be supplied by the client to verify who they are.
would actually be your application and your client secret would not leave your server any more than your /etc/passwd file. This secret is what is used by the RP to talk to the OP to get the data.
The flow in a nutshell is
User connects to your API endpoint e.g. /restapi
Your endpoint redirects the user to Google where you have registered your application
User signs into the OP (e.g. Google) and gets a code to pass to the RP
RP will go to OP to get openid information e.g. e-mail
RP will then use that openid information to look up its own authorization tables
Once RP validates the authorization for the user RP will provide the rest of the information.