How to allow a public app to connect to the GitHub API v4 without an access token? - security

I have decided to try to manage releases of one of my apps on GitHub as with GitHub Actions, I can build on Mac, Linux and Windows and automatically push the artifacts to the GitHub Releases page, where anyone can go and download the app from.
However, I want my app to self-update, so the app itself also needs to be able to query what's the latest version in the repo releases, and then download the relevant asset for the user's OS... which I thought would be a non-issue... however, there's no way to access the GitHub API v4 without either an OAuth app or a personal access token.
I don't want an OAuth app because the users of my app are absolutely not expected to be GitHub customers. So I tried to use a personal access token whose only scope was access to public release assets (which, again, is a public resource anyone can go and manually download).
As this token can't do anything you or anyone else can't do manually, even without a GitHub account, I thought it would be fine to put the token in the source code of my application, but GitHub revokes the token when it detects it on a commit.
Is there a good way to work around this? Should I put the token in a GitHub secret and then try to replace a placeholder with it during compilation?? I wanted to avoid that as that makes it hard for me to test the app locally, and also, it doesn't solve anything as anyone can easily decompile the app and find the token there (supposing GitHub would not detect the secret is present in the "processed" sources during compilation).
Any suggestions would be appreciated.

however, there's no way to access the GitHub API v4 without either an OAuth app or a personal access token.
The GitHub API v3 does support unauthenticated calls, but it's limited to 60 requests/hr per IP address: https://developer.github.com/v3/#rate-limiting
For unauthenticated requests, the rate limit allows for up to 60 requests per hour. Unauthenticated requests are associated with the originating IP address, and not the user making requests.
The Latest Release API docs will show you what information is returned, but I suspect you'll need to make a secondary call to List Assets for a release to know the files the client needs to download.
If that's not satisfactory (e.g. you know you'll have many clients try to update using the same IP address), and you'd like to ensure they aren't being rate-limited, read on for a different approach.
Is there a good way to work around this?
How I would tackle this is by deploying a small web service (e.g. Heroku dyno) that your app can will call without needing authentication, which then performs the actual lookup for the latest version (using a PAT that gets embedded as an environment variable) and returns a simple JSON response that the client will understand.
Benefits:
no token embedded in client
development mode can even call same service
add logic to service that the client would perform to simplify your app
e.g. call /latest/beta or /latest/stable to indicate it's looking for a specific channel
perform both API calls and return the assets that the client needs
can update token in service whenever necessary (e.g. to refresh token) without changing client
can cache response to reduce risk of being rate-limited
Downsides:
more moving parts to manage in your overall architecture
need to worry about uptime of the service if there are lots of clients connecting
this can be offset by making the client resilient to failure cases

Related

Google API Authentication: are there alternatives to service account keys?

I'm seeking your advice to piece together a mechanism that would facilitate authentication to Dialogflow ES and CX to allow running experiments on multiple agents (projects) from our workbench application in a smooth and error-proof manner. The workbench is an internal tool written in TypeScript (using the dialogflow RPC node module) running outside of GCP. Our users analyze the results of sending the same inputs (utterances) to multiple agents, usually going back and forth between them in the course of their work.
With proper IAM configuration, we have been able to detect intents successfully by doing a gcloud auth application-default login, however we haven't found a way to update the quota project programmatically or to specify the quota project through the google.cloud.dialogflow library, so we haven't been able to fix the "switch easily between projects" part. It looks like tampering with the quota_project_id property in application_default_credentials.json once authenticated is the way to go (gcloud auth application-default set-quota-project <project>) but we would have preferred doing this programmatically.
Using service account keys (JSON) works as expected and that's what we have been doing so far, that's also what we do in our CI/CD pipeline and in our agents running in production. But we aim at reducing the amount of service account credentials file that we share with individuals. Ideally, speech/data scientists would use their own end-user credentials to perform experiments.
We are looking for alternatives so that users would authenticate once with gcloud auth application-default login and the workbench would handle the rest behind the scenes, using only, as additional argument, the project-id against which the experiment must be run. This would eliminate the need to pause the experiment to update the quota project (using set-quota-project), or to update the GOOGLE_APPLICATION_CREDENTIALS variable when using service account keys.
Another thing we tried was Service Account Impersonation, unfortunately this does not seem supported by the google.cloud.dialogflow library, so even though we were able to successfully submit requests (with Curl/Postman) to the Dialogflow RESTful API using impersonation, we haven’t been able to leverage this mechanism in our code.
Has anyone been able to overcome a similar challenge? Is there any other authentication mechanism that could help us achieve this goal?

