CAPTCHA (Noch kein Key)
Dieser Commit ist enthalten in:
@@ -17,6 +17,7 @@ from apscheduler.schedulers.background import BackgroundScheduler
|
||||
import logging
|
||||
import random
|
||||
import hashlib
|
||||
import requests
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -512,6 +513,41 @@ def send_security_alert_email(ip_address, username, attempt_count):
|
||||
logging.warning(f"Sicherheitswarnung: {attempt_count} fehlgeschlagene Versuche von IP {ip_address}")
|
||||
print(f"E-Mail würde gesendet: {subject}")
|
||||
|
||||
def verify_recaptcha(response):
|
||||
"""Verifiziert die reCAPTCHA v2 Response mit Google"""
|
||||
secret_key = os.getenv('RECAPTCHA_SECRET_KEY')
|
||||
|
||||
# Wenn kein Secret Key konfiguriert ist, CAPTCHA als bestanden werten (für PoC)
|
||||
if not secret_key:
|
||||
logging.warning("RECAPTCHA_SECRET_KEY nicht konfiguriert - CAPTCHA wird übersprungen")
|
||||
return True
|
||||
|
||||
# Verifizierung bei Google
|
||||
try:
|
||||
verify_url = 'https://www.google.com/recaptcha/api/siteverify'
|
||||
data = {
|
||||
'secret': secret_key,
|
||||
'response': response
|
||||
}
|
||||
|
||||
# Timeout für Request setzen
|
||||
r = requests.post(verify_url, data=data, timeout=5)
|
||||
result = r.json()
|
||||
|
||||
# Log für Debugging
|
||||
if not result.get('success'):
|
||||
logging.warning(f"reCAPTCHA Validierung fehlgeschlagen: {result.get('error-codes', [])}")
|
||||
|
||||
return result.get('success', False)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error(f"reCAPTCHA Verifizierung fehlgeschlagen: {str(e)}")
|
||||
# Bei Netzwerkfehlern CAPTCHA als bestanden werten
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"Unerwarteter Fehler bei reCAPTCHA: {str(e)}")
|
||||
return False
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
# Timing-Attack Schutz - Start Zeit merken
|
||||
@@ -545,7 +581,22 @@ def login():
|
||||
return render_template("login.html",
|
||||
error="CAPTCHA ERFORDERLICH!",
|
||||
show_captcha=True,
|
||||
error_type="captcha")
|
||||
error_type="captcha",
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - attempt_count),
|
||||
recaptcha_site_key=os.getenv('RECAPTCHA_SITE_KEY'))
|
||||
|
||||
# CAPTCHA validieren
|
||||
if not verify_recaptcha(captcha_response):
|
||||
# Timing-Attack Schutz
|
||||
elapsed = time.time() - start_time
|
||||
if elapsed < 1.0:
|
||||
time.sleep(1.0 - elapsed)
|
||||
return render_template("login.html",
|
||||
error="CAPTCHA UNGÜLTIG! Bitte erneut versuchen.",
|
||||
show_captcha=True,
|
||||
error_type="captcha",
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - attempt_count),
|
||||
recaptcha_site_key=os.getenv('RECAPTCHA_SITE_KEY'))
|
||||
|
||||
# Check gegen beide Admin-Accounts aus .env
|
||||
admin1_user = os.getenv("ADMIN1_USERNAME")
|
||||
@@ -589,12 +640,14 @@ def login():
|
||||
error=error_message,
|
||||
show_captcha=(new_attempt_count >= CAPTCHA_AFTER_ATTEMPTS),
|
||||
error_type="failed",
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - new_attempt_count))
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - new_attempt_count),
|
||||
recaptcha_site_key=os.getenv('RECAPTCHA_SITE_KEY'))
|
||||
|
||||
# GET Request
|
||||
return render_template("login.html",
|
||||
show_captcha=(attempt_count >= CAPTCHA_AFTER_ATTEMPTS),
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - attempt_count))
|
||||
attempts_left=max(0, MAX_LOGIN_ATTEMPTS - attempt_count),
|
||||
recaptcha_site_key=os.getenv('RECAPTCHA_SITE_KEY'))
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
|
||||
@@ -7,3 +7,4 @@ pandas
|
||||
openpyxl
|
||||
cryptography
|
||||
apscheduler
|
||||
requests
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren