Is there a way to specify the connection method when using a proxy?
I'm using the below code which sends an HTTP CONNECT. That is not supported by my load balancer. A GET request would terminate the TLS connection between the proxy and the website. The CONNECT method creates a TLS connection end to end between the end user and website. Essentially I need to inspect the traffic at the proxy.
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder
.setConnectionManager(connectionManager)
.setProxy(proxy)
.setDefaultRequestConfig(config);
Below is what the connection looks like:
Hypertext Transfer Protocol
CONNECT xyz.com:443 HTTP/1.1\r\n
Host: xyz.com\r\n
User-Agent: Apache-HttpClient/4.5.13 (Java/19.0.1)\r\n
\r\n
For HTTPS communications through a proxy, the client will use a CONNECT request to create a connection through the proxy to the remote trusted site.
With HTTPS, the client will only communicate with a server that it trusts. The trust usually requires that the server presents an X.509 certificate that is signed by a trusted authority (not self-signed), not expired, and has a subject that matches the site the client is trying to reach.
When communicating with a proxy, the proxy is typically unable to match that criteria. However, there are proxies that can match the above criteria by generating a new cert on the fly that has a matching subject to that expected by the client.
In that case, once the client has established a TLS connection with the proxy, the proxy can then decrypt the payload of the HTTPS traffic.
For the proxy to create a certificate trusted by the client, it must be signed by a CA (certificate authority) that is trusted by the client. Now, by default, the client will not trust the cert since it will not recognize the CA. However, you may modify the client by placing a cert for the CA on the client. Once the client trusts the CA, it will trust all of the certs generated by the proxy.
That being said, here's configuration for an HTTPS proxy (written by Cisco) that provides instructions for just that:
https://www.cisco.com/c/en/us/support/docs/unified-communications/jabber/212044-Configure-Charles-Proxy-to-Capture-HTTPS.html
The configuration action you'll need for Apache (if Apache supports this) will be similar - you'll need to get a cert from the Apache proxy to install on your client.
I'm currently searching the web for similar proxies. I'm essentially looking for a key word that describes this technique of enabling your HTTPS proxy to do man-in-the-middle attacks with a dynamically generated cert matching the request. If I find the terms, I'll update the post.
EDIT: Update for squid
I found an article about configuring squid for inspecting HTTPS traffic: https://scubarda.com/2020/03/23/configure-squid-proxy-for-ssl-tls-inspection-https-interception/
In the article, the author indicates that you would have to install the X.509 Cyber Saiyan certificate in your browser (client's) certificate/authorities section (but this is just for this specific configuration).
Some good keywords to search for now are HTTPS inspection...
If this is a temporary debug solution, you can use one of the Man In The Middle (MITM) proxies that are designed just for this:
Burp
Charles
Zap
Once installed somewhere, you'll just need to import the proxy CA cert into the server making the connections (each of the above proxies has a how-to guide for this), and set the proxy address to the MITM.
Related
I am writing a NodeJS proxy that will replace a Java Jetty Proxy. I am using node-http-proxy. The only piece remaining is to have the original client certificate passed along to the proxied server.
From my understanding, the Java Servlet specification requires that a Servlet container pull the Client Certificate from an HTTPS request and store that as an attribute on the HttpServletRequest.
I am not sure how the Servlet Container handles the Attributes when proxying the request to a new server. I presume that it is attaching them somehow either as headers or by some other means.
Does anyone know how those attributes (specifically the javax.servlet.request.X509Certificate) are passed on a proxied HTTPS request? And two, how do I achieve the same functionality using NodeJS.
In the event that is helps someone else out... The issue turned out to be the node module I was using (node-http-proxy) wasn't reusing the HTTP server connection certificates. That is, when attempting to create a connection with the proxy server, it was using a default (generated) certificate.
To properly connect with the proxy server, I had to pass the ca, pfx, and passphrase to the proxy connector.
const ca = ...
const pfx = ...
const passphrase = ...
// proxy connection
server.web(req, res, { ca: ca, pfx: pfx, passphrase: passphrase }, function(err) {});
After doing so, the Proxy server was able to pull and validate the certificate.
I am using the great Charles Web Proxy do make a reverse proxy and debug an exchange between my client and a secure server.I accepted the Charles certificate as a trusted authority and it works generally very well when using it in Proxy Mode, the problem is when I try to make a reverse proxy.
I am using an external library over which I have no control that uses an HttpUrlConnection and lets me specify the URL. Following the Charles documentation, I set my URL to https://mybox.test.com:100 (note that I used a hostname, added to my host file, instead of localhost in the hope that I can have a valid certificate).
The problem is that as part of the Https validation, HttpUrlConnection verifies the host name (mybox.test.com since it is pointing to my reverse proxy) against the one in the certificate (the one of the secure site I am connecting to). Obviously that does not match and causes a
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching localhost found.
I realize that Charles cannot generate a certificate for mybox.test.com, since it only listens to a particular port and has no knowledge of the URL used in the HttpUrlConnection. I do not see how it could generate a correct certificate that would be accepted.
My question is: is there a better way to use a reverse proxy with Https or do I need to disable the host name and certificate validation ?
If so, How do you set certificate for authentication, what files do you need? is it .pfx? How would you install that in browser? Been stuck trying to test 2 way ssl through browser. I have a webservice, and trying to connect always returns certification authentication failed.
Expanding on nickrak's answer. 2-way SSL means that the client trusts the webservice, and that the webservice trusts/authenticates the client.
On the webservice side:
Add the client's CA cert into the webservice's trusted certificates. The "CN" in the webservice server certificate must match the URL of the webservice. The webservice server certificate must not be expired. The webservice may choose to do further authentication based on the client certificate...for example, is the client certificate in a "whitelist" of authorized clients. Perhaps the webservice has multiple levels of access, so the client certificate is checked to determine how much access to give the client.
On the client side:
The CA that signed the webservice server certificate will need to be added to the client's trusted certificate list. In a browser, this will be in the "Trusted Root Certification Authorities" section (IE, Chrome) or "Authorities" section (Firefox). The extensions for these certificates are usually .der, .cer, .crt, or .pem. Also, the client's own private key/certificate combination need to be added to the client browser. This will be in the "Personal" section (IE, Chrome) or "Your Certificates" (Firefox). The extensions for these keystores are usually .p12 or .pfx.
Add the client's CA's public certificate to the Trusted Root Certificate Store.
Add the client's public and private key to the browser's Personal Certificate Store. (usually a pfx, but might also be a der/pem/crt/cer.)
Navigate to page requiring certificate
Optionally, depending on browser: select the certificate you want to use for this connection.
Hopefully, success.
We have configure a Big F5 load balancer virtual server for a particular IP address which redirects incoming https requests to several Windows servers where there is functionality to generate responses.
I am using SoapUI to test access to these windows servers via the IP address of virtual server in the Big F5.
Using Server and Client certificates generated by the organization where the we have also this set up and sending requests via SoapUI I get the predicted responses back.
The business requirements call for Commercially signed certificates by Thawte.
We created a Certifcate Servcice Request (CSR) to generate a Server certificate and its private key and then we had it signed by Thawte, and also requested a Client Commercially signed certificate from Thawte.
We loaded both certificates in SoapUI client and the Big F5 load balancer but we attempting to test the requests we get the "javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake" error.
My questions are:
How can I monitor where exactly the 2 way SSL handshake is terminated
The actual reason what exactly is happening?.. why using commercially signed certificates this does not work now?
Any replies are welcome. Thanks.
However when we swithch Serverto commercially signed by Thawte
This is possibly due to the Java security feature. If so you need to edit the soapui-4.x.x.vmoptions file located at soapui-4.x.x\bin folder and add -Dsun.security.ssl.allowUnsafeRenegotiation=true to the end.
You may also need to export the certificate as a pfx file and set it up in soapUI preference page. For details you can check http://geekswithblogs.net/gvdmaaden/archive/2011/02/24/how-to-configure-soapui-with-client-certificate-authentication.aspx and http://forums.devarticles.com/java-development-38/javax-net-ssl-sslhandshakeexception-received-fatal-alert-handshake-failure-11809.html .
The client is a SoapUI request that has not changed except a different client certificate
That suggests that the server doesn't trust the new client certificate, which in turn implies that the client certificate wasn't even sent because it wasn't signed by one of the server's trusted signers. Closing the connection is the server's only real option in this circumstance, as there isn't an SSL alert for it.
Make sure you have address translation on and the SNAt set to Auto Map for your VIP
I am using https to connect to an https server.
Specifically I am using apache httpclient and I configure the ssl context to use my keystore and truststore.
The https server I am using is IIS7 and is configured to require client authentication.
I think I have set it up properly.
Anyway, if I configure the httpClent's ssl context with a keystore (i.e. with client certificates) valid for IIS then there is no problem connecting.
Now my problem is the following:
If I do not configure the ssl context with any client certificate to send to IIS, there is no connection with the server. What makes me think though, is the fact that I was expecting to see some java exception in the code as a result of a hanshake failure alert.
Monitoring what is happening with wireshark, I could not see a certificate request from IIS to my application, but I noticed that after ServerHelloDone everything was encrypted.
I did not expect that. I think the handshake is usually in cleartext.
I used private key to decrypt traces and i saw a certificate request from IIS but after many starting and opening of new connections.
My app send back as a response a certificate of length 0 and IIS replies with a TLSv1 Finished.
After that the packets stop (i.e. seems that the communication ends).
I was expecting a handshake alert.
My question is, is this how it is supposed to work or at least how IIS works?
Or if I do not see the alert something is wrong with my use case?
Thanks
It sounds like IIS is only requiring client certificates for certain URLs (ie, for example.com/foo, but not example.com/bar).
In the initial handshake, it does not know which url you are requesting, so it does not require a certificate. When it sees that you are requesting a restricted resource (/foo), it then rehandshakes, requiring a certificate.
However, I would still expect a handshake_failure to occur.
As I was saying in an answer to this question, as far as I remember, IIS uses re-negotiation to get the client certificate. You should be able to change this behaviour using netsh and clientcertnegotiate=enable (depending on the version of IIS you're using).
You might also be interest in this similar question.
Failing to supply a certificate in response to a CertificateRequest isn't an SSL protocol error, so there is no handshake_error. 'Requiring' instead of just 'needing' client certificates is added-in by SSL libraries, and all they can do if you don't send one is just close the connection.