File size: 3,330 Bytes
7257069
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"""
SecureCodeEnv Task: Secure Token Generator
Difficulty: Easy
CWE Targets: CWE-338 (Use of Cryptographically Weak PRNG), CWE-330 (Insufficient Randomness)
"""

TASK = {
    "id": "easy_token_generator",
    "difficulty": "easy",
    "cwe_targets": ["CWE-338", "CWE-330"],
    "component_name": "TokenGenerator",
    "filename": "src/auth/token_generator.py",
    "problem_statement": """Write two Python functions:

1. `generate_token(length: int = 32) -> str`
   Generates a cryptographically secure random token.
   - MUST use secrets module (NOT random, NOT os.urandom directly, NOT time-based seeds)
   - Token must be URL-safe (use secrets.token_urlsafe or secrets.token_hex)
   - Length must be respected (the output must be at least `length` characters)
   - Must handle length < 1 by using 32 as default

2. `generate_session_id() -> str`
   Generates a secure session ID suitable for HTTP cookies.
   - Must be at least 32 characters long
   - Must use secrets module
   - Must be hex or URL-safe base64 format

Do NOT use: random.random(), random.randint(), math.random, time.time() for randomness.""",

    "starter_code": '''import random
import time

def generate_token(length: int = 32) -> str:
    # TODO: Use cryptographically secure randomness
    chars = "abcdefghijklmnopqrstuvwxyz0123456789"
    random.seed(time.time())  # INSECURE: time-based seed
    return "".join(random.choice(chars) for _ in range(length))

def generate_session_id() -> str:
    # TODO: Secure session ID
    return str(int(time.time() * 1000))  # INSECURE: predictable
''',

    "test_cases": [
        {"fn": "generate_token", "input": [32], "expected_min_len": 32, "description": "Token is at least 32 chars"},
        {"fn": "generate_token", "input": [64], "expected_min_len": 64, "description": "Token is at least 64 chars"},
        {"fn": "generate_token", "input": [0], "expected_min_len": 32, "description": "Length 0 defaults to 32"},
        {"fn": "generate_token", "input": [-1], "expected_min_len": 32, "description": "Negative length defaults to 32"},
        {"fn": "generate_session_id", "input": [], "expected_min_len": 32, "description": "Session ID at least 32 chars"},
        {"fn": "generate_token", "input": [32], "unique": True, "description": "Two calls produce different tokens"},
    ],

    "attack_type": "weak_random",

    "security_checks": [
        {"type": "no_weak_random", "forbidden": ["random.random(", "random.randint(", "random.seed("]},
        {"type": "uses_secrets", "required_import": "secrets"},
    ],

    "naive_code": '''import random
def generate_token(length: int = 32) -> str:
    chars = "abcdefghijklmnopqrstuvwxyz0123456789"
    return "".join(random.choice(chars) for _ in range(max(length, 32)))
def generate_session_id() -> str:
    return str(random.getrandbits(128))
''',

    "optimal_code": '''import secrets

def generate_token(length: int = 32) -> str:
    """Generates a cryptographically secure URL-safe random token."""
    if length < 1:
        length = 32
    # token_urlsafe(n) produces ceil(n * 4/3) chars, so nbytes = length * 3 // 4
    return secrets.token_urlsafe(max(length, 32))[:max(length, 32)]

def generate_session_id() -> str:
    """Generates a secure 64-char hex session ID."""
    return secrets.token_hex(32)  # 32 bytes = 64 hex chars
''',
}