I've always been an end consumer of HTTPS and have never really understood it that well but am looking to change that.
I am calling a RESTful web service over HTTPS. For example...
curl -X GET \
https://myCompanydns/rest/connect/v1.4/myEndpoint
With all my requests I send a basic authentication header i.e a username and password.
When I make these calls via my application I was expecting to have to add a certificate into like a jks (which I've had to do in the past) but on this occasion I've found that I can call the HTTPS web service without that.
For HTTPS to work I believe there is an SSL handshake? How is that happening successfully is this scenario without a jks?
Again, sorry for this beginner type question.
When doing a https://... request the client needs to verify that the servers certificate is the expected one - and not some man in the middle. This is done (among other things) by making sure that the servers certificate was issued by a trusted certificate authority (CA). Which CA is trusted is setup in the local trust store (i.e. local to the client). In the above call where no explicit trust store is given curl is using its default trust store. In the case where you've explicitly gave a jks you've provided the application with a specific trust store it should use.
For more on how the server certificates gets validated see SSL Certificate framework 101: How does the browser actually verify the validity of a given server certificate?.
Related
I've read quite a few articles on the client certificate authentication in IIS but they mostly talk about the Required mode for the client certificate. In this case, the authentication is fully done on the web server side and the user is redirected to the error page in case the certificate is missing or invalid. What I need is to configure IIS to check the client certificate if it exists and pass the results as http headers to my backend. It can be easily done with nginx or apache web servers. The client authentication can be set up as optional. Then, the web server checks the certificate and pass the results of the check as SSL_CLIENT_CERT (PEM representation of the certificate) and SSL_CLIENT_VERIFY (the result of the check - SUCCESS, NONE,...) headers to the application backend. So, on the backend part, I can read the headers and use the values to do the actual authentication -- find a user in the database, issue an auth token. Is it possible in IIS? If yes, is there any documentation on how to bypass the certificate and the check state as http headers?
After a while, I'm writing an answer to my question.
IIS has to be set up with ARR extension to act as a reverse proxy. Then, the client certificate authentication can be enabled for the default web site. Here are several links to instructions how to achieve it:
https://blogs.msdn.microsoft.com/benjaminperkins/2014/06/02/configure-application-request-routing-arr-with-client-certificates/
https://blogs.msdn.microsoft.com/asiatech/2014/01/27/configuring-arr-with-client-certificate/
and couple of links to very solid explanations of the SSL/TLS handshake and certificates in general:
https://blogs.msdn.microsoft.com/kaushal/2013/08/02/ssl-handshake-and-https-bindings-on-iis/
https://blogs.msdn.microsoft.com/kaushal/2013/01/09/self-signed-root-ca-and-intermediate-ca-certificates/
https://blogs.msdn.microsoft.com/kaushal/2015/05/27/client-certificate-authentication-part-1/
Basically, the Application Request Routing (ARR) extension should be enabled for the IIS to act as a proxy. Then, you set up proxy bypass routes. Next, you need to set up a valid server certificate for the IIS server and use it in the Default Web Site https bindings. The certificate should be issued by a CA which certificate should be placed into the Trusted Root Certification Authorities and Intermediate Certification Authorities of the Local Computer. Then, you should require SSL in the SSL settings of the Default Web Site with the client certificates setting equal to Accept. In this case, any client that connects to the web server will be asked for a valid client certificate that has been issued by the same CA as the server certificate.
Actually, IIS sends a list of distinguished names of root issuers that are trusted by the web server to the client browser. The browser finds an intersection of this names with client trusted certificate issuers and looks for valid certificates that have been issued by the issuers in the intersection. After that, the user selects one of them (or none) and the selected certificate is checked against the CA certificate. If the certificate passes the check the request is "redirected" to the backend application with the certificate in the X-ARR-ClientCert header. The name of the header can be changed in the Server -> Configuration Editor -> system.webServer/proxy -> clientCertHeaderName IIS parameter. In case the user selects (or has) none of the required certificates, the request is "redirected" to the app backend without the header.
Seems, there is no need in the SSL_CLIENT_VERIFY header with the state of the check at all. If the certificate is valid it is passed in the header. If the certificate is missing the header is empty. If the certificate is provided by the client but is invalid then the request fails and is not "redirected" to the backend app server at all. Seems, it is a rare case but I have an example.
Imagine, a server certificate is issued by a CA with a distinguished name XXX, and there is a client certificate YYY (on the client computer) that is issued by a CA with the distinguished name XXX but those CAs are not the same (one or both of them are self-signed). In this case, the YYY certificate is present in the certificate selection dialog that is shown by a browser but the certificate doesn't pass the further validation against the real web server CA.
That's it. Also, seems IIS has no way to require (or accept) a client certificate for some app endpoints (addresses) only. I haven't found any other option apart from enabling in for the whole web site.
IIS ARR can also be configured with a client certificate for the backend or upstream server. In this case users connecting to this IIS do not need to provide the certificate as it will be attached by IIS automatically.
This configuration is available on IIS server level only.
I am putting a web test up for clients that visit "https://oursite.com/poodlesecurityfailed.js"
Question,
Do I need a valid certificate even though its on a test domain for certificate negotiation? If client can visit it, they failed the poodle test. (SSLv3 is enabled) on that host.
Ideas?
Do I need a valid certificate even though its on a test domain for certificate negotiation? If client can visit it, they failed the poodle test. (SSLv3 is enabled) on that host.
Depends on the client.
If the clients is has enough knowledge to understand, that "invalid certificate" when accessing the site means in reality that the client has still SSL 3.0 enabled, then a self-signed certificate would be enough.
If you instead want to provide an explanation of the problem at this site and don't expect the client to explicitly accept an invalid certificate just to see this explanation, then you should better use a properly trusted certificate.
I am trying to create an HTTPS-tunnel on my machine. My intention is having all requests to https://localhost:8888/<something> (the port where Fiddler is listening to) be directed to https://myserver.net/<something>. I am using the following script as per Fiddler doc:
static function OnBeforeRequest(oSession: Session) {
// <Fiddler 2 preexisting code>
// HTTPS redirect -----------------------
if (oSession.HTTPMethodIs("CONNECT") &&
(oSession.PathAndQuery == "localhost:8888"))
{
oSession.PathAndQuery = "myserver.net:443";
}
if (oSession.HostnameIs("localhost"))
oSession.hostname = "myserver.net";
// --------------------------------------
// <Fiddler 2 preexisting code>
}
Also in Fiddler settings I checked the decryption check and installed certificates as you can see in the image below:
I restart Fiddler, it prompts me to install its fake certificates, I agree. I can see the certificate in my Windows Certificate System Repository when using certmgr. It is a self-signed certificate.
So What I do is opening a browser and type: https://localhost:8888/mypage.html, and what I get is an error. Internet Explorer reports this:
Error: Mismatched Address. The security certificate presented by this
website was issued for a different website's address. This problem
might indicate an attempt to fool you or intercept any data...
When I get certificate info (basically the certificate presented by the contacted host is being rejected, the same certificate can be displayed), I can see that the rejected certificate was issued by Fiddler and the subject is myserver.net.
So the certificate is ok because it is certifying myserver.net, I see that the problem is that probably my browser was expecting a certificate whose subject is localhost. Is it true?
How to handle this situation?
Assumption
I can understand that the problem is a certificate being issued for a website which I did not ask for. So the solution would be using a certificate certifying localhost:8888?
A certificate is valid if it is directly or indirectly (via intermediate certificates) signed by a trusted CA and if the hostname matches the certificate. If the last condition would not be enforced anybody with a valid certificate from a trusted CA could incorporate any other site.
To make use of fiddler and not run into this problem you should configure your browser to use fiddler as a web proxy and then use the real URL inside the browser instead of ip:port of fiddler.
My application requires client authentication for a specific URL, after client authentication succeeds the application itself also does some verification on the client certificate subject (using spring security x509 filter). I wanted to configure tomcat to force client authentication (clientAuth=true) for the specific URL, but based on this post it seems I can't do this only using tomcat - configure tomcat for client authentication only for specific URL patterns.
My question is, if I use clientAuth=want, will the following be as below when the server requests a certificate:
If device has an identity certificate but not trusted by the CA configured in tomcat truststoreFile, no certificate will be passed and the request will fail in the spring security filter (certificate will be null)
If device has an identity certificate trusted by the CA configured in tomcat truststoreFile, but is invalid (not sure what validations are done) or expired, either the authentication will fail in tomcat (before the security filter) or as in option 1 no certificate will be passed and the request will fail in the spring security filter (certificate will be null)
Is there a security hole I may be missing using this configuration of want + security filter? I guess the question is - if a certificate is eventually passed from the device to the server, the server will always validate it (not expired, trusted etc) even when using clientAuth=want and will not allow the client to continue if the certificate is invalid? The case where no certificate is passed is covered by the security filter that will check the certificate is not null..
Thanks!
Your assumptions in both 1. and 2. are correct. Tomcat will not allow untrusted or invalid certificates through to your application. If you get a null certificate, you can assume that either no certificate was passed, or an untrusted/invalid certificate was passed.
On the project I am working on we have the same requirement as you: client certificates for certain URLs only. We found out by experimentation how "clientAuth=want" works.
I am testing a web service with an external partner using 2 way SSL under IIS 7.5. I am requiring SSL, requiring a client cert, and using one to one mapping to authenticate to a domain account. I have configured everything and it works fine on our network (I am able to provide a client cert, get authenticated and invoke the service from browser and test harness).
From outside of our network (in most cases, see below), I am getting a 403.7 error. I have gone through the machine level certificate store and made sure the certificates and CAs are trusted.
Here's the weird thing. I obtained a Type I cert to test from home (and got 403.7 like our intended partner is). So I setup Fiddler to debug SSL and send my certificate, and this works for some reason. I setup a test harness to pass the exact same certificate, and got 403.7. I test in my browser (IE 9), don't get a prompt for a client cert, and get 403.7.
Any help appreciated.
Bill
Last time I checked, IIS was using re-negotiation (by default) to get the client certificate: there is a first handshake where the server doesn't request a client certificate, followed by another handshake (encrypted this time) where the server requests the certificate (via a TLS CertificateRequest message). This will prevent you from seeing anything from Wireshark, unless you configure it to use the server's private key and decipher the traffic (note that this only works with some cipher suites).
One way to see the client-certificate negotiation is to configure IIS to use initial client certificate negotiation, using netsh and clientcertnegotiation=true (which is about initial negotiation). At least the CertificateRequest and the certificate will be sent in clear during the handshake, so you should be able to see this with Wireshark.
If the client isn't sending a certificate to the server as a response to the CertificateRequest, you'll still see an empty Certificate message from the client.
If you don't export the private key with the certificate to use with Fiddler or whichever other client, there is no chance that it will be able to use the certificate. It may at best try to send the certificate, but the handshake will fail (since the CertificateVerify message needs to be signed by the client's private key).
I guess you may encounter a problem whereby:
not presenting a certificate is accepted by the server (it's effectively optional),
presenting an invalid certificate makes it fail and causes this 403.7 status code (many servers and SSL/TLS stacks would implement this as a fatal error, but TLS specification doesn't say that unsupported_certificate, certificate_revoked, certificate_expired, certificate_unknown should be fatal, so this is at the server's discretion).
Are you using the same physical machine to test both the in-network and external-network connections? If not, are you sure that the external-network client has the private key accessible?
I have not configured Fiddler client authentication before. Does it read the client certificate and key from the standard certificate stores? Does it read directly from a PKCS12?
One other thing that may be helpful is inspecting the TLS handshake in WireShark. Specifically, check out the Server's "Certificate Request" message, as the data here clues the client (IE9) which client certificates it should display in the prompt. Compare this for the internal and external connections.