How to properly store client secret for Google Drive API on Electron app?

I have an Electron app that requires access to the users Google Drive and I want to implement the api functionality without having to expose the client secret. From my understanding, this is impossible to do in certain scenarios like mobile applications, but what is the proper way of going about this on a local app?
When trying to follow the web-app OAuth instructions from Google, it looks like you can't use this method on a local application. When trying to setup the OAuth process this way it doesn't even let you whitelist localhost as a domain to authenticate users on (which breaks the process since this is a local app running on Electron). Add on to that this paper that Google released and it also seems like you can't trick the auth process to think it's not running on localhost, and you also can't run Node.js in the browser (I'm using Electron so this is impossible to do).
I then tried following their Mobile and Desktop app workflow which seemed promising. The issue arises when you need to Exchange authorization code for refresh and access tokens. This again requires that you show your client secret in your main app. I then though of splitting this up and doing some of it locally and then having an auth server that held the client secret and exchanged the authorization code from the client and returned a refresh and access token. Looking at the diagram that Google provides for visualizing this process, it clearly shows that your app needs to do both parts of the authorization process so that idea was also out.
One application that I personally use and looked at was rclone and from the looks of it they just list their client ID and secret directly in their code. The client secret is encrypted, but if you follow the workflow it gets revealed with a key that is also just stored locally on the app. So it's plain text is obscured, but there is nothing preventing anyone from getting hold of the client secret by slightly modifying the code.
I should also mention this app is in a public repo on GitHub and will stay that way.
This is my first time using OAuth so I may be misunderstanding something, but I tried following the documentation as closely as I could and can't shake the feeling that I'm overlooking a piece of this process.
And if the only way to solve this problem is to expose both the client id and secret, is there any way this could lead to users data being compromised? Since the Google Drive API is free to use I don't really mind if others use some of my quota. I'm more worried about security.
For public clients like Desktop apps you're developing, you'll need to use the PKCE flow. You're right that Google's documentation seems off here - you shouldn't need to pass the client_secret as part of the authorization code exchange.
That's supported by the documentation here: https://www.oauth.com/oauth2-servers/pkce/authorization-code-exchange/
It's possible that Google requires the client_secret but it doesn't treat the parameter as a real "secret" for public clients, but rather an additional identifier that is not sensitive, and not sufficient on its own to do anything on behalf of your application. Section 8.5 of the specification reads:
Secrets that are statically included as part of an app distributed to
multiple users should not be treated as confidential secrets, as one
user may inspect their copy and learn the shared secret. For this
reason, and those stated in Section 5.3.1 of [RFC6819], it is NOT
RECOMMENDED for authorization servers to require client authentication of public native apps clients using a shared secret,
as this serves little value beyond client identification which is
already provided by the "client_id" request parameter.
Authorization servers that still require a statically included shared
secret for native app clients MUST treat the client as a public
client (as defined by Section 2.1 of OAuth 2.0 [RFC6749]), and not
accept the secret as proof of the client's identity. Without
additional measures, such clients are subject to client impersonation
(see Section 8.6).
You might also look into standalone OAuth service providers, like Xkit where I work. That would let you keep the secret confidential while still going through an OAuth flow.

Do I need to host the backend server for Stripe\Braintree payment gateway after I move the app to production?

