Security hardening for production readiness

- Add security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, etc.)
- Strengthen password requirements (10+ chars, mixed case, numbers)
- Increase shared list slug entropy from 4 to 16 bytes
- Add rate limiting to login, registration, upload, and restore endpoints
- Add file magic number validation for image uploads (JPEG, PNG, WebP, HEIC)
- Add CSV row limit (50k) to restore endpoint
- Update client-side registration form to match new password policy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
JP Scott
2026-03-01 12:55:16 -07:00
parent 969bc9347a
commit 8a582bfa7f
8 changed files with 149 additions and 10 deletions

View File

@@ -26,8 +26,13 @@ export default function RegisterPage() {
return
}
if (password.length < 8) {
setError("Password must be at least 8 characters")
if (password.length < 10) {
setError("Password must be at least 10 characters")
return
}
if (!/[a-z]/.test(password) || !/[A-Z]/.test(password) || !/[0-9]/.test(password)) {
setError("Password must contain lowercase, uppercase, and a number")
return
}
@@ -112,11 +117,12 @@ export default function RegisterPage() {
<Input
id="password"
type="password"
placeholder="At least 8 characters"
placeholder="Min 10 chars, upper+lower+number"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength={8}
minLength={10}
maxLength={128}
disabled={loading}
/>
</div>
@@ -130,7 +136,7 @@ export default function RegisterPage() {
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
required
minLength={8}
minLength={10}
disabled={loading}
/>
</div>