Observable Timing Discrepancy

ID

go.observable_timing_discrepancy

Severity

high

Resource

Information Leak

Language

Go

Tags

CWE:208, NIST.SP.800-53

Description

Observable Timing Discrepancy occurs when the time it takes for certain operations to complete can be measured and observed by attackers.

Rationale

When conducting plaintext password comparisons, there’s a risk that an attacker could discern the password’s value by observing the timing of comparisons. This is because the comparison takes less time as fewer bytes match.

Consider the following Golang script:

package observable_timing_discrepancy

import (
	"encoding/json"
	"net/http"
)

// Hypothetical stored password (for demonstration purposes)
var storedPassword = "securePassword123"

func checkPassword(inputPassword, storedPassword string) bool {
	if inputPassword == storedPassword { // FLAW
		// Do something secure
		return true
	}
	return false
}

func checkPasswordHandler(w http.ResponseWriter, r *http.Request) {
	inputPassword := r.URL.Query().Get("example")

	if checkPassword(inputPassword, storedPassword) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"message": "Password is correct"})
	} else {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"message": "Password is incorrect"})
	}
}

func main() {
	http.HandleFunc("/check-password", checkPasswordHandler)
	http.ListenAndServe(":8080", nil)
}

Remediation

To remediate issues related to plaintext storage of passwords, implement the following practices:

  1. Use Secure Hashing Algorithms: Store passwords using a strong, one-way hashing algorithm combined with a salt to protect against dictionary and rainbow table attacks.

  2. Leverage Strong Cryptography: When passwords must be stored for validation, use a combination of hashing and salting. Ensure the algorithms used are well-regarded and up-to-date with industry standards (e.g., PBKDF2, bcrypt, scrypt).

  3. Protect Access to Passwords: Ensure access to stored hashed passwords and salts is tightly controlled using access controls and encryption.

Following these practices will significantly enhance the security of password storage in your applications, reducing the risk of unauthorized access.

The remediated Golang script would look like this:

package observable_timing_discrepancy

import (
	"crypto/subtle"
	"encoding/json"
	"net/http"
)

// Hypothetical stored password (for demonstration purposes)
var storedPassword2 = "securePassword123"

func checkPassword2(inputPassword, storedPassword string) bool {
	// Use subtle.ConstantTimeCompare for constant-time comparison
	return subtle.ConstantTimeCompare([]byte(inputPassword), []byte(storedPassword)) == 1
}

func checkPasswordHandler2(w http.ResponseWriter, r *http.Request) {
	inputPassword := r.URL.Query().Get("example")

	if checkPassword2(inputPassword, storedPassword2) {
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]string{"message": "Password is correct"})
	} else {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(map[string]string{"message": "Password is incorrect"})
	}
}

func main() {
	http.HandleFunc("/check-password2", checkPasswordHandler2)
	http.ListenAndServe(":8080", nil)
}

Here, the subtle.ConstantTimeCompare function is used to achieve a constant-time comparison. This function returns 1 if the two strings match, and 0 if they differ, returning immediately if the strings have different lengths. This approach eliminates timing discrepancies, making it more difficult for attackers to infer information from the comparison time.

References