I am designing a system in a client server architecture - TCP based. There is a requirement that all the messages between the server & client should be encrypted. So I am thinking of using SslStream class in .NET Framework.
From SslStream MSDN, my understanding is that we need to use Client & server certificates to make a proper channel & communicate.
I don't want to use any certificate specific to particular machine(client) or server. I Just wanted to have a common key between the system.
Is there any possibility to use the SSL stream without certificates??
Whilst not required by the TLS spec, the use of the .NET SslStream implementation requires that the server has a certificate (and its associated private key). This allows any client to confirm that it is communicating with the server it expects to be. Optionally, clients can also be authenticated by having them provide a client certificate to the server. So, if you want to use SslStream, you're at a minimum going to have to create a certificate for the server, because that is how this particular implementation works.
If you don't wish to use certificates at all, then there are other options. E.g. if you are planning on using your application within a Windows domain, and both client/server are Windows based, you may be able to use NegotiateStream instead. This also supports encryption/authentication, but does not use certificates, and will additionally allow you to identify the user on the other side of the connection.
Related
I am working on a legacy architecture that has a server that has an existing certificate for communication. Multiple existing services in the legacy architecutre use this for communication. I am working on creating a communication channel on a much newer system that is built for scale that will communicate with our old framework. This will be used to perform a phased migration where we rely on the old architecture for a period of time, while still running the old system.
Due to some internal constraints, we can't simply add the existing certificate to the new architecture. Furthermore, changing the certificate to the new one will require changing every single service that communicates with the server to have retry logic & both certificates. Furthermore, this has the potential to instantly break the old system entirely (as all the services rely on the server to perform - one of the limitations of the old architecture).
So the ideal solution is that the service simply accepts two different certificates for a period of time while we perform the migration. The new services communicate with their certificate and the old services communicate with theirs. Then we can deprecate & decommission the old services
The only way I see to set a certificate is either in config or how we currently do it:
host.Credentials.ServiceCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType.FindByThumbprint,
thumbprint);
Calling this again would overwrite the certificate set on the host. So is there any way that I can add an additional certificate that the server can distinguish between and use the appropriate certificate for communication with the client when it receives a connection?
Thanks for your time
As Ding Peng mentioned in the comments:
This solution is not feasible, if use certificate verification, the server can only bind one certificate, as you said, if you add two certificates, one of the certificates will be overwritten.
This is correct, but I was misunderstanding how certificate encryption worked and it was unnecessary to add an additional certificate.
Simply by adding logic to whitelist the client certificate subject names of the new architecture - it was able to authenticate.
I had assumed that if the server certificate did not share the subject name of the client cert, that there would be an issue with authentication & encryption. However, this is not the case and simply whitelisting the new subject name was enough to perform the auth.
I have a Client & Server application set, both written in C# but some client versions might be distributed in other languages in the future. I want to protect my applications.
I was looking for some kind of advice to stop just random people sending messages to a server and acting like a client, what kind of validation can I put in place?
My client applications I distribute will be obfuscated but is this enough? I'm just looking for some advice in this situation, is it wise for me to add some kind of encryption other than SSL, or am I just being over protective and over curious? Any input is welcomed & accepted.
It is impossible to determine if you are communicating remotely with "your client" or another piece of software that also knows how to communicate in the way that your client does.
What you can do is ensure that you are communicating with someone that is authorized to communicate with you by using client certificates for your SSL session.
The server proves who it is to the client and the client proves who it is to your server. The security then rests in whoever holds the private key to the client certificate (and the password for this key file).
The C# SslStream Class has support for this. Namely the AuthenticateAsClient method is relevant here.
In summary, if your software is only secure when communicating with a client you wrote, then your software isn't secure period. Instead, design your server in such a way that you can serve client requests securely. Using authentication is one of these ways.
You would want to do two things....one is look up certificate pinning. Your app will validate your SSL cert to thwart man in the middle attacks and it makes it hard to circumvent. The other is when making requests to the server have some type of user name / password block on the server side script before the server side does anything so the requests will simply be discarded by the server if they are from an unknown source.
I'm currently developing a C# application that communicates between a client and server using TCP/IP. After connecting I'm swapping session based RSA public keys to then pass a session based AES symmetrical key. This all works fine and means I have a secure channel to communicate on.
The trouble now is that I need to ensure that the server and client are both the ones I wish to communicate with. Before anyone suggests SSL/TLS: I'm not connected to the Internet to allow the use of a root CA.
Would it be valid, that after establishing a secure channel between the client and server that I provide a simple challenge-response method? For example, if the client sends an identifier (GUID?) the server compares this value to known clients and accepts or rejects it, and the same is repeated in the opposite direction. As the data is encrypted and the encryption is session based is this a valid method of verification?
I understand that the storage of these identifiers is the weak point.
Before anyone suggests SSL/TLS: I'm not connected to the Internet to allow the use of a root CA.
Before you are re-inventing the wheel: you don't need root CA with SSL/TLS but can simply use self-signed certificates with key pinning. Public root CAs are only usually used because it scales much better to provide only few common CAs instead of exchanging all self-signed certificates (or their fingerprint) to all peers of the communication.
Apart from that it looks like you proposal assumes a secure connection already to check credentials which you then will use to verify that the connection is really secure. Or in short: to provide a secure connection you need a secure connection first.
I am currently looking for the best way to establish a stateful and encrypted connection between a C# client and server application. First, I thought about using IPsec, but as it works on a low level (OSI: Internet Layer), I would be very hard to implement, if you want the functionality inside your program and don't want to rely on the OS.
What technologies would you recommend for this purpose? Is there some functionality already built into .NET (4.5)? It does not neccessarily have to be stateful, working with some kind of heartbeat would be a valid option, too.
You'll want to use a standard protocol such as SSL rather than trying to make your own. First the implementation will be much easier because the .NET framework will support it, and the transport protocol that runs underneath it is stateful (e.g. TCP). Second developing a cryptographic protocol that is secure is very difficult, and SSL has already been implemented so why reinvent the wheel?
SSL works by using PKI (Public Key Infrastructure) to generate a shared symmetric key. The handshake consists of a number of steps. First the client sends a request for a secure session, then the server responds with it's certificate, the client verifies the certificate by crawling up the ladder through the certificate authorities (e.g. Verisign, Thawte, GeoTrust etc...) or if it already trusts the server it can just accept the certificate that is self signed.... and once it finds the certificate is trustworthy it generates a symmetric key and picks an algorithm (e.g. AES, 3DES, RC4, IDEA etc...). The client then encrypts the key and algorithm being used with the public key, then the client sends that value to the server and a secure session can proceed using symmetric encryption which is much faster.
SSL itself is can be used in a stateful manner because it actually works over the transport layer in the OSI Model, HTTPS on the other hand is not a stateful protocol by design. HTTPS is HTTP over SSL so the two technically don't really have anything to do with each other, except that in HTTPS SSL is used to secure the application data that is being requested. With HTTPS as with HTTP once a request is made to the server it basically forgets about you (not exactly how it happens but for all intents and purposes you can think of it this way). I myself would prefer the use of HTTPS if you can get around having to have a stateful protocol. The main reason for doing so is so that I wouldn't have to write the code and possibly have a mistake in the implementation of SSL. All you have to do is build a WCF or REST based service that runs on IIS and get a certificate for your server.
That being said, if you still want to create your own SSL server that doesn't use HTTP on the application level you can use the TcpListener and TcpClient classes along with the SslStream class provided as part of .NET to create your own. MSDN has a good example of how to create an SSL server and client: http://msdn.microsoft.com/en-us/library/system.net.security.sslstream%28v=vs.110%29.aspx
Side Notes
Securing the transport of your data does not secure your app, do not make the mistake of thinking you get automatic security
If you choose to make your own server and client you can use either openssl to generate your certificate or you can use makecert which is part of .NET to make your certificate.
Just form a regular TCP connection between the applications, and write up a simple packet protocol (EG, 4 bytes indicate packet size, followed by packet data)
Except the data within this base-level packet is encrypted through System.Cryptography.AesManaged
If you have trouble encrypting the packets using AesManaged, try using The Encryptamajig - if that doesn't help, post further questions and we'll give you further specific help.
-- You can either have both sides know the password ahead of time (EG, tell the person at the other end the password in person), or quickly pass it unencrypted at the start of the connection (or, rather, encrypted with a default known password)
Not necessarily the best method but it should do the job.
Why not just the regular HTTPS? HTTP is just one level above TCP but it is far easier to work with and firewalls tend to be generally easy on HTTP/HTTPS ports namely 80 and 443. Of course, plain HTTP is not suitable for you but can you not use HTTPS instead of coming up with your own encrypted communication mechanism? In the client side (C#), all .NET classes such as HttpClient supports HTTPS very well. I quote Ayende in support of my suggestion to go with HTTP :)
I have a specialist web app written in C# - my C# code acts as a web server, accepts connections from browsers, and presents the app as web pages.
The existing app uses SSL to secure the connection from the browser, but I am concerned about BEAST, which renders many of the older SSL ciphers insecure. I therefore want to ensure that I only accept connections using TLS1.1 or later, and/or secure cyphers like RC4.
I have already accepted that I will have to ditch the SSL library I was using, and probably switch to .NET 4.5 with SslStream.
Although I see how I can check the cypher for a stream using SslProtocol and CipherAlgorithm, I cannot find a way to force a connection to prefer one of the more secure algorithms. Am I missing something?
For the avoidance of doubt, this is nothing to do with ASP - this server is written in raw C#. I need a programatic way of making SslStream prefer particular ciphers. It is unlikely that I will have the necessary permissions to alter ssl registry settings on the host server.