HSTS header response processing over secured transport - ssl

As per the RFC6797-
[..] "An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport." [..]
https://www.rfc-editor.org/rfc/rfc6797#page-18
My question is - if the client is trying to access the host over non-secured HTTP (e.g. TCP port 80) and the server implements HSTS policy the server MUST respond with HSTS policy header over secured transport.
Now considering the secured transport as SSL - when does the SSL key exchange and handshake happen, for client to decrypt the server response over secured transport/SSL?
The https://www.ssl2buy.com/wiki/http-strict-transport-security-hsts-better-security-for-applications link nicely explains the HSTS policy implementation but I am unable to put it together how the SSL handshake happens.

HSTS has nothing to do with the SSL handshake.
It simply means if the browser is instructed to go to http://www.example.com, then instead act as if they were instructed to go to https://www.example.com.
The SSL negotiation happens afterwards - exactly as if they went to the https version directly.

Related

Getting "IDX10108: The address specified is not valid as per HTTPS scheme" when calling IdentityServer4 in AWS

We've implemented an Identity Server using IdentityServer4 and have deployed it to AWS. It works great until we enabled https on the ELB. Now when the client tries to authenticate we get the following error:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
An unhandled exception has occurred while executing the request
System.InvalidOperationException: IDX10803: Unable to obtain configuration from: 'https://int.mycompany.com/.well-known/openid-configuration'. ---> System.ArgumentException: IDX10108: The address specified is not valid as per HTTPS scheme. Please specify an https address for security reasons. If you want to test with http address, set the RequireHttps property on IDocumentRetriever to false.
From what I've read the client is not happy with the certificate. This could possibly be related to the host name of the identity server and the name in the certificate. We have a valid wildcard certificate with subject "*.mycompany.com". We configured the client with Authority as "https://int.mycompany.com" so that seems to line up.
I've also read in these load balancing configuration that some headers have to be forwarded to the middleware but I'm not exactly sure how that would work.
Looks like HTTPS request are not recognized as such. Try to add the following settings into ConfigureServices method in the Startup class:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
});
From HTTP Headers and Elastic Load Balancing AWS documentation:
The X-Forwarded-Proto request header helps you identify the protocol (HTTP or HTTPS) that a client used to connect to your server. Your server access logs contain only the protocol used between the server and the load balancer; they contain no information about the protocol used between the client and the load balancer. To determine the protocol used between the client and the load balancer, use the X-Forwarded-Proto request header. Elastic Load Balancing stores the protocol used between the client and the load balancer in the X-Forwarded-Proto request header and passes the header along to your server.

WL-Proxy-Client-Cert header not sent

I m using Oracle HTTP Server as reverse proxy for WebLogic. I have set up SSL on both the proxy and the server with client certificate authentication. It works and the clients get authenticated by OHS, but i need to pass client certificate information to WebLogic so i can look at this certificate in my servlet. Documentation says that the proxy can forward client certificate within "WL-Proxy-Client-Cert" http header to the WebLogic server.
However, i can't get this to work. Within my servlet i tried both request.getHeader() and request.getAttribute() and getting null. I looked at both headers and attributes of the request objects and don't see anything like WL-Proxy-Client-Cert. In fact i don't see any headers starting with WL, only couple of headers starting with X-WebLogic, none of which has the certificate.
I did enable "Client Cert Proxy Enabled" option in Administration Console as described in the docs. Also i know that clients get authenticated since i see the certificate requested by the browser, after which i can successfully access the site.
Am i missing something?
I have finally got an answer from Oracle support on this. The problem was that i had to add one SSL directive to my virtual host configuration:
SSLOptions +ExportCertData
It goes under "IfModule ossl_module", right next to "SSLVerifyClient require" directive that specifies 2-way authentication for the proxy.
Note that after this, in the servlet, the certificate will be present in the usual "javax.servlet.request.X509Certificate" attribute, as if the server was doing client certificate authentication itself (no extra headers are received).
Also, note that you can have the server use 1-way SSL, if you feel secure with authentication done by the proxy, and you will still receive the certificate in the attribute in your servlet (in this case you should probably add a filter as they recommend to ensure the requests come from the proxy only). I have a feeling it will work even if the server port is regular http, though i haven't tested it yet.

Putting X509 Certificate in HTTP Request

I'm using Spring Security for X.509 preauthentication.
To make sure the client sends its certificate per HTTP request, is it necessary to:
Modify pom.xml to set <wantClientAuth> and <needClientAuth> to true
Set Apache's SSLVerifyClient to require reference
Based on reading, the web server must tell the client-side to sends its certificate in order for the client to actually send it. I'm confused if Spring Security AND Apache configuration is required to achieve this.
Spring Security configuration has nothing to do with whether the client sends a certificate or not. That's decided at the SSL protocol level and hence by the negotiation between the client and the server. Your question is a bit unclear in that it refers to a maven pom and an Apache configuration without explaining how your system is set up. Are you running the maven Jetty plugin with an Apache server in front?
Spring Security's X.509 authentication won't work if the SSL connection doesn't terminate at the servlet container. So if you have HTTPS between the client and Apache, and a non-SSL connection from Apache to the servlet container, then the client certificate won't normally be available.
If you are using an AJP connector, then you can configure Apache to pass the certificate on to the back end using the ExportCertData option. If you aren't, you can still take the exported certificate and pass it as a request header (you'll find examples of this elsewhere on SO). You would also need to customize the Spring Security X.509 code to extract the certificate from the header, rather than the standard java property name which it uses by default.

HTTPS Web(only)Proxy