if anyone could give me a clear high level answer that would be great. I want to integrate a payment gateway into my app eg: Strip/Braintree, and I have gotten it all working to the testing part but now I am wondering for me to move it to production do I need to host the back end server for retrieving the tokens myself?
Currently I hosted the test server locally to test that it works. But what now? Do I need to host this on a server for all time so my app can get its tokens?
Please help.
Yes, you have to.
You can start with a Virtual Machine at DigitalOcean or Vultr. Replicate your test environment there, then harden the server, etc.
If you're new to that then I recommend you to find someone who has experience setting up servers in production environments.
Thanks for your help. I spoke with Stripe and below was there response. They confirmed that you do need a server backend all the time.
--
Unfortunately, we don’t provide any hosted solutions when working with app based payment flows—you would need to have a back-end setup in place or use a serverless solution such as Heroku, both for your eventual move to a production environment and also while in development to test your back-end.
Generally speaking, you’ll use our SDKs when building your app to implement our client-side framework enabling you to securely collect and tokenize payment details from customers from within your app. However, the back-end server is where you’ll actually make requests to Stripe when you need to create a charge, refund a payment or take some other API related action.
Additionally, your back-end server will play a critical role as that’s where you’ll need to generate the ephemeral keys that will be used as the client-side session credentials for the app’s user. The use of ephemeral keys will facilitate the retrieval and updating of customer objects in Stripe for a given user (the persistent creation and use of individual customer objects is a default behavior for our mobile SDKs), but will ensure that your Stripe account’s secret API keys remain protected (public API keys are still used in the client).

How to restrict Firebase data modification?

Firebase provides database back-end so that developers can focus on the client side code.
So if someone takes my firebase uri (for example, https://firebaseinstance.firebaseio.com) then develop on it locally.
Then, would they be able to create another app off my Firebase instance, signup and authenticate themselves to read all data of my Firebase app?
#Frank van Puffelen,
You mentioned the phishing attack. There actually is a way to secure for that.
If you login to your googleAPIs API Manager console, you have an option to lock down which HTTP referrer your app will accept request from.
visit https://console.developers.google.com/apis
Go to your firebase project
Go to credentials
Under API keys, select the Browser key associated with your firebase project (should have the same key as the API key you use to initialize your firebase app.)
Under "Accept requests from these HTTP referrers (web sites), simply add the URL of your app.
This should only allow the whitelisted domain to use your app.
This is also described here in the firebase launch-checklist here: https://firebase.google.com/support/guides/launch-checklist
Perhaps the firebase documentation could make this more visible or automatically lock down the domain by default and require users to allow access?
The fact that someone knows your URL is not a security risk.
For example: I have no problem telling you that my bank hosts its web site at bankofamerica.com and it speaks the HTTP protocol there. Unless you also know the credentials I use to access that site, knowing the URL doesn't do you any good.
To secure your data, your database should be protected with:
validation rules that ensure all data adheres to a structure that you want
authorization rules to ensure that each bit of data can only be read and modified by the authorized users
This is all covered in the Firebase documentation on Security & Rules, which I highly recommend.
With these security rules in place, the only way somebody else's app can access the data in your database is if they copy the functionality of your application, have the users sign in to their app instead of yours and sign in/read from/write to your database; essentially a phishing attack. In that case there is no security problem in the database, although it's probably time to get some authorities involved.
Update May 2021: Thanks to the new feature called Firebase App Check, it is now actually possible to limit access to your Realtime Database to only those coming from iOS, Android and Web apps that are registered in your Firebase project.
You'll typically want to combine this with the user authentication based security described above, so that you have another shield against abusive users that do use your app.
By combining App Check with security rules you have both broad protection against abuse, and fine gained control over what data each user can access.
Regarding the Auth white-listing for mobile apps, where the domain name is not applicable, Firebase has
SHA1 fingerprint for Android apps and
App Store ID and Bundle ID and Team ID (if necessary) for your iOS apps
which you will have to configure in the Firebase console.
With this protection, since validation is not just if someone has a valid API key, Auth domain, etc, but also, is it coming from our authorized apps and domain name/HTTP referrer in case of Web.
That said, we don't have to worry if these API keys and other connection params are exposed to others.
For more info, https://firebase.google.com/support/guides/launch-checklist

Paypal API credentials, security issue

Thinking about a situation where multiple developers cooperate on a project.
A project that is tested on a development server and then moved on a webserver when ready.
This project talks with paypal API so in dev-mode uses the Sandbox credentials, and when online uses LIVE api credentials.
Problem is security, since I want that only the team leader have access to the file that contains the live API data.
the only solution i've reach until now is to limit the FTP access to the webserver to one person, and this person is the only one who can access the credentials file. But this could be not very practical. Since there will be no synch with the dev server....
I guess this is a common pattern, where sensitive data has to be placed in a secured place, and just accessed from the ProjectLeader, and from the Live web-application.
I need an idea... any suggestion?

Resources