Jetty client / server mutual authentication - java

I am trying to build a client / server servlet application with these general requisites:
both the client and the server are jetty embedded;
the server expose a servlet in order to receive json data via POST;
the connection must be secured via SSL (i.e. the connection will be done via Internet via https);
I want that only my Jetty client be able to send data to my server, all other tentative must be refused by the server;
the server and the client are unattended machines (i.e. not password via command line could be inserted by human);
no password in clear must be stored on the client device. In general I don't want someone could open the remote client device and stole the password and building a fake remote device capable to send data to my server too.
I have build a perfectly working client / server application via HTTP but I am confused about the security.
I have read that there is the possibility to use client / server mutual authentication and seems what I am looking for but I can't get the complete picture.
In this document client-certificate-authentication there is a more or less clear explanation about how to build a shared trusted CA but the password for accessing the TrustStore and the KeyStore are in clear in the code.
I think I am missing a tile in the puzzle.
Could someone point me in the right direction?
Thanks,
S.

I'm going with a simple answer (for now).
If you just want only your clients to talk to the server, then yes, Client SSL/TLS certificates are the way to go.
You'll want the server's SslContextFactory.Server.setNeedClientAuth(true) set to true. That will in turn cause Java's javax.net.ssl.SSLParameters.setNeedClientAuth(true) to be set on incoming connection establishment. If the client fails to provide the client certificate, the connection is closed, and no HTTP request is sent or processed.
As for securing the client certificate, that's up to you, you can do anything you want to do, as long as it results in a valid client SslContextFactory.Client that the Jetty client can access. This includes ...
Using plaintext passwords
Using obfuscated passwords (minimal effort, minimal security)
Encrypted keystore/truststore passwords elsewhere in your client, provided to the SslContextFactory.Client at the last minute. (modest security, wouldn't be that hard to figure out)
Creating the java.security.KeyStore object yourself and handing it to SslContextFactory.Client.setKeyStore(KeyStore) and SslContextFactory.Client.setTrustStore(KeyStore) methods prior to starting the Jetty Client. (a bit better security wise, puts more work on your behalf)
You might want to consider having the client certificates be short-lived (24 hours?) dynamically refreshed from the server, and have the client certificates be revokable (at the server/CA side) if you encounter abuse. (such as the same client certificate from multiple different client IPs)

Related

How does SASL_SSL security protocol work? Does client verify the server (X.509 cert)?

How SSL works is well know as it's quite widely used and described well every where. In short - SSL involves
Verifying server authenticity by client by verifying the servers X.509 certificate.
Then arriving at a symmetric key using diffie-hellman key exchange algorithm.
But I am not sure what happens withsecurity.protocol=SASL_SSL. Clients and Server communication of few technologies like Kafka etc rely on this security protocol as one of the option. Here I am worried about the point 1 above. If i get a wrong broker address (as a trick ) from some one, does SASL_SSL verify the server certificate or not is my question. If it does, then I can be sure that the received broker is not genuine and my application will not publish or subscribe to messages from this server and my data is safe.
Edit 1: Following #steffen-ullrich answer and comments And little more dig, i see below. Looks like the certificate validation is happening when used through chrome and probably its loaded in the cacerts too. So the java code is able to authenticate the server.. so seems ok..
Edit 2: Right the certificates DST and ISRG are preloaded in the JDK 11 cacerts, so the client is able to authenticate the server as commented by Stephen.
SASL is a standard for authentication of the client - see Simple Authentication and Security Layer. SASL_SSL simply means that the client authentication (SASL) is used over a protected connection (SSL) to prevent interception instead of over a plain connection.
What you are asking is related to another configuration please read the following description.
ssl.endpoint.identification.algorithm
The endpoint identification algorithm used by clients to validate server host name. The default value is https. Clients including client connections created by the broker for inter-broker communication verify that the broker host name matches the host name in the broker’s certificate. Disable server host name verification by setting ssl.endpoint.identification.algorithm to an empty string.
Type: string
Default: https
Importance: medium

Is there a way to dynamically trigger SSL/TLS renegotiation in a servlet?

I want to be able to accept both web browser clients and (automated) service clients to a single servlet running in my application. Some of the service clients will authenticate with TLS client certificates, but some will not. I do not want web browser clients to be prompted for a certificate ever, even if the user has some installed in their browser. The decision on whether to prompt for a client certificate is dynamic and based on policy according to the client, so cannot be statically configured in web.xml.
Is there a way to dynamically trigger TLS renegotiation to request a client certificate from within a servlet? If I had access to the raw SSLSocket then I could configure it to require a client certificate and then call startHandshake() to force renegotiation. As far as I can tell, there is no portable way to get hold of the SSLSocket associated with a servlet request/response though.
My application has to run in a variety of servlet containers, so I'd prefer to avoid container-specific solutions if possible. Ideally the solution would not involve a redirect, but I will accept that if it is the only way.
You wrote in comments above:
because that setting will cause a web browser to prompt the user to
choose a certificate if they have one installed that matches one of
the configured CAs. I never want that to happen for web browser
clients
Then I vote for this is impossible to achieve from server side. TLS takes first before any data sent through secure channel. You can't determine is it web browser or not knocking at your door not asking for client identity. From TLS point of view this is just yet another unnamed network client attempts to connect. After secure connection established, data is sent, and you can determine this is browser or not.
You may want to pipe browsers (1 way ssl) and server client (2 way ssl) through different endpoints.
Otherwise you may want to implement you own TLS protocol handshake procedure.
You may want to configure browsers not to answer to client certificate requests instead of configure server not to ask if (if it would be possible) to determine this is browser-based client. May be try to guess it through the cypher suit (list of supported crypto modes) but this is definitely not servlet level of interaction.
I am curious somebody know ho to solve you question.

Request encryption over https?

In HTTPS (SSL) browser send the encrypted data which can be Decrypted by server only.
To confirm it, i did set up the burp proxy on my Firefox browser so that it intercepts the request sent to HTTPS server by browser .
When i receive it at burp, i see the data as entered by user though i was expecting browser must have encrypted that but did not.
So at what point of time browser encrypt data over HTTPS ?
Most pieces of software that do this (e.g. Anti-virus scanners) replace the https certificate with their own so the https traffic can be man-in-the-middled by the software.
While I'm not familiar with Burp, it looks like it does the same: https://portswigger.net/burp/help/proxy_using.html
So instead of
browser --(via https)--> server
Which only the server could read as only the server has the private key to decrypt the http so, it becomes:
browser --(via https)--> burp -- (via https)--> server
If you look at the https cert in your browser you'll probably notice it's been issued by Burp rather than being the real cert that the site shows when not using Burp.
This is the only real way of doing this, without majorly changing the browser to intercept it before the encryption happens, but can create its own problems: Should software really intercept traffic between you and your bank? What if that first connection can be compromised (see the Lenovo superfish incident for example). Many people (myself included) dislike MITM https services for this reason.

X.509 certificates for authentication without using client SSL

I'm trying to improve some code that enables logging in to our application using digital certificates, probably certificates stored on PKCS11 tokens.
It's a Java client server application, with the server on JBoss [Wildfly], and a rich Java thick client. We also have a GWT/Javascript based web client, but this doesn't yet support certificate auth.
The current implementation uses 2-way SSL authentication if certificate authentication is configured, i.e. the server will require a client certificate when the connection is opened. This causes some problems, and in trying to find ways to address them I've been searching madly to see if there is a standard, 'Right Way To Do PKI Auth To A JBoss Application'.
However just about everything I have found on the subject seems also to revolve around using two-way SSL, which kind of implies that is the Right Way to Do It.
It seems undesirable to me, in that the network transport is quite a low-level concern, heavily separated from the application logic and stuff like authentication and user management.
In order to prove the client is a valid user of the system (as opposed to merely someone with credentials endorsed by a CA in the server trust store), the server application logic has to rummage around looking to find the certificate that was used on the incoming connection in order to scrape the Common Name off it. I've discovered that javax.servlet.request.X509Certificate is a standard-ish parameter one can query on the servlet, so it ought at least to be possible.
The other architectural problem this causes is that our app requires reauthentication for the lifetime of certain sensitive operations. If one is using the SSL connection to prove the user has the private key, then logically that would require opening a whole separate connection.
Logically, authenticating with a certificate would seem to require
The server generating a nonce
The client encrypting the nonce using the client's private key
The client sending that encrypted value to the server with the accompanying public certificate [or certificate chain].
Now, that is exactly what happens during an SSL handshake, but obviously a whole load of other baggage comes with it that is irrelevant to the application-level concern of authenticating the user.
I thought about implementing the steps directly myself, but this would seem to violate the first rule of crypto (Don't implement your own crypto).
If the server generates random nonces then that introduces a level of chattiness and statefulness to the process, which is doable but a pain when you are striving for a stateless and clusterable server.
Time-based One-Time Password implementations circumvent this, and seem to be a standardized mechanism for 2-factor authentication that is getting support from Google+ and the like.
However I can't find anything in the way of out-of-the-box libraries that will let me build an implementation using certificates directly from an imposed PKI.

How to secure communication in client-server app?

I've got backend running on the tomcat server and client running in the browser. Application is built on Spring 3 MVC + Spring security framework. How to secure the communication ? Is there other option than just to set the server to be accessed only via HTTPS ? I've got no experience with this so it might be a stupid question, but will this affect my application and do I have to set something up in my app, when the server shall communicate with client via GET/POST request via https ?
It depends somewhat what you mean by "secure." If you want privacy, you must use TLS (SSL) as a transport.
If you're only concerned with authentication, then you have another option: Digest Authentication.
Digest Authentication allows the client (browser, usually) and the server to exchange authentication credentials in a secure manner without securing the entire communication. If you use Digest Authentication, then third parties can still:
See what data the client and server exchange
Insert themselves between the client and server and alter the exchange
What third parties cannot do is spoof the authentication or steal username/passwords in transit.
If that's not secure enough, you need TLS. You do not necessarily have to purchase a certificate. You can use OpenSSL to generate your own. This certificate will not automatically be trusted by browsers, however, so you can't really use it for public sites.
You will need to consult your server documentation for how to set up HTTPS or Digest Authentication, depending on which fits your needs.
Your application should not be affected by switching from HTTP to HTTPS, Tomcat handles this or maybe an Apache in front. It's important to understand, that HTTPS is a server-thing, not an application topic, because the client makes a connection to the server (Tomcat), not to your application. Check out the Tomcat documentation, it's pretty clear about how things work.
And, like the others said: From what you've said it's best to use HTTPS (TLS/SSL). Certificates are a bit frightning at the beginning, but it's worth to invest the time.
HTTPS is the (S)ecure form of HTTP, since you have an HTTP client server application I would certainly used HTTPS. All you need is to create an SSL certicate for your website and restrict access to your website to HTTPS only, then you are 99.99% secure.
Your certicate can be either commercial from Versign or equivalent or some open source engine.
for the clients nothing needs to be done to support HTTPS

Categories

Resources