I just read over node-tls-proxy (http://code.google.com/p/node-tls-proxy/), a https proxy. I like the idea of it, but I'm not getting why this proxy needs a local http server (see the local-proxy.js script).
So I was wondering if this is necessary?
My idea of the proxy was actually like this: Client -> HTTPS Connection to trusted Server/Proxy -> Internets
In this case network sniffing between the Client and the Server wouldn't (hardly) be possible because it would be ssl encrypted.
Thanks,
Seb
If I get the idea correctly, the goal is to set up a "remote" proxy in a location that one trusts to be secure. Your client shall only communicate with this remote proxy using TLS, the remote proxy is then allowed to do the actual (no longer encrypted) HTTP requests.
What you do on the client side now is this: you configure the "local" proxy in your browser. Since you type "http://..." in your browser even when using the proxy, your browser will initiate an unencrypted HTTP connection to the local proxy first. Then the local proxy will open an encrypted TLS connection to the remote proxy and forward your request over a secured channel.
This means you need the local proxy for the purpose of "transforming" HTTP into HTTPS requests because your browser will dutifully only use HTTP when asked to make an actual HTTP request.

CONNECT request to a forward HTTP proxy over an SSL connection?

I am writing an HTTP proxy and I am having trouble understanding some details of making a CONNECT request over TLS. To get a better picture, I am experimenting with Apache to observe how it interacts with clients. This is from my default virtual host.
NameVirtualHost *:443
<VirtualHost>
ServerName example.com
DocumentRoot htdocs/example.com
ProxyRequests On
AllowConnect 22
SSLEngine on
SSLCertificateFile /root/ssl/example.com-startssl.pem
SSLCertificateKeyFile /root/ssl/example.com-startssl.key
SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
SSLStrictSNIVHostCheck off
</VirtualHost>
The conversation between Apache and my client goes like this.
a. client connects to example.com:443 and sends example.com in the TLS handshake.
b. client sends HTTP request.
CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive
c. Apache says HTTP/1.1 400 Bad Request. The Apache error log says
Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different.
It appears that Apache does not look at the Host header other than to see that it is there since HTTP/1.1 requires it. I get identical failed behavior if the client sends Host: foo. If I make the HTTP request to example.com:80 without TLS, then Apache will connect me to 192.168.1.1:22.
I don't completely understand this behavior. Is there something wrong with the CONNECT request? I can't seem to locate the relevant parts of the RFCs that explain all this.
It's not clear whether you're trying to use Apache Httpd as a proxy server, this would explain the 400 status code you're getting.
CONNECT is used by the client, and sent to the proxy server (possibly Apache Httpd, but usually not), not to the destination web server.
CONNECT is used between the client and the proxy server before establishing the TLS connection between the client and the end server. The client (C) connects to the proxy (P) proxy.example.com and sends this request (including blank line):
C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:
The proxy opens a TCP connection to www.example.com:443 (P-S) and responds to the client with a 200 status code, accepting the request:
P->C: 200 OK
P->C:
After this, the connection between the client and the proxy (C-P) is kept open. The proxy server relays everything on the C-P connection to and from P-S. The client upgrades its active (P-S) connection to an SSL/TLS connection, by initiating a TLS handshake on that channel. Since everything is now relayed to the server, it's as if the TLS exchange was done directly with www.example.com:443.
The proxy doesn't play any role in the handshake (and thus with SNI). The TLS handshake effectively happens directly between the client and the end server.
If you're writing a proxy server, all you need to do for allowing your clients to connect to HTTPS servers is read in the CONNECT request, make a connection from the proxy to the end server (given in the CONNECT request), send the client with a 200 OK reply and then forward everything that you read from the client to the server, and vice versa.
RFC 2616 treats CONNECT as a a way to establish a simple tunnel (which it is). There is more about it in RFC 2817, although the rest of RFC 2817 (upgrades to TLS within a non-proxy HTTP connection) is rarely used.
It looks like what you're trying to do is to have the connection between the client (C) and the proxy (P) over TLS. That's fine, but the client won't use CONNECT to connect to external web servers (unless it's a connection to an HTTPS server too).
You're doing everything right. It's Apache that got things wrong. Support for CONNECT over TLS was only added recently (https://issues.apache.org/bugzilla/show_bug.cgi?id=29744) and there's still some things to be ironed out. The issue you're hitting is one of them.
From RFC 2616 (section 14.23):
The Host request-header field specifies the Internet host and port
number of the resource being requested, as obtained from the original
URI given by the user or referring resource (generally an HTTP URL,
as described in section 3.2.2). The Host field value MUST represent
the naming authority of the origin server or gateway given by the
original URL.
My understanding is that you need to copy the address from CONNECT line to HOST line. All in all, the address of the resource is 192.168.1.1, and the fact that you are connecting via example.com doesn't change anything from RFC point of view.
It is quite seldom to see CONNECT Method inside TLS (https). I actually don't know any client who does that (and I would be interested to know who it does, cause I think it is actually a good feature).
Normally the client connects with http (plain tcp) to the proxy and sends the CONNECT method (and host header) to host:443. Then the proxy will make a transparent connection to the endpoint and then the client sends the SSL handshake through.
In this scenario the data is ssl protected "end to end".
The CONNECT method is not really specified, it is only reserved in the HTTP RFC. But typically it is quite simple so it is interoperable. The Method specifies host[:port]. Host: header can simply be ignored. Some additional proxy authentication headers might be needed. When the body of the connection begins no parsing has to happen by the proxy anymore (some do, because they check for valid SSL handshake).