Insecure Randomness
ID |
swift.insecure_randomness |
Severity |
high |
Resource |
Predictability |
Language |
Swift |
Tags |
CWE:330, CWE:332, CWE:336, CWE:337, CWE:338, MASWE:0027, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:6.5.3 |
Description
Cryptographically weak pseudo-random number generators (PRNGs) should not be used in security-sensitive contexts. Standard PRNGs like arc4random(), drand48(), or Int.random() are designed for general-purpose use (simulations, games, testing) but are not suitable for cryptographic purposes.
These functions produce predictable sequences that can be guessed or reproduced by attackers, especially when: - The seed is predictable or derived from weak entropy - The algorithm has known mathematical weaknesses - Side-channel attacks can observe the internal state
In Swift, susceptible code might look like this:
import Foundation
func generateSessionToken() -> String {
// FLAW: Using insecure random for security-sensitive token
let randomValue = Int.random(in: 0...Int.max)
return String(format: "%016x", randomValue)
}
func generateEncryptionKey() -> Data {
var bytes = [UInt8](repeating: 0, count: 32)
for i in 0..<bytes.count {
// FLAW: Using arc4random for cryptographic key
bytes[i] = UInt8(arc4random_uniform(256))
}
return Data(bytes)
}
func generatePassword() -> String {
let length = 16
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// FLAW: Using drand48 for password generation
return String((0..<length).map { _ in
chars[chars.index(chars.startIndex, offsetBy: Int(drand48() * Double(chars.count)))]
})
}
In these instances, insecure PRNGs are used to generate security-critical values (session tokens, encryption keys, passwords). An attacker who can predict or reproduce these values could: - Hijack user sessions - Decrypt encrypted data - Bypass authentication mechanisms - Forge cryptographic signatures
Rationale
The use of cryptographically weak PRNGs in security contexts poses several risks:
Predictability: Standard PRNGs use deterministic algorithms. If an attacker can observe several outputs or guess the seed, they may be able to predict future values.
Insufficient Entropy: Functions like arc4random() may not gather sufficient entropy from secure sources on all platforms.
Mathematical Weaknesses: Algorithms like RC4 (used by arc4random) and linear congruential generators (used by drand48) have known cryptographic weaknesses.
Reproducibility: Given the same seed, these PRNGs produce identical sequences, enabling replay attacks.
Security-sensitive contexts include: - Session tokens and identifiers - CSRF tokens - Password generation - Cryptographic keys and initialization vectors - Nonces and salts - Authentication challenges - Random UUIDs for security purposes
Remediation
For security-sensitive random number generation in Swift, use cryptographically secure alternatives:
Option 1: Use SecRandomCopyBytes (Security framework)
import Foundation
import Security
func generateSessionToken() -> String {
var bytes = [UInt8](repeating: 0, count: 32)
// FIXED: Using SecRandomCopyBytes for cryptographically secure random
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
guard status == errSecSuccess else {
fatalError("Failed to generate secure random bytes")
}
return bytes.map { String(format: "%02x", $0) }.joined()
}
func generateEncryptionKey() -> Data {
var bytes = [UInt8](repeating: 0, count: 32)
// FIXED: Using SecRandomCopyBytes for key generation
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
guard status == errSecSuccess else {
fatalError("Failed to generate secure random key")
}
return Data(bytes)
}
Option 2: Use SystemRandomNumberGenerator (Swift standard library)
import Foundation
func generateSessionToken() -> String {
// FIXED: Using SystemRandomNumberGenerator (cryptographically secure)
var generator = SystemRandomNumberGenerator()
let randomBytes = (0..<32).map { _ in UInt8.random(in: 0...255, using: &generator) }
return randomBytes.map { String(format: "%02x", $0) }.joined()
}
func generatePassword(length: Int = 16) -> String {
let chars = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()")
// FIXED: Using SystemRandomNumberGenerator for secure selection
var generator = SystemRandomNumberGenerator()
return String((0..<length).map { _ in
chars[Int.random(in: 0..<chars.count, using: &generator)]
})
}
Option 3: Use CryptoKit (iOS 13+, macOS 10.15+)
import CryptoKit
func generateEncryptionKey() -> SymmetricKey {
// FIXED: CryptoKit automatically uses secure random
return SymmetricKey(size: .bits256)
}
func generateNonce() -> Data {
// FIXED: SystemRandomNumberGenerator can be used
// _on most platforms_ for cryptographic uses
var generator = SystemRandomNumberGenerator()
var nonce = Data(count: 12)
nonce.withUnsafeMutableBytes { bytes in
for i in 0..<bytes.count {
bytes[i] = UInt8.random(in: 0...255, using: &generator)
}
}
return nonce
}
print( generateNonce().base64EncodedString(options: .endLineWithLineFeed) )
Important Notes:
-
Always use secure random for security-sensitive operations: Session tokens, keys, passwords, nonces, salts, IVs, etc.
-
Standard PRNGs are fine for non-security contexts: Games, simulations, testing, UI animations, etc.
-
Platform Availability:
-
SecRandomCopyBytesis available on all Apple platforms -
SystemRandomNumberGeneratorrequires Swift 4.2+ (iOS 8+, macOS 10.10+) -
CryptoKitrequires iOS 13+, macOS 10.15+
-
-
Performance: Secure random is slightly slower than insecure PRNG, but the overhead is negligible for typical security operations.
Configuration
The detector can be configured to check only security-sensitive contexts or all uses of insecure random:
properties:
# Only flag insecure random in security contexts (default: true)
checkSecurityContext: true
# Pattern to identify security-sensitive contexts (regex)
securityContextPattern: (auth|csrf|digest|guid|hash|key|nonce|passwd|password|salt|secret|session|token|user|uuid|encrypt|random)
To flag all uses of insecure random regardless of context:
swift.insecure_randomness:
properties:
checkSecurityContext: false
References
-
CWE-338 : Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG).
-
CWE-330 : Use of Insufficiently Random Values
-
CWE-332 : Insufficient Entropy in PRNG
-
CWE-336 : Same Seed in Pseudo-Random Number Generator (PRNG)
-
CWE-337 : Predictable Seed in Pseudo-Random Number Generator (PRNG)
-
OWASP - Top 10 2021 - A2 : Cryptographic Failures
-
MASWE-0027: Improper Random Number Generation.
-
SecRandomCopyBytes - Cryptographically secure random bytes.
-
SystemRandomNumberGenerator - Secure random number generator in Swift standard library.
-
CryptoKit - Apple’s cryptography framework.