Security Notes
Coding

Python for Security Engineering

This directory contains everything you need to be interview-ready in Python: hands-on exercises across 10 topic areas, security-specific code patterns, a quick cheatsheet, and common interview questions with hints.

11 min read 7 sections

New to the algorithm patterns?Start with patterns-primer.md — the canonical template for each of the 14 core patterns (sliding window, two pointers, binary search, BFS/DFS, heap, backtracking, DP, etc.) with comments explaining why each works and how to pick the right one in an interview.


Exercise Ladder

12 topic areas, 10 levels each. Each file is self-contained and self-testing.

python/
├── cheatsheet.py              — one-file reference for syntax, builtins, comprehensions
│
├── strings/                   — manipulation, regex, ciphers, sliding substring
├── lists/                     — in-place ops, two-sum, rotate, merge sorted, intervals
├── dicts/                     — frequency counting, grouping, inversion, Top K, anagrams
├── sets/                      — uniqueness, intersection, Jaccard, consecutive sequences
├── iteration/                 — enumerate, zip, comprehensions, matrix ops, Pascal's triangle
├── recursion/                 — factorial, Fibonacci, GCD, flatten, permutations
├── classes/                   — OOP, properties, dunders (__eq__, __repr__), context managers
├── tuples_and_unpacking/      — structured records, namedtuple, variadic unpacking, zip/unzip
├── sorting_and_lambdas/       — key functions, multi-key sort, sort by frequency/priority
├── sliding_window/            — fixed window, variable window, rate limiter, anagram search
├── log_parsing/               — split/regex field extraction, brute-force-by-IP, access logs, JSON logs
└── time_windows/              — windowing over timestamped events: bursts, scans, sessions, rate alerts

Practice formatlog_parsing/ and time_windows/ ship levels 01–02 as solved reference templates (read these first to learn the pattern) and levels 03–10 as stubs (pass) for you to implement. Run a stub before you've filled it in and it raises AssertionError — that's the practice loop working.


How to Run Exercises

Each file runs independently. A passing solution prints OK; a failing one raises AssertionError with a helpful message.

bash
# Run a single exercise
python strings/level_01_reverse_string.py

# Run all exercises in a topic
for f in strings/level_*.py; do python "$f" && echo "PASS: $f" || echo "FAIL: $f"; done

# Run everything
for f in */level_*.py; do python "$f" && echo "PASS: $f" || echo "FAIL: $f"; done

Difficulty guide

LevelEffortWhat it tests
01–02~2 minSingle built-in or operation
03–05~5 minCombining 2 concepts; light logic
06–08~10 minAlgorithm design, edge cases
09–10~15 minFull patterns: OT, dunders, rate limiter, deduplication

Also check cheatsheet.py for a fast syntax refresher before an interview.


Topic Breakdown

strings/

Core string manipulation. By level 10 you can implement decode-string (LeetCode 394) and longest palindromic substring from scratch.

LevelProblem
01Reverse a string
02Count vowels / palindrome check
03Anagram check, reverse words, first non-repeating char
04Capitalize words
05Caesar cipher (useful for security interviews)
06Run-length encoding / longest unique substring (WIP)
07Longest common prefix
08Is rotation (string contains rotated version)
09Longest palindromic substring
10Decode string (bracket expansion)

lists/

In-place operations, classic two-pointer and interval problems.

LevelProblem
01Sum of list / find largest number
02Find min and max
03Running sum
04Remove duplicates, preserve order
05Rotate list by k positions
06Two Sum (hash map approach)
07Move zeroes in-place
08Merge two sorted lists
09Merge overlapping intervals
10Product of array except self

dicts/

Counting, grouping, and classic hash map patterns that come up constantly in security log analysis.

LevelProblem
01Word frequency count
02Dict from two lists (zip)
03Invert a dictionary
04Group words by first letter
05Most common element
06Merge dicts by summing values
07First unique character
08Top K frequent elements
09Isomorphic strings
10Group anagrams

sets/

Set operations and uniqueness problems. Bloom filter intuition lives here.

LevelProblem
01Unique elements
02Intersection of two lists
03Symmetric difference
04Anagram check (Counter)
05Contains duplicate within distance k
06Jaccard similarity
07Elements common to all lists
08Find all duplicates
09Longest consecutive sequence
10Smallest missing positive

sliding_window/

The pattern behind rate limiters, anomaly detection windows, and substring search.

LevelProblem
01Count increasing adjacent pairs
02Max pair sum
03Window averages (fixed size)
04Max sum of k consecutive / longest subarray sum ≤ k
05Max average fixed window
06Count anagram substrings
07Longest substring with k distinct chars
08Min window with sum
09Max in each window (deque)
10Rate limiter with deduplication

