👨‍💻
Application Security Handbook
  • Application Security Handbook
  • Web Application
    • Authentication
      • Authentication with Login and Password
      • Authentication with Phone Number
      • OAuth 2.0 Authentication
      • Multi-factor Authentication
      • Default Passwords
      • Password Change
      • Password Policy
      • Password Reset
      • Password Storage
      • One Time Password (OTP)
      • Email Address Confirmation
    • Authorization
    • Concept of Trusted Devices
    • Content Security Policy (CSP)
    • Cookie Security
    • Cryptography
      • Cryptographic Keys Management
      • Encryption
      • Hash-based Message Authentication Code (HMAC)
      • Hashing
      • Random Generators
      • Universal Unique Identifier (UUID)
    • Error and Exception Handling
    • File Upload
    • Input Validation
    • JSON Web Token (JWT)
    • Logging and Monitoring
    • Output Encoding
    • Regular Expressions
    • Sensitive Data Management
    • Session Management
    • Transport Layer Protection
    • Vulnerability Mitigation
      • Brute-force
      • Command Injection
      • Cross-Site Request Forgery (CSRF)
      • Cross-Site Scripting (XSS)
      • Mass Parameter Assignment
      • Parameter Pollution
      • Path Traversal
      • Regular Expression Denial of Service (ReDoS)
      • SQL Injection (SQLi)
      • XML External Entity (XXE) Injection
Powered by GitBook
On this page
  • Overview
  • General
  • Error and exception handling
  • References
  1. Web Application

Error and Exception Handling

PreviousUniversal Unique Identifier (UUID)NextFile Upload

Last updated 1 year ago

Overview

This page contains recommendations for handling errors and exceptions.

General

  • Handle each error and exception using a common handling component.

  • Override the default error page for unhandled errors and exceptions.

  • Error and exception handling complies with the fail-secure security design principle:

    • An application is returned to the most secure state when an error or exception occurs.

    • An application denies access by default when an error or exception occurs.

    • Error messages are not verbose in nature:

      • Do not include a stack trace in error messages and HTTP responses.

      • Do not pass server configuration information (name, version, etc.) in error messages.

Clarification

The fail-secure principle states that raising an error or exception must not lead an application to an insecure state that allows a user to gain additional privileges. It means that a user will not be able to bypass security checks, get additional information or elevate their privileges by causing an error or exception in an application.

Consider the following code snippet that implements an authorization check:

isAdmin = true
try {
    codeWhichMayFail()
    isAdmin = isUserInRole("ADMIN")
} catch (error) {
    log.warn(error)
}
return isAdmin

As can be seen, admin access is allowed by default. Therefore, if codeWhichMayFail raises an exception, isAdmin will be set to true and the authorization check will be bypassed.

The proper validation will look like this:

try {
    codeWhichMayFail()
    isAdmin = isUserInRole("ADMIN")
    return isAdmin
} catch (error) {
    log.warn(error)
    return false
}
  • Do not ignore errors in security-related components like crypto modules.

Error and exception handling

package main

func main() {
    panic("oops!")
}
$ go run crash.go
panic: oops!

goroutine 1 [running]:
main.main()
	/tmp.MVY5tcbe/crash.go:4 +0x2c
exit status 2
$ GOTRACEBACK=0 go run crash.go
panic: oops!
exit status 2

Additionally, you can override a panic recovery and implement custom logic.

Use the following approaches to implement panic handling:

  1. defer func() {
        if err := recover(); err != nil {
            fmt.Printf("recovering from err %v", err)
        }
    }()
    handler(w, r)
  2. Implement a middleware to handle panics.

    func panicRecovery(h func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            defer func() {
                if err := recover(); err != nil {
                    buf := make([]byte, 2048)
                    n := runtime.Stack(buf, false)
                    buf = buf[:n]
                    fmt.Printf("recovering from err %v\n %s", err, buf)
                    w.Write([]byte(`{"error":"our server got panic"}`))
                }
            }()
            h(w, r)
        }
    }
    http.HandleFunc("/endpoint", panicRecovery(handler))

References

Do not pass sensitive data in error messages see the page.

Log errors according to the page.

In Go, you have to be aware of uncaught panics and handle them to prevent an application from crashing. You can omit the goroutine stack traces entirely by setting the GOTRACEBACK environment variable to none. In this case, you will only receive a panic message. See

Recover only works when called from the same goroutine as the panic is called in, see

Use the defer statement to handle panics, see

Remember that some packages can handle panics out of the box, as an example.

Sensitive Data Management
Logging and Monitoring
https://pkg.go.dev/runtime#hdr-Environment_Variables
https://go.dev/ref/spec#Handling_panics
https://go.dev/blog/defer-panic-and-recover
net/http
OWASP Cheat Sheet Series: Error Handling Cheat Sheet
OWASP: Fail Securely
CWE-636: Not Failing Securely ('Failing Open')