Session-Fixierung

Beschreibung

Session-Fixierung tritt auf, wenn bei der Authentifizierung eines Benutzers oder beim sonstigen Aufbau einer neuen Benutzersitzung keine bestehende Sitzungskennung ungültig gemacht wird. Dies gibt einem Angreifer die Möglichkeit, authentifizierte Sitzungen zu stehlen. Der Angreifer erhält zunächst eine gültige Sitzungskennung (auf verschiedenen Wegen), und bringt dann ein Opfer dazu, sich mit dieser Sitzungskennung zu authentifizieren. Da die Anwendung bei der Authentifizierung keine neue Sitzungs-ID generiert, besitzt der Angreifer nun einen gültigen, authentifizierten Sitzungstoken und kann das Opfer imitieren.

Risiko

Session-Fixierung ermöglicht es Angreifern, Benutzersitzungen zu übernehmen, ohne Anmeldedaten oder Sitzungstoken durch Netzwerküberwachung abfangen zu müssen. CVE-2025-4644 in Payload CMS demonstrierte eine neuartige Variante, bei der JWT-Token nach Kontolöschung gültig blieben und es Angreifern ermöglichten, Sitzungen von neu erstellten Konten zu kapern, die dieselbe Kennung wiederverwendeten. ABB ASPECT-Enterprise, NEXUS und MATRIX Series Produkte hatten 2025 hochgradig kritische Session-Fixierung-Schwachstellen. Das Jenkins OpenId Connect Authentication Plugin war ebenfalls betroffen. Im Gegensatz zu Session-Hijacking, das das Abfangen einer aktiven Sitzung erfordert, ermöglicht Session-Fixierung Vor-Authentifizierungs-Angriffe, bei denen der Angreifer die Sitzung einrichtet, bevor sich das Opfer überhaupt anmeldet.

Lösung

Generieren Sie immer eine neue Sitzungskennung bei erfolgreicher Authentifizierung. Invalidieren Sie die alte Sitzung vollständig. Binden Sie Sitzungen als sekundäre Verifikation an zusätzliche Benutzerattribute (IP-Adresse, User-Agent). Implementieren Sie Sitzungs-Timeout-Richtlinien. Verwenden Sie Secure-, HttpOnly- und SameSite-Cookie-Flags. Lehnen Sie Sitzungskennungen aus URL-Parametern ab – akzeptieren Sie sie nur aus Cookies. Implementieren Sie Sitzungsrotation bei Änderungen der Berechtigungsstufe. Überwachen Sie auf Sitzungsanomalien wie geografische Unmöglichkeiten oder gleichzeitige Sitzungen von verschiedenen Standorten.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleUmfang: Session-Hijacking

Angreifer erhalten vollen Zugriff auf die authentifizierte Sitzung des Opfers und können jede Aktion als das Opfer ausführen.
AuthentifizierungUmfang: Identitätsdiebstahl

Der Angreifer übernimmt effektiv die Identität des Opfers für die Dauer der Sitzung.
Nicht-AbstreitbarkeitUmfang: Aktionszuordnung

Böswillige Aktionen werden unter dem Konto des Opfers protokolliert, was es potenziell für die Aktivitäten des Angreifers verantwortlich macht.

Beispielcode

Anfälliger Code

<?php
// ANFÄLLIG: Sitzungs-ID wird nach Login nicht neu generiert
session_start();

if ($_POST['username'] && $_POST['password']) {
    if (authenticate($_POST['username'], $_POST['password'])) {
        // Sitzungs-ID bleibt gleich - voreingestellte ID des Angreifers ist nun authentifiziert!
        $_SESSION['authenticated'] = true;
        $_SESSION['username'] = $_POST['username'];
        header('Location: /dashboard');
    }
}
?>

<!-- ANFÄLLIG: Sitzungs-ID in URL -->
<a href="login.php?PHPSESSID=attacker_controlled_id">Login</a>
# ANFÄLLIG: Flask ohne Sitzungs-Regenerierung
from flask import Flask, session, redirect

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']

    if authenticate(username, password):
        # Sitzungs-ID bleibt nach Authentifizierung gleich!
        session['authenticated'] = True
        session['user'] = username
        return redirect('/dashboard')

    return 'Login fehlgeschlagen'
// ANFÄLLIG: Java Servlet ohne Sitzungs-Invalidierung
@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticate(username, password)) {
            // Alte Sitzung wird beibehalten - anfällig für Fixierung!
            HttpSession session = request.getSession();
            session.setAttribute("authenticated", true);
            session.setAttribute("username", username);
            response.sendRedirect("/dashboard");
        }
    }
}

Korrigierter Code

<?php
// SICHER: Sitzungs-ID nach Authentifizierung neu generieren
session_start();

// Sitzungs-ID in URLs verhindern
ini_set('session.use_only_cookies', 1);
ini_set('session.use_trans_sid', 0);