log_parsing/

Turning raw log text into structured data — the first step of almost every security task. Levels 01–02 are solved templates; 03–10 are practice stubs.

LevelProblem
01Parse a pipe-delimited log line (maxsplit) — solved
02Extract all IPv4 addresses with regex — solved
03Count log lines by severity level
04Filter to ERROR lines only
05Parse key=value (logfmt) structured logs
06Brute-force detection: failed logins by IP
07Count HTTP status codes from an access log
08Top N requested paths
09Total response bytes per client IP
10Extract messages from JSON-lines logs (skip malformed)

time_windows/

Windowing over timestamped event streams — the two-pointer-over-time pattern that powers burst detection, scan detection, and rate alerts. The natural follow-on to log_parsing/ (parse events, then window them). Levels 01–02 solved.

LevelProblem
01Count events in a time window — solved
02Bucket timestamps into fixed time buckets — solved
03Most events in any sliding time window (burst size)
04Time of the first burst (alert trigger)
05Most distinct keys in any time window
06Port-scan detection (distinct ports per source)
07Sessionize an event stream by idle gap
08Rolling per-key count (live sliding window)
09Maximum value sum in any time window
10Brute-force alert (window + per-IP threshold) — capstone

classes/

OOP patterns. Levels 8–10 cover the dunder methods and context managers that come up in "write a thread-safe cache" style questions.

LevelProblem
01Cookie class / Counter class
02Point class with distance
03Bank account (balance, transactions)
04Rectangle with area and perimeter
05Stack with push/pop/peek
06Animal inheritance (polymorphism)
07Temperature with property getter/setter
08Dunder methods (eq, repr, len, add)
09Countdown iterator (iter, next)
10Context manager (enter, exit, resource cleanup)

Security Code Patterns

Log Parsing & Brute Force Detection

python
import re
from collections import Counter

LOG_LINE = r'Failed password for (\w+) from ([\d.]+) port (\d+)'

def parse_auth_failures(log_text: str) -> list[dict]:
    return [
        {"user": m.group(1), "ip": m.group(2), "port": int(m.group(3))}
        for m in re.finditer(LOG_LINE, log_text)
    ]

def find_brute_force(failures: list[dict], threshold: int = 5) -> list[str]:
    counts = Counter(f["ip"] for f in failures)
    return [ip for ip, count in counts.items() if count >= threshold]

Port Scanner

python
import socket
from concurrent.futures import ThreadPoolExecutor

def scan_port(host: str, port: int, timeout: float = 0.5) -> int | None:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.settimeout(timeout)
        return port if s.connect_ex((host, port)) == 0 else None

def scan_ports(host: str, ports: range) -> list[int]:
    with ThreadPoolExecutor(max_workers=100) as pool:
        results = pool.map(lambda p: scan_port(host, p), ports)
    return [p for p in results if p is not None]

HMAC Signature Verification

python
import hmac, hashlib

def sign_payload(payload: bytes, key: bytes) -> str:
    return hmac.new(key, payload, hashlib.sha256).hexdigest()

def verify_payload(payload: bytes, key: bytes, signature: str) -> bool:
    expected = sign_payload(payload, key)
    return hmac.compare_digest(expected, signature)  # constant-time — prevents timing attacks

Timing-Safe Comparison

python
import hmac

def safe_compare(a: str, b: str) -> bool:
    return hmac.compare_digest(a.encode(), b.encode())

# Never use == for secrets: early exit leaks information via timing

DNS Exfiltration Detector

python
import math
from collections import Counter

def shannon_entropy(s: str) -> float:
    counts = Counter(s)
    length = len(s)
    return -sum((c / length) * math.log2(c / length) for c in counts.values())

def detect_dns_exfil(queries: list[str], threshold: float = 4.0) -> list[str]:
    suspicious = []
    for query in queries:
        subdomain = query.split('.')[0]
        if len(subdomain) > 20 and shannon_entropy(subdomain) > threshold:
            suspicious.append(query)
    return suspicious

# High entropy + long subdomain = likely base64/hex encoded data in DNS query

YARA-like Malware Scanner

python
import re
from dataclasses import dataclass

@dataclass
class Rule:
    name: str
    patterns: list[bytes]

    def matches(self, content: bytes) -> bool:
        return all(re.search(p, content) for p in self.patterns)

RULES = [
    Rule("crypto_miner", [rb"stratum\+tcp", rb"xmrig"]),
    Rule("reverse_shell", [rb"/bin/sh", rb"connect\(", rb"socket\("]),
    Rule("credential_dump", [rb"lsass", rb"mimikatz", rb"sekurlsa"]),
]

def scan_binary(path: str) -> list[str]:
    with open(path, 'rb') as f:
        content = f.read()
    return [rule.name for rule in RULES if rule.matches(content)]

Rate Limiter (Sliding Window)

This is level 10 in sliding_window/ — and a genuine interview question.

python
from collections import deque
import time

class RateLimiter:
    """Sliding window rate limiter. O(1) amortised allow() calls."""

    def __init__(self, max_requests: int, window_seconds: float):
        self.max_requests = max_requests
        self.window = window_seconds
        self.timestamps: deque[float] = deque()

    def allow(self) -> bool:
        now = time.monotonic()
        while self.timestamps and now - self.timestamps[0] > self.window:
            self.timestamps.popleft()
        if len(self.timestamps) < self.max_requests:
            self.timestamps.append(now)
            return True
        return False

# Usage: limiter = RateLimiter(max_requests=100, window_seconds=60)

Common Security Interview Questions

ProblemKey TopicsHint
Parse Apache/nginx logs, count 4xx errors by IPRegex, Counterre.findall, dict comprehension
Detect port scan: same src IP, many distinct dst ports in 60sSliding window, CounterCount unique dsts per src in time window
Implement Caesar cipher / ROT-13Strings, modular arithmeticord, chr, (x - base + shift) % 26
Implement HMAC-SHA256 request signingCryptohmac.new(key, payload, hashlib.sha256)
Find duplicate files by content hashHashing, dict groupinghashlib.sha256, defaultdict(list)
Sliding window rate limiterSliding window, dequecollections.deque, time.monotonic
Binary search in sorted list of timestampsBinary searchbisect.bisect_left
Detect high-entropy DNS subdomains (exfil)Shannon entropy, strings-sum(p * log2(p) for p in probabilities)
Build a Trie for IP prefix matchingClasses, recursionchildren: dict[str, TrieNode]
Recursive directory listing with depth limitRecursion, pathlibPath.iterdir(), track current depth
Parse CIDR notation, check if IP is in rangeBitwise opsipaddress.ip_network, ip_address in network
Decode a base64-encoded payload, extract fieldsbase64, jsonbase64.b64decode, json.loads

Security Anti-Patterns

Anti-patternRiskCorrect approach
eval(user_input)RCE — executes arbitrary Pythonast.literal_eval for safe data parsing only
subprocess(cmd, shell=True) with user dataCommand injectionshell=False, pass args as list
if token == expected:Timing side-channel leaks secret lengthhmac.compare_digest(token, expected)
pickle.loads(untrusted_bytes)RCE — pickle executes __reduce__ on loadUse JSON or msgpack for untrusted data
yaml.load(data)RCE — PyYAML executes Python constructorsyaml.safe_load(data) always
Hard-coded secrets in sourceCredential exposure in repos, logsos.environ["SECRET"] or secrets manager
requests.get(url, verify=False)Disables TLS cert verification; MITM riskKeep verify=True (default); pin certs if needed
Logging request.body or auth headersSensitive data leaks to log aggregatorsScrub secrets before logging; use structured logging
random.randint() for tokens/keysPredictable output; not cryptographically securesecrets.token_hex(32) or secrets.token_urlsafe()
String formatting in SQL queriesSQL injectionParameterised queries; ORM

Standard Library Quick Reference

python
# Cryptography & integrity
import hashlib          # hashlib.sha256(data).hexdigest()
import hmac             # hmac.new(key, msg, hashlib.sha256).hexdigest()
import secrets          # secrets.token_hex(32), secrets.token_urlsafe(32)

# Encoding
import base64           # base64.b64encode/b64decode
import binascii         # hexlify / unhexlify

# Network
import socket           # TCP/UDP, connect_ex for port scanning
import ssl              # TLS wrapping, ssl.create_default_context()
import ipaddress        # ip_address, ip_network, CIDR membership

# Process & OS
import subprocess       # run(args, shell=False, capture_output=True)
import os               # os.environ, os.walk, os.stat
import pathlib          # Path traversal, iterdir, glob

# Parsing
import re               # findall, finditer, sub, compile
import json             # loads / dumps
import csv              # DictReader for structured log files
import ast              # ast.literal_eval — safe eval for Python literals

# Data structures
from collections import Counter, defaultdict, deque, OrderedDict
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor

# Time
import time             # time.monotonic() for rate limiters (no clock drift)
import datetime         # datetime.utcnow(), timedelta