Web Security Fundamentals: Hashing, JWTs, and Certificates

By the BoltQuickTools Team | April 9, 2026 | 10 min read

I remember the first time I saw a data breach notification in my inbox. It was for a service I had used once, years earlier, and they were telling me my password had been stored in plain text. That moment changed how I thought about security. If you are building anything on the web, even a side project, security is not something you bolt on later. It needs to be baked in from the start.

In this article, I will walk through the security fundamentals that every developer should understand: cryptographic hashing, password hashing, JSON Web Tokens (JWTs), SSL/TLS certificates, SSH keys, and UUID generation. These are the building blocks that keep data safe in transit and at rest.

Why Every Developer Needs Security Basics

Security vulnerabilities do not discriminate between junior developers and staff engineers. A misconfigured JWT, a missing certificate validation, or a naive hashing choice can expose user data regardless of how clean the rest of your code is. Understanding these fundamentals helps you make better decisions during design, catch problems during code review, and respond effectively when something goes wrong.

The goal is not to become a cryptographer. The goal is to know enough to choose the right tool, use it correctly, and recognize when something looks off.

Cryptographic Hashing: The Foundation

A hash function takes an input of any size and produces a fixed-length output. The same input always produces the same output, but even a single changed character results in a completely different hash. This property makes hashing useful for verifying data integrity, generating checksums, and fingerprinting content.

MD5: Fast but Broken

MD5 produces a 128-bit (32-character hex) hash and was the go-to algorithm for years. However, researchers demonstrated practical collision attacks in 2004, meaning two different inputs can produce the same hash. You should never use MD5 for security purposes. It is still fine for non-security tasks like cache keys or deduplication checksums, but keep it away from anything that protects user data.

SHA-1: Deprecated

SHA-1 produces a 160-bit (40-character) hash. Google demonstrated a practical SHA-1 collision in 2017 (the SHAttered attack), and major browsers stopped trusting SHA-1 certificates. Like MD5, SHA-1 should not be used for new security applications. You will still see it in legacy systems and Git commit identifiers, but it is on its way out.

SHA-256: The Current Standard

SHA-256 is part of the SHA-2 family and produces a 256-bit (64-character) hash. It remains the standard recommendation for most security applications: file integrity verification, digital signatures, and certificate fingerprints. When a software publisher posts a checksum alongside a download, it is almost always SHA-256.

You can try generating hashes for your own text or files with our Hash Generator. It computes MD5, SHA-1, SHA-256, and SHA-512 simultaneously so you can compare the output lengths and formats side by side.

# Verify a downloaded file on the command line
sha256sum ubuntu-24.04-desktop-amd64.iso
# Compare the output against the published checksum

Password Hashing: A Different Problem

General-purpose hash functions like SHA-256 are designed to be fast. That is a problem for password storage, because an attacker with a leaked database can try billions of SHA-256 guesses per second on a modern GPU. Password hashing algorithms solve this by being deliberately slow.

bcrypt, Argon2, and PBKDF2

bcrypt has been the industry standard for over two decades. It includes a configurable "cost factor" that controls how many rounds of computation it performs, and it automatically generates and embeds a random salt into the output. As hardware gets faster, you increase the cost factor.

Argon2 is the newer recommendation (winner of the 2015 Password Hashing Competition). It lets you tune time cost, memory cost, and parallelism independently, which makes it resistant to both GPU attacks and specialized hardware (ASICs). If you are starting a new project, Argon2id is the best choice.

PBKDF2 is the oldest of the three and is built into many standard libraries. It applies a hash function (usually SHA-256) thousands of times. While acceptable, it lacks memory-hardness, which makes it more vulnerable to GPU-based attacks than bcrypt or Argon2.

// Node.js example: hashing a password with bcrypt
const bcrypt = require('bcrypt');
const saltRounds = 12;

// Hashing
const hash = await bcrypt.hash('user-password', saltRounds);

// Verifying
const match = await bcrypt.compare('user-password', hash);
console.log(match); // true

Need to generate strong passwords for testing? Our Password Generator creates cryptographically random passwords with configurable length and character sets.

JWTs: Authentication Tokens Explained

JSON Web Tokens are the most common way to handle authentication in modern web applications. A JWT is a compact, URL-safe string made of three Base64URL-encoded parts separated by dots: header.payload.signature.

The Three Parts

The header specifies the algorithm (like HS256 or RS256) and the token type. The payload contains claims: data like user ID, roles, expiration time, and issuer. The signature is created by signing the encoded header and payload with a secret key (symmetric) or private key (asymmetric).

// JWT structure (decoded)
// Header
{ "alg": "HS256", "typ": "JWT" }

// Payload
{
  "sub": "user-12345",
  "name": "Alice",
  "role": "admin",
  "iat": 1712620800,
  "exp": 1712624400
}

// Signature
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

How Verification Works

When a server receives a JWT, it re-computes the signature using the encoded header and payload plus its own copy of the secret. If the computed signature matches the one in the token, the token has not been tampered with. For asymmetric algorithms (RS256), the server uses the public key to verify the signature made with the private key.

Common JWT Mistakes

You can inspect and decode any JWT with our JWT Decoder. It splits the token into its three parts, decodes the header and payload, and shows the signature.

SSL/TLS Certificates: Securing Data in Transit