if ($_POST['username'] && $_POST['password']) {
    if (authenticate($_POST['username'], $_POST['password'])) {
        // Alte Sitzung zerstoren und neue erstellen
        session_regenerate_id(true);  // true = alte Sitzung löschen

        $_SESSION['authenticated'] = true;
        $_SESSION['username'] = $_POST['username'];
        $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
        $_SESSION['created_at'] = time();

        header('Location: /dashboard');
        exit;
    }
}

// Sitzungsintegrität bei jeder Anfrage validieren
function validate_session() {
    if (!isset($_SESSION['authenticated'])) {
        return false;
    }

    // Sitzungsbindung prüfen
    if ($_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
        session_destroy();
        return false;
    }

    // Sitzungsalter prüfen
    if (time() - $_SESSION['created_at'] > 3600) {  // 1 Stunde
        session_destroy();
        return false;
    }

    return true;
}
?>
# SICHER: Flask mit Sitzungs-Regenerierung
from flask import Flask, session, redirect, request
from flask_session import Session
import secrets

app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(32)
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'

@app.route('/login', methods=['POST'])
def login_safe():
    username = request.form['username']
    password = request.form['password']

    if authenticate(username, password):
        # Bestehende Sitzungsdaten löschen
        session.clear()

        # Neue Sitzung generieren (Flask-Session handhabt ID-Regenerierung)
        session['authenticated'] = True
        session['user'] = username
        session['ip_address'] = request.remote_addr
        session['user_agent'] = request.user_agent.string
        session['created_at'] = time.time()

        # Für zusätzliche Sicherheit Sitzungs-ID explizit regenerieren
        session.modified = True

        return redirect('/dashboard')

    return 'Login fehlgeschlagen', 401

@app.before_request
def validate_session():
    if 'authenticated' in session:
        # Sitzungsbindung validieren
        if session.get('ip_address') != request.remote_addr:
            session.clear()
            return redirect('/login')

        # Sitzungs-ID periodisch rotieren
        if time.time() - session.get('created_at', 0) > 900:  # 15 Minuten
            session['created_at'] = time.time()
            session.modified = True
// SICHER: Java Servlet mit Sitzungs-Invalidierung und -Regenerierung
@WebServlet("/login")
public class SecureLoginServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticate(username, password)) {
            // Bestehende Sitzung vollständig invalidieren
            HttpSession oldSession = request.getSession(false);
            if (oldSession != null) {
                oldSession.invalidate();
            }

            // Neue Sitzung mit frischer ID erstellen
            HttpSession newSession = request.getSession(true);
            newSession.setAttribute("authenticated", true);
            newSession.setAttribute("username", username);
            newSession.setAttribute("ip_address", request.getRemoteAddr());
            newSession.setAttribute("user_agent", request.getHeader("User-Agent"));
            newSession.setAttribute("created_at", System.currentTimeMillis());

            // Sitzungs-Timeout setzen
            newSession.setMaxInactiveInterval(3600);  // 1 Stunde

            response.sendRedirect("/dashboard");
        } else {
            response.sendRedirect("/login?error=invalid");
        }
    }
}

// Sitzungs-Validierungsfilter
@WebFilter("/*")
public class SessionValidationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpSession session = request.getSession(false);

        if (session != null && session.getAttribute("authenticated") != null) {
            String storedIP = (String) session.getAttribute("ip_address");

            if (!request.getRemoteAddr().equals(storedIP)) {
                session.invalidate();
                ((HttpServletResponse) res).sendRedirect("/login?error=session");
                return;
            }
        }

        chain.doFilter(req, res);
    }
}

Ausgenutzt in der Praxis

Payload CMS JWT-Wiederverwendung (Payload CMS, 2025)

CVE-2025-4644 in Payload CMS vor Version 3.44.0 ermöglichte es Angreifern, JWTs von selbst erstellten Konten abzufangen, diese Konten zu löschen und dann die noch gültigen JWTs zu verwenden, um Sitzungen neuer Benutzer zu kapern, denen dieselbe Kennung zugewiesen wurde.

ABB Industrielle Steuerungssysteme (ABB, 2025)

Session-Fixierung-Schwachstellen in ABB ASPECT-Enterprise, NEXUS und MATRIX Series Industriesteuerungsprodukten ermöglichten es Angreifern, Bediener-Sitzungen in kritischen Infrastrukturumgebungen zu übernehmen.

Jenkins OpenId Connect Plugin (Jenkins, 2024)

Eine hochgradig kritische Session-Fixierung-Schwachstelle im Jenkins OpenId Connect Authentication Plugin ermöglichte es Angreifern, authentifizierte Sitzungen in CI/CD-Umgebungen zu kapern.


Tools zum Testen/Ausnutzen


CVE-Beispiele


Referenzen

  1. MITRE. "CWE-384: Session Fixation." https://cwe.mitre.org/data/definitions/384.html

  2. OWASP. "Session Fixation." https://owasp.org/www-community/attacks/Session_fixation