My problem is that I want to get deployment information from Github for headless devices. The devices only have ssh & can call REST API. I.e. they do not have git for example.
There are a number of existing solutions:
Deployment keys – Requires git executable to be installed and I need to also access Github Container registry
OAuth App – Tokens have are associated with a real user while the devices are owned by an organization. And having a shared ghost user account has many drawbacks. This would work perfect if the tokens could be owned & managed by an organization.
Github App – Installation tokens expire after an hour, normal tokens after 10 mins. This means I need a highly reliable server process to create the tokens on the fly and the device is more complicated.
Since deployment keys & OAuth apps use tokens that can be revoked instead of time out, I am curious why this feature is unavailable with Github Apps? After all, for headless devices they just now force you to create a server that authenticates the device and creates a temporary token. This seems more error prone than if they had a long term token with revocation?
Am I missing something?
Related
I have a use case where I need to provide a small CLI application that can be installed on headless servers of customers and transact data over REST APIs. I'm trying to search for a solution which allows the user who is generating tokens for the headless servers and the servers individually as well. I've looked at Auth0 which provides a simple way of doing this. However, the only catch is that the customer will have to generate device tokens corresponding to every server that they have. This will fail if the servers have to autoscale.
Are there more ways to achieve this while not compromising on security with the following identifications possible?
The user generating the token should be identifiable.
The device individually should be identifiable as well.
At any point, if I want I should be able to revoke authorisation from a particular device/server.
At any point, I should be able to revoke authorisation for all devices/servers registered by a particular user.
I asked it here a while back but got no response: https://security.stackexchange.com/questions/262580/authenticating-headless-autoscaling-clients
Consider a developer portal where a developer can create an OAuth2 application Acme Pay. The dev gets a client_id, client_secret, access_token, and a refresh_token, along with a redirect_uri field that can be configured.
The state of the app will be in a test/sandbox environment and the dev can play around within the constraints of the sandbox environment.
As a next step, once the developer has implemented the app locally and wants to push it to prod, I am ideating a flow where the dev would be able to simply toggle the app's environment to a live environment in the developer portal where they get a new token pair for the same app, along with environment-specific access privileges and rate-limits.
I'm a PM trying to understand if such an implementation is possible with OAuth2.
My motivation here is to prevent the developer from creating two OAuth apps for testing and production. I noticed a similar flow in Stripe. Although in my case, the developer will be able to create multiple OAuth apps under one account, hence I feel it is better for each app to have two environments co-existing parallelly at the app level to provide a better developer experience.
The OAuth client configuration is created separately for each stage of your deployment pipeline. Sometimes in portals the wording is Create Application but these are just security related configuration settings.
Separate config per stage of the pipeline enables settings to be versioned reliably over time and tested first. Also the change ownership is often controlled by different people and done at different times. Typically though the deployment is automated in a parameterized and reliable manner.
The actual application code should only ever be built into binaries once though. It is then pushed down a pipeline where binaries are combined with the stage specific configuration.
So I grant access of my resource to application A, and that application gets that access token. It is just a string. Sometimes the application will pass that access token to its backend server, and then use it to retrieve my resource. Usually the access token is valid for say one month.
Now my question is, what if application A leaks my access token, so any application B can use that access token to get my resource, which is not what I want. I only want application A can access my resource, not application B.
How do we trust application and give it my access token?
YOUR PROBLEM
Usually the access token is valid for say one month.
Using 1 month to the access token expiration time is way to long, not matter if is for admin or normal users.
Depending on your use case I recommend you to use the access tokens with an expiration time in the range of minute, lesser time you can have better will be for security.
So I would recommend you to switch to use refresh tokens, that will keep the access tokens short lived while refresh tokens can be long lived, but in the hours range, not days, weeks or years.
Refresh Token flow example:
Sourced from: Mobile API Security Techniques - part 2
NOTE: While the above graphic belongs to a series of articles written in the context of mobile APIs, they have a lot of information that is also valid for APIs serving web apps and third party clients.
By using the refresh tokens approach, when a client request fails to validate the short lived access token will mean that the client needs to request a new one by sending a refresh token in order to get a new short lived access token.
The important bit here is that the refresh token should not be sent to the browser, only the access token can be sent, therefore your third party clients must kept refresh tokens private, aka in their backends, therefore they MUST NOT send refresh tokens from javascript, instead any renewal of the short lived acess tokens MUST BE delegated to their backends.
Now my question is, what if application A leaks my access token, so any application B can use that access token to get my resource, which is not what I want.
That's why you should use the Refresh Tokens approach I mentioned earlier, because you limit their access to the amount of time remaining in the access token, and this is why I said that the short lived access tokens should be in the range of minutes.
I only want application A can access my resource, not application B.
I am gonna tell you a cruel truth... this is not doable at 100%, specially for web apps, where you can just hit F12 to access the developer tools console and search for the access token, or if you prefer to right click on the page and select view source.
Mobile apps seem to be more secure at a first glance, because they are shipped as a binary, thus you would expect to be hard to reverse engineer it? Wrong, it's indeed easy with the plethora of open source tools that we can use to reverse engineer them, and my preference goes to the MobSF:
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis.
So if you cannot find the access tokens via static analysis, then you can resort to dynamic analysis with open source tools to, like Frida:
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
And if that's is not enough you also perform a Man in the Middle(MitM) Attack wit another open source tools, like mitmproxy:
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
So, stealing your access token for a mobile app is not as easy as in the Web App, but it's not that hard to.
POSSIBLE SOLUTIONS
How do we trust application and give it my access token?
I don't know if your application is a web or mobile app, therefore I will show you possible solutions for both.
Before I mention the possible solutions, I need to first clear out a usual misconception among developers, regarding who vs what is accessing the backend. This is discussed in detail in this article, where we can read:
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.
If you still have doubts please go and read the section of the linked article, that also includes a graphic to help with understanding this. The article is in the context of a mobile app, but for understanding the difference between what and who is accessing the backend, the references to mobile app can be replaced with web app.
For Web Apps
If your use case is a web app the most affordable solution to try to mitigate the who vs what is accessing your backend it's by using:
Google Recaptcha V3:
reCAPTCHA is a free service that protects your site from spam and abuse. It uses advanced risk analysis techniques to tell humans and bots apart.
This is uses User Behaviour Analytics(UBA) in a best effort basis to tell appart who and what is accessing your backend.
User behavior analytics (UBA) as defined by Gartner is a cybersecurity process about detection of insider threats, targeted attacks, and financial fraud. UBA solutions look at patterns of human behavior, and then apply algorithms and statistical analysis to detect meaningful anomalies from those patterns—anomalies that indicate potential threats.[1] Instead of tracking devices or security events, UBA tracks a system's users.
This is prone to false positives, therefore you need to be careful when deciding to accept or not the request based on the score returned by reCPATCHA V3 for each request:
reCAPTCHA v3 returns a score for each request without user friction. The score is based on interactions with your site and enables you to take an appropriate action for your site.
For Mobile Apps
As you saw by the plethora of tools available to reverse engineer the mobile apps, statically or dynamically, the access token to identify your user is not that safe, plus this only identifies the who in the request, not what is doing it.
The solution that can let your backend to be sure that the request is indeed from the same exact mobile app that was uploaded to the Google Play or Apple store is a Mobile App Attestation solution, that is a concept that introduces a new way of dealing with security for your mobile app and backend in an unified manner.
The usual approaches focus to much on the mobile app side, but in first place the data you want to protect is in your backend server, and it's here that you want to have a way to know that what is making the request is really the thinh you expect to be, your genuine mobile app.
The Mobile App Attestation concept is described in this section of another article I wrote, from where I will quote the following text:
The role of a Mobile App Attestation service is to authenticate what is sending the requests, thus only responding to requests coming from genuine mobile app instances and rejecting all other requests from unauthorized sources.
In order to know what is sending the requests to the API server, a Mobile App Attestation service, at run-time, will identify with high confidence that your mobile app is present, has not been tampered/repackaged, is not running in a rooted device, has not been hooked into by an instrumentation framework (Frida, xPosed, Cydia, etc.) and is not the object of a Man in the Middle Attack (MitM). This is achieved by running an SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device it is running on.
On a successful attestation of the mobile app integrity, a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud know. In the case that attestation fails the JWT token is signed with an incorrect secret. Since the secret used by the Mobile App Attestation service is not known by the mobile app, it is not possible to reverse engineer it at run-time even when the app has been tampered with, is running in a rooted device or communicating over a connection that is the target of a MitM attack.
The mobile app must send the JWT token in the header of every API request. This allows the API server to only serve requests when it can verify that the JWT token was signed with the shared secret and that it has not expired. All other requests will be refused. In other words a valid JWT token tells the API server that what is making the request is the genuine mobile app uploaded to the Google or Apple store, while an invalid or missing JWT token means that what is making the request is not authorized to do so, because it may be a bot, a repackaged app or an attacker making a MitM attack.
So this approach will let your backend server to trust with a very high degree of confidence that the request is coming indeed from the same exact mobile app you uploaded to the Google Play and Apple store, provided the JWT token has a valid signature and expire time, and discard all other requests as untrustworthy ones.
GOING THE EXTRA MILE
To finish my answer I cannot resist to recommend you the excellent work of the OWASP foundation, because off their excellent work and for me no security solution for web and mobile is complete without going through their guides:
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.
The Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
I am using the Goodreads api to get book data for my react native app. I have to use a key for using the api. Is it OK for me to store the api key on the app itself or should I put the key on a server that redirects all the data to the app?
Is it OK for me to store the api key on the app itself
No, because as I demonstrate in the article How to Extract an API Key from a Mobile App by Static binary analysis it can be extracted with the help of several open source tools, like by using the Mobile Security Framework, but you can also grab the API key with a MitM attack, as I show in the article Steal that API Key with a Man in the Middle Attack, that uses the open source tool MiTM Proxy.
If you leave a third party API key in the mobile app, then they are up for grabs from attackers, and when they start using it without your knowledge your bill in the third party provider may go through the roof before you acknowledge that something is wrong, and on that time the only solution is to revoke the API key, thus shutting down the use of the mobile app, and if you make a new release of your mobile app with a new API key it will be just a matter of hours until the attacker come back and steal the API key again.
or should I put the key on a server that redirects all the data to the app?
Yes, and this is a good approach, because now you have only one place to store and protect all third part API keys. This have the benefit to let you control and throttle the use of them as you see fit.
With this solution you still need an API key in your mobile app to allow access to your API server, but while you continue vulnerable for attackers to steal it, you are now in direct control of throttling the access to your API server and if you identify in each access the WHO and the WHAT is accessing the API server, then you have a more fine grade control, but attacker will continue to be able to slip between all our defenses, because is very hard to know WHAT is accessing the API server.
You may be thinking by now... do you mind to explain the WHO vs the WHAT?
The Difference Between WHO and WHAT is Accessing the API Server
To better understand the differences between the WHO and the WHAT are accessing an API server, let’s use this picture:
The Intended Communication Channel represents the mobile app being used as you expected, by a legit user without any malicious intentions, using an untampered version of the mobile app, and communicating directly with the API server without being man in the middle attacked.
The actual channel may represent several different scenarios, like a legit user with malicious intentions that may be using a repackaged version of the mobile app, a hacker using the genuine version of the mobile app, while man in the middle attacking it, to understand how the communication between the mobile app and the API server is being done in order to be able to automate attacks against your API. Many other scenarios are possible, but we will not enumerate each one here.
I hope that by now you may already have a clue why the WHO and the WHAT are not the same, but if not it will become clear in a moment.
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.
OAUTH
Generally, OAuth provides to clients a "secure delegated access" to server resources on behalf of a resource owner. It specifies a process for resource owners to authorize third-party access to their server resources without sharing their credentials. Designed specifically to work with Hypertext Transfer Protocol (HTTP), OAuth essentially allows access tokens to be issued to third-party clients by an authorization server, with the approval of the resource owner. The third party then uses the access token to access the protected resources hosted by the resource server.
OpenID Connect
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
While user authentication may let the API server know WHO is using the API, it cannot guarantee that the requests have originated from WHAT you expect, the original version of the mobile app.
Now we need a way to identify WHAT is calling the API server, and here things become more tricky than most developers may think. The WHAT is the thing making the request to the API server. Is it really a genuine instance of the mobile app, or is a bot, an automated script or an attacker manually poking around with the API server, using a tool like Postman?
For your surprise you may end up discovering that It can be one of the legit users using a repackaged version of the mobile app or an automated script that is trying to gamify and take advantage of the service provided by the application.
Well, to identify the WHAT, developers tend to resort to an API key that usually they hard-code in the code of their mobile app. Some developers go the extra mile and compute the key at run-time in the mobile app, thus it becomes a runtime secret as opposed to the former approach when a static secret is embedded in the code.
The above write-up was extracted from an article I wrote, entitled WHY DOES YOUR MOBILE APP NEED AN API KEY?, and that you can read in full here, that is the first article in a series of articles about API keys.
Your problem is not solved yet
Now that you know the difference between WHO and WHAT is accessing your API server you must have realized that your API server is still vulnerable to be abused by attackers.
You can resort now to employ several layers of defense, starting with reCaptcha V3, followed by Web Application Firewall(WAF) and finally if you can afford it a User Behavior Analytics(UBA) solution.
Google reCAPTCHA V3:
reCAPTCHA is a free service that protects your website from spam and abuse. reCAPTCHA uses an advanced risk analysis engine and adaptive challenges to keep automated software from engaging in abusive activities on your site. It does this while letting your valid users pass through with ease.
...helps you detect abusive traffic on your website without any user friction. It returns a score based on the interactions with your website and provides you more flexibility to take appropriate actions.
WAF - Web Application Firewall:
A web application firewall (or WAF) filters, monitors, and blocks HTTP traffic to and from a web application. A WAF is differentiated from a regular firewall in that a WAF is able to filter the content of specific web applications while regular firewalls serve as a safety gate between servers. By inspecting HTTP traffic, it can prevent attacks stemming from web application security flaws, such as SQL injection, cross-site scripting (XSS), file inclusion, and security misconfigurations.
UBA - User Behavior Analytics:
User behavior analytics (UBA) as defined by Gartner is a cybersecurity process about detection of insider threats, targeted attacks, and financial fraud. UBA solutions look at patterns of human behavior, and then apply algorithms and statistical analysis to detect meaningful anomalies from those patterns—anomalies that indicate potential threats. Instead of tracking devices or security events, UBA tracks a system's users. Big data platforms like Apache Hadoop are increasing UBA functionality by allowing them to analyze petabytes worth of data to detect insider threats and advanced persistent threats.
All this solutions work based on a negative identification model, by other words they try their best to differentiate the bad from the good by identifying what is bad, not what is good, thus they are prone to false positives, despite of the advanced technology used by some of them, like machine learning and artificial intelligence.
So you may find yourself more often than not in having to relax how you block the access to the API server in order to not affect the good users. This also means that this solutions require constant monitoring to validate that the false positives are not blocking your legit users and that at same time they are properly keeping at bay the unauthorized ones.
Regarding APIs serving mobile apps a positive identification model can be used by using a Mobile App Attestation solution that guarantees to the API server that the requests can be trusted without the possibility of false positives.
Mobile App Attestation
Use a Mobile App Attestation solution to enable the API server to know is receiving only requests from a genuine mobile app.
The role of a Mobile App Attestation service is to guarantee at run-time that your mobile app was not tampered or is not running in a rooted device by running a SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device is running on.
On successful attestation of the mobile app integrity a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud are aware. In the case of failure on the mobile app attestation the JWT token is signed with a secret that the API server does not know.
Now the App must sent with every API call the JWT token in the headers of the request. This will allow the API server to only serve requests when it can verify the signature and expiration time in the JWT token and refuse them when it fails the verification.
Once the secret used by the Mobile App Attestation service is not known by the mobile app, is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.
The Mobile App Attestation service already exists as a SAAS solution at Approov(I work here) that provides SDKs for several platforms, including iOS, Android, React Native and others. The integration will also need a small check in the API server code to verify the JWT token issued by the cloud service. This check is necessary for the API server to be able to decide what requests to serve and what ones to deny.
Summary
Anything that runs on the client side and needs some secret to access an API can be abused in different ways and you must delegate the access to all third part APIs to a backend under your control, so that you reduce the attack surface, and at the same time protect their secrets from public pry eyes.
In the end, the solution to use in order to protect your API server must be chosen in accordance with the value of what you are trying to protect and the legal requirements for that type of data, like the GDPR regulations in Europe.
For react native use react-native-config library. While using this library you can secure your api keys as well as you can save more secret keys which use in the native code. Like we can save onesignal, codepush etc keys.
https://github.com/luggit/react-native-config
Store them in a .env file like this API_KEY=yourKey.
Install npm package react-native-dotenv.
Then import to to files as needed with react-native-dotenv package;
import { API_KEY } from 'react-native-dotenv'
The .env file should never be committed to Github.
Is there way to let the user who installs a GitHub App generate a permanent installation access token which can be used by the app to authenticate and perform actions as that app?
I am wanting to create a simple GitHub App that will run on a CI server and comment on PRs with data from one of the tests.
As this app is being run by the user on their CI server there is no place to store the private key for the GitHub App that would usually be used to generate the access token as described here.
Ideally if the user could generate a permanent installation access token for the app they could securely provide that key to the app when it runs on the CI server so the app can communicate with the GitHub API and authenticate as the app.
I realize that the user could provide a user access token and the app could authenticate that way - but when the app comments it needs to show up as originating from the app, not the user (and I don't believe that would happen if the app authenticates with a user access token).
I think you might be confusing "GitHub Apps" with the more generic idea of tools that access the GitHub API. The Apps system a specific way to build hosted services for GitHub that has its own authentication model. Users can't run an App themselves as it is only designed around hosted/SaaS tooling. For things that someone would run themselves, you would need the end user to create a new user account on GitHub for the bot and then authenticate as it (either OAuth or personal access token, doesn't matter).
This is an old question, but in the interest of having the correct info here...
#osowskit's answer is correct in terms of mentioning you need to use JWT but not in terms of that has to be done using webhooks. There are indeed advantages of using Apps for access control - the GitHub App can be given specific access for only some repos. Now at least some CI systems (well at least Jenkins) support GitHub App access natively for some uses.
The basic flaw in the original request was the request of a permanent PAT associated with the App. This is not how they work. Instead you generate a Private Key for the App and it is this that should be stored in the CI secrets system. Now you do indeed need some sort of PAT to actually do the action - here to add the PR comment - it is just that you don't have a permanent one. Instead you generate temporary PATs each time you need to run - IIRC these PATs last for about an hour, so are useful for most single jobs but are to be generated each time and not stored as such.
Once you get the code, it is no big deal using the jwt tokens - it just involves a couple of extra REST calls.
Is there way to let the user who installs a GitHub App generate a permanent installation access token which can be used by the app to authenticate and perform actions as that app?
Maybe but it shouldn't be necessary. A GitHub App will only perform actions on data a user grants it access to. Any data modified on GitHub by the App will appear as an action 'performed' by the App.
Ideally if the user could generate a permanent installation access token for the app they could securely provide that key to the app when it runs on the CI server so the app can communicate with the GitHub API and authenticate as the app.
This shouldn't be necessary based on the information you've provided. Users grant access to a GitHub App to access specific resources and listen for specific events; a GitHub App needs a installation ID (or multiple installation IDs) to interact with GitHub data.
The good news is that for the CI workflow you outlined, GitHub would send the installation ID in the webhook payload - likely a push event.
I realize that the user could provide a user access token and the app could authenticate that way - but when the app comments it needs to show up as originating from the app, not the user (and I don't believe that would happen if the app authenticates with a user access token).
Generating a personal access token (PAT) isn't required and GitHub Apps were created to avoid creating service accounts or adding credentials to your CI environment.
Author your GitHub App to listen for webhook events.
On receiving an event, parse the payload for the installation id
Generate an installation access token by authenticating as an application after creating a JWT.
Use the installation access token generated above to modify data. Note that this token expires in an hour.
Profit!