Observable Timing Discrepancy
ID |
python.observable_timing_discrepancy |
Severity |
high |
Resource |
Information Leak |
Language |
Python |
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 Python script:
from flask import Flask, request, jsonify
app = Flask(__name__)
# Hypothetical stored password (for demonstration purposes)
stored_password = "securePassword123"
def check_password(input_password, stored_password):
if input_password == stored_password: # FLAW
# Do something secure
return True
return False
@app.route('/check-password', methods=['POST'])
def check_password_endpoint():
data = request.get_json()
input_password = data.get('password')
if check_password(input_password, stored_password):
return jsonify({"message": "Password is correct"}), 200
else:
return jsonify({"message": "Password is incorrect"}), 401
if __name__ == '__main__':
app.run(debug=True)
Remediation
To remediate issues related to plaintext storage of passwords, implement the following practices:
-
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.
-
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).
-
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 Python script would look like this:
import hmac
app = Flask(__name__)
# Hypothetical stored password (for demonstration purposes)
stored_password = "securePassword123"
def check_password(input_password, stored_password):
# Use hmac.compare_digest for constant-time comparison
if hmac.compare_digest(input_password, stored_password):
# Do something secure
return True
return False
@app.route('/check-password', methods=['POST'])
def check_password_endpoint():
data = request.get_json()
input_password = data.get('password')
if check_password(input_password, stored_password):
return jsonify({"message": "Password is correct"}), 200
else:
return jsonify({"message": "Password is incorrect"}), 401
if __name__ == '__main__':
app.run(debug=True)
Here the hmac.compare_digest
function is used. According to the docs: This function uses an approach designed to prevent timing analysis by avoiding content-based short circuiting behaviour, making it appropriate for cryptography.
References
-
CWE-208 : Observable Timing Discrepancy