Compiling Service Account Credentials Into Executable? - c#

I have a program (compiled into a DLL to be used in other applications) that uses a Google Service Account to create and upload some files to Google Drive. The credentials are stored in a credentials.json file. I want to be able to ship this program to clients but do not want to have these credentials readable to them as that presents an obvious security concern. What is the best way to go about compiling these credentials into the DLL so that they don't exist in plaintext anywhere accessible to the end user?

You could just hard code it in a string on your application:
var apiKey = "my key";
But as mentioned in the comment above, someone can decompile the IL and see it. That would also make it difficult to change if you need to.
Or, you could encrypt it in the configuration file.
But in either of those options, or really any option where your application talks directly to the Google API, any savvy user can use something like Fiddler to inspect the traffic and see the key (even if it's over SSL).
The only way to keep your Google API key safe is to not let your application talk directly to the Google API. You can setup your own API as a proxy. The user authenticates to your API using different credentials for each user, and your API talks to Google. That way, if anyone misbehaves, you know who it is and you can disable their credentials.

Related

Obtaining access_token from Google Drive API from Desktop application

I am creating a desktop application that should be able to store and download date from Google Drive. I am using Google.Apis.Drive.v3 to handle the Authorization flow. I am facing an issue how and where to store client_secret that is needed in authorization flow.
This application should be available for wide public so the idea of every user creating its credentials is not acceptable.
I tried:
hard-coding the ClientId and ClientSecret directly to code which works but it is not ideal due to the system versioning and possible secret loss caused by program decompilation.
reading about PKCE which I read it is not supported by the library.
What are other options to achieve desired result?
Thanks for your help,
TheSecurity
hard-coding the ClientId and ClientSecret directly to code which works but it is not ideal due to the system versioning and possible secret loss caused by program decompilation.
I am going to go out on a limb and say your creating a installed application. You should do as you have done and compile the client id and client secret into your application. You should not be checking these into your version control system so you will need to set it as a secret as part of your build script so that it is only added at build time.
As for the issue of it being decompiled, there is no workaround. I have asked google about this serval times over the last ten years. They know your app could be decompiled but there's really no other option.
My creative work around
Serval years ago I had a client. What we did was when the app was installed by the user it would make a call to an api end point on our servers, which would return the client secret. This was then encoded into a file hashed to heck and back so that it was not clear text and then the application would run. This did require that the person installing the app had an internet connection to get the secret from our servers.

Store secret key securely in .NET Standard cross-platform app

I'm working on a C# PowerShell module, which is going to be a simple wrapper around some service REST API. I'd like to target PowerShell Standard / .NET Standard and make module available across all supported platforms.
For this app authentication requires API token, issued on a service website by the user. Entering key every time you open a session would be extremely inconvenient and therefore I need some way to securely store the API key in a user profile.
The problem is - I cannot find an easy way to encrypt data that has transparent cross-platform support. Initially, I wanted to use SecureString, but it is (a) deprecated and (b) doesn't seem to have good support on Linux. In a perfect world I'd like to have some mechanism similar to Windows encryption - user certificate encrypts API key and I put result in a text file in a user folder.
This is not a financial or mission-critical application, top-notch security is not required, but still keening plain text secrets in my home folder makes me nervous. Yes, I'm talking to you, AWS SDK authors :)
My first thought was: "just save secret key to ENV variables..."
But if I understood OP's question correctly, it is required to restrict unauthorized reading of this secret even on OP's machine.
One option I could see is just create a folder (or maybe file) and give it the access permissions only for one particular user. Ultimately one can create new user account which will be used to run the code in powershell and give this new user exclusive permissions to read secret file. This will prevent some 3rd party programs running from OP's account to read secret file.

Permissions for Azure database management

I'm working on a small application to connect to Microsoft Azure, list all databases belonging to a certain resource group, and export all said databases. I'm using the Microsoft.WindowsAzure.Management.Sql library for this.
Following this guide, I've managed to set up an app registration in AD for my application and assign it the Owner role (for testing), authenticate with Azure and get an access token.
However, when I try to use that token to perform any operations on the database (such as listing all databases, using IServerOperations.List), I get the following exception:
ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
The tenant ID, subscription ID, client ID and client secret are all correct, and changing any of them results in a different exception, already at the authentication stage.
How can I fix this? If the correct answer is "switch to Microsoft.Azure.Management.Sql" I'm perfectly fine with that, but if possible I'd at least like to understand why this is happening.
HIf the correct answer is "switch to Microsoft.Azure.Management.Sql" I'm perfectly fine with that, but if possible I'd at least like to understand why this is happening.
Microsoft.WindowsAzure.Management.Sql implements the ASM API(Azure old API).
The reason you're getting this error is because you're trying to authenticate/authorize an Azure Resource Manager (ASM) API with application permission.
But Service Management API is a delegated permission and not an application permission.
For more detail information about how to authenticate for ASM and ARM Rest API, please refer to another SO thread.
How can I fix this?
Microsoft.Azure.Management.Sql implements the ARM API. As you mentioned that you could use the Microsoft.Azure.Management.Sql to instand of Microsoft.WindowsAzure.Management.Sql
or you could use X509 Certificate based authorization to authorize your ASM API requests.
For more information about how to authenticate using a management certificate, you could refer to this tutorial.
Note: It is recommanded that to use Microsoft.Azure.Management.Sql to instead of Microsoft.WindowsAzure.Management.Sql

How do I prevent an app from using my api key?

My organization has a Win32 application that is written in the "fat client" style. I am writing a C# Client / Server solution that will replace this Win32 application. I am using ASP.NET MVC for the server and the client is a WPF application. I did my own custom implementation of the OAuth 2 spec. I am planning on creating a Restful API, and I want for not only my client to use it, but also allow 3rd parties to use it as well.
Every app will have an api key issued to it including the official client, but the official client's api key should be allowed additional api scopes (permissions) that 3rd party users aren't allowed to use. It is pretty obvious how to solve this but if you consider not everyone plays nicely, you have to ask "What would stop someone from just pretending like they are the official client and using it's api key?" Communication will be encrypted, but the server is not in the cloud or anything like that where we could control it. Our customers install the servers on their own machines and they will more than likely have access to the server application's SSL cert. Once you have that you can easily write an app that would run on our customer's machine that could glean the API key and secret from the official client app and use that info to request tokens from the server as if you were the official client.
I am planning on self signing the default key that the server uses and I could try and hide it in the application, but that really is just obfuscation. Besides, I wanted to allow users to provide their own SSL certs so browser based 3rd party applications wouldn't have issues with the browsers complaining that they are trying to communicate with on a self-signed SSL channel.
Is there anything I can do? Here are my choices as I see it:
1) I can set it up so that only SSL certs provided by us can be used and we hide them on disk encrypted using a secret that is obfuscated in the application code. We then just hope no one bothers to take the time to dig through our .net assemblies to find the secret used to encrypt/decrypt the certs on disk.
2) We allow them to provide certs so that we don't need to be involved with that process at all when they want to use a signed cert (we don't want to be in the cert business). Now we can't even hide behind obfuscation so if someone wants it, then the official client's API key and secret is easily obtainable.
Neither seems very desirable to me. Option 1 makes us have to request addition funds from them and manage SSL certs when self-signed doesn't work for them and in the end if someone really wants them they can still take the time to get them. Option 2 just makes it super easy to steal the official client's secret.
Reasons to want to limit unofficial Apps:
1. Discourage clones
A. Tell people not do it. Have a lawyer send cease and desist letters to authors of popular apps (and to anyone helping distribute them). Intermittently download them and alter the client/server code so that the popular apps will break. For added discouragement, temporarily ban any users who used the popular app. Authors will mostly give up on cloning your app; temporarily banning users will kill their install base. This is not great for your reputation.
2. Prevent unauthorized behavior.
A. Any behavior allowed by the official app should be allowed by the custom app. Whatever scenario you are worried about, block it server-side so that neither app can do it.
You can try to hide credentials (code obfuscation, hidden credentials, etc.), but this is only raises the cost/difficulty. This is often enough to discourage code theft (no need to make code theft impossible; it is sufficient to make it more difficult than copying it by hand). However, users who want to use your api in unsupported ways can work around this.
The answer is simple. each instance of you app should have its own unique key effectively a user sign up. You then ban users who infringe your rules. in this case signing in with a non authorised client. should be pretty easy to detect by pushing updates more frequently than it would be cost effective to reverse engineer them. Much like punk buster or other anti cheating tech

Protecting Facebook API Secret in C#

Given that C# can be decompiled incredibly easily, exposing all set variables as well as functionality, is there a way I can fully protect the API Secret that Facebook provides for creating an App?
Thanks
A general rule of software design is to not trust the client. Whatever the client can do, anyone can do. You can try some security by obscurity and have a method that does something to "generate" the secret or you can hide it away in a seemingly unrelated class, but at the end of the day, anyone with a little bit of time can just look at the outgoing packets and extract the key from that.
If you want real security, route all your networking through your server. Have the client send commands to your server, which will interpret the commands and use the Facebook API with your secret to send the client back the proper data.
One possible solution to this problem is to store these credentials in your app.config file and then encrypting the section containing these credentials using DPAPI.
http://msdn.microsoft.com/en-us/library/ff647398.aspx
Decrypting config values is transparent and can still be done through the ConfigurationManager class.

Categories