Securing a go REST API - Part 2: Timeouts

This is part 2 of a multipart series on how to secure your API in golang. We covered session management in part 1.

Filippo Valsorda makes an excellent case about exposing your go service. This blogpost will only talk about one little piece of all this, namely timeouts. Timeouts are one of the rare cases where the default values aren’t secure in golang. This is mostly due to historical reasons and maintaining backwards compatibility, however the often used helper methods http.ListenAndServe and http.ListenAndServeTLS are vulnerable to DoS (Denial of Service) or EDoS (Economic Denial of Sustainability) attacks because they use no timeouts. Thus, clients can keep the connections open and your server will run out of connections once the file descriptors run out.

http.Server offers you three types of timeouts: ReadTimeout does specify the time until the body is read (if you don’t read the body it’s defined as the time until the headers are read). WriteTimeout is defined as the maximum duration before timing out writes. It is reset every time you read a new header. Lastly, IdleTimeout is used to limit the time keep-alive connections are allowed to be idle.

These three timeouts should definitely be set when you open your service to the internet, but will also provide helpful on an internal service. You can easily use an http.Server instead of calling http.ListenAndServe:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func (s *server) run() {
	srv := &http.Server{
		Addr:         addr,
		Handler:      s.router,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
		IdleTimeout:  15 * time.Second,
	}
	if err := srv.ListenAndServer(); err != nil {
		log.Fatalf("Can't start server: %v", err)
	}
}

When you use these timeouts, the server will close the connection once these timeouts are exceeded. Browsers like Firefox might go for a retry immediately, clients like curl will just exit with an error. If you want to close the connection properly, you can wrap all your handlers in http.TimeoutHandler. This allows you to send a response body with an actual error code if your application is choking internally.

Continue with Part 3: Passwords, Tokens and Secrets.