Authentication Scripts
CGI authentication scripts: login, session management, and password hashing
How does a CGI script authenticate a user and maintain a login session?
A CGI login script reads the submitted username and password, looks up the stored password hash for that username, hashes the submitted password with the same algorithm and salt, and compares the two hashes. If they match, it generates a secure random session token, writes the token and user ID to a server-side session store (file or database), sets a session cookie in the response, and redirects to the protected area. Subsequent requests carry the cookie; a guard script on each protected page validates the token against the session store.
Why you must hash passwords, and how
Storing passwords as plaintext means any breach of your password file exposes every user's credentials immediately. Storing a plain MD5 or SHA1 hash is almost as bad, since rainbow tables can reverse common passwords near-instantly. The correct approach is a slow, salted hashing algorithm designed specifically for password storage: bcrypt, Argon2, or scrypt. These add a random salt (preventing rainbow tables) and are deliberately slow to compute (making brute force impractical). Perl has Crypt::Bcrypt on CPAN; Python 3 has the bcrypt package and the built-in hashlib for SHA-256 (though bcrypt is strongly preferred for passwords).
When checking a password at login, you do not decrypt the stored hash. You hash the submitted password with the same algorithm and parameters used when the password was set, and compare the result to the stored hash. A match means the password is correct. This means even you, as the site operator, cannot learn a user's password from the stored hash, which is the correct design.
Session tokens and cookies
After a successful login, generate a session token using a cryptographically secure random number generator. In Perl, use Bytes::Random::Secure or read from /dev/urandom. In Python 3, use secrets.token_hex(). A 32-byte (64 hex character) token is sufficient for most uses. Store the token server-side (in a session file or database row) mapped to the user ID and an expiry time. Send the token to the browser as a cookie with the Secure, HttpOnly, and SameSite=Lax attributes set.
HttpOnly prevents JavaScript from reading the cookie, which reduces the impact of an XSS vulnerability. Secure ensures the cookie is only sent over HTTPS. SameSite=Lax prevents the cookie from being sent in cross-site requests, which is the most practical mitigation for CSRF on standard navigation flows. Set an expiry time and clean up expired sessions server-side, or they accumulate forever.
Protecting pages with a guard script
Each protected page needs to include or call a guard script that runs before the page content is sent. The guard reads the session cookie, queries the session store for that token, checks that the session exists and has not expired, and either proceeds with the page or redirects to the login form. In Perl, requiring a common auth.pl file at the top of each protected script is the typical pattern. In Python, a shared function imported at the top of each handler does the same.
Never output any page content before the session check completes, because HTTP headers (including the redirect) must be sent before any body content. A premature print statement can cause a 'headers already sent' error that prevents the redirect. Print only the Content-Type and any cookie headers before the body, and do the session check before any of that.
What to know
Key points
- Use bcrypt or Argon2 for password hashing. MD5 and plain SHA hashes are not safe for passwords; use an algorithm designed for slow, salted password storage.
- Generate session tokens with a secure RNG. In Python 3 use secrets.token_hex(); in Perl use /dev/urandom or Bytes::Random::Secure.
- Set Secure, HttpOnly, and SameSite on session cookies. These three attributes together cover the most common cookie-based attacks.
- Run the session check before printing any output. Headers including the redirect Location must be sent before any body; a premature print breaks the redirect.
- Expire and clean up sessions. Set a session lifetime and delete expired records to prevent disk space exhaustion and stale sessions.
Get help
Listings and a local agent, when you are ready
Need a CGI script built, debugged, or a hosting environment configured? Forms use a clearly-marked placeholder endpoint until wired to a real system.
Reserved for an affiliate link to a vetted shared or VPS hosting provider that supports CGI and Perl/Python execution. Operator wires affiliate link here.
Self-hosted lead form for custom CGI development inquiries. Placeholder endpoint until wired to the operator's CRM or email handler.
Open inquiry form →Custom CGI development
Hosting setup help
Questions