Your login page is the highest-value target on your website. It is the gateway to every privileged action in your application, it must be publicly accessible, and it receives more deliberate attack traffic than any other endpoint. A login page with missing HTTPS enforcement, no brute force protection, insecure cookie attributes, or absent security headers fails in ways that are completely preventable and straightforward to test. This checklist covers every control a secure login page must have.
1. HTTPS on the Form Action
The login form's action attribute must point to an HTTPS URL. An HTTP form action transmits credentials in plaintext over the network, where they are readable by anyone between the user and the server — even if the page itself loaded over HTTPS. Check your form tag: <form method="POST" action="https://...">.
The login page itself must also be served exclusively over HTTPS. Serving it over HTTP allows a network attacker to modify the page in transit — substituting a malicious form action or adding a keylogger script — before it reaches the user. Enforce HTTPS with a permanent 301 redirect from HTTP to HTTPS at the web server level, and set HSTS with max-age=31536000 (one year) so browsers remember the preference and refuse HTTP connections proactively.
2. Cookie Security Flags
Session cookies issued after successful authentication must carry three attributes:
- HttpOnly: Prevents JavaScript from reading the cookie value, blocking XSS-based session theft. Without it, a single XSS vulnerability anywhere on your domain can steal every active user's session token.
- Secure: Ensures the cookie is sent only over HTTPS connections. Without it, the session cookie may be transmitted in plaintext if the user visits any HTTP URL on your domain — for example, a cached bookmark or a link from an email.
- SameSite=Strict (or Lax): Prevents the cookie from being sent in cross-site requests, blocking CSRF attacks.
Strictprovides stronger protection;Laxallows the cookie on top-level navigation GET requests and is the practical default for most applications.
Complete example: Set-Cookie: session=TOKEN; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
3. Security Headers on the Login Response
The login page response must include these headers:
- Content-Security-Policy: Restricts which scripts, styles, and resources can execute on the page. A strict CSP prevents XSS from being exploitable even if a vulnerability exists in your code or a dependency. At minimum:
script-src 'self'— no inline scripts, no external script sources other than explicitly named ones. - X-Frame-Options: DENY: Prevents the login page from being embedded in an iframe, blocking clickjacking attacks where an attacker overlays your login form on a malicious page to intercept submitted credentials.
- X-Content-Type-Options: nosniff: Prevents browsers from MIME-sniffing response bodies, which can cause browsers to execute uploaded content (such as an image containing embedded script) as JavaScript.
- Referrer-Policy: strict-origin-when-cross-origin: Prevents the login page URL from leaking in Referer headers to third-party resources — important if your login URL contains query parameters such as return URLs or session identifiers.
4. CSRF Protection
Login forms require CSRF protection. A login CSRF attack forces a victim to log in to the attacker's account — the attacker can then access anything the victim stores or submits while authenticated to that account. Implement a CSRF token: a unique, unpredictable value generated per session and embedded in the form as a hidden field, validated server-side on every POST submission.
<input type="hidden" name="csrf_token" value="CRYPTORANDOM_VALUE">
SameSite cookie attributes provide partial CSRF protection but do not fully replace explicit CSRF tokens, particularly for older browsers and for GET-based state-changing actions.
5. Brute Force Protection
Every login endpoint requires rate limiting. Implement at minimum: IP-based rate limiting (5–10 attempts per 15-minute window), account-level progressive delays (2-second server-side delay after 3 failures, doubling with each subsequent failure), and CAPTCHA after 5 consecutive failures. Do not use hard account lockout — it enables denial-of-service against any account whose username is known. See the full rate limiting guide for implementation details.
6. Generic, Constant-Time Error Messages
Return the same error message for an invalid username and an invalid password: "Invalid username or password." Separate messages allow username enumeration — an attacker submitting thousands of email addresses can determine which ones have accounts before attempting credential attacks. Response time must also be consistent: use constant-time password comparison and always execute the same code path regardless of whether the username exists, to prevent timing-based enumeration.
7. Password Field Attributes
Password inputs must use type="password" — this prevents the value from appearing in page source, browser history, and server logs when the value is submitted. For the autocomplete attribute, use autocomplete="current-password" on login forms (not autocomplete="off", which modern browsers ignore). This signals to browser password managers that they should offer saved credentials, integrating with the user's secure credential storage rather than fighting it.
8. Multi-Factor Authentication
MFA is the most effective defense against account compromise from stolen or reused credentials. With MFA, a correct password alone cannot authenticate — the attacker also needs access to the second factor. Implement TOTP (RFC 6238, compatible with Google Authenticator and Authy), email-based OTP for lower-risk accounts, or FIDO2/WebAuthn (passkeys, hardware security keys) for the highest security. FIDO2 is additionally phishing-resistant because the credential is cryptographically bound to your specific domain — it cannot be used on a lookalike phishing site.
9. Secure the Password Reset Flow
Password reset endpoints are frequently less hardened than the login form itself. Reset tokens must be: cryptographically random with at least 128 bits of entropy, single-use and invalidated immediately after first use, short-lived (15–60 minute expiry), and delivered only via a channel the user controls (email or SMS). Never reflect the token in a URL that could appear in server logs, Referer headers, or browser history in a way that could leak it. Rate-limit the reset request endpoint to prevent email flooding of target accounts.
How Shieldome Checks This
Shieldome performs a dedicated login page analysis as part of its OWASP A07 (Authentication Failures) checks. When you run a Shieldome scan, it automatically detects your login page by probing common paths — /login, /signin, /wp-login.php, /admin/login, /user/login — and then analyzes the response:
- Whether the form action attribute uses an explicit HTTPS URL — a login form posting to HTTP is flagged Critical severity
- Whether cookies set on the login response include
HttpOnly,Secure, andSameSiteattributes — missing flags are flagged High severity - Whether the response includes
X-Content-Type-Options,X-Frame-Options, andContent-Security-Policyheaders — missing security headers on login pages are flagged High severity - Whether the password input uses
type="password" - Whether the page contains observable brute force protection signals: CAPTCHA widget patterns from reCAPTCHA, hCaptcha, or Cloudflare Turnstile
Each finding includes the specific header or attribute that is missing, its severity, and the exact value to add for remediation — so you have a specific action rather than a vague recommendation.
Frequently Asked Questions
Should my login page live on a separate subdomain?
Isolating the login page on a separate subdomain (e.g., auth.example.com) limits cookie scope and can reduce the impact of XSS on the main domain from stealing session cookies. It adds complexity and requires careful CORS and redirect configuration. For most applications, a well-configured login page on the main domain with HttpOnly, Secure, and SameSite=Strict cookies provides equivalent practical protection without the operational overhead.
What is clickjacking and how does X-Frame-Options stop it?
Clickjacking embeds your login page in a transparent iframe on a malicious site, then tricks a user into interacting with it — submitting their credentials to your real login form, but through the attacker's framing. X-Frame-Options: DENY instructs browsers to refuse to render the page inside any frame or iframe. The modern equivalent is Content-Security-Policy: frame-ancestors 'none', which provides the same protection with more flexibility and overrides X-Frame-Options in current browsers.
Is it safe to use "Remember Me" functionality?
Yes, with correct implementation. Remember-me tokens must be cryptographically random (not derived from the user ID or timestamp), stored as hashed values in the database (not the raw token), single-use with rotation on each request (this detects token theft — if the old token is presented after it should have been rotated, it indicates compromise), and associated with a specific device fingerprint to limit their validity. They must also be revocable by the user from an active session management page.
Should I log failed login attempts?
Yes, but carefully. Log the timestamp, IP address, and username attempted — this data is essential for detecting brute force attacks and for incident investigation. Do not log the submitted password, because users frequently type their password into the username field by mistake. Ensure access logs are stored securely with restricted access and a defined retention period, since login attempt logs contain sensitive information about targeted accounts.
Does HTTPS prevent credential interception on public Wi-Fi?
HTTPS encrypts the connection between the browser and server, preventing passive eavesdropping on shared networks. It does not protect against: SSL stripping attacks (where an attacker controlling the network intercepts the connection before HTTPS is established — which is why HSTS preloading matters), malware on the user's device that reads form values before encryption, or phishing sites using valid HTTPS certificates for their own domain. HTTPS is necessary but must be combined with HSTS, correct certificate validation, and HSTS preloading for robust transport security.
What is account enumeration and why is it a security risk?
Account enumeration is the ability to determine whether a specific email address or username is registered in your system. If your login form returns different messages for "User not found" versus "Incorrect password," an attacker can submit thousands of email addresses and build a confirmed list of which ones have accounts — useful for targeted phishing, credential stuffing, and privacy attacks. Return the same message and take the same processing time regardless of whether the account exists.
What is the minimum password policy I should enforce?
NIST SP 800-63B current guidance (which most modern security standards now follow) recommends: minimum 8 characters with no maximum below 64 characters, no complexity requirements (they lead to predictable patterns like P@ssw0rd), no periodic forced rotation (it trains users to make predictable incremental changes), and checking new passwords against a list of known breached passwords. Focus on length and breach-list checking rather than arbitrary complexity rules.
A login page is only as secure as its weakest control. Run a free Shieldome scan to get a specific, prioritized checklist of security controls your login page is missing — with exact remediation steps for each.