Add security hardening, captcha login, and password reset via email

- .htaccess: HTTPS enforcement, security headers, block sensitive files
- data/.htaccess: deny all direct access to data directory
- Secure session settings (httponly, secure, strict mode, samesite)
- Rate limiting on login (10 attempts per 15 min per IP)
- Math captcha on login form (server-side validated)
- Password reset via email with token (1 hour expiry)
- Forgot password UI with reset link flow
- Email field added to user management
- Updated .gitignore for reset_tokens.json and login_attempts.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 01:00:19 +02:00
parent e4914e9edb
commit 8a07689a1f
7 changed files with 388 additions and 8 deletions

View File

@@ -15,9 +15,38 @@
<form id="login-form">
<input type="text" id="login-username" placeholder="Käyttäjätunnus" required autofocus>
<input type="password" id="login-password" placeholder="Salasana" required>
<div class="captcha-row">
<span id="captcha-question" class="captcha-question">Ladataan...</span>
<input type="number" id="login-captcha" placeholder="Vastaus" required>
</div>
<button type="submit">Kirjaudu</button>
</form>
<div id="login-error" class="error" style="display:none"></div>
<a href="#" id="forgot-link" class="forgot-link">Unohdin salasanan</a>
</div>
<!-- Salasanan palautuspyyntö -->
<div class="login-box" id="forgot-box" style="display:none">
<h1>CuituNet Intra</h1>
<p>Salasanan palautus</p>
<form id="forgot-form">
<input type="text" id="forgot-username" placeholder="Käyttäjätunnus" required autofocus>
<button type="submit">Lähetä palautuslinkki</button>
</form>
<div id="forgot-msg" class="success-msg" style="display:none"></div>
<div id="forgot-error" class="error" style="display:none"></div>
<a href="#" id="forgot-back" class="forgot-link">Takaisin kirjautumiseen</a>
</div>
<!-- Uusi salasana (reset token) -->
<div class="login-box" id="reset-box" style="display:none">
<h1>CuituNet Intra</h1>
<p>Aseta uusi salasana</p>
<form id="reset-form">
<input type="password" id="reset-password" placeholder="Uusi salasana" required>
<input type="password" id="reset-password2" placeholder="Salasana uudelleen" required>
<button type="submit">Vaihda salasana</button>
</form>
<div id="reset-msg" class="success-msg" style="display:none"></div>
<div id="reset-error" class="error" style="display:none"></div>
</div>
</div>
@@ -180,6 +209,7 @@
<tr>
<th>Käyttäjätunnus</th>
<th>Nimi</th>
<th>Sähköposti</th>
<th>Rooli</th>
<th>Luotu</th>
<th>Toiminnot</th>
@@ -316,6 +346,10 @@
<label for="user-form-nimi">Nimi</label>
<input type="text" id="user-form-nimi">
</div>
<div class="form-group">
<label for="user-form-email">Sähköposti</label>
<input type="email" id="user-form-email" placeholder="nimi@esimerkki.fi">
</div>
<div class="form-group">
<label for="user-form-password">Salasana <span id="user-pw-hint"></span></label>
<input type="password" id="user-form-password">