{ "cells": [ { "cell_type": "markdown", "id": "29386723", "metadata": {}, "source": [ "# Day 3 โ€” Data, Passwords & Security Foundations\n", "### Summer Coding & Cybersecurity Camp\n", "\n", "We can now write robust programs. Today we protect the **data** those programs handle โ€”\n", "the actual job of cybersecurity.\n", "\n", "**By the end of today you can:**\n", "- Read and write files\n", "- Explain the **CIA triad** (Confidentiality, Integrity, Availability)\n", "- Explain why you must **never store passwords as plain text**\n", "- Use **hashing** (one-way functions) with `hashlib`\n", "- Understand **salting** at a basic level\n", "- Recognize **hardcoded secrets** and weak passwords" ] }, { "cell_type": "markdown", "id": "647e3039", "metadata": {}, "source": [ "## 1. The big picture: the CIA Triad\n", "Every security decision protects one of three things:\n", "\n", "| Letter | Means | Example |\n", "|--------|-------|---------|\n", "| **C**onfidentiality | only the right people can see data | passwords, messages |\n", "| **I**ntegrity | data isn't secretly changed | bank balance, grades |\n", "| **A**vailability | the system is up when needed | a website that doesn't crash |\n", "\n", "Keep these in mind โ€” they're the *why* behind everything today." ] }, { "cell_type": "markdown", "id": "5e4131bf", "metadata": {}, "source": [ "## 2. Reading and writing files\n", "Programs save data so it survives after they close." ] }, { "cell_type": "code", "execution_count": null, "id": "3c086619", "metadata": {}, "outputs": [], "source": [ "# write some lines to a file\n", "with open(\"notes.txt\", \"w\") as f:\n", " f.write(\"first note\\n\")\n", " f.write(\"second note\\n\")\n", "\n", "# read it back\n", "with open(\"notes.txt\", \"r\") as f:\n", " contents = f.read()\n", "\n", "print(contents)" ] }, { "cell_type": "markdown", "id": "13d78b3c", "metadata": {}, "source": [ "## 3. ๐Ÿ” The plain-text password disaster\n", "Imagine a website stores logins like this in a file:\n", "\n", "```\n", "sam,p@ssw0rd\n", "alex,letmein\n", "```\n", "\n", "If an attacker steals that file, **every account is instantly compromised** โ€” and\n", "people reuse passwords, so other accounts fall too. This breaks **Confidentiality**.\n", "\n", "**Rule: never store the actual password.** Instead we store a *hash* of it." ] }, { "cell_type": "markdown", "id": "c1c5d568", "metadata": {}, "source": [ "## 4. Hashing โ€” one-way math\n", "A **hash function** turns any input into a fixed scrambled string. It is *one-way*:\n", "easy to go forward, practically impossible to reverse.\n", "\n", "- Same input โ†’ always the same hash\n", "- Tiny change in input โ†’ completely different hash\n", "\n", "Run this and change one letter to see the hash change completely." ] }, { "cell_type": "code", "execution_count": null, "id": "753ba556", "metadata": {}, "outputs": [], "source": [ "import hashlib\n", "\n", "def hash_text(text):\n", " return hashlib.sha256(text.encode()).hexdigest()\n", "\n", "print(hash_text(\"hello\"))\n", "print(hash_text(\"hellp\")) # one letter different!\n", "print(hash_text(\"hello\")) # same as the first โ€” deterministic" ] }, { "cell_type": "markdown", "id": "751bdc44", "metadata": {}, "source": [ "### How login *really* works (simplified)\n", "1. When you sign up, store the **hash** of your password, not the password.\n", "2. When you log in, hash what you typed and compare it to the stored hash.\n", "3. The real password is **never** saved anywhere." ] }, { "cell_type": "code", "execution_count": null, "id": "b7fd1a41", "metadata": {}, "outputs": [], "source": [ "import hashlib\n", "def hash_text(t): return hashlib.sha256(t.encode()).hexdigest()\n", "\n", "# --- sign up ---\n", "stored_hash = hash_text(\"SuperSecret123\") # only the hash is kept\n", "\n", "# --- log in later ---\n", "attempt = input(\"Enter password to log in: \")\n", "if hash_text(attempt) == stored_hash:\n", " print(\"โœ… Access granted\")\n", "else:\n", " print(\"โŒ Wrong password\")" ] }, { "cell_type": "markdown", "id": "2813a720", "metadata": {}, "source": [ "## 5. ๐Ÿ” Salting (a peek under the hood)\n", "Problem: two people with the same password get the *same* hash, and attackers\n", "precompute hashes of common passwords. A **salt** is random text added before hashing\n", "so every hash is unique.\n", "\n", "> Note: `sha256` is great for *learning*. Real apps use slow, salted algorithms made\n", "> for passwords like **bcrypt**, **scrypt**, or **Argon2**. We use sha256 here because\n", "> it's built in and easy to see." ] }, { "cell_type": "code", "execution_count": null, "id": "10c0c6d2", "metadata": {}, "outputs": [], "source": [ "import hashlib, secrets\n", "\n", "def hash_with_salt(password, salt):\n", " return hashlib.sha256((salt + password).encode()).hexdigest()\n", "\n", "salt = secrets.token_hex(8) # random salt\n", "print(\"salt:\", salt)\n", "print(\"salted hash:\", hash_with_salt(\"hunter2\", salt))\n", "# Same password + different salt = different hash โ†’ much harder to crack in bulk" ] }, { "cell_type": "markdown", "id": "c428a7a2", "metadata": {}, "source": [ "## 6. ๐Ÿ” Hardcoded secrets are dangerous\n", "Putting passwords or API keys directly in code is a classic mistake โ€” anyone who\n", "sees the code (e.g. on GitHub) gets the secret.\n", "\n", "```python\n", "# โŒ BAD โ€” secret baked into the code\n", "api_key = \"sk_live_8f3kd92ksecretkey\"\n", "```\n", "\n", "The fix (in real projects) is to load secrets from a separate file or environment\n", "variable that is **never shared**. For now, just learn to *spot* this smell." ] }, { "cell_type": "markdown", "id": "ab9f1130", "metadata": {}, "source": [ "---\n", "## ๐Ÿงช LAB 3A โ€” Password Strength Checker\n", "Write a function `password_strength(pw)` that returns a message based on rules:\n", "- at least 8 characters\n", "- contains a number (hint: `any(c.isdigit() for c in pw)`)\n", "- contains a letter\n", "- contains a symbol (anything not letter/number)\n", "\n", "Give a score or rating (Weak / Okay / Strong). Fill in the `TODO`s." ] }, { "cell_type": "code", "execution_count": null, "id": "9e91a33e", "metadata": {}, "outputs": [], "source": [ "# LAB 3A โ€” your code here\n", "def password_strength(pw):\n", " length_ok = len(pw) >= 8\n", " has_digit = any(c.isdigit() for c in pw)\n", " has_alpha = any(c.isalpha() for c in pw)\n", " has_symbol = any(not c.isalnum() for c in pw)\n", "\n", " # TODO: count how many rules passed and return Weak / Okay / Strong\n", " pass\n", "\n", "print(password_strength(input(\"Test a password: \")))" ] }, { "cell_type": "markdown", "id": "4cb72d7b", "metadata": {}, "source": [ "## ๐Ÿงช LAB 3B โ€” Tiny Secure Login\n", "Build a mini login that **never stores the plain password**:\n", "1. Ask the user to *create* a password โ†’ store only its salted hash\n", "2. Ask them to log in โ†’ hash the attempt and compare\n", "3. Give them 3 tries\n", "\n", "Use the helpers from section 5." ] }, { "cell_type": "code", "execution_count": null, "id": "80307c21", "metadata": {}, "outputs": [], "source": [ "# LAB 3B โ€” your code here\n", "import hashlib, secrets\n", "def hash_with_salt(pw, salt): return hashlib.sha256((salt+pw).encode()).hexdigest()\n", "\n", "# TODO: create account (store salt + stored_hash)\n", "# TODO: give the user up to 3 login attempts\n" ] }, { "cell_type": "markdown", "id": "7e4a987e", "metadata": {}, "source": [ "## ๐Ÿงช LAB 3C โ€” Spot the Security Flaws (code review)\n", "Below is some code with **3 security problems** planted in it. Read it like a security\n", "reviewer and, in the text cell after it, list each problem and how you'd fix it.\n", "*(Don't run it โ€” just read.)*" ] }, { "cell_type": "code", "execution_count": null, "id": "5323b952", "metadata": {}, "outputs": [], "source": [ "# ๐Ÿ”Ž REVIEW THIS CODE โ€” do not run, just analyze\n", "def login(username):\n", " api_key = \"sk_live_REALsecret_9f8d7\" # used to talk to a server\n", "\n", " with open(\"passwords.txt\", \"r\") as f: # file stores: user,password\n", " for line in f:\n", " user, password = line.strip().split(\",\")\n", " if user == username:\n", " guess = input(\"Password: \")\n", " if guess == password:\n", " print(\"Welcome\", username)\n", " return True\n", " return False" ] }, { "cell_type": "markdown", "id": "2e947dcd", "metadata": {}, "source": [ "**โœ๏ธ Your code review โ€” list the 3 flaws and fixes here:**\n", "\n", "1. *...*\n", "2. *...*\n", "3. *...*\n", "\n", "---\n", "### โœ… Solutions (try first!)" ] }, { "cell_type": "code", "execution_count": null, "id": "0c09cf31", "metadata": {}, "outputs": [], "source": [ "# --- LAB 3A solution ---\n", "def password_strength(pw):\n", " checks = [\n", " len(pw) >= 8,\n", " any(c.isdigit() for c in pw),\n", " any(c.isalpha() for c in pw),\n", " any(not c.isalnum() for c in pw),\n", " ]\n", " score = sum(checks)\n", " if score <= 2:\n", " return \"Weak โš ๏ธ\"\n", " elif score == 3:\n", " return \"Okay ๐Ÿ™‚\"\n", " else:\n", " return \"Strong ๐Ÿ’ช\"\n", "\n", "print(password_strength(\"abc\")) # Weak\n", "print(password_strength(\"abcd1234\")) # Okay\n", "print(password_strength(\"Abcd123!@\")) # Strong" ] }, { "cell_type": "code", "execution_count": null, "id": "7e936ffb", "metadata": {}, "outputs": [], "source": [ "# --- LAB 3B solution ---\n", "import hashlib, secrets\n", "def hash_with_salt(pw, salt): return hashlib.sha256((salt + pw).encode()).hexdigest()\n", "\n", "salt = secrets.token_hex(8)\n", "new_pw = input(\"Create a password: \")\n", "stored_hash = hash_with_salt(new_pw, salt) # plain password is now discarded\n", "print(\"Account created (we only kept a salted hash).\")\n", "\n", "for attempt_num in range(3):\n", " guess = input(\"Log in - enter password: \")\n", " if hash_with_salt(guess, salt) == stored_hash:\n", " print(\"โœ… Logged in!\")\n", " break\n", " else:\n", " print(f\"โŒ Wrong. {2 - attempt_num} tries left.\")\n", "else:\n", " print(\"๐Ÿ”’ Locked out.\")" ] }, { "cell_type": "markdown", "id": "aaebb77c", "metadata": {}, "source": [ "**LAB 3C answer key (the 3 flaws):**\n", "1. **Hardcoded secret** โ€” `api_key` is written in the code; anyone reading it steals it.\n", " *Fix: load it from a separate, untracked config/environment.*\n", "2. **Plain-text passwords** โ€” `passwords.txt` stores real passwords; one leak = total breach.\n", " *Fix: store salted hashes and compare hashes, never the raw password.*\n", "3. **No input validation / no attempt limit** โ€” no checks on `username`, unlimited guesses\n", " invite brute-forcing.\n", " *Fix: validate input and limit login attempts (like Lab 3B).*\n", "\n", "### ๐Ÿ“ Day 3 recap\n", "- CIA triad = the *why* of security\n", "- ๐Ÿ” Never store plain passwords โ†’ store **salted hashes**\n", "- Hashing is one-way; salting makes each hash unique\n", "- Hardcoded secrets are a classic, dangerous mistake\n", "- Tomorrow: combine everything into a secure mini-app + the **ethics** of security." ] } ], "metadata": { "colab": { "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }