Communication Security

When approaching communication security, developers should be certain that the channels used for communication are secure. Types of communication include server-client, server-database, as well as all backend communications. These must be encrypted to guarantee data integrity, and to protect against common attacks related to communication security. Failure to secure these channels allows known attacks like MITM, which allows attacker to intercept and read the traffic in these channels.

HTTP/TLS

TLS/SSL is a cryptographic protocol that allows encryption over otherwise insecure communication channels. The most common usage of TLS/SSL 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 its 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 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” grade 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.

Here’s an example of 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 cipher. This allows the connection to be downgraded to a vulnerable cipher.

By default, Go disables SSLv3, and the cipher’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 ciphers 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][3]. In Go, there is no fallback.

Quote from Google developer Adam Langley:

The Go client doesn’t do fallback so it 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 its 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.

HTTP Header Leak Image Credits : John Mitchell

WEBSOCKETS

WebSocket is a new browser capability developed for HTML 5, which enables fully interactive applications. With WebSockets, both the browser and the server can send asynchronous messages over a single TCP socket, without resorting to long polling or comet.

Essentially, a WebSocket is a standard bidirectional TCP socket between the client and the server. The socket starts out as a regular HTTP connection, and then “Upgrades” to a TCP socket after a HTTP handshake. Either side can send data after the handshake.

Origin Header

The Origin header in the HTTP WebSocket handshake is used to guarantee that the connection accepted by the WebSocket is from a trusted origin domain. Failure to enforce can lead to Cross Site Request Forgery (CSRF).

It is the server’s responsibility to verify the Origin header in the initial HTTP WebSocket handshake. If the server does not validate the origin header in the initial WebSocket handshake, the WebSocket server may accept connections from any origin.

The following example uses an Origin header check, which prevents attackers from performing CSWSH (Cross-Site WebSocket Hijacking).

HTTP Header Leak

The application should validate the Host and the Origin to make sure the request’s Origin is the trusted Host, rejecting the connection if not.

A simple check is demonstrated in the following snippet:

//Compare our origin with Host and act accordingly
if r.Header.Get("Origin") != "http://"+r.Host {
  http.Error(w, "Origin not allowed", 403)
    return
} else {
    websocket.Handler(EchoHandler).ServeHTTP(w, r)
}

Confidentiality and Integrity

The WebSocket communication channel can be established over unencrypted TCP or over encrypted TLS.

When unencrypted WebSockets are used, the URI scheme is ws:// and its default port is 80. If using TLS WebSockets, the URI scheme is wss:// and the default port is 443.

When referring to WebSockets, we must consider the original connection and whether it uses TLS or if it is being sent unencrypted.

In this section we will show the information being sent when the connection upgrades from HTTP to WebSocket and the risks it poses if not handled correctly. In the first example, we see a regular HTTP connection being upgraded to a WebSocket connection:

HTTP Cookie Leak

Notice that the header contains our cookie for the session. To ensure no sensitive information is leaked, TLS should be used when upgrading our connection, as shown in the following image:

HTTP Cookie TLS

In the latter example, our connection upgrade request is using SSL, as well as our WebSocket:

Websocket SSL

Authentication and Authorization

WebSockets do not handle Authentication or Authorization, which means that mechanisms such as cookies, HTTP authentication or TLS authentication must be used to ensure security. More detailed information regarding this can be found in the Authentication and the Access Control parts of this document.

Input Sanitization

As with any data originating from untrusted sources, the data should be properly sanitized and encoded. For a more detailed coverage of these topics, see the Sanitization and the Output Encoding parts of this document.


Licenses and Attributions


Speak Your Mind