Getting Started With Go Programming Languaue (golang) Code Review
Publish date: Mar 20, 2019
This is a compilation of security knowledge related to Go Language. It is written from the perspective of someone who is going to review code written in Go language to find security vulnerabilities. It might still be helpful to you if you are going to develop code in Go language and wish to learn what to do and what mistakes to avoid.
Use of unsafe package
Use of unsafe
package is big red flag.
https://golang.org/pkg/unsafe/
Entry points - URL path matching
To identify entry points, look for URL handling.
mux := http.NewServeMux()
mux.Handle("/login", rh)
Input sanitization
Common input sanitization related functions are described here. https://checkmarx.gitbooks.io/go-scp/input-validation/sanitization.html
Automatic Setting of Content-Type
Content-Type is set based on response content if no content type is explicitly set. https://checkmarx.gitbooks.io/go-scp/output-encoding/cross-site-scripting.html
Templating
Use of text/template doesn’t escape html tags. Only html/template does, however it has its own security issues. Best practice is to use safehtml/template instead.
SQL injection
Look at second parameter “query” for QueryContext. If it is not parameterized, SQL injection is possible. https://checkmarx.gitbooks.io/go-scp/output-encoding/sql-injection.html
Look for db.Query() and db.Exec() for raw query processing and SQL injection.
Shell Invocation
Look for exec.Command() for command injection issues.
Random number generation
math/rand is insecure. Use crypto/rand instead. crypto/rand cannot be seeded.
Encryption and Hash generation
A good indicator to look for cryptograpy usage is use of crypto/* packages.
For example,
- crypto/aes
- crypto/cipher
- crypto/sha256
- crypto/rand
- crypto/md5
- crypto/sha1
For AEAD (GCM) ciphers, Seal is encrypt, Open is decrypt.
For others, Encrypt and Decrypt are typically used.
Non-constant time comparison of sensitive strings - Timing attack
strings/Compare, == operator, strings/EqualFold (case insensitive comparison) is insecure for comparison of sensitive strings such as passwords as it leaks timing info.
The right way for constant time comparison is as follows.
- Convert strings to byte slices.
- crypto/subtle/ConstantTimeEq to check length equality.
- crypto/subtle/ConstantTimeCompare to do actual comparison.
Go XML Decoder
The Go XML decoder silently ignores non XML content before and after the expected XML root. This can lead to surprising security issues such as: https://googleprojectzero.blogspot.com/2020/10/enter-the-vault-auth-issues-hashicorp-vault.html?m=1
Before parsing XML using the decoder, it is advisable to validate that the text is valid XML. One way to do that is to validate Content-Type header before processing an expected XML response.
JWT
Look for jwt.NewWithClaims for token generation, jwt.ParseWithClaims for token verification. When verifying token, remember to check token’s signing algorithm, issuer and audience restrictions, maybe client id as well. Issue and expiry time should be checked by library itself but if you are doing your own validation, you can check it too.
Use a library that doesn’t have issues. There are several JWT Go libraries at https://jwt.io/.
Cookies
Cookie generation typically happens using http.Cookie as below. Check for HttpOnly and Secure flags.
cookie := http.Cookie{
Name: "Auth",
Value: signedToken,
Expires: expireCookie,
HttpOnly: true,
Path: "/",
Domain: "127.0.0.1",
Secure: true
}
HTTP/HTTPS Endpoints And TLS Configuration
- http.ListenAndServe creates http endpoint
- http.ListenAndServeTLS creates https endpoint
- http.Server creates customer server endpoint. TLSConfig can be added to it.
- http.Transport has TLS configuration and proxy configuration.
- net.Listen starts tcp socket.
- tls.NewListener creates TLS endpoint.
- tls.Listen creates TLS endpoint.
- tls.Dial connects to TLS endpoint.
- tls.Config sets configuration.
- CipherSuites and minVersion and maxVersion in tls.Config set ciphers and TLS version.
- By default, Go disables SSLv3.
- tls.VersionSSL30 can be used to force sslv3
- tls.VersionTLS10 for TLS v1.
- InsecureSkipVerify to disable cert validation.
- ServerName property for Hostname validation.
- tls.LoadX509KeyPair loads cert and keys.
https://golang.org/pkg/crypto/tls/#pkg-constants
Example of insecure client:
conf := &tls.Config{
InsecureSkipVerify: true,
}
Format string related functions
- fmt/Errorf
- fmt/Fprintf
- fmt/Fscanf
- fmt/Printf
- fmt/Scanf
- fmt/Sprintf
- fmt/Sscanf
- fmt/Formatter
Error handling functions
- The following keywords are similar to try catch.
- panic
- defer
- recover
- log.Fatal exits after logging.
- os.Exit also exits.
Logging
log.New creates logger.
Sensitive information in URLs
Look for sensitive information passed in URLs.
req, _ := http.NewRequest("GET", "http://server.com/api/a?api_key=s3cr3t", nil)
HTTP Headers
Look for w.Header().Add. By default following information won’t be leaked by Go but if you use any type of external package or framework, check for following response headers.
- OS version
- Webserver version
- Framework or programming language version
- Websockets
- x/net/websocket means websockets are in play.
Typical related functions to check include:
- websocket.Handler(EchoHandler).ServeHTTP(w, r) will let you know the Handler for requests
- websocket.Message.Receive
- websocket.Message.Send
Don’t forget to check Origin header for websockets.
r.Header.Get("Origin")
The config property contains TLSConfig.
Directory listings
http.ListenAndServe(":8080", http.FileServer(http.Dir("/tmp/static")))
DB Creds
Look for sql.Open to identify where username and password come from. https://checkmarx.gitbooks.io/go-scp/database-security/connections.html
File upload
Check accepted filetypes using DetectContentType.
Go code import, plugins and library loading
Identify code import using import keyword. Identify loading of compiled Go plugins.
- plugin.Open
- plugin.Lookup https://golang.org/pkg/plugin/
Identify external DLL loading using syscall.LoadLibrary call. Typical DLL hijacking issues can ensue.
Boundary checks
Automatic Boundary checks are part of golang runtime. Accessing out of bound for lists causes panic.
func main() {
strings := []string{"aaa", "bbb", "ccc", "ddd"}
// Our loop is not checking the MAP length -> BAD
for i := 0; i < 5; i++ {
if len(strings[i]) > 0 {
fmt.Println(strings[i])
}
}
}
Output:
aaa
bbb
ccc
ddd
panic: runtime error: index out of range
Web security issues
Check for web security issues such as XSS, CSRF etc. This is not really specific to Go.
Concurrency
Look for race conditions in threads. go keyword is used to run goroutines (threads).
Compliance issues
Go uses BoringSSL by default which is not FIPS compliant.
Static Code Analysis Tools
gosec: https://github.com/securego/gosec
Temporary files and Symlink Attacks
To safely create temporary files and avoiding symlink attacks when creating files in shared folders, use ioutil.TempFile (and rename it if you want to put it in a specific location). It is caller’s duty to cleanup the file afterwards.
References
- The Go Programming Language - Documentation, https://golang.org/doc/
- Go Language - Web Application Secure Coding Practices, https://checkmarx.gitbooks.io/go-scp
- Go Code Auditing, http://0xdabbad00.com/2015/04/18/go_code_auditing/
- Secure Application Development with Go, https://www.rsaconference.com/writable/presentations/file_upload/asd-f02-secure-application-development-with-go.pdf
- Go Safe HTML, https://blogtitle.github.io/go-safe-html/
- Smart (and simple) ways to prevent symlink attacks in Go, https://blog.trailofbits.com/2020/11/24/smart-and-simple-ways-to-prevent-symlink-attacks-in-go/