"Safely" store (on client side) tokens for reuse? - c#

I'm trying to create a desktop application that will send updates to a web-service I am developing.
Ideally, the application would be configured only once and deployed to a network share. When configuring the application, the user will enter a password that is used to authenticate within the web-service. After that, a token will be created to be used on future connections.
This would allow any computer with access to the network share (even if it is not the computer in which the app was configured) to just run the application (which will connect to the web-service) without entering any credentials (because the token has been saved).
Question is: How should I protect this token?
I know that storing it client-side will never be completely secure, but I want to make it as hard as possible for someone to gain access to the plaintext token.
I'm looking for an answer that, preferably, does not depend on any operational-system resource (since the application can be executed from different devices).
Assume I have full control over the application and the web-server
I'm developing the console application using C#, but I believe this to be more of a theoretical question (not tied to any specific language)
Here are a few things I've tried/thought about:
Serializing the token using something like C#'s SecureString and storing it on a file: it's the best I've come with. But obviously, very trivial to reverse if someone gains access to the key file.
This answer suggests to use the Windows Data Protection API (DPAPI) (in C#, the ProtectedData class), but apparently, this would allow only the user who initially saved the credentials to access them, which would not work because I have to access the protected data from multiple users/devices.
Pass the token as a parameter to the application: this just changes where I'm going to store the token (on a batch file or OS task that calls the program, for example), but I don't think it makes it any more secure.

Since the user is not an administrator of the machine (this is a fundamental hypothesis), there are many ways to hide things from her.
What I propose is:
Make sure the main app runs under different credentials than the
logged user, a "special user".
Write another end-user app, just for setup, that talks to this app (using any interprocess communication you see fit, TCPIP, whatever, maybe secure but I wouldn't care too much at this). This app is used only to gather credentials and send them to the first app
Now, the main app can write the token anywhere the logged user has no access, but I recommand protected data because it's very easy to use
Here is some graphical explanation:
Since data encrypted using protected data (Windows Data Protection) can only be decrypted by the Windows user who has encrypted it, the logged on user will not be able to read the "special user" data.

I would suggest using JWT.
Your server would generate a Token after a successful authentication. The token would be sent to the client. Each subsequent call to the server would send the token in the header to the server. The server would then verify the token. If verified, the server knows the client has been authenticated.
No need to store usernames/passwords on the client.

There is no bullet-proof way to solve this problem, the client finally needs access to the server, and so can do an attacker with enough privileges on the client.
What you describe is a typical scenario for the OAuth2 protocol, since you have control over the server. With OAuth2 you cannot avoid the need to store a secret on the client, but by exchanging it for a token, you can protect the original password and you can guarantee that the token is very strong (user passwords tends to be weak).
To store the token/password on the client one could encrypt it before storage, but this immediately raises the question of where to store the key for this encryption. An attacker could extract it from the client. There are some ways, which can improve security for the key storage.
Depending on your situation you may consider the usage of a Hardware security module (HSM).
You can use an OS specific key-store like you mentioned with the data-protection-api. A key-store can only help protecting a key, because it has the support of the operating system (I think this is what you meant with SO-independend?). With the DPAPI you can not only restrict access to the logged in user, rather you can restrict it to the local machine. Key-stores are available on other operating systems as well.
Instead of storing the password on the client, it can be requested from the user each time the client starts. This can be reduced to the startup of the device, the password can then be hold exclusively in the memory.

Well, you can't protect anything in client side. Once it's there, anyone with privileged access can see it.
What you can do is make this piece of information useless without something else.
The best approach here would be to store a kind of public key in the client side and use this public key to create a hash to authenticate the user via webservice.
When the user configure the application, the server send this public key that the application stores locally. When the application call the server it will create a hash using this public key and a private key that is only known by the application and the server. Then the server can check if the hash is correct using its private key.
To improve security, you can use a timestamp in the hashing too, so it will change overtime and prevent the reuse of keys. Or it could send a new public key with the each webservice answer.

I would suggest you to use IdentityServer4 as it provides RFC compliant protocols and depending on the GrantType a client application is given in your context your desktop application.
Even though the token is in plaintext it is protected in the webservice where the Access Control(Issuer of token) validates that a token is being received from the correct client by checking the Origin in the clients request and the one stored in the database.

Related

Client Credentials Flow or Authorization Code Flow (with PCKE) for a trusted desktop client

I'm developing the authentication/authorization architecture for several APIs.
I'm using IdentityServer4 as a Security Token Service (STS).
From what I've read from "Dominick Baier" (one of the persons that built IdentitySever4), there are only two types of Flows that should be used:
Client Credentials Flow. (machine-to-machine)
Authorization Code Flow + PCKE. (for iteractive users).
I have several C# Web API's that will communicate with each (Machine-To-Machine), and I will use the Client Credentials Flow.
But then there are some WPF Desktop Applications, that will need to access some APIs, and don't have a user.
Which flow should be used?
I've read that:
Desktop/Native & Mobile Applications should use Authorization with Authorization Code Flow (with Public Client and PKCE), since they are hosted on the Client side, and the Client/Secret is can be leaked (maybe on a Desktop application we can Encrypt the Secret? But then will need to manage a way how to store the secret that decrypts that right?)
Then I've read:
"Anytime you have a system that isn’t concerned with the end-user identity (and just needs to authenticate the system), use the OAuth2 Client Credential Grant."
For now, this is my case, I'm not concerned with the end-user identity (but maybe in a near future I will).
So since the above points conflict with each other:
- Which flow should I use?
- Can I have a Desktop Client using Clients Credential Flow and be safe?
Also, I've read a bit about Mutual TLS, If I use that, does this change which flow should I use?
You can't trust a client because you can't be sure a request originates from the client. And another problem is that clients are not good in keeping secrets. But there are different types of clients.
Clients that run on servers often having a single task, like synchronizing data which is user independent, are suitable to use the client credentials flow. To some degree they can keep a secret (running on a server).
You can use unique credentials for each instance but that doesn't make it safer. It helps you to identify the client, but doesn't add security. Security is about monitoring behaviour and detecting anomalies. Or perhaps narrowing access by filtering on ip address.
But you are not limited to use the two flows you've mentioned. Being a token provider, you can extend IdentityServer with custom flows using extension grants.
Without user the client credentials are somewhat similar to the resource owner password credentials (ROPC) flow (another option that is no longer covered in the grant type documentation but still exists, see the old docs). Neither are really safe in the sense that both can be automated. The user factor can be eliminated since user interaction isn't required for these flows.
But I wonder why your app has no user, running on a user machine. Because ideally you have a client (without secret) where the user logs in and let the client contact the api (delegation).
So there are two things: do you need to identify the client? If not you could suffice with an ApiKey, like e.g. Sendgrid. And you can never trust a client. Security has to be server side.
So basically it doesn't really matter, there is nothing you can do to make it much safer client side. The only thing you can do is add the requirement of user interaction. So perhaps now you don't need it, but it will increase security and allows you to delegate api access to the client.

Implement Pass-Through Authentication in C#

I am developing a TcpClient/TcpListener based client-server application.
Now I have come to the point where I need to authenticate the user. I could use the PrincipalContext-Class on the server side and request username/password/domain from the client, but I don't want to send the credentials over the network. Additionally, I don't want to ask the user for their credentials again.
So, I know the Citrix Receiver which supports pass-through authentication. It uses the current logged on user and does not request any credentials and authenticates the user against the server. It just works.
How can I do this in my application? I thought about some kind of token which can be sent to the server, but I could not find any solution.
Wrap the NetworkStream in a NegotiateStream, and call the appropriate NegotiateAs... methods on both client and server.
The client can specify what impersonation level to allow, and the server can specify what level it requires (minimally Identification in order to determine client identity, but if you need to access local or network resources as the client, you could also specify Impersonation or, with the right network configuration, Delegation).
Once authenticated, the server can determine the client's identity and/or impersonate using the NegotiateStream's RemoteIdentity property.
As I mentioned in my comment, I don't know how Citrix affects this setup (never having used it), but if it's basically completely transparent to the application and everything uses standard Windows credentials, then this should work.
The .net Framework does have functions for Diffie-Hellman Key Exchange:
http://de.wikipedia.org/wiki/Diffie-Hellman-Schl%C3%BCsselaustausch
http://www.codeproject.com/Articles/24632/Shared-Key-Generation-using-Diffie-Hellman
If you are writing both the client and the server parts of the application, then you can encrypt the user's credentials for passing across the network and decrypt at the other end.
Working on the assumption that on the client machine, a malicious user could extract the encryption key from your application (using strings or similar) then symmetric encryption is not suitable. Therefore asymmetric (public-private) encryption seems suitable. Generate a pair of keys and the server's key should remain private (and only on the server) and the clients' key can be included in the application on the client machines. Then it doesn't matter if the key is extracted from the app as credentials can only be decrypted with the secret and secure private key on the server. This class has done most of the ground work for you.

Hiding MySQL credentials in a C# app

I am extending an open-source VoIP softphone application (written in C#/.NET) to my needs but don't know how to best approach this issue. I want the application to connect to database when a user enters his email address to log in, and perform a SQL query to fetch his account number using that email and authenticate with account number. But, I think including my MySQL connection credentials (host, username, database) is insecure? How should I do it?
It is indeed insecure.
You need software running on the server, that can accept said email and password as input and connect to your database (so the connection string is sitting on a machine in your control), check it and return either ACCEPTED or DENIED to the client. In your case, ACCEPTED could be just the account number you mention.
Bonus points if the email and password are transmitted from client to server app over an encrypted link (public key).
You should put the connection strings into a configuration file and then encrypt that portion of the file. There's a tutorial on how to do that here: Protecting Connection Strings and Other Configuration Information. Although the tutorial is for ASP.NET, the same principle will apply to pretty much any .NET config file.
There's also a similar question here: Encrypting passwords in WinForms app.config, .NET.
Our rule of thumb when designing database applications is to always use delegation and isolation.
What isolation means is that we isolate database interaction from the end user application through the use of services (i.e. web services, wcf, .net remoting, etc). In this way, the database is never directly exposed to the user.
What delegation means is that the database access is always performed on behalf of the end user by a well-known, limited-access database user (generally the user that the service is running as). If at all possible, the database access should be performed by a user authenticated by the network rather than by storing user names and passwords in connection strings or other semi-secure locations.
Finally, one important note: you should always encrypt your end-user's login and password information before sending it over the wire. This is a little extra work, but well worth it from a security perspective.
Can MySQL do Windows based authentication (i.e. on a domain)? If so, you could use that. Otherwise you might want to have credentials to a service, or use encryption, but you would need to include the encryption key so anyone dedicated to discovering it would.
You could code your connection strings so that they end up in your assembly and use a code obfuscator to protect it from disassemblers
There are many ways to do it, including obfuscation and other ways making it difficult to use outside of the application, but not impossible to retrieve/use.
How should you do it? The best way (as far as I know) is to give the account the minimum credentials necessary so that if someone does have the username and password he/she cannot do anything malicious with it. Permissions can be set up in many ways for user-specific data, such as views so a user can only access the correct rows. Basically, if security is a top concern, assign permissions conservatively and if necessary give different users different credentials.
You should host a (php/jsp/asp) script at your server with which your application will talk. you should not store your credentials inside the app at any cost.
Tthere are so many ways to just take out the information. Especially .NET applications. it doesn't takes more that 30 mins :p

Best way for storing a static password on an automated client

I'm building a system that consists of many clients connecting to a server. The clients automatically push data to the server via a web service call.
I've built an authentication mechanism in order for the clients to authenticate with the server so only authenticated clients can upload data.
The problem is that I've hardcoded the password into the client code and it is accessible if someone uses a reflector.
In this scenario, where I have no user input, what would be the best way to store the static password on the client?
Thanks
(.Net version on the client is 2.0 and the .net version on the server is 3.5)
You have a number of methods that you can use, but one of the easiest to implement would be to encrypt the password and then just store it in the app.config for the application that gets deployed to the user.
Have you looked at http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx?
Also, are your webservices WCF? If so, you could use mutual certificate security. It is much more robust than a password.
HTH
"I've built an authentication mechanism in order for the clients to authenticate with the server so only authenticated clients can upload data."
How are they authenticated to become "authenticated clients"?
Can someone just copy your application to their home computer and now they are an authenticated client?
This seems like a huge security oversight if you're trying to decide who can upload based on a value in your assembly.
If you can do IP based validation, if you want to avoid passwords and login mechanisms.
I would consider getting a good obfuscator for your code, for one thing. That will prevent (or at least deter) people from using reflector on your assemblies.
However, your authentication system doesn't sound too secure. Even if you did encrypt the password, if the password is always the same, it would be as easy as sniffing packets to figure out what needed to be sent to your server to authenticate. Because it would have to be decrypted before it was sent.
You'd have to go over an SSL at the very least.
Also you might want to look into using Asynchronous Encryption with Signed XML using a Machine Hash if you're installing this in some public client's environment. Something like a Licensing Scheme.
I don't know anything about your architecture or the environment you're running in, so I can't make any recommendation as to what would be the best security implementation, but I can tell you the current setup doesn't sound secure to me.

Temporarily load SSL Client Key for Client Authentication in C#

I am using the WebBrowser control to add a WebInterface to C# app. My desire is to verify that only such app is able to connect to our Web server using SSL client certificates.
My idea was to embed the client certificate in the app and just use when connecting via my app. Anybody have a sugestion on how to do this? Or the only way to make it work is to load the key in the X509Store.
If I put it in X509Store, will it make my key available for general Internet Explorer Usage?
Are you sure this is what you want to do? If you embed the private key in your application (as your approach entails), an attacker can extract it and use it to authenticate their rogue software.
A server cannot authenticate client software. It can only test whether a client possesses some secret. When you embed a private key in your client and distribute it, it will not be a secret anymore.
I'd recommend authenticating users of your software, rather than the software itself. You need to let users generate their own secret, whether it is a password or a private key, and give them an incentive to protect it.
So, several thoughts here:
1.
I agree with 'erickson', validating that ONLY your app can communicate with the app is nearly impossible with your current design. It's just a matter of time before someone reverse engineer's your app and then its game over (if that's you only form of security). If you want to validate that its your app and a valid user then you need to authenticate the user as well as some mechanism of checking the signature of the app in question (which I don't believe is possible in a client-server model...after all I can always lie and say that my 'hackyou' app has the same signature as your 'realapp' and you can't verify that from the server-side)
2.
Remember the WebBrowser control is essentially a wrapper around IE, so without some tricks (which I'll get to in a sec) you would have to add the cert to the user store.
3.
Here's a hacky way to accomplish what you're asking (even though its a bad idea):
First use the WebRequest.Create to create a HttpWebRequest object
Manually load a X509Certificate2 object from either a file or the binary stream encoded in the program
use the HttpWebRequest.ClientCertificates to add your cert to the webrequest
Send the request, get the response
Send the response to the WebBrowser by pushing the ResponseStream of the HttpWebResponse to the DocumentStream of the WebBrowser
This essentially means that you will have to write some wrapper classes to handle the Requests and Responses to and from the Server and are just using the WebBrowser to handling the viewing of the HTML.
In reality, you need to redesign and look at the threats you're trying to handle!
The intent of using the key is not so much to validate the users as to restrict access to users of the app instead of using any WebBrowser. This is sort of an intranet behavior over the public internet.
This is a poor man's DRM. The losses due to people extracting the key are not that important. I think the risk of this happening is low and what we could loose is minimal.
Nevertheless if there is any other idea to restrict access to the WebServer to only users of the App I am open for any suggestions. Basically my desire is now to have a public WebServer wide open to be read by anyone, but access over the public network from diverse places is necessary so setting up a intranet infrastructure is not possible either.

Categories

Resources