How to make WinInet HTTPS subsequent requests to reuse connection? - winapi

I'm sending a few subsequent http-requests on my server using wininet, and until I use TLS (INTERNET_FLAG_SECURE flag in HttpOpenRequestA) the connection is being reused ok. Now I want to use TLS, set the mentioned flag, and also flags INTERNET_FLAG_IGNORE_CERT_CN_INVALID and INTERNET_FLAG_IGNORE_CERT_DATE_INVALID (to skip self-signed cert verification) - now a new connection is established for every HttpOpenRequest call. How to reuse conn with tls?
p.s. INTERNET_FLAG_EXISTING_CONNECT has no effect

Each new connection does a separate TCP handshake and a separate TLS handshake.In case of session reuse no key exchange is performed, that is the same symmetric key is re-used.
See How does SSL/TLS work?

Related

Handling encrypted request depending on cert trust state using mitmproxy

I've read a lot of related topics in the net, but I still don't have an answer to my question.
Is it possible to implement flow described below?
Proxy receive request.
If request is encrypted and proxy cert is trusted then intercept.
If request is not encrypted, then intercept.
If request is encrypted and proxy cert is NOT trusted then pass it through without interception.
This behaviour should be default for all traffic going through the proxy.
It'd be also really nice to be able to get all possible info for passing encrypted requests (src and dst ip addresses etc.). Basically the same info which I can get with fiddler.
Not really. The main problem is that mitmproxy can not know if proxy cert is trusted by the client or not.
In the SSL/TLS protocol client starts with the CLIENT_HELLO and in response the server (in this case motmproxy) sends back the SERVER_HELLO message containing the generated server certificate.
The client now checks if the received server certificate is trusted. If not the connection is terminated. As far as I know the SSL/TLS spec does not define how to do so. Sems clients end back an SSL_ALERT message, other simply drop the connection, and a third group continues the SSL/TLS handshake but have certain internal values set in a way that always let the handshake fail.
There is a mitmproxy script that tries to identify connections that were not successful and then if the client asks for the same domain a second time bypasses interception.
Of course this requires that the client resends requests which is not always the case.
https://github.com/sociam/x-ray/blob/master/mitmproxy/examples/tls_passthrough.py

TLS session resumption

I use Caddy (a webserver written in GO), I have TLS 1.0-TLS 1.2 allowed, and GO supports only the tickets option of session resumption (the TLS session data is stored on the client side).
Now I'm not quite sure about when the TLS resumption should occur.
Regardless of ticket lifetime (which I think is a week by default) and Session Ticket Encryption Key (which are rotated every 10 hours and Caddy "remembers" the last 4) - so non of those should be the issue.
As far as I understand the session resumption should occur whenever the ticket is still valid and the browser hasn't been restarted, which means that even if I changed my IP address, the TLS ticket should still work.
But that's not the case for me; when I access the webserver (using both Chrome and Firefox) I get a TLS ticket, which remains valid throughout surfs to that webserver, but when I change my IP address (either by proxy or changing WIFI) the ticket is not accepted on the server side and a full TLS handshake is made, in which I get a new ticket.
So my main question: does TLS session resumption only work within a TCP session and whenever a new TCP session is started the former TLS ticket becomes invalid?
... does TLS session resumption only work within a TCP session
Given that there is almost always only a single TLS handshake in the TCP connection that would not make much sense.
Session resumption with tickets works as long as the client sends a session ticket and the server has the necessary secrets to extract the information from the ticket. The server might implement additional restrictions though, like encoding the client IP in the ticket and checking if it is still the same.

Difference between ws and wss?

