How to secure an API connection from a static site hosted on a CDN - api

How can I protect an API request sent from a static site hosted on a CDN?
Use case:
A single page application using react is hosted on S3 + Cloudfront. The site calls the Yahoo Finance API to request some market data. The third-party API uses an API key to authenticate the requests. I can only store the third party API key in the static site making it available for anyone.
Considerations:
The static site and the API are not in the same cloud provider or service, so a solution using roles wouldn't work.
A Lambda (Function) proxy solution is my best choice at the moment IMO but this would still allow a request to be sent directly to the Lambda (Function).
The request to the function should also be secure, making the above option still vulnerable. This means that getting the URL to the Proxy Function from the source code and calling the Function is not acceptable either.
Looked around at some other questions posted but I haven't found one that addresses the particular circumstances stated here.

Related

How to do authentication with a site and two reusable web services with Open ID Connect and Azure AD?

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.

How to securely store an API key in static website

I have a SPA website that is hosted in AWS s3 and served by cloudfront
There are multiple CNAMES that connects to this website, e.g. A.Mysite.com, B.Mysite.com
I have an API that the static website connects to that only want to serve content for A if the request comes from A.Mysite.com and B if the request comes from B.Mysite.com
Where should I store the API key? I'm guessing it's a bad idea to expose API key on the client side right?
I've looked through OAuth, JWT tokens etc. it seems like no matter what way, I still have to send a Access Key to the client side if I don't have a server...
Please help me understand this, since i'm very confused on how security between a static site and API can be achieved without a server.
Have you looked into Environment variables?
https://www.twilio.com/blog/2017/08/working-with-environment-variables-in-node-js.html
https://hackernoon.com/how-to-use-environment-variables-keep-your-secret-keys-safe-secure-8b1a7877d69c

How to restrict api gateway rest api to CloudFront hosted S3 website

I have hosted a S3 static site into CloudFront. That site using rest api deployed into api gateway. API gateway has not access control.
I want to protect my api from being accessed by others. Only my static site can access it. I know I can use api key but that could expose by browser console which is not expected.
Is there other way to control my api access?
Thanks in advance
I have a similar issue as well. It seems like using referer or CORS restrictions are the best way to go. However, in practice I haven't been able to make it work after trying both CORS and referer restrictions. API Gateway has automatic protection against malicious behavior like DDOS attacks according to their FAQs, but it is disheartening that I haven't found a specific solution for protecting my API gateway that is only used for my S3/Cloudfront static site.
Google Cloud allows you to use their API keys on the frontend for integrations with services like Google Maps. The way they protect those keys is through restricting the API keys to certain domains. Unfortunately, I haven't found similar functionality for AWS keys. As you know, the only way to throttle or put quotas on API gateway is through API keys, so it looks like this would be useless for a static site that can't expose those API keys publicly on the frontend.
It defeats the whole purpose of going completely serverless if I am unable to configure my serverless API Gateway the same way I could congfigure a normal backend EC2 server. For now, I've created billing alarms so I don't get surprised with a huge AWS bill if something goes wrong with my unprotected API gateway.

How to authenticate calls to a plumber API from an app hosted on shinyapps.io?

I want to build an app with the following architecture:
The frontend would be deployed on shinyapps.io and would make call to an API written with plumber to interact with data.
The app would be private so a user would have to authenticate with the shinyapps.io auth module. The API would be hosted on a cloud platform.
I would like to know if it is safe to authenticate calls to the API by adding a secret key to the header on all HTTP requests.
The secret key would be defined in a .Renviron file deployed on Shinyapps.io and also on the API server.
This plumber filter should ensure that the secret key from the front and from the API match before sending the appropriate response.
Define safe? It is going to work for sure. If it is exposed to the public web, assume nothing is safe.
The filter you mentionned is there specifically for this use case. But it is still not safe against DDOS attacks.
Good luck.

API security in Azure best practice

I'm developing a web API that will be called by other web apps in the same Azure host and also other 3rd party services/ app. I'm currently looking into API Apps and API management, but there are several things unclear for me regarding security implementation:
Does API App need to have authentication when implemented with API management? If yes, what are the options? This link http://www.kefalidis.me/2015/06/taking-advantage-of-api-management-for-api-apps/ mentions "Keep in mind that it’s not necessary to have authentication on the API App, as you can enable authentication on API Management and let it handle all the details." So that means having the API App authentication to public anonymous? But then someone who knows the direct URL of the API App can access it directly.
What is the best way to implement API Management security? The one mentioned in the tutorial (Having a raw subscription key passed in the header) seems to be prone to man in the middle attack
What advantages does API App add instead of implementing with normal Web API project?
Thanks in advance.
I can answer from API Management perspective. To secure the connection between API Mgmt and your backend (sometimes called last-mile security), there are a few options:
Basic Authentication: this is the simplest solution
Mutual certificate authentication: https://azure.microsoft.com/en-us/documentation/articles/api-management-howto-mutual-certificates/ - this is the most common approach.
IP Whitelisting: if you have a Standard or Premium tier APIM instance, the IP address of the proxy will remain constant. Thus you can configure firewall rules to block unknown IP addresses.
JWT token: if your backend has the capability to validate JWT tokens, you can block any callers without a valid JWT.
This video might also be helpful: https://channel9.msdn.com/Blogs/AzureApiMgmt/Last-mile-Security
I think the document meant you can do the JWT token validation in APIM. However, to prevent someone calling your backend directly, you'll have to implement one of the options mentioned above in your Api Apps