Security: add rate limiting, input validation, and filter category

validation
Backend:
- Add rate limiting middleware (mw/ratelimit.go) - in-memory per-IP
  limiter
- Apply rate limits per endpoint group:
  - Public read-only: 120/min
  - Registration: 10/min
  - Portfolio filters: 60/min
  - Authenticated users: 120/min
  - Admin: none (trusted)
- Add 256 char input length validation on portfolio endpoints
- Validate filter categories exist in DB before querying
- Secure GetImage endpoint: only allow UUID or numeric timestamp (15-20
  digits)
- Remove pattern-based image lookup to prevent enumeration
- Add services validation: name (100), duration (1-480), patch test
  (0-168)
  Frontend:
- Add maxlength=256 to portfolio tag/search inputs
- Add maxlength to registration: name (50), email (255), phone (20),
  password (72)
- Add maxlength=100 to service name input
This commit is contained in:
2026-02-20 12:03:14 +00:00
parent f9eec94f2f
commit a5a2ffd83e
9 changed files with 153 additions and 31 deletions
+5
View File
@@ -371,6 +371,7 @@
<Input
id="firstName"
placeholder="John"
maxlength={50}
bind:value={formData.firstName}
onblur={() => (formData.firstName = formData.firstName.trim())}
required
@@ -381,6 +382,7 @@
<Input
id="lastName"
placeholder="Doe"
maxlength={50}
bind:value={formData.lastName}
onblur={() => (formData.lastName = formData.lastName.trim())}
required
@@ -394,6 +396,7 @@
id="phone"
type="tel"
placeholder="07123 456789 or +44 7123 456789"
maxlength={20}
value={formData.phone}
oninput={handlePhoneInput}
onblur={() => validatePhone(formData.phone)}
@@ -428,6 +431,7 @@
id="email"
type="email"
placeholder="john@example.com"
maxlength={255}
bind:value={formData.email}
onblur={() => validateEmail(formData.email)}
required
@@ -443,6 +447,7 @@
id="password"
type="password"
placeholder="Enter your password"
maxlength={72}
bind:value={formData.password}
required
/>