Security tools
The everyday security chores of web engineering — hashing, password entropy, JWT claims, CSP authoring and redacting captures before sharing them — and which tool fits each job.
11 tools
The chore layer of web security
Most security work in a normal engineering week is not adversarial. It is
mechanical: pick a digest algorithm, generate a credential that satisfies
somebody’s policy, read a token’s claims to see why auth failed, write a
Content-Security-Policy that does not break the site, scrub a capture before
pasting it into a ticket. None of it looks like a pentest, and all of it is where
real incidents start — the failure mode is a bad habit, not a missing skill.
The model that prevents most of those habits is a three-way split people collapse
into one. Encoding — Base64, percent-encoding, Punycode — is reversible and
involves no secret; it changes the shape of data, never its confidentiality.
Hashing — SHA-256, SHA-512 — is one-way and also involves no secret; it
proves two byte strings are identical, nothing more. Keyed operations — HMAC,
JWT signatures, TLS — are the only ones that prove who produced something, and
only while the key stays secret. No key, no authentication: a Base64 blob, a bare
digest and a decoded JWT payload are readable claims with nothing behind them.
The second axis is direction. Chores that emit policy — CSP directives, headers, generated secrets — are only correct once you verify the artifact in the deployed response. Chores that inspect something handed to you carry the opposite risk: what is inside the artifact. Redaction belongs here because the usual way secrets leave a company is a HAR attached to a bug report, not an exploit.
What each primitive actually guarantees
| Primitive | Proves | Does not provide | Common misuse |
|---|---|---|---|
| Base64 / URL-encoding | Safe transport of bytes through text channels | Confidentiality — anyone can reverse it | ”Hiding” an API key in a payload |
SHA-256 / SHA-512 | Integrity: same input, same digest | Secrecy; brute-force cost on low-entropy input | Storing password hashes |
SHA-1 | Legacy checksum compatibility | Collision resistance (practically broken) | Signatures; dedupe of hostile input |
| HMAC (hash + secret key) | Authenticity while the key stays secret | Confidentiality — payload still readable | Shipping the key to a browser |
| Argon2id / bcrypt / scrypt | Salted, deliberately slow password storage | Speed — slowness is the feature | Swapping in a fast hash “for perf” |
JWT signature (HS256, RS256) | Issuer authenticity — only after verification | Anything, if you merely decode | Trusting a decoded payload’s claims |
Content-Security-Policy | Browser-enforced allowlist for resource loads | A fix for the injection; non-browser clients | 'unsafe-inline' left in script-src |
TLS + Strict-Transport-Security | Transport confidentiality; no downgrade to http | Any statement about application logic | Reading a padlock as “app is secure” |
How much entropy is enough
Entropy is length × log2(pool size), so the pool matters as much as the length.
| Character pool | Bits per char | 8 chars | 14 chars | 20 chars |
|---|---|---|---|---|
a–z (26) | 4.70 | 38 | 66 | 94 |
a–z0–9 (36) | 5.17 | 41 | 72 | 103 |
a–zA–Z0–9 (62) | 5.95 | 48 | 83 | 119 |
| all four sets (87) | 6.44 | 52 | 90 | 129 |
Under 40 bits is broken; 80 is the floor for an account that matters; a random UUID v4 carries 122 bits.
Picking the right tool
For fingerprints, Hash Generator computes SHA-1, SHA-256,
SHA-384 and SHA-512 at once via Web Crypto, so a digest matches
echo -n "text" | shasum -a 256 byte for byte — the fast way to reconcile a
checksum whose algorithm nobody recorded. MD5 is absent because Web Crypto does
not implement it.
For secrets you create, the question is who holds the value.
Password Generator fits when a human or password manager does
and a site imposes a length or charset policy; it reports live entropy for the
pool you enabled. UUID v4 Generator fits when the consumer is a
machine and you want an opaque identifier with no charset negotiation. Both are
CSPRNG-backed — the password generator draws from crypto.getRandomValues, the
UUID generator from crypto.randomUUID() — so neither falls back to
Math.random.
For tokens, JWT Token Decoder splits
header.payload.signature, pretty-prints the first two parts, and renders iat,
exp and nbf as ISO 8601 with an expiry verdict — enough to settle “is this
stale, or are the claims wrong?” in one paste. Use
Base64 Encode / Decode when all you salvaged from a log is a single
segment; Base64url uses - and _, so swap them for + and / first.
For policy, keep authoring and verification separate.
Content Security Policy Generator assembles the header from 14
per-directive fields over a hardened baseline — default-src 'self',
object-src 'none', base-uri 'self', frame-ancestors 'none' — and the
CSP hub goes directive by directive. Then prove the deployed
response carries it with HTTP Headers Checker, which fetches
server-side and shows raw headers as the origin sent them. CDNs rewrite headers,
and a <meta> tag cannot carry frame-ancestors.
Before sharing, HAR File Viewer reads your own capture — method,
status, MIME type, size, timing per entry — while
HAR File Sanitizer prepares the copy that leaves your machine,
replacing cookie, authorization, x-api-key and similar headers with
[REDACTED], blanking bodies, masking token-like query parameters. When the
suspect is one URL, URL Parser & Analyzer decodes the query
string to show whether a signed token sits in it, and
IDN / Punycode Converter reveals whether a look-alike domain
is really Cyrillic in xn-- form.
All of this runs locally except the headers checker, which sends your URL to
api.sitekits.dev. /for/security/ collects most of these on
one page — the general-purpose ones (UUID, Base64, the HAR viewer) sit in other
role sets; the privacy hub covers what your browser leaks.
Gotchas that cause real incidents
A decoded token is not a verified token
Decoding proves only well-formed Base64url. Verification needs the issuer’s key,
a pinned algorithm, and server-side exp / nbf / iss / aud checks. Never
take the algorithm from the token’s own alg header — that is how alg: none
and RS256-to-HS256 confusion work.
A fast hash is not password storage
A bare SHA-256 of a password is a GPU benchmark, not a defense; unsalted, one
rainbow table cracks every user. Hashing to compare files is the opposite case —
there a fast digest is correct.
'unsafe-inline' cancels most of CSP
It re-permits exactly the injected inline script CSP exists to block. Use nonces
or hashes. A wildcard connect-src is the same trap from the other side:
exfiltration stays open even when script execution is locked down.
Redaction is pattern matching, not comprehension
The sanitizer matches a fixed header list and parameter names containing token,
key, secret, password, passwd, pwd, auth, session, sig or
signature. A credential in a URL path segment, or named t, survives — and a
redaction count of zero on an authenticated session is a signal, not a pass.
Entropy describes the generator, not the string
The formula holds only when every character was drawn randomly. P@ssw0rd!2024
has 13 characters and all four classes yet sits in every cracking wordlist. Only
how a string was generated decides whether a meter’s score means anything.