What is the procedure to change ws into wss?
Whether wss is make upgrade over normal HTTP or wss works only HTTPS?
webSocket = new WebSocket("ws://localhost:port/Esv/ocp");
works fine, when I changed ws to wss
webSocket = new WebSocket("wss://localhost:port/Esv/ocp");
it shows this error:
Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
Short version
To SSL or not SSL
You may have a SSL certificate issue. The connection point rule can be summarized as:
wss connects on https only
ws connects on http
and vice-versa:
https accepts wss only
http accepts ws only
Errors
Following situations will lead you to an error (tests done under Firefox):
If you want to connect a wss connection to a http endpoint. In my tests, I had an
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
If you want to connect a ws connection to a https endpoint, you'll have the error
SecurityError: The operation is insecure.
Formal answer
The bible of websocket is RFC 6455. In section 4.1.5:
If /secure/ is true, the client MUST perform a TLS handshake over the connection after opening the connection and before sending the handshake data [RFC2818]. If this fails (e.g., the server's certificate could not be verified), then the client MUST Fail the WebSocket Connection and abort the connection. Otherwise, all further communication on this channel MUST run through the encrypted tunnel [RFC5246].
The secure flag is defined by the URI. Section 3 defines what is secure
The URI is called "secure" (and it is said that "the secure flag is set") if the scheme component matches "wss" case-insensitively.
TL;DR
If you want to use wss:
you must have SSL activated
your endpoint point must be secured (https://...): "security downgrade" is not allowed
If you want to use ws:
Make sure your endpoint does not have SSL enabled (http://...)

Is a websocket connection secure after it's been established?

Provided that you somehow successfully established an authenticated secure websocket connection, would that connection be considered safe from then on? Meaning, do you have to send authentication data with each message so that if an attacker somehow connects to the already established websocket, they can't send anything meaningful? I assume for wss connections such a condition can't occur, but what about a regular ws connection?
A WebSocket is a point-to-point connection, so nobody else can connect to that particular socket. If you're using current cyphers for the TLS, then this should be secure (there are cyphers out there which are being deprecated at the moment since they are/may be broken).
For a non-TLS WebSocket connection the same goes as for anything done over regular HTTP (or any other unencrypted protocol): any intermediary can alter the data, so this cannot be considered secure.
Here is a good 2 part blog post on WebSocket security that should help you:
http://blog.kaazing.com/2012/02/28/html5-websocket-security-is-strong/

When should one use CONNECT and GET HTTP methods at HTTP Proxy Server?

I'm building a WebClient library. Now I'm implementing a proxy feature, so I am making some research and I saw some code using the CONNECT method to request a URL.
But checking it within my web browser, it doesn't use the CONNECT method but calls the GET method instead.
So I'm confused. When I should use both methods?
TL;DR a web client uses CONNECT only when it knows it talks to a proxy and the final URI begins with https://.
When a browser says:
CONNECT www.google.com:443 HTTP/1.1
it means:
Hi proxy, please open a raw TCP connection to google; any following
bytes I write, you just repeat over that connection without any
interpretation. Oh, and one more thing. Do that only if you talk to
Google directly, but if you use another proxy yourself, instead you
just tell them the same CONNECT.
Note how this says nothing about TLS (https). In fact CONNECT is orthogonal to TLS; you can have only one, you can have other, or you can have both of them.
That being said, the intent of CONNECT is to allow end-to-end encrypted TLS session, so the data is unreadable to a proxy (or a whole proxy chain). It works even if a proxy doesn't understand TLS at all, because CONNECT can be issued inside plain HTTP and requires from the proxy nothing more than copying raw bytes around.
But the connection to the first proxy can be TLS (https) although it means a double encryption of traffic between you and the first proxy.
Obviously, it makes no sense to CONNECT when talking directly to the final server. You just start talking TLS and then issue HTTP GET. The end servers normally disable CONNECT altogether.
To a proxy, CONNECT support adds security risks. Any data can be passed through CONNECT, even ssh hacking attempt to a server on 192.168.1.*, even SMTP sending spam. Outside world sees these attacks as regular TCP connections initiated by a proxy. They don't care what is the reason, they cannot check whether HTTP CONNECT is to blame. Hence it's up to proxies to secure themselves against misuse.
A CONNECT request urges your proxy to establish an HTTP tunnel to the remote end-point.
Usually is it used for SSL connections, though it can be used with HTTP as well (used for the purposes of proxy-chaining and tunneling)
CONNECT www.google.com:443
The above line opens a connection from your proxy to www.google.com on port 443.
After this, content that is sent by the client is forwarded by the proxy to www.google.com:443.
If a user tries to retrieve a page http://www.google.com, the proxy can send the exact same request and retrieve response for him, on his behalf.
With SSL(HTTPS), only the two remote end-points understand the requests, and the proxy cannot decipher them. Hence, all it does is open that tunnel using CONNECT, and lets the two end-points (webserver and client) talk to each other directly.
Proxy Chaining:
If you are chaining 2 proxy servers, this is the sequence of requests to be issued.
GET1 is the original GET request (HTTP URL)
CONNECT1 is the original CONNECT request (SSL/HTTPS URL or Another Proxy)
User Request ==CONNECT1==> (Your_Primary_Proxy ==CONNECT==> AnotherProxy-1 ... ==CONNECT==> AnotherProxy-n) ==GET1(IF is http)/CONNECT1(IF is https)==> Destination_URL
As a rule of thumb GET is used for plain HTTP and CONNECT for HTTPS
There are more details though so you probably want to read the relevant RFC-s
http://www.ietf.org/rfc/rfc2068.txt
http://www.ietf.org/rfc/rfc2817.txt
The CONNECT method converts the request connection to a transparent TCP/IP tunnel, usually to facilitate SSL-encrypted communication (HTTPS) through an unencrypted HTTP proxy.

Resources