Obtaining access_token from Google Drive API from Desktop application - c#

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.

Related

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.

Compiling Service Account Credentials Into Executable?

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.

Complete Sample of video Creation and on demand token issuance in Azure Media Services

I'm trying to create an elearning system that has videos associated with lessons. When a user gets to a lesson a video needs to play. The videos should not play unless I authenticate that the user can play that video and can play it right now. I'm trying to accomplish this using the azure video player.
I can make this work with azure media services without encryption without issue.
However when I go to do the encryption, the samples are VERY week.
What I'm trying to do is encrypt the video so that it can play on all browsers and have everything that the azure video player needs.
Further, at the time that the user requests to play the video I want to use their authentication with our website to determine if the video should play, and then set the token on the media services.
I would have expected that media services would use oAuth 2 and I could point it at our endpoint with a specific claim required for the specific video the user requested and I would return an auth token or not. But it appears to work backwards from this.
So I've done the following:
Gone into the classic portal (because apparently this hasn't been updated to either use the new portal or the new way of doing storage...)
Created the Media Services account.
Gone to content protection as as best as I can figure from the videos enter Type token for both and json web token.
Under issuer for aes and playready I've put in the path to our oAuth provider, but I"m not at all sure what this should be and I can't find any documentation that explains what this should be.
Scope: Under ae, the samples have something similar to urn:Portal but under playready this has to be a full URI, which I can't figure out what's supposed to be there.
I created the verification keys for both types
I have no idea what to put in claims or how this is relevant.
License type = non-persistent
Passing Video Content to Unknown Outputs I have set to Allowed. I don't know what allowed with constriction does or how it should be setup.
Allow test devices is enabled for now.
Then in my encoding stuff I've put in the following after creating the asset from samples:
//Add encryption
var key = CreateEnvelopeTypeContentKey(context, finalAsset);
var tokenTemplateString = AddTokenRestrictedAuthorizationPolicy(context, key, audience, issuer);
CreateAssetDeliveryPolicy(context, finalAsset, key);
var tokenTemplate = TokenRestrictionTemplateSerializer.Deserialize(tokenTemplateString);
var rawKey = EncryptionUtils.GetKeyIdAsGuid(key.Id);
string testToken = TokenRestrictionTemplateSerializer.GenerateTestToken(tokenTemplate, null, rawKey);
But if I try and enable this stuff to get playready, wildvine AND BaselineHttp it all blows up and I cannot find examples of all 3 (which appear to be required for Chrome, Firefox and IE/Edge to work reliably) enabled and working in the code as you'd expect. (note the methods called above are directly from the samples)
Further I can't figure out how to use the verification keys from the portal in this code because I can't find any samples on this.
And presumably this sets up the asset to have it's own authentication. Although I can't tell. But what I want and need to do is have each asset be separately authentication by the asset and by the user and not have the bearer token be usable anywhere else.
At this point I'm completely lost, because the only code I can find to generate the JWT is the test stuff which obviously shouldn't be used in production.
What I'm looking for is code that doesn't use Azure AD and allows me to do my own, so that when a user wants to watch a video, they come to me, I say, yup, you're good, here's your token just for you and only you and no one else that is created just for you in C# in my web api that returns the token in the json response.
Then I want to set it in the security credentials (and put all of the permutations in!) so that it will just work on the browser in question (ie, edge, firefox, chrome, safari) and the player sends that along with the rest and the video just plays no matter what browser.
But since I can neither encrypt the video with the right keys, nor encrypt it for all permutations based on the samples nor find any example of creating the JTW properly based on the shared keys and whatever I need to store in my database based on the encryption process I'm stuck.
So is there a sample somewhere that takes you through this full process to make this work in any web browser when done and generate the encryption for all of them, and the token for the client on a per issue basis?
If not, can someone help answer these questions?
And if this is MS watching this, I'd suggest that you consider giving us the ability to have just the single url in the client, and pass our oAuth2 bearer token (not yours) and have you use that to single sign on with us, and demand a claim passing the asset id and getting a yea/nea to play the video with a timespan their authorized to play it on the specific client involved. If this is possible now, please provide a full sample or instructions on how this can be accomplished because it's very not clear at this point and everything is geared to AD which isn't useful and there are a ton of missing pieces.
Ultimately, I need to be able to live stream this content on the web and on mobile clients AND be able to download this content encrypted and play it on those same mobile clients offline but still encrypted and locked down. Those last pieces I don't have a clue how to do at this point and I can't find any documentation on either, but I'll ask that separately.
Thanks!
Bonus Reading
Resources found that are relevant but don't answer the question or only partially answer the question and break other parts:
Configure asset delivery policies with .NET SDK 🕗
Use AES-128 dynamic encryption and the key delivery service 🕗
Azure Media Player - Protected Content 🕗
Azure Media Player - Playback Technology ("Tech") 🕗
How to make Token authorized AES encrypted HLS stream working in Safari 🕗
Integrate Azure Media Services OWIN MVC based app with Azure Active Directory 🕗 (this one appears to be the closest but I've been unable to decouple it from Azure AD)
We don't have lot of samples to build customized Security Token Service (STS), because each business may have its own requirements and lots of customers are doing integration work (i.e. they already have a token issuer service).
As said, I am happy to help you to complete your workflow. You can email me at yanmf#microsoft.com and I could have a call to troubleshoot your workflow.
Cheers,
Mingfei Yan

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

Windows Store Apps - Let user to remove trial mode via code

I have developed application which supports trial mode. But now I need let some users to get full via activation code. Scenario is user downloads trial application and he can enter activation code for the app and then user can use full features of the app.
Can anyone please suggest me a way to do this.
You need to think about how you will authenticate the code - I'm guessing that you don't want them to authenticate the code via the store so you will have to provide some backend service to do this.
The service will obviously require the activation code to be sent to it (you should store this in the remotesettings), and you might perhaps want a device unique ID sent to - you can use the unique id for this.
Your service should then validate how many times it has seen the code, and if it's happy it should hash the code, the device ID, and a secret shared with your application - this will need to be embedded inside your app code.
For additional privacy for the user I would advice hashing the device unique ID with the shared secret before sending it to the server.
You need to store the returned activation code inside your app - and there isn't a lot of choice - I would personally store this code in the LocalSettings area.
Now on startup you need to verify that the stored activation code is valid. If you have an internet connection then you can do this by asking the service if the code is valid, but you must make an arrangement for offline checking. This is simple enough as the activation code, plus the hashed device ID hashed against the shared secret should equal the stored activation code - depending on your type of application you might want to only allow 5 activations this way before requiring internet access (pick a high number as this could really annoy users)
Finally you need to consider users that have multiple devices - according to the store you can have 5 installs of the same application, for the same users, across different devices. To accommodate this we have stored the activation code in remotesettings, so on startup check if the code exists, and if it does automatically send the code and the device id to your service for activation.
The only other thing you need to consider is how on earth do you secure the shared secret in your application? Unfortunately there aren't many options for this. It really depends on how secure your app need to be. If you are totally paranoid then obfuscate your code, but this just buys time. If you need more than that then I suggest you send the device code, hashed with a cryptographically random nonce to your service, this will return back what you sent, but hashed with the secret. Unfortunately this will make offline validation of the activation token impossible, so you will have to build in a grace period where internet connection is not required.
Or you could use in app purchases.

Categories