---
title: Dùng SecRandomCopyBytes cho random bảo mật
impact: HIGH
impactDescription: arc4random, drand48 và random() không phải CSPRNG thực sự và có thể bị predict. Dùng chúng để tạo token hay nonce là lỗ hổng bảo mật.
tags: swift, ios, csprng, random, security, nonce, token
---

## Dùng SecRandomCopyBytes cho random bảo mật

Khi cần số ngẫu nhiên cho mục đích bảo mật (token, nonce, IV, session ID), phải dùng `SecRandomCopyBytes` (Security framework) hoặc `CryptoKit`'s `random()`. `arc4random_uniform()`, `Int.random()`, hay `drand48()` là PRNG thông thường, không phù hợp cho mục đích security.

**Incorrect (PRNG không an toàn cho security):**

```swift
// !! arc4random không đủ entropy cho security token
func generateSessionToken() -> String {
    let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    return String((0..<32).map { _ in chars.randomElement()! })  // randomElement() dùng PRNG
}

// !! Int.random không phải CSPRNG
func generateOTPCode() -> String {
    return String(format: "%06d", Int.random(in: 100000...999999))
}

// !! drand48 hoàn toàn không an toàn
func generateNonce() -> Double {
    return drand48()
}
```

**Correct (CSPRNG cho security-sensitive randomness):**

```swift
import Security
import CryptoKit

// Secure random bytes dùng Security framework
func generateSecureToken(length: Int = 32) -> Data? {
    var randomBytes = [UInt8](repeating: 0, count: length)
    let status = SecRandomCopyBytes(kSecRandomDefault, length, &randomBytes)
    guard status == errSecSuccess else { return nil }
    return Data(randomBytes)
}

// Tạo session token dạng hex string (64 chars = 32 bytes = 256-bit entropy)
func generateSessionToken() -> String {
    guard let tokenData = generateSecureToken(length: 32) else {
        fatalError("Security framework unavailable")
    }
    return tokenData.map { String(format: "%02x", $0) }.joined()
}

// Nonce cho AES-GCM (CryptoKit tự tạo random nonce)
func encryptWithRandomNonce(_ data: Data, key: SymmetricKey) throws -> AES.GCM.SealedBox {
    // CryptoKit tự tạo random nonce dùng CSPRNG
    return try AES.GCM.seal(data, using: key)
}

// PKCE code verifier cho OAuth
func generatePKCECodeVerifier() -> String {
    guard let bytes = generateSecureToken(length: 32) else { fatalError() }
    return bytes.base64EncodedString()
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .replacingOccurrences(of: "=", with: "")
}
```

**Tools:** Security framework (`SecRandomCopyBytes`), CryptoKit, Code Review

