Implement Pass-Through Authentication in C# - 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.

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.

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

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.

Managing Active Directory securely from another computer

I have created an ASP.NET website that has to access Active Directory on another server and change users passwords. The problem is that I need to authenticate with existing AD account and I cannot send AD user's password in plaintext when communicating with the Active Directory server. How do I communicate with AD server from ASP.NET website, so that connection is secure? My AD server supports LDAP protocol, but I do not know how to enforce communication with LDAP via a secure channel.
ASP.NET Website --------------LDAP/another protocol (secure)------------> AD Server
Fairly simple, you need to do two things :
Configure your Active Directory instance to accept connections over LDAPS, or port 636. You'll need a certificate (it can be self-signed) to set that up.
Update your LDAP authorization code to use this the new connection. This shouldn't be anything more than changing the server to "ldaps://{{IP OR DNS}}", and ensuring you're setting SessionOptions.SecureSocketLayer = true;
If you want to verify that it's working properly, Wireshark the traffic leaving your ASP.Net site that's going over port 636, and you should notice it's now heavily encrypted, and impossible to discern anything meaningful from.
I've done a ton of this stuff over the years, so I've had a few other questions surrounding this that should also help you out :
Set callback for System.DirectoryServices.DirectoryEntry to handle self-signed SSL certificate?
(This contains a full implementation of LDAPS)
Custom Multi-factor Active Directory Authentication
(This is a much more simple example, but would work perfectly fine for your purposes)

How to prevent someone from overriding the code that grabs the windows authentication and uses the username to make wcf calls?

Basically, if you use WindowsAuthentication to grab the username, store in a variable and then pass that to any services you use, what's to stop someone from hacking your code and passing in another username?
On the client end you can check the IsAuthenticated, but then after that it only lets you grab the Windows Username, not the Windows password.
Is there some way to just pass that authentication object itself without letting it be hacked? Otherwise, I might have to switch back to not using Windows Authentication as my Authentication and custom rolling a user/pass with a db table.
You can't pass user's credentials outside of your server due to "NTLM one hop" behavior. You may be able to configure Kerberos authentication to handle cases when you need user's credentials flow between front end and backend servers.
The other option is to establish trust between servers (i.e. HTTPS with client certificate) so backend server is able to trust user name coming from your server (as it would be the only one with correct client certificate). You will not be able to impersonate the user on backend server as you will on ly have a name.

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.

Categories

Resources