TL;DR
Forms are primary attack vectors. Protect them with CSRF tokens, server-side validation, rate limiting, and honeypot fields for bots. Autocomplete attributes help password managers, and proper input types improve mobile UX. These prompts help you build secure forms.
Form Security Essentials
Review my forms and add security best practices.
For each form, ensure:
- method="POST" for data-changing forms
- CSRF token included and validated
- autocomplete attributes set correctly
- Input types match data (email, tel, number)
- Server-side validation matches client-side
- Error messages don't leak information
Security additions:
- Add honeypot field for bot detection
- Rate limit submissions per IP
- Log form submissions (without passwords)
- Validate file uploads if present
For login forms specifically:
- autocomplete="username" on username field
- autocomplete="current-password" on password
- Don't reveal if username exists in errors
Show updated HTML and server-side handler.
CSRF Protection
Implement CSRF protection for all my forms.
Framework: Next.js/Express/Django
CSRF flow:
- Generate unique token per session
- Include token in form (hidden field or header)
- Validate token on form submission
- Reject if missing or mismatched
For traditional forms:
For AJAX/fetch:
- Send token in X-CSRF-Token header
- Or include in request body
Token generation:
- Cryptographically random
- Bound to user session
- Regenerate on login
- Expires with session
Also check:
- SameSite cookie attribute (additional CSRF defense)
- Referer/Origin header validation (supplementary)
GET requests should never change data: CSRF protection typically only applies to POST/PUT/DELETE. If your GET endpoints modify data, attackers can CSRF them via image tags regardless of tokens.
Bot and Spam Prevention
Add bot and spam protection to my forms.
Techniques:
- Honeypot field (hidden field bots fill)
- Time-based validation (too fast = bot)
- JavaScript token (bots often don't run JS)
- Rate limiting per IP
- CAPTCHA for high-value forms
Honeypot implementation:
On server: if (formData.website) { // Bot detected - silently reject or log return { success: true }; // Don't reveal detection }
Time-based:
- Include timestamp in hidden field
- Reject if submitted in < 3 seconds
- Reject if submitted after > 1 hour
Rate limiting:
- Max 5 submissions per minute per IP
- Max 20 per hour for same email
Accessible Password Fields
Create secure and accessible password form fields.
Password input should have:
- type="password" (masks input)
- autocomplete attribute (helps password managers)
- Show/hide toggle (accessibility)
- Strength meter (user feedback)
- Clear requirements list
Autocomplete values:
- Login: autocomplete="current-password"
- Registration: autocomplete="new-password"
- Change password: both fields appropriately
Show/hide toggle:
- Button to toggle type between password/text
- aria-label updates based on state
- Don't use checkbox (poor UX)
Password requirements display:
- Show requirements before user types
- Update checkmarks in real-time as user types
- Clear visual feedback (colors, icons)
Don't:
- Disable paste (breaks password managers)
- Mask with asterisks only (use proper type)
- Auto-clear on failed submission
Pro tip: Test your forms with a password manager. If it can't fill credentials correctly, users will choose weaker passwords or reuse them. Proper autocomplete attributes matter.
Do I need CSRF protection if I use JWT?
If JWTs are sent in Authorization headers, CSRF isn't possible (headers can't be set cross-origin). But if JWTs are in cookies, you still need CSRF protection.
Honeypot vs CAPTCHA?
Honeypots are invisible to users (better UX) but only catch dumb bots. CAPTCHAs stop sophisticated bots but hurt UX. Use honeypot first, add CAPTCHA only if spam persists.