Security Principles, Cryptography & Privacy by Design
Look at your Task 2C code. There's a subtle bug — can you spot it?
for num in numbers:
if num % 7 == 0:
print(f"Found one divisible by 7!")
break
else:
iterator_counter += 1
print("No terms divisible by 7")
The print("No terms divisible by 7") line is outside the loop — it runs no matter what, even when a match IS found. This is a common logic bug.
Use a boolean "flag" to track whether you found a match:
found = False # The flag starts as False
for num in numbers:
if num % 7 == 0:
print(f"Found: {num}")
found = True # Flip the flag
break
if not found: # Only prints if flag was never flipped
print("No terms divisible by 7")
for num in numbers:
if num % 7 == 0:
print(f"Found: {num}")
break
else: # This 'else' belongs to the FOR loop
print("No terms divisible by 7") # Only runs if loop completes WITHOUT break
Python's for...else: The else block on a for loop runs only if the loop finished normally (no break). It's unusual — most languages don't have this — but it's perfect for "search and report" patterns.
for vs whileYour homework answer was: "for is for one-time occasions." Let's sharpen that:
Use for when... |
Use while when... |
|---|---|
| You know how many times to loop | You don't know how many times — loop until a condition changes |
| Iterating over a collection (list, string, range) | Waiting for user input, game loops, polling |
for item in items: |
while not done: |
| Example: "Check every student in the class" | Example: "Keep asking until password is correct" |
Connection to today's lesson: That "keep asking until password is correct" example? That's authentication — and that's exactly what we're covering today.
You already know the SDLC phases. The Year 12 twist: security must be built into every single phase, not bolted on at the end.
| SDLC Phase | Security Consideration |
|---|---|
| Requirements | Define who can access what. What data is sensitive? What laws apply (e.g. Privacy Act)? |
| Specifications | Specify encryption standards, password policies, data retention rules |
| Design | Plan authentication system, authorisation levels, secure data flow |
| Development | Validate all input, handle exceptions, use secure coding practices |
| Integration | Secure APIs between components, test data flow between modules |
| Testing | Security testing (SAST, DAST), penetration testing, vulnerability scanning |
| Installation | Secure deployment, HTTPS configuration, environment variable protection |
| Maintenance | Patch vulnerabilities, monitor logs, update dependencies |
The three core security principles:
CIA tells us what to protect. AAA tells us how to enforce it:
Proving your identity to the system. Methods include:
Multi-Factor Authentication (MFA) combines two or more of these. For example: password (know) + SMS code (have).
After you prove who you are, the system checks your permissions:
Tracking and recording actions so they can be reviewed later:
CIA (What to protect) AAA (How to enforce it) ┌─────────────────┐ ┌──────────────────────┐ │ Confidentiality │──────────▶│ Authentication │ │ │ │ (Verify identity) │ ├─────────────────┤ ├──────────────────────┤ │ Integrity │──────────▶│ Authorisation │ │ │ │ (Check permissions) │ ├─────────────────┤ ├──────────────────────┤ │ Availability │──────────▶│ Accountability │ │ │ │ (Log everything) │ └─────────────────┘ └──────────────────────┘
Real-world example: Think about your school portal. You authenticate with your student ID + password. You're authorised to see your own marks but not other students'. Every login is logged for accountability.
On Luis's tutoring site (the one you're reading this on), the login system uses all three:
Your website has a "secret password" feature — but the password is visible in the JavaScript source code. Anyone can right-click, view source, and see it.
Why? Because JavaScript runs client-side — in the user's browser. The user has full access to everything the browser receives.
This is a fundamental concept for understanding web security:
| Client-Side (Browser) | Server-Side (Server) | |
|---|---|---|
| Runs on | User's computer | Website owner's server |
| Languages | HTML, CSS, JavaScript | Python, Node.js, PHP, Java |
| User can see code? | Yes — View Source, DevTools | No — code stays on the server |
| Safe for secrets? | NEVER | Yes — that's the whole point |
| Example | Your Sanguine Aetherium password check | Luis's tutoring login system |
Never put secrets in client-side code. No passwords, no API keys, no encryption keys. If the browser can see it, so can the user.
Encryption transforms readable data (plaintext) into unreadable data (ciphertext) using a key. With the right key, you can reverse it.
One key to encrypt AND decrypt. Like a padlock where the same key locks and unlocks it.
Symmetric Encryption (AES)
──────────────────────────
"Hello Blake" ──▶ [ AES + Key123 ] ──▶ "x8Kp2mQ..."
(plaintext) (encrypt) (ciphertext)
"x8Kp2mQ..." ──▶ [ AES + Key123 ] ──▶ "Hello Blake"
(ciphertext) (decrypt) (plaintext)
Same key (Key123) used for both directions
Two mathematically related keys: a public key (shared freely) and a private key (kept secret). What one encrypts, only the other can decrypt.
Asymmetric Encryption (RSA)
───────────────────────────
Blake wants to send a secret message to Luis:
"Secret msg" ──▶ [ RSA + Luis's PUBLIC key ] ──▶ "Qz9xW..."
(plaintext) (encrypt) (ciphertext)
"Qz9xW..." ──▶ [ RSA + Luis's PRIVATE key ] ──▶ "Secret msg"
(ciphertext) (decrypt) (plaintext)
Anyone can encrypt with the public key.
Only Luis can decrypt with his private key.
Hashing is NOT encryption. It's a one-way function — you can't reverse it.
| Encryption | Hashing | |
|---|---|---|
| Reversible? | Yes (with the key) | No — one-way only |
| Purpose | Protect data in transit/storage | Verify data without storing the original |
| Output size | Varies with input | Always fixed length |
| Use case | Sending a secret message | Storing passwords |
# Hashing is one-way: same input ALWAYS gives same output
# SHA-256 examples:
"blake2025" → "a3f2b8c1d4e5..." (always 64 hex characters)
"blake2026" → "7x9m2k4p1q8..." (completely different!)
"Blake2025" → "r5t8w2y6n3a..." (case matters!)
# You CAN'T go backwards:
"a3f2b8c1d4e5..." → ??? (impossible to reverse)
The server never stores your actual password. Here's the flow:
"blake2025"bcrypt("blake2025") → "$2b$10$xK...""$2b$10$xK...""blake2025"bcrypt("blake2025") → "$2b$10$xK...""$2b$10$xK..." == "$2b$10$xK..."
Password Verification Flow
──────────────────────────
SIGN UP:
"blake2025" ──▶ [ bcrypt hash ] ──▶ "$2b$10$xK..." ──▶ Store in database
(hash only!)
LOGIN:
"blake2025" ──▶ [ bcrypt hash ] ──▶ "$2b$10$xK..."
│
▼
Compare ══▶ Match? ──▶ Access granted!
▲
│
Database: "$2b$10$xK..."
A salt is random data added to the password before hashing. This means even if two users have the same password, their hashes are different.
hash("blake2025") → same hash every time (attackers can use pre-computed "rainbow tables")bcrypt("blake2025", random_salt) → different hash every timebcrypt automatically generates and stores the salt inside the hash string.
Sandboxing means running code in an isolated environment where it can't affect the rest of the system.
Created by Dr. Ann Cavoukian. The idea: build privacy into the system from the start, don't add it as an afterthought.
Exam note: You don't need to memorise all 7 word-for-word. Know the key ideas: proactive, default privacy, embedded in design, transparency, and user control. Be able to apply them to a scenario.
Remember exception handling from Lesson 3? Input validation takes it further — never trust user input.
Checking that input meets expected criteria before processing it:
Cleaning input by removing or escaping dangerous content:
def validate_age(user_input):
"""Validate that age is a reasonable integer."""
# Type check
try:
age = int(user_input)
except ValueError:
return None, "Age must be a number"
# Range check
if age < 0 or age > 150:
return None, "Age must be between 0 and 150"
return age, "Valid"
# Test it
age, msg = validate_age("25") # (25, "Valid")
age, msg = validate_age("abc") # (None, "Age must be a number")
age, msg = validate_age("-5") # (None, "Age must be between 0 and 150")
age, msg = validate_age("999") # (None, "Age must be between 0 and 150")
| Whitelist (Allow List) | Blacklist (Block List) | |
|---|---|---|
| Approach | Only allow known-good input | Block known-bad input |
| Example | "Username must be letters and numbers only" | "Username cannot contain < or > or ;" |
| Security | Stronger — you can't forget to block something | Weaker — attackers find characters you forgot to block |
password123 in a JavaScript file on a website. Identify TWO security issues with this approach. (2 marks)Authentication is the process of verifying a user's identity — confirming they are who they claim to be (e.g. entering a password or scanning a fingerprint).
Authorisation is determining what an authenticated user is permitted to do — their access level and permissions (e.g. a student can view grades but not edit them).
Hashing is a one-way function — it cannot be reversed, so even if attackers access the database, they cannot recover the original passwords. Encryption is reversible — if an attacker obtains the decryption key, all passwords are exposed. With hashing, verification works by hashing the login attempt and comparing it to the stored hash, so the original password is never needed or stored.
Issue 1: JavaScript runs client-side, meaning users can view the source code and see the password in plaintext through browser developer tools.
Issue 2: The password is stored in plaintext rather than being hashed, so it is immediately usable if discovered — there is no cryptographic protection.
Before building the system, the developer would conduct a privacy impact assessment to identify what student data is collected, who can access it, and potential risks. Security measures such as encryption, access controls, and data minimisation (only collecting what is necessary) would be built into the system's architecture from the start, rather than being added after a data breach occurs.
Input validation checks whether input meets expected criteria and rejects it if not. Example: checking that an email address contains an @ symbol and a domain name before accepting it.
Input sanitisation modifies input by removing or escaping dangerous characters so it can be safely processed. Example: converting <script> tags in user comments to harmless text so they display as text rather than executing as code.
for...else for search-and-reportfor when you know the iterations, while when you don'tNext lesson: Secure Software Architecture II — Vulnerabilities & Testing. We'll cover real attack types (XSS, SQL Injection, CSRF), security testing (SAST, DAST, penetration testing), and how to write defensive code.
Task 1: Fix Your Website Password
Look at the password feature on your Sanguine Aetherium website. Write a short paragraph explaining:
Task 2: AAA Scenario Analysis
Pick any app or website you use regularly. Identify examples of:
Task 3: Input Validation Practice
Write a Python function validate_password(password) that checks:
(True, "Valid") or (False, "reason")You can use .isupper(), .isdigit(), and the any() function:
any(char.isupper() for char in password) — returns True if at least one character is uppercase.