If I'm making TLS requests to an API server that I'm referencing by IP, are the kinds of MITM attacks that certificate validation prevents still possible?
Background info if it clarifies the question: I'm making TLS requests to a REST API with a static IP that has no domain name associated with it. To make this work in Go, I have to set the InsecureSkipVerify: true, at the Transport layer of my HTTP Client. Does this make my requests less secure?
I would assume it does but I don't really know why.
As #James noted the IP is an irrelevant component of a TLS handshake.
While the standard procedure is:
dial hostname/port
DNS lookup hostname to get IP
TLS handshake w/ IP
reveals hostnames certificate identity
verify cert name matches hostname
Using InsecureSkipVerify: true skips the last step - and is generally only used during development/testing.
You can however use a different name, in this last step, for the certificate identity to match: leveraging the ServerName field in tls.Config:
tc = &tls.Config{
ServerName: "myhostname", // certificate identity
RootCAs: rootca,
// InsecureSkipVerify: true // <- avoid using this
}
d := tls.Dialer{
Config: tc
}
conn, err := d.Dial("tcp", "127.0.0.1:8080")
Here we are dialing an IP address, performing a TLS handshake, but instead of the default behavior of comparing the host cert with 127.0.0.1, it will instead verify it matches myhostname.
Related
I'm trying to run the buildlet at https://github.com/golang/build/tree/master/cmd/coordinator
There is a locally hosted server connection that keeps failing to connect giving the error:
first record does not look like a TLS handshake
The piece of code that fails is from build/cmd/buildlet/reverse.go and it is:
tcpConn.SetDeadline(time.Now().Add(30 * time.Second))
config := &tls.Config{
ServerName: serverName,
InsecureSkipVerify: devMode,
}
conn := tls.Client(tcpConn, config)
if err := conn.Handshake(); err != nil {
return nil, fmt.Errorf("failed to handshake with coordinator: %v", err)
}
I've gathered that the connection should be established while ignoring TLS issues because the server is at localhost
I can't seem to figure out how to fix this issue.
Instructions on recreating my problem are at the above link. The only change I recommend is using
go run . -mode=dev -listen-http=localhost:8119
for the first command
InsecureSkipVerify just means that TLS certificate validation constraints are relaxed (to a point where your connection is insecure and prone to MITM attacks)
From the documentation:
If InsecureSkipVerify is true, crypto/tls accepts any certificate presented by the server and any host name in that certificate.
You still need to have a connection that uses TLS at the other end. The error that you're getting means that the other side of the connect doesn't speak TLS.
If you don't want to use TLS in devMode, then you should use the tcpConn directly while in dev mode, without wrapping it with a *tls.Conn. *tls.Conn implements net.Conn so after the handshake there shouldn't be any difference in how you use the connection, whether it has TLS or not.
Trying to set up a TLS connection through a NLB appliance in AWS. The connection is good through there(telnet, curl with --insecure). In my Go code, I need to be able to ignore the NLB SNI in the cert verify logic, but I want to keep all other checks. Setting InsecureVerify false is a no go. I know I can set a custom VerifyPeerCertificates in the tls.Config, but how do i go about just ignoring my 1 NLB SNI?
My cert is coming across as:
original url(1) for endpoint (on actual cert)
original url(2) for endpoint (on actual cert)
mnlb-elb.us-east-1.amazonaws.com (added to check, this needs to be ignored)
func customVerify(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
return nil
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{
VerifyPeerCertificate: customVerify
}
}
Good day!
I have difficulties with requests in Go. Locally service works fine, but in the server I have this error:
"Post "https://x.x.x.x:xxxx/": x509: cannot validate certificate for x.x.x.x because it doesn't contain any IP SANs
Solutions like using dns is not suite, only ip address with port, since it is an internal service.
Also, tried out:
TLSConfig: &tls.Config{
InsecureSkipVerify: true
}
Updated! Tried out with NodeJS, works fine, so I think problem with Go's tls configs
Please, hint me how can eliminate this error?
I'm trying to connect to G Suite's LDAPS server with Golang's LDAP library.
However, in the example, I don't really understand two things.
It seems like it connects via non-encrypted LDAP first? Then it upgrades? Is that true, if so, can't I just start out by connecting encrypted?
Google supplies a .cer & .key file to connect to their ldap server. I don't see where it use these files. I do see in their docs that a lot of LDAP clients require the files to be combined into a .p12. Is that necessary for Go?
If the person that answers this could supply an example, that would really help. Thank you.
StartTLS, as you've noted, allows one to upgrade a connection to use a TLS later on in the connections lifecycle.
If you want to connect via TLS immediately, then use the well known ldaps port 636 (instead of 389) - and use DialTLS:
// l, err := ldap.Dial("tcp", "ldap.example.com:389"))
var tlsConf *tls.Config
ldaps, err := ldap.DialTLS("tcp", "gsuite.google.com:636", tlsConf)
You may also use DialURL which infers TLS or non-TLS by the schema e.g.
conn, err := ldap.DialURL("ldap://ldap.example.com") // non-TLS on default port 389
conn, err := ldap.DialURL("ldaps://ldap.example.com") // TLS on default port 636
conn, err := ldap.DialURL("ldaps://myserver.com:1234") // TLS on custom port 1234
// Note: there is no way to add a custom tls.Config with this method
So if using, DialTLS: since you are using a Google service, it's trust cert should already be in your keychain, so a simple tls.Config should suffice:
tlsConf = &tls.Config{ServerName:"gsuite.google.com"} // <- ensure this matches the hostname provided by the server
If you want to get things up an running for testing:
// DONT EVER USE THIS IN PRODUCTION...
tlsConf = &tls.Config{InsecureSkipVerify: true} // DO NOT USE EVER
To add a client cert for client-side authentication:
// Load cer & key files into a pair of []byte
cert, err := tls.X509KeyPair(cer, key)
if err != nil {
log.Fatal(err)
}
tlsCong := &tls.Config{Certificates: []tls.Certificate{cert}}
I'm reading the spec and trying to understand exactly when 421 might be returned. An example is given but I don't completely understand it.
Background
The spec establishes two conditions that allow for connection reuse:
For TCP connections without TLS, this depends on the host having resolved to the same IP address.
and
For https resources, connection reuse additionally depends on having a
certificate that is valid for the host in the URI.
If the certificate used in the connection has multiple subjectAltName or any of the subjectAltName is a wildcard, then the connection can be reused for any request that has a hostname that is in the list of subjectAltNames or matches any of the wildcards.
Specific Example In the spec
In some deployments, reusing a connection for multiple origins can
result in requests being directed to the wrong origin server. For
example, TLS termination might be performed by a middlebox that uses
the TLS Server Name Indication (SNI) [TLS-EXT] extension to select an
origin server. This means that it is possible for clients to send
confidential information to servers that might not be the intended
target for the request, even though the server is otherwise
authoritative.
Please explain where my understanding of this example is wrong:
An https connection is established to a middlebox with a request that has domain x.com. The middlebox has IP address 1.2.3.4 and x.com resolves to that address. Using SNI, the TLS handshake has x.com and the middlebox returns a certificate valid for that domain. All messages on this connection go from the client to the middlebox or from middlebox to client. Applicaiton level messages from client to middlebox are forwarded by middlebox to an origin on a different connection. Messages from origin to middlebox are forwarded to the client. If the connection is to be reused, meeting the two conditions discussed above is not enough. Specifically, for a request with domain y.com: if y.com resolves to 1.2.3.4 and the middlebox has a certificate valid for y.com, there can still be a problem. Because the original connection did its TLS handshake using x.com and because handshakes are only done at the beginning of new connections, there is no way establishing an https connection that would get the certificate for y.com. So the client incorrectly sends a request on the same connection to y.com. The middlebox rejects the request because the certificate associated with the connection is valid for x.com - not y.com. (The x.com certificate is only valid for x.com and the y.com certificate is only valid for y.com).
None of your examples will trigger a 421 as far as I can see.
Yes you are correct that a connection needs both the IP address and the SAN field in the certificate to be valid - without those a connection should not be reused.
So what would trigger a 421? As far as I can tell it will be mostly due to different SSL/TLS setups.
For example:
Assume website A (siteA.example.com) and website B (www.example.com) are both on same IP address. Assume website A has a wildcard cert for *.example.com and website B has a specific one. Could be a few reasons for this: for example it serves an EV cert for the main website which can't be a wildcard cert.
So cert A covers website A and website B. As does the IP address. So if you are connected to website siteA.example.com, and then try to connect to www.example.com then technically, by HTTP/2 standards, you could reuse the connection. But we wouldn't want that to happen, as we want to use our EV cert. So the server should reject with a 421. Now in this example the webserver is able to distinguish the correct host and has a valid cert for that host so could, in theory, serve the correct content under the wildcard cert, instead of sending a 421 - but since that wildcard cert is not defined for that virtualhost it should not do this.
Other examples include if you have different ciphers set up on different hosts. For example site A has super lax HTTPS config, because it's not really secure content and they want to reach even legacy browsers, but site B has super secure config and only accepts the latest TLS version and strong ciphers. Here you obviously wouldn't want them to reuse the same connection details. See here for a real would example of this.
Also this is only an issue for certain browsers, depending on how they decide to connection share. This page shows how different each of them do this (at least at the time of this blog post not not aware of anything changing since then): https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/
Also note that some bugs will exist with this (for example: https://bugs.chromium.org/p/chromium/issues/detail?id=546991). Best advice is: if you do not want connection sharing to happen, have a different IP address and/or ensure no overlaps in certificates.