When you visit a site over HTTPS, your browser and the server perform a TLS handshake. The server presents its certificate, which proves its identity and establishes an encrypted channel. Understanding how this works helps you debug certificate errors and set up HTTPS correctly.

How HTTPS Works

During the TLS handshake, the server sends its certificate (containing its public key) to the client. The client verifies the certificate against a chain of trust that leads back to a trusted Certificate Authority (CA). Once verified, the two sides negotiate a symmetric session key for encrypting the actual data. This hybrid approach uses asymmetric cryptography for the handshake and symmetric cryptography for speed during data transfer.

Certificate Chains

A certificate chain typically has three levels: the root CA (trusted by the operating system or browser), an intermediate CA (signed by the root), and the end-entity certificate (signed by the intermediate). If any link in the chain is missing or expired, the connection fails.

SANs and Expiration

Subject Alternative Names (SANs) specify which domains a certificate covers. A single certificate might cover example.com, www.example.com, and api.example.com. Wildcard certificates cover *.example.com but not the bare domain itself unless explicitly listed.

Certificate expiration is a common cause of outages. Let's Encrypt certificates expire after 90 days, and even paid certificates have finite lifetimes. Automated renewal and monitoring are essential. You can inspect any certificate's details, including its chain, SANs, and expiration date, using our SSL Certificate Decoder.

SSH Keys: Secure Remote Access

SSH keys use public-key cryptography to authenticate you to remote servers without passwords. You generate a key pair: the private key stays on your machine, and the public key goes on the server. When you connect, the server challenges you to prove you hold the private key, and your SSH client responds without ever sending the key itself.

RSA vs ECDSA vs Ed25519

RSA is the oldest and most widely supported. A 4096-bit RSA key provides strong security but the keys are large and generation is slower.

ECDSA uses elliptic curve cryptography, producing shorter keys with equivalent security. A 256-bit ECDSA key provides roughly the same security as a 3072-bit RSA key. However, ECDSA has a subtle vulnerability: if the random number generator used during signing is weak, the private key can be recovered.

Ed25519 is the current recommendation. It uses the Edwards curve (Curve25519), is fast, produces compact keys, and is not vulnerable to the random number issues that affect ECDSA. Unless you need compatibility with very old systems, Ed25519 is the best choice.

# Generate an Ed25519 SSH key pair
ssh-keygen -t ed25519 -C "[email protected]"

# The public key goes on the server
cat ~/.ssh/id_ed25519.pub

# The private key stays on your machine (never share it)
# ~/.ssh/id_ed25519

You can generate SSH key pairs directly in your browser with our SSH Key Generator. It supports RSA, ECDSA, and Ed25519 formats.

UUID Generation: Unique Identifiers Done Right

UUIDs (Universally Unique Identifiers) are 128-bit values used as primary keys, request IDs, and correlation tokens. Two versions are worth knowing about.

UUID v4: Random

UUID v4 is generated from random bytes. It has no inherent ordering, which means database indexes built on v4 UUIDs can suffer from fragmentation because new entries are scattered randomly across index pages. UUID v4 is perfect when you just need a unique identifier and ordering does not matter.

UUID v7: Time-Sorted

UUID v7 (standardized in RFC 9562 in 2024) embeds a Unix timestamp in the most significant bits, followed by random data. This means v7 UUIDs sort chronologically, which dramatically improves database index performance. If you are using UUIDs as primary keys in a database, v7 is almost always the better choice.

// UUID v4 example (random)
// 550e8400-e29b-41d4-a716-446655440000

// UUID v7 example (time-sorted)
// 018ef4c8-5a3b-7000-8000-1a2b3c4d5e6f
//  ^timestamp^  ^random^

// In JavaScript (crypto API)
const uuid = crypto.randomUUID(); // Generates v4

Generate both versions instantly with our UUID Generator.

Practical Security Checklist

Here is a condensed checklist you can reference when building or reviewing a web application:

  1. Password storage: Use Argon2id or bcrypt. Never SHA-256 or MD5.
  2. File integrity: Use SHA-256 checksums. Publish them alongside downloads.
  3. JWTs: Store in HttpOnly cookies. Enforce the signing algorithm on the server. Always set and validate expiration.
  4. HTTPS: Use TLS 1.2 or 1.3. Redirect HTTP to HTTPS. Enable HSTS.
  5. Certificates: Automate renewal. Monitor expiration dates. Verify the full chain.
  6. SSH: Use Ed25519 keys. Disable password authentication on servers. Rotate keys periodically.
  7. UUIDs: Use v7 for database primary keys. Use v4 when ordering does not matter.
  8. Secrets: Never commit API keys to version control. Use environment variables or a secrets manager.
  9. Dependencies: Run npm audit or equivalent regularly. Pin dependency versions.
  10. Headers: Set Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and Strict-Transport-Security.

Wrapping Up

Security is not a feature you add at the end of a project. It is a set of decisions you make throughout development: which hashing algorithm to use, where to store tokens, how to handle certificates, and which key type to generate. None of these decisions require deep cryptographic expertise, but they do require awareness.

The tools I mentioned throughout this article can help you experiment, debug, and verify. Try hashing some text, decoding a JWT, or inspecting a certificate to see these concepts in action. The more comfortable you are with these fundamentals, the better your applications will be.