Why economics matter in defense
Attackers optimize for profit per hour. Defenses that don't change attacker economics don't reduce risk — they just shuffle which doors get opened. To build defenses that actually deter attacks, you need to understand what makes a compromise profitable and what makes it not.
This tutorial walks through the main monetization patterns for web app compromise and the specific defenses that disrupt each.
Pattern 1 — Credential resale at scale
The most common monetization route, requires the least skill from the buyer.
The flow
- Attacker scrapes login forms from thousands of websites
- Runs credential-stuffing botnet against each, using stolen credential dumps
- Successful logins compiled into "combolists" — sold on dark forums
- Buyers use them for higher-value attacks: SaaS account takeover, banking fraud, identity theft
The economics
- Generic SaaS credentials: €0.10-€1.00 per working combo
- Streaming/media credentials: €2-€20
- Banking credentials: €50-€500 (US/EU)
- Corporate credentials at known companies: €200-€10,000 (resold to IABs)
A successful stuffing campaign returns 0.1%-1% of attempted credentials. The math works because compute is cheap and attempts are unlimited.
Defenses that change the economics
- MFA — single biggest disruption. Combos without working MFA codes are nearly worthless.
- Rate limiting per IP and per account — botnets need clean IPs, which cost money. Forcing them to rotate slows attacks dramatically.
- Block known breached passwords on login — pwndpwd k-anonymity lookup, fail if hit. Defeats stuffing because the breached creds being stuffed are the exact ones being blocked.
- Account lockout with timing-safe messaging — "username/password incorrect or too many attempts, try again later" — same response regardless of which condition, so enumeration is harder.
- CAPTCHA on suspicious patterns — not on every login (terrible UX), only when risk signals fire (new IP, new device, fast retries).
- Device fingerprinting — even when the password is right, an unrecognized device triggers step-up auth.
# Django example: enforce breached-password check on login
import hashlib
import requests
def is_breached(password: str) -> bool:
sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
prefix, suffix = sha1[:5], sha1[5:]
r = requests.get(f"https://api.pwnedpasswords.com/range/{prefix}", timeout=2)
if r.status_code != 200:
return False # Fail open — don't lock users out on API issues
return any(line.startswith(suffix) for line in r.text.splitlines())
def login_view(request):
if request.method == 'POST':
password = request.POST['password']
if is_breached(password):
messages.error(request, 'This password appears in known breaches. Please use a different password.')
return redirect('password_reset')
# ...regular auth flow
Pattern 2 — Payment data theft
The classic and still highly profitable. Attackers compromise either:
- The site's card storage (PCI breach — disastrous, regulated, fineable)
- The checkout flow (Magecart-style JavaScript injection that exfiltrates cards as customers type)
- The payment processor integration (stolen Stripe API keys = fraudulent charges)
Magecart in detail
Attackers compromise either the host directly or a CDN/script you load. Inject JavaScript into the checkout page that copies form data and POSTs it to attacker-controlled infrastructure. The page works normally — customer pays, gets product. But their card is now stolen.
Famous victims: British Airways, Ticketmaster, Newegg. Losses in the hundreds of millions, plus regulatory fines.
Defenses
- Don't store card data — let Stripe / your PSP handle storage. Tokenization moves PCI scope off your servers.
- Content Security Policy (CSP) — strict CSP prevents arbitrary script injection.
script-src 'self' plus explicit allowlist for CDNs.
- Subresource Integrity (SRI) on every external script —
<script src="..." integrity="sha384-..."> ensures the loaded content matches the expected hash.
- CSP report-uri — get notified when CSP violations occur, often the first sign of injection attempts.
- Stripe API key restriction — restrict by IP (covered in earlier Stripe series), use restricted keys for production not full secret keys.
- Webhook signature verification — never trust unsigned webhook calls. Stripe-Signature header check on every event.
# CSP middleware in Django settings
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'", "https://js.stripe.com", "https://cdn.jsdelivr.net")
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net")
CSP_FRAME_SRC = ("https://js.stripe.com",)
CSP_CONNECT_SRC = ("'self'", "https://api.stripe.com")
CSP_REPORT_URI = "/csp-report/"
Pattern 3 — Account takeover for high-value users
The economics shift when the target is a specific account, not a bulk credential. Attackers take over:
- Influencer / executive accounts — used for blackmail, brand damage, or to send messages to their network
- Customer support / staff accounts — to access customer data without raising flags
- Developer accounts — to push malicious code through CI/CD, leak source, plant backdoors
- Finance / AP accounts — to authorize fraudulent transfers
The attack: targeted phishing, SIM swap to bypass SMS-MFA, OAuth consent phishing, or session token theft.
Specific defenses
- Phishing-resistant MFA for high-value roles (WebAuthn / FIDO2, not SMS or TOTP)
- Approval workflows for high-impact actions even within an authenticated session
- Session reauthentication — "this action requires re-entering your password"
- Anomaly detection — alerts when an admin logs in from a new location/device
- Audit logs that can be reviewed after a suspected incident
- OAuth scope minimization — apps should never grant broader scopes than needed
Pattern 4 — Cryptominer drop and infrastructure abuse
Attacker doesn't want your data. They want your CPU.
The flow
- Exploit any RCE vulnerability in the web stack
- Drop a miner pointed at attacker's pool
- Sometimes drop a reverse shell as a backup persistence mechanism
- Stay quiet — mining is more profitable when not detected
Why it's persistent
The miner often doesn't even need root — runs as the application user, indistinguishable from a busy worker process. Easy to miss until the cloud bill arrives.
Defenses
- Patch promptly — CVE-to-exploit is now hours, not weeks
- Egress firewall — miners need to connect to pools. Block outbound to anywhere other than known endpoints
- CPU/memory anomaly alerting — sustained 100% CPU outside known job windows is suspicious
- Cloud bill alerting — set a daily threshold; sudden 5x spike means something
- Container hardening — read-only filesystems, no shell, drop unnecessary capabilities
- Runtime detection — Falco, Wazuh, or commercial EDR will catch most miner deployments
Pattern 5 — Business Email Compromise via the web app
Less obvious than the others but extremely lucrative.
Many web apps integrate with email — sending invoices, password resets, notifications, customer communications. Compromise of the app may give attackers:
- The ability to send email from your domain (passes SPF/DKIM)
- Access to email templates that look legitimate
- Customer data to craft personalized pretexts
The attacker uses this to send convincing emails to your customers' AP departments, requesting that future invoices be paid to an attacker-controlled bank account.
Defenses
- DMARC enforcement —
p=reject with monitoring
- Restrict who can send email from your domain — application servers via authenticated SMTP, no other source
- Output sanitization in admin tools — preventing internal staff from accidentally including customer-controlled content in outgoing communications
- Audit logging of all transactional emails sent — anomalies show up here
- Vendor banking change verification — your own customers should refuse to update banking info via email alone
Pattern 6 — Supply chain via your web app
A specific and growing pattern: your web app loads JS/CSS from a third-party CDN or package manager. The third party gets compromised. Your users get malicious code.
Recent examples:
- eslint-scope (2018) — npm package compromised, malicious code shipped to thousands of CI systems
- CodeCov (2021) — bash uploader modified to exfiltrate env vars, including AWS keys
- xz Utils (2024) — multi-year supply chain attack into a core OS library
Defenses
- Pin dependency versions with integrity hashes (package-lock.json, poetry.lock with hashes)
- SRI on every external script load
- Mirror critical dependencies internally
- Periodic audit of dependencies — what loaded, what version, when last updated
- Egress filtering on build systems — supply chain malware often phones home with secrets
The defense-economics summary
Mapping defense priorities to threat types:
| Defense |
Disrupts |
| MFA (phishing-resistant) |
Credential stuffing, account takeover, BEC |
| Rate limiting on auth |
Credential stuffing |
| Breached password blocking |
Credential stuffing |
| CSP + SRI |
Magecart, supply chain JS injection |
| DMARC |
Email spoofing, BEC |
| Egress filtering |
Cryptominer C2, data exfiltration |
| Dependency pinning + scanning |
Supply chain |
| Audit logging + anomaly alerting |
All categories — your detection layer |
The combination is multiplicative. Each defense alone deters some attackers; the stack deters the ones who'd otherwise persist.
Where SMEs typically fail
Patterns in real-world Dutch SME web app breaches:
- No MFA on a single forgotten staff account — the rest of the security was solid, but one admin account without MFA was enough
- Outdated framework with public CVE — patched four hours after disclosure, but breached three hours after disclosure
- Phishing → OAuth consent — sophisticated phishing led to an OAuth grant that bypassed all the password-focused defenses
- CMS plugin with leaked DB credentials — third-party plugin had a hardcoded API endpoint; that endpoint was misconfigured and leaked the connection string
- Default admin URL with weak password and brute force — the WAF didn't see
/admin/ as needing special protection
Each is preventable with the basics from tutorial 1 plus the disruptions in this tutorial. None require nation-state-tier defenses — just consistent execution of fundamentals.
Closing thought
Attackers will always find the cheapest path to monetization. Your job is to make every path expensive enough that they move to another target. Perfect security is impossible. Sufficient deterrent is achievable.
Build defenses that change the economic calculation. Track them. Test them. The next eight tutorials show you how at the technical level.