HTTP/TLS
TLS/SSL
is a cryptographic protocol that allows encryption over otherwise
unsecure communication channels. The most common usage of it is to provide
secure HTTP
communication, also known as HTTPS
. The protocol ensures that
the following properties apply to the communication channel:
- Privacy
- Authentication
- Data integrity
Its implementation in Go is in the crypto/tls
package.
In this section we will focus on the Go implementation and usage.
Although the theoretical part of the protocol design and it's cryptographic
practices are beyond the scope of this article, additional information is
available on the Cryptography Practices section of this document.
The following is a simple example of an HTTP with TLS:
import "log"
import "net/http"
func main() {
http.HandleFunc("/", func (w http.ResponseWriter, req *http.Request) {
w.Write([]byte("This is an example server.\n"))
})
// yourCert.pem - path to your server certificate in PEM format
// yourKey.pem - path to your server private key in PEM format
log.Fatal(http.ListenAndServeTLS(":443", "yourCert.pem", "yourKey.pem", nil))
}
This is a simple out-of-the-box implementation of SSL in a webserver using Go. It's worth noting that this example gets an "A" on SSL Labs.
To further improve the communication security, the following flag could be added to the header, in order to enforce HSTS (HTTP Strict Transport Security):
w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
Go's TLS implementation is in the crypto/tls
package. When using TLS, make
sure that a single standard TLS implementation is used and that it's
appropriately configured.
Implementing SNI (Server Name Indication) based on the previous example:
...
type Certificates struct {
CertFile string
KeyFile string
}
func main() {
httpsServer := &http.Server{
Addr: ":8080",
}
var certs []Certificates
certs = append(certs, Certificates{
CertFile: "../etc/yourSite.pem", //Your site certificate key
KeyFile: "../etc/yourSite.key", //Your site private key
})
config := &tls.Config{}
var err error
config.Certificates = make([]tls.Certificate, len(certs))
for i, v := range certs {
config.Certificates[i], err = tls.LoadX509KeyPair(v.CertFile, v.KeyFile)
}
conn, err := net.Listen("tcp", ":8080")
tlsListener := tls.NewListener(conn, config)
httpsServer.Serve(tlsListener)
fmt.Println("Listening on port 8080...")
}
It should be noted that when using TLS, the certificates should be valid, have the correct domain name, should not be expired, and should be installed with intermediate certificates when required, as recommended in the OWASP SCP Quick Reference Guide.
Important: Invalid TLS certificates should always be rejected.
Make sure that the InsecureSkipVerify
configuration is not set
to true
in a production environment.
The following snippet is an example of how to set this:
config := &tls.Config{InsecureSkipVerify: false}
Use the correct hostname in order to set the server name:
config := &tls.Config{ServerName: "yourHostname"}
Another known attack against TLS to be aware of is called POODLE. It is related to TLS connection fallback when the client does not support the server's cypher. This allows the connection to be downgraded to a vulnerable cypher.
By default, Go disables SSLv3 and the cypher's minimum version and maximum version can be set with the following configurations:
// MinVersion contains the minimum SSL/TLS version that is acceptable.
// If zero, then TLS 1.0 is taken as the minimum.
MinVersion uint16
// MaxVersion contains the maximum SSL/TLS version that is acceptable.
// If zero, then the maximum version supported by this package is used,
// which is currently TLS 1.2.
MaxVersion uint16
The safety of the used cyphers can be checked with SSL Labs.
An additional flag that is commonly used to mitigate downgrade attacks is the
TLS_FALLBACK_SCSV
as defined in RFC7507. In Go, there is no fallback.
Quote from Google developer Adam Langley:
The Go client doesn't do fallback so doesn't need to send TLS_FALLBACK_SCSV.
Another attack known as CRIME affects TLS sessions that use compression.
Compression is part of the core protocol, but it's optional. Programs written in
the Go programming language are likely not vulnerable, simply because there is
currently no compression mechanism supported by crypto/tls
. An important
note to keep in mind is if a Go wrapper is used for an external security
library, the application may be vulnerable.
Another part of TLS is related to the connection renegotiation. To guarantee no
insecure connections are established, use the GetClientCertificate
and it's
associated error code in case the handshake is aborted.
The error code can be captured to prevent an insecure channel from being used.
All requests should also be encoded to a pre-determined character encoding such as UTF-8. This can be set in the header:
w.Header().Set("Content-Type", "Desired Content Type; charset=utf-8")
Another important aspect when handling HTTP connections is to verify that the HTTP header does not contain any sensitive information when accessing external sites. Since the connection could be insecure, the HTTP header may leak information.
Image Credits : John Mitchell