After reading around it appears that trying to protect a publically accessible API (API used by an app/site that does not need a user to log in) appears to be fruitless, e.g. store key in app, user can reverse engineer app.
My question relates to how one can protect as much as possible and slow down abuse of a public accessible API...
Rate-limiting? Check request origin (although can be spoofed).... anything else?
Also if the site is SSR, could it just be protected by the server's IP?
YOUR QUESTIONS?
After reading around it appears that trying to protect a publically accessible API (API used by an app/site that does not need a user to log in) appears to be fruitless, e.g. store key in app, user can reverse engineer app.
Security is all about defense in depth, thus is all about adding as many layers as you can afford and required by law in order to mitigate the risk, therefore any defense you add it's one more layer that will prevent that simple/dumb automated scripts from accessing it, while at same time will increase the level of skills and effort necessary for an hacker poking around to overcome all defenses.
Rate-limiting?
This is kind of mandatory for any API to employ, otherwise an automated script can easily extract an huge amount of data in seconds. The more strict this rate limit is applied, the greater may be the chances for other layers of defense to detect that unauthorized access to the API may be happening and try to mitigate/block it. To bear in mind that the rate limits can be bypassed by adapting the attack to make requests that do not trigger it, and in some cases easily automated for that Software that give back in the response header the throttling values being applied.
Check request origin (although can be spoofed)....
Yest it is easily bypassed, but why not? It will be one more layer of defense that filters out some dumb automated scripts/bots.
Also if the site is SSR, could it just be protected by the server's IP?
No matter if a SSR site or any other type of app, when used from a mobile phone the IP address can change during the load of a page or mobile app screen, because when the phone switches between masters the IP will change. Also to bear in mind that in an office or public wifi all the users on it will have the same IP.
The use of it as a blocking measure on its own needs to be carefully evaluated, and normally requires fingerprinting the request in order to reduce the risk of blocking other valid users sharing the same network.
I would use it very carefully to avoid/block/throttle requests only when I could establish that hey are known bad IPs, that you can collect from your own requests history and/or from public datasets.
WHO IS IN THE REQUEST VS WHAT IS MAKING THE REQUEST
A common misconception around developers of any seniority is about not being aware that the who is in the request is not the same as what is making the request, therefore we will first clear it out...
The Difference Between WHO and WHAT is Accessing the API Server
While your API is not using user authentication is important to be aware of this distinction in order to better perform informed decisions around the security measures to be adapted in the API server.
I wrote a series of articles about API and Mobile security, and in the article Why Does Your Mobile App Need An Api Key? you can read in more detail the difference between who and what is accessing your API server, but I will quote here the main takes from it:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.
The best way to remember the difference is to think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and think about the what as the software making that request in behalf of the user.
DEFENDING THE API SERVER
My question relates to how one can protect as much as possible and slow down abuse of a public accessible API...
For Mobile APIs
For an API serving only mobile apps you can use the Mobile App Attestation concept as I describe in my answer to the question How to secure an API REST for mobile app?.
For Web APPs
For an API that only serves a Web app I would recommend you to read my answer to the question secure api data from calls out of the app?.
DO YOU WANT TO GO THE EXTRA MILE?
anything else?
It seems you already have done some research but you may not know yet the OWASP guides and top risks.
For Web Apps
The Web Security Testing Guide:
The OWASP Web Security Testing Guide includes a "best practice" penetration testing framework which users can implement in their own organizations and a "low level" penetration testing guide that describes techniques for testing most common web application and web service security issues.
For Mobile Apps
OWASP Mobile Security Project - Top 10 risks
The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.
OWASP - Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
For APIS
OWASP API Security Top 10
The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.
Just for a quick answer
I can suggest at least one via solution which is to use an API Gateway (like Kong, Express Gateway or AWS API Gateway, etc.).
The API Gateway allows you to create API consumers (e.g: buyer mobile app, seller mobile app, buyer TV app). For each API consumer, an auth key (or even OAuth 2.0 credentials) will be generated and asigned respectively.
You then can use the auth key or OAuth 2.0 credentials (ID and secret) to access the APIs securely (even for the public ones, as API Gateways will only allow access from valid API consumers).
How about request from web?
You can configure API Gateway to detect requests from web and instead of using auth key or Oauth mechanism, it can use domain white-listing CORS protection mechanism.
How about user access token (generated from successful login)? Any conflict here?
IMHO (emphasized), after getting user access token (e.g: a JWT), for every authenticated-user-only requests you will send both API Gateway auth key token user auth access token. Referencing to Exadra's answer above, we can consider API Gateway key is to verify the "what" (mobile app) while user access token is to verify the "who" (login user).
Related
I'm working on a project that involves an SPA web application built with React, connected to an API that runs Express.
I have read many articles and questions on stackoverflow. (Especially this link has a very detailed answer on it). However, there is a point that I couldn't understand. I searched the questions and couldn't find any answer that includes IP restriction on the backend API side.
I want to send JWT to authorized users that login from the SPA and store JWT in localstorage on the client side. The backend API will only be accessible from the SPA's IP address and will be closed to any other IPs. CORS will be configured to work only with the SPAs domain name as well.
So with this configuration in mind, is it still not safe to store JWTs in localstorage? As the API can only be still accessible by one IP, how can an attacker use the access Token after grabbing it with an XSS attack?
There are several attacks that can be applied in order to access the server:
Ip spoofing
SSRF
Ip validation vulnerabilities, think of the fact that you need to check ip, ip has many forms, ipv4, ipv6, hex, oct etc...
Firewall / Reverse proxy exploits
Best practices are meant to avoid mistakes, follow them.
BTW, I always recommend this article to make sense of JTW auth. (I've changed my app implementation after I've read it :) )
Is there anyway to secure an API key when using it on a React javascript file ? For example;
emailjs.init("API_KEY");
You may want to check how Google Firebase does pure client-side authentication: https://firebase.google.com/products/auth/
Edited:
This general introduction to Authentication using API-keys, OAuth etc (source: codecademy course on bulding web-apps) may help understand what API keys are meant for and why it should't be necessary to secure them. The reason is that there are other ways to deal with secret information, as described in this article.
Authentication
INTRODUCTION
Authentication is the process used by applications to determine and confirm identities of users. It ensures that the correct content is shown to users. More importantly, it ensures that incorrect content is secured and unavailable to unauthorized users.
In this article, we’ll discuss a few of the common design patterns for these interactions. You’ll need to have some basic understanding of HTTP requests, since these methods all use HTTP requests to exchange information.
PASSWORD AUTHENTICATION
The most common implementation of authentication requires a user to input their username or email and a password. The application's server then checks the supplied credentials to determine if the user exists and if the supplied password is correct. If the credentials are correct, the user is logged in and able to use the application as thatthe user.
Typically, upon a successful login, the application will respond with an authentication token (or auth token) for the client to use for additional HTTP requests. This token is then stored on the user's computer, preventing the need for users to continuously log in.
This token generally expires after a certain amount of time, ensuring the correct user is using the application over time as well.
API KEYS
While it is common to think of authentication as the interaction between a human user and an application, sometimes the user is another application.
Many apps expose interfaces to their information in the form of an API (application program interface). For example, the Spotify API provides endpoints for almost all of its functionality. This allows applications to fetch data from the Spotify music catalog and manage user’s playlists and saved music.
Since these external requests could overwhelm a service and also access user information, they need to be secured using authentication.
The most basic pattern for API access from another application is using an API key.
Public APIs usually provide a developer portal where you can register your application and generate a corresponding API key. This key is then unique to your application. When your application makes a request, this key is sent along with it. The API can then verify that your application is allowed access and provide the correct response based on the permission level of your application.
The API can track what type and frequency of requests each application is making. This data can be used to throttle requests from a specific application to a pre-defined level of service. This prevents applications from spamming an endpoint or abusing user data, since the API can easily block that application's API key and prevent further malicious use of the API by that application.
OAUTH
For many applications, a generic developer-level API key is not sufficient. As mentioned earlier, APIs sometimes have the ability to provide access to user-level data. However, most services only provide this private data if the user enables it.
For example, Facebook doesn't want Tinder to access all of their users' data, just the users who have opted in to allowing the sharing of data to better help them find a match in their area.
A basic approach to this problem might be to have the user provide their login credentials to the intermediary application, but this is not very secure and would give full access to the requesting application, when the requesting application might only need a very limited set of privileges to function.
OAuth defines a more elegant approach to this problem. It was developed in November 2006 by lead Twitter developer Blaine Cook and version 1.0 was published in April 2010.
OAuth is an open standard and is commonly used to grant permission for applications to access user information without forcing users to give away their passwords.
An open standard is a publicly available definition of how some functionality should work. However, the standard does not actually build out that functionality.
As a result, each API is required to implement their own version of OAuth and therefore may have a slightly different implementation or flow. However, they're all based around the same OAuth specification.
This can make using a new OAuth API a little more frustrating. However, with time you will begin noticing the similarities between API authentication flows and be able to use them in your applications with increasing ease. Below is a summary of the standard OAuth flow.
GENERIC OAUTH FLOW
Many applications implementing OAuth will first ask the user to select which service they would like to use for credentials:
Login with Google, Facebook or Twitter
After selecting the service, the user will be redirected to the service to login. This login confirms the user’s identity and typically provides the user with a list of permissions the originating application is attempting to gain on the user’s account.
If the user confirms they want to allow this access, they will be redirected back to the original site, along with an access token. This access token is then saved by the originating application.
Like a developer API key, this access token will be included on requests by the application to prove that the user has granted access and enable access to the appropriate content for that user. When a user returns to the application, the token will be retrieved and they will not have to re-authenticate.
OAUTH 2
Since OAuth evolved out of Twitter, there were important use cases not originally considered as part of the specification. Eventually, this led to the creation of a new version of the specification, called OAuth 2.
Among other improvements, OAuth 2 allows for different authentication flows depending on the specific application requesting access and the level of access being requested.
OAuth 2 is still an open standard, so each API will have its own flow based on its particular implementation. Below, we’ll discuss a few of the common OAuth 2 flows and how they are used.
CLIENT CREDENTIALS GRANT
Sometimes an application will not need access to user information but may implement the added security and consistency of the OAuth 2 specification. This type of grant is used to access application-level data (similar to the developer API key above) and the end user does not participate in this flow.
Instead of an API key, a client ID and a client secret (strings provided to the application when it was authorized to use the API) are exchanged for an access token (and sometimes a refresh token). We will discuss refresh tokens in more depth later.
This flow is similar to our first example, where an email and password were exchanged for an authentication token.
It is essential to ensure the client secret does not become public information, just like a password. As a result, developers should be careful not to accidentally commit this information to a public git repository. Additionally, to ensure integrity of the secret key, it should not be exposed on the client-side and all requests containing it should be sent server-side.
Similar to the previously-mentioned keys, the returned access token is included on requests to identify the client making the requests and is subject to API restrictions.
This access token is often short-lived, expiring frequently. Upon expiration, a new access token can be obtained by re-sending the client credentials or, preferably, a refresh token.
Refresh tokens are an important feature of the OAuth 2 updates, encouraging access tokens to expire often and, as a result, be continuously changed (in the original OAuth specification, access tokens could last for time periods in the range of years). When a refresh token is used to generate a new access token, it typically expires any previous access tokens.
AUTHORIZATION CODE GRANT
This flow is one of the most common implementations of OAuth and will look familiar if you’ve ever signed into a web application with Google or Facebook. It is similar to the OAuth flow described earlier with an added step linking the requesting application to the authentication.
A user is redirected to the authenticating site, verifies the application requesting access and permissions, and is redirected back to the referring site with an authorization code.
The requesting application then takes this code and submits it to the authenticating API, along with the application’s client ID and client secret to receive an access token and a refresh token. This access token and refresh token are then used in the same manner as the previous flow.
To avoid exposing the client ID and secret, this step of the flow should be done on the server side of the requesting application.
Since tokens are tied both to users and requesting applications, the API has a great deal of control over limiting access based on user behavior, application behavior, or both.
IMPLICIT GRANT
The previous two methods cause the client secret key to be exposed, so they need to be handled server-side. Some applications may need to access an OAuth API but don't have the necessary server-side capabilities to keep this information secure.
The Implicit Grant OAuth flow was designed for this very use case. This flow prompts the user through similar authorization steps as the Authorization Code flow, but does not involve the exchange of the client secret.
The result of this interaction is an access token, and typically no refresh token. The access token is then used by application to make additional requests to the service, but is not sent to the server side of the requesting application.
This flow allows applications to use OAuth APIs without fear of potentially exposing long-term access to a user or application's information.
CONCLUSION
OAuth provides powerful access to a diverse set of sites and information. By using it correctly, you can reduce sign-up friction and enrich user experience in your applications.
No, if it's out in public, it is public.
But you can set up a server that takes care of the communication in the background so you key would be kept secret.
In the case of Firebase it seams, that there shouldn't be a security risk though. See this answer here
I'm a regular reader here at stack overflow but this is my first question.
I'm developing an authorization-server using the OAuth2 specs. And I just got stuck with how do I ensure the first-party client authenticity while using the password flow. I read many forums and this is what I got:
Javascript single-page clients
This blog post by Alex Bilbie, he states that to avoid the client_secret problem we should just:
It’s simple; proxy all of your API calls via a thin server side component. This component (let’s just call it a proxy from here on)
will authenticate ajax requests from the user’s session. The access
and refresh tokens can be stored in an encrypted form in a cookie
which only the proxy can decrypt. The application client credentials
will also be hardcoded into the proxy so they’re not publicly
accessible either.
But now this proxy can be accessed by someone impersonating my
angular app. And then I came across this blog post from Andy
Fielder: How Secure is the OAuth2 Resourc Owner Password Flow
for Single Page Apps. He basically says to rely on CORS to
avoid impersonating JS clients.
It is a good idea to use both approaches to secure my JS app?
Native Apps (Desktop and Mobile)
In the case of mobile apps, I only found cases for Authorization
Code and Implicit flows. This is not what I want, as the redirects
will compromise the user experience. So my thoughts on this is:
I will use the ROP flow and then register the client with a
client_id generated for this particular installation and attach it
to the user account, receiving the access_token and a
client_secret as response. Any other token request made by this
client MUST carry this credentials (as the client_id is specific
for the installation, I will be able to check if this client is
already authenticated). This way if someone uses any credential for
impersonating a client, or even registers a bogus client, I can take
mesures to revoke the user and client access.
I know that this can be overthinking, and I also know that some of this matters doesn't avoid anything. I just feel that is my job to protect my API as much as I can.
I would really appreciate your thoughts about this matters! Am I really overthinking? Should I just use the concept of a 'public client' and carry on?
Thank you all and happy coding!
First of all, this problem is not a common priority because most applications are developed first with website, and after with the API. This is probably the reason because no one knows how to deal first clients with oauth2, because everyone have developed other ways to do that and oauth2 is needed only to grant user access to third party applications.
Even if you have develop the oauth2 authorization server only for your first clients applications (thinking about a single authentication mechanism instead of developing many), you should try to develop the authorization code or implicit grant types. You will realize that you need a way to check what user is actually logged in.
The two common methods are:
user session (based on Cookies)
user access from localStorage (based javascript)
In either ways you need to check your application security, user session is vulnerable to CSRF, localStorage are vulnerable to XSS. There are a lot of articles about how to secure your website against either, so I will not suggest anything here, you just need to know that they exist.
Now that you choose your authentication method we can start to do some consideration about:
Javascript single pages applications
Proxy
Having a proxy that filter all requests in my opinion is like to have a door with the keys always inserted. It's useless even build the door.
However, for session based authentication it's the only way to do it. Allowing session authentication on your Rest API will open to CSRF security issues, so you need to have a proxy layer that get the user session, retrieve the access token from the session and do the request to the Rest API adding the Authorization header.
CORS
With this method you need to store the user access token in the localStorage, because the token is retrieved from the Js client directly.
Using CORS you are sure that other websites cannot do requests to your Rest API from a browser. But your first client need to be public (ie: it does not have a client_secret).
Native Apps (Desktop and Mobile)
In my first application I tried to use the same mechanism that you suggest to secure the auth flow. However that type of mechanism require that you identify every user client in an unique way. This is not possible in iOS for privacy reasons and with some probability it will denied in the future releases of Android. So you should rely on a public client and add only the client_id in your native application code.
This means that your native app client/your js client can be impersonalized? Yes, and there is no way to prevent this with oAuth2 resource owner password credentials grant type.
The main reason about this is because oAuth2 is not for authentication, only for third-party authorization, and that grant type was added only for specific third-party applications trusted enought to use directly the user password. You could read more about this argument here and here.
At the end
You still need a way to auhorize your user, and I think that the best you can achieve using oAuth2 is what Auth0 did.
Essentially this Saas manage your users with an oAuth2 server + OpenID connect, so you are always managing your users like its a third-party application and everything works fine.
Indeed, you can see on this page that for mobile applications they suggest to use a browser based login form, because the native one can be impersonalized by everyone that decompile your application, but if you wrap it into an authorization code flow it works fine.
I am going to build a web service with all resources exposed via RESTful API. I will have my own database of users and the main way they are going to access the web service will be through a web site which I will also write. The web site will consist of HTML pages and JavaScript which will make calls to the API.
There will also be third party applications which will be able to access the API, given the user authorizes them to do so via my authorization server (which I plan to be physically identical to the API server). So using OAuth 2.0 seems like a good fit here.
To reduce the complexity and improve the maintainability, I would like to treat my own web site in the same way I am going to treat the third party apps with regards to authentication and authorization.
This, however, raises some concerns which I was not able to address to my satisfaction so far. The following issues relate to the web site of mine, not to the third party apps as they in fact will have a simpler job in my opinion.
Using OAuth means appending access token with each request. I can obtain the access token by having the user provide his username and password and using the implicit grant flow. But
Implicit grant does not support the issuance of refresh tokens. So either I will force the user to login again from time to time, destroying the user experience or issued access token will have a really long expiration period.
The JavaScript app will have to store the access token somewhere. I do not have an experience with how this works, but I presume a session or a local storage is used to achieve this. But then if an attacker gains access to the user's browser, he can send valid API requests on his own since he will probably be able to read the access token. Are the CSRF prevention measures enough to avoid this? Or should I just give up and assume that once anyone gains access to the user's browser, all hell breaks loose and there is no point addressing this threat in any extra way?
I have read so much about this over the last few days that I am overwhelmed with information and cannot make my mind on the definite solution. If I did not have to support third party applications eventually, I would probably go with just setting a Forms authentication cookie which would be appended automatically by the client to each request and that would be it. But I do not want to have double logic for validating the requests (access tokens for third party apps and cookie for my own website).
There are people who discourage the implicit grant altogether...
Please please please just avoid the implicit grant, it's a bag of hurt for everyone and it's just not worth implementing if you care even slightly about user experience and security.
...which further adds uncertainty to my decision.
All communication will use only HTTPS, of course.
Edit: The official ASP.NET tutorial on how to secure an API using OAuth also uses the flow described above for a website (except they use the "Password" grant type and not the "Implicit" one), so maybe I am overthinking this and should just take this route.
How would you combine OpenID with a RESTful web service?
The personal project I'm working on is using the RPX SaaS to do OpenID. The key result of this is URL describing the logged in user. The app itself is heavily Javascript and I'm planning on using a REST api to communicate with the backend for database persistence and spatial processing.
The security requirements on this application aren't big. I want to know which user is making a request. I don't believe I need to use SSL to be confidential about the data and I don't want the overhead of running SSL.
I'm using Spring and would like to use Spring Security (Acegi) if possible but I'm not wedded to that idea.
Options:
Return the OpenID URL to the Javascript app, use this to retrieve the list of resources for the user and then retrieve/save/etc those resources by id.
Create a session table which connects the OpenID URL with a random session token. Return the token to the Javascript app which must then return the token with every subsequent request.
Use the session from option 2 as the Consumer Token, etc for OAuth. Initially, the session would be sent to the app using PKI encryption.
Rely on J2EE HTTP Session.
Of these options I'm leaning towards option 2. Hijacking the session would be difficult as the attacker would have to guess the session id and I don't believe the application requires protection from sniffing. Option 3 is essentially the same as option 2 but the session id isn't available for sniffing. Option 4 puts the OpenID URL into the server's memory and causes all the scalability problems REST is designed to avoid.
I'm grateful for any discussion on this.
So, 2 years 3 months later I can answer my own question. I implemented this for my personal project and I have separately implemented it for my employer.
Plugging into Spring Security is the best way to go. You can choose to use the pre-authenticated flow but you may find the CasAuthenticationFilter (and CasAuthenticationEntryPoint) work better as they have most of the flow you need.