Verwendung des Referer-Feldes für Authentifizierung

Beschreibung

Verwendung des Referer-Feldes für Authentifizierung ist eine Schwachstelle, die auftritt, wenn ein Produkt sich auf den HTTP-Referer-Header als Mittel der Authentifizierung oder Zugriffskontrolle verlässt. Das Referer-Feld in HTTP-Anfragen kann von Clients leicht modifiziert werden und ist daher kein gültiges Mittel zur Nachrichtenintegritätsprüfung oder Authentifizierung. Böswillige Benutzer können den Referer-Header trivial fälschen, indem sie ihre HTTP-Anfragen modifizieren, um jeden beliebigen Wert einzufügen, wodurch jede auf diesem Header basierende Sicherheitsprüfung vollständig unwirksam wird.

Risiko

Der Verlass auf den Referer-Header für Authentifizierung bietet keine echte Sicherheit. Angreifer können den Referer-Header auf jeden Wert setzen, indem sie Browser-Entwicklertools, Proxy-Tools wie Burp Suite oder programmatische HTTP-Clients verwenden. Der Referer-Header wurde nur entwickelt, um die vorherige Seite in der Benutzernavigation anzuzeigen, nicht um irgendeine Sicherheitsgarantie zu bieten. Systeme, die Referer prüfen, um sicherzustellen, dass Anfragen von "vertrauenswürdigen" internen Seiten kommen, werden trivial umgangen. Das Risiko erstreckt sich auf CSRF-Schutzmaßnahmen, die sich allein auf Referer-Prüfung verlassen - während Referer-Validierung Teil einer Defense-in-Depth-Strategie sein kann, sollte sie nie der primäre Schutz sein. Datenschutzbewusste Benutzer und Browser können Referer-Header entfernen oder gar nicht senden, was solche Prüfungen selbst für legitime Benutzer unzuverlässig macht.

Lösung

Verwenden Sie robuste Authentifizierungsmechanismen, die nicht leicht gefälscht werden können. Ersetzen Sie Referer-basierte Prüfungen durch ordnungsgemäße Authentifizierungssysteme wie Benutzername/Passwort-Anmeldedaten, Sitzungstoken, API-Schlüssel oder digitale Zertifikate. Für CSRF-Schutz verwenden Sie kryptografisch zufällige Token, die in Formulare eingebettet und auf dem Server validiert werden, nicht Referer-Header. Wenn Referer-Prüfung für Defense-in-Depth beibehalten wird, kombinieren Sie sie mit ordnungsgemäßer Authentifizierung anstatt sie als einzige Sicherheitskontrolle zu verwenden. Implementieren Sie ordnungsgemäße Autorisierungsprüfungen, die Benutzeridentität und Berechtigungen durch serverseitige Sitzungsverwaltung verifizieren. Vertrauen Sie nie clientgelieferten Daten, einschließlich HTTP-Headern, für sicherheitskritische Entscheidungen ohne kryptografische Verifikation.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Angreifer können Privilegien erlangen oder Identitäten annehmen, indem sie den Referer-Header fälschen. Unbefugte Aktionen können ausgeführt werden, als ob sie von einem vertrauenswürdigen Server validiert wurden, was Zugang zu geschützten Ressourcen und administrativen Funktionen ermöglicht.

Beispielcode

Anfälliger Code (C++)

Die folgenden Beispiele demonstrieren die Verwendung des Referer-Feldes für Authentifizierung:

// Anfällig: C++ prüft Referer für Authentifizierung
#include <string>

class VulnerableRefererAuth {
private:
    std::string trustedReferer = "http://www.example.com/";

public:
    bool authenticateRequest(HttpRequest& request) {
        // Anfällig: Referer kann gefälscht werden
        if (request.getHeader("referer") == trustedReferer) {
            return true;  // Basierend auf fälschbarem Header authentifiziert
        }
        return false;
        // Angreifer setzt: Referer: http://www.example.com/
    }

    void handleRequest(HttpRequest& request) {
        if (authenticateRequest(request)) {
            openNewSecureSession(request);
        } else {
            denyAccess(request);
        }
    }
};
// Anfällig: Java-Servlet prüft Referer
import javax.servlet.http.*;

public class VulnerableRefererServlet extends HttpServlet {

    private static final String TRUSTED_REFERER = "https://admin.example.com/";

    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response) {
        // Anfällig: Vertraut Referer-Header für Zugriffskontrolle
        String referer = request.getHeader("referer");

        if (referer != null && referer.startsWith(TRUSTED_REFERER)) {
            // Gewährt privilegierten Zugang basierend auf gefälschtem Header
            openPrivilegedConnection(request);
        } else {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
        }
        // Angreifer: curl -H "Referer: https://admin.example.com/" ...
    }
}
# Anfällig: Flask-Anwendung verwendet Referer für Authentifizierung
from flask import Flask, request, abort

app = Flask(__name__)

INTERNAL_DOMAINS = ['internal.company.com', 'admin.company.com']

@app.route('/api/sensitive')
def vulnerable_api():
    # Anfällig: Referer-basierte Zugriffskontrolle
    referer = request.headers.get('Referer', '')

    for domain in INTERNAL_DOMAINS:
        if domain in referer:
            # Zugang gewährt basierend auf fälschbarem Header
            return get_sensitive_data()

    abort(403)
    # Angreifer: Setzt Referer-Header um Prüfung zu umgehen

@app.route('/admin/action', methods=['POST'])
def vulnerable_admin():
    # Anfällig: Verwendet Referer für CSRF-ähnlichen Schutz
    referer = request.headers.get('Referer', '')

    if not referer.startswith('https://admin.company.com'):
        abort(403, 'Ungültiger Ursprung')

    # Führt Admin-Aktion aus - leicht umgehbar
    return execute_admin_action()

Korrigierter Code (Java)

// Korrigiert: Ordnungsgemäße Authentifizierung statt Referer-Prüfung
import javax.servlet.http.*;
import java.security.SecureRandom;
import java.util.Base64;

public class SecureAuthServlet extends HttpServlet {

    private final SessionManager sessionManager;
    private final TokenValidator tokenValidator;

    protected void doPost(HttpServletRequest request,
                         HttpServletResponse response) {

        // Korrigiert: Ordnungsgemäßes Authentifizierungstoken prüfen
        String authHeader = request.getHeader("Authorization");

        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        String token = authHeader.substring(7);

        if (!tokenValidator.isValid(token)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        // Korrigiert: Sitzung verifizieren
        HttpSession session = request.getSession(false);
        if (session == null || !sessionManager.isValid(session.getId())) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        // Referer kann protokolliert werden, aber nicht für Auth verwendet
        String referer = request.getHeader("referer");
        auditLog.record("request", token, referer);

        processPrivilegedRequest(request, response);
    }

    // Korrigiert: Ordnungsgemäßer CSRF-Schutz mit Token
    protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) {

        HttpSession session = request.getSession(true);

        // CSRF-Token generieren
        String csrfToken = generateSecureToken();
        session.setAttribute("csrf_token", csrfToken);

        // Token in Antwort für Formulare einschließen
        request.setAttribute("csrf_token", csrfToken);
        request.getRequestDispatcher("/admin.jsp").forward(request, response);
    }

    private String generateSecureToken() {
        byte[] bytes = new byte[32];
        new SecureRandom().nextBytes(bytes);
        return Base64.getUrlEncoder().encodeToString(bytes);
    }
}
# Korrigiert: Flask mit ordnungsgemäßer Authentifizierung
from flask import Flask, request, abort, session
from functools import wraps
import secrets
import hmac

app = Flask(__name__)
app.secret_key = secrets.token_hex(32)

def require_auth(f):
    """Korrigiert: Ordnungsgemäße token-basierte Authentifizierung"""
    @wraps(f)
    def decorated(*args, **kwargs):
        # Sitzungsauthentifizierung verifizieren
        if not session.get('authenticated'):
            abort(401)

        # Sitzungstoken verifizieren
        session_token = request.headers.get('X-Session-Token')
        if not session_token or session_token != session.get('token'):
            abort(401)

        return f(*args, **kwargs)
    return decorated

def require_csrf_token(f):
    """Korrigiert: Ordnungsgemäßer CSRF-Schutz mit Token"""
    @wraps(f)
    def decorated(*args, **kwargs):
        # CSRF-Token aus Formular/Header holen
        csrf_token = request.form.get('csrf_token') or \
                    request.headers.get('X-CSRF-Token')

        # Gegen Sitzung verifizieren
        expected = session.get('csrf_token')
        if not csrf_token or not expected:
            abort(403, 'CSRF-Token fehlt')

        if not hmac.compare_digest(csrf_token, expected):
            abort(403, 'Ungültiges CSRF-Token')

        return f(*args, **kwargs)
    return decorated

@app.route('/api/sensitive')
@require_auth
def secure_api():
    # Korrigiert: Ordnungsgemäße Authentifizierung via Decorator
    # Referer wird nur für Auditing protokolliert
    referer = request.headers.get('Referer', 'none')
    app.logger.info(f"API-Zugriff von Benutzer {session['user_id']}, Referer: {referer}")

    return get_sensitive_data()

@app.route('/admin/action', methods=['POST'])
@require_auth
@require_csrf_token
def secure_admin():
    # Korrigiert: CSRF-Schutz via kryptografisches Token
    return execute_admin_action()

@app.before_request
def generate_csrf_token():
    """CSRF-Token für jede Sitzung generieren"""
    if 'csrf_token' not in session:
        session['csrf_token'] = secrets.token_hex(32)

Die Korrektur ersetzt Referer-basierte Prüfungen durch ordnungsgemäße Sitzungsauthentifizierung und kryptografische CSRF-Token.


Ausgenutzt in der Praxis

Referer-basierte Zugriffskontrollumgehung (Webanwendungen, Fortlaufend)

Viele Webanwendungen wurden von Angreifern ausgenutzt, die Referer-basierte Zugriffskontrollen entdeckten. Einfaches Setzen des entsprechenden Referer-Headers ermöglicht die Umgehung beabsichtigter Schutzmaßnahmen für administrative Funktionen und sensible Daten.

CSRF-Angriffe auf Referer-geschützte Formulare (Webanwendungen, Historisch)

Anwendungen, die sich ausschließlich auf Referer-Validierung für CSRF-Schutz verließen, wurden angegriffen, wenn Browser keine Referer-Header sendeten oder wenn Angreifer Techniken verwendeten, die Referer-Spoofing ermöglichten.


Tools zum Testen/Ausnutzen

  • Burp Suite — Web-Sicherheitstool mit einfachen Referer-Header-Modifikationsfähigkeiten.

  • cURL — Kommandozeilen-HTTP-Client, der das Setzen beliebiger Header einschließlich Referer ermöglicht.

  • ModHeader — Browser-Erweiterung zum Modifizieren von HTTP-Headern einschließlich Referer.


CVE-Beispiele

Referer-basierte Authentifizierungsschwachstellen werden oft als Teil größerer Zugriffskontrollprobleme dokumentiert anstatt als eigenständige CVEs. Viele Anwendungen haben Referer-Abhängigkeiten stillschweigend ohne CVE-Zuweisung behoben.


Referenzen

  1. MITRE Corporation. "CWE-293: Using Referer Field for Authentication." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/293.html

  2. OWASP Foundation. "Cross-Site Request Forgery Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html

  3. OWASP Foundation. "Authentication Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html