>
Software Security Training

Exercise: The Salted Vault

In this activity, you will defeat Rainbow Table attacks by implementing Salted Hashing.

Scenario: A simple hash (SHA-256) is not enough! Attackers use pre-computed tables (Rainbow Tables) to crack common passwords instantly. You must add a unique "Salt" to every password before hashing it.

Your Task

Modify the save_user function to secure the data:

  1. Generate a Salt: Use secrets.token_hex(16) to create a random string.
  2. Combine: Create a new string: salt + password.
  3. Hash It: Hash that combined string using SHA-256.
  4. Store Both: Save a dictionary into the database: {'salt': salt, 'hash': hashed_value}.

Why This Matters

By adding a random salt, two users with the same password ("password123") will have completely different hashes. This makes Rainbow Tables useless.

PYTHON EDITOR (storage_module.py)
1
SECURITY CONSOLE OUTPUT
Ready... Waiting for registration simulation.
from js import document, window import sys import hashlib import secrets def setup(): loading = document.getElementById("loading") if loading: loading.style.display = "none" setup() class ConsoleOutput: def write(self, text): if text.strip(): log(text.strip(), "normal") def flush(self): pass sys.stdout = ConsoleOutput() sys.stderr = ConsoleOutput() def log(message, type="normal"): console = document.getElementById("console-output") if type == "clear": console.innerHTML = "" return color = "#ffffff" if type == "pass": color = "#2ecc71" if type == "fail": color = "#e74c3c" if type == "info": color = "#3498db" if type == "system": color = "#d4d4d4" safe_message = message.replace("<", "<").replace(">", ">") console.innerHTML += f'
{safe_message}
' console.scrollTop = console.scrollHeight # --- TEST RUNNER --- def run_tests(*args): log("", "clear") log("[SYSTEM] Verifying Crypto Implementation...", "system") user_code = document.getElementById("code-editor").value # Pass required modules to the student's scope test_env = { 'hashlib': hashlib, 'secrets': secrets } window.submissionStatus = "INCOMPLETE / FAILED" try: exec(user_code, test_env) if "save_user" not in test_env: log("[!] Error: Function 'save_user' not found.", "fail") return save_user = test_env["save_user"] # --- TEST 1: Functional Check --- log("--- TEST 1: Saving User 'Bob' ---", "system") password_input = "securePass!@#" result = save_user("Bob", password_input) if not isinstance(result, dict): log(" -> FAIL: Function must return a dictionary.", "fail") return if 'salt' not in result or 'hash' not in result: log(" -> FAIL: Dictionary must contain keys 'salt' and 'hash'.", "fail") return log(" -> PASS: Data structure is correct.", "pass") # --- TEST 2: Salt Randomness --- log("--- TEST 2: Checking Salt Uniqueness ---", "system") result2 = save_user("Bob", password_input) if result['salt'] == result2['salt']: log(" -> FAIL: Salt is not random! It didn't change on the second run.", "fail") log(" Did you hardcode the salt?", "fail") window.submissionStatus = "FAILED - Static Salt" return log(" -> PASS: Salt is random and unique.", "pass") # --- TEST 3: Cryptographic Verification --- log("--- TEST 3: Verifying Hash Integrity ---", "system") stored_salt = result['salt'] stored_hash = result['hash'] # Calculate expected hash expected_hash = hashlib.sha256((stored_salt + password_input).encode()).hexdigest() # Check for "Encoding Only" mistake encoded_only = (stored_salt + password_input).encode() if stored_hash == encoded_only: log(" -> FAIL: You encoded the bytes but forgot to HASH them!", "fail") log(" [HINT] Wrap your code in hashlib.sha256(...).hexdigest()", "info") window.submissionStatus = "FAILED - Not Hashed" return if stored_hash == expected_hash: log(" -> PASS: Hash matches SHA-256(salt + password).", "pass") log(" SUCCESS: Salted Hashing Implemented Correctly!", "pass") window.submissionStatus = "PASSED - Secure" else: log(" -> FAIL: Hash mismatch.", "fail") log(" Ensure you are hashing (salt + password).", "fail") window.submissionStatus = "FAILED - Bad Hash" except Exception as e: log(f"[!] Runtime Error: {e}", "fail") window.submissionStatus = "ERROR - Syntax/Runtime"