Ungeschützter Primärkanal

Beschreibung

Ungeschützter Primärkanal tritt auf, wenn ein Produkt einen Primärkanal für administrative oder eingeschränkte Operationen implementiert, aber diesen Kanal nicht ausreichend gegen unbefugten Zugriff oder Missbrauch absichert. Der Primärkanal ist der hauptsächlich vorgesehene Kommunikationspfad für sensible Operationen, aber ohne ordnungsgemäße Schutzmechanismen können Angreifer auf administrative Funktionalität zugreifen, Privilegien eskalieren oder Sicherheitskontrollen umgehen, die solchen Zugriff einschränken sollen.

Risiko

Ungeschützte Primärkanale haben schwerwiegende Auswirkungen. Unbefugter administrativer Zugriff. Privilegieneskalation. Vollständige Systemkompromittierung. Umgehung von Authentifizierungskontrollen. Datenmanipulation. Konfigurationsmanipulation. Dienststörung. Hohe Wahrscheinlichkeit wenn administrative Schnittstellen keine ordnungsgemäßen Zugriffskontrollen haben.

Lösung

Stellen Sie administrative Funktionalität nicht auf der Benutzer-UI während der Architektur- und Entwurfsphase bereit. Schützen Sie die administrative/eingeschränkte Funktionalität mit einem starken Authentifizierungsmechanismus. Implementieren Sie Zugriffskontrollen auf Netzwerkebene für administrative Kanäle. Verwenden Sie separate Netzwerksegmente für administrativen Zugriff. Verschlüsseln Sie administrative Kommunikation.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleUmfang: Zugriffskontrolle

Privilegien erlangen oder Identität annehmen - Angreifer können Privilegien durch ungeschützte administrative Kanäle eskalieren.
AutorisierungUmfang: Autorisierung

Schutzmechanismus umgehen - Sicherheitskontrollen können über den ungeschützten Kanal umgangen werden.

Beispielcode

Anfälliger Code

# Anfällig: Ungeschützter administrativer Kanal

from flask import Flask, request, jsonify

app = Flask(__name__)

# ANFÄLLIG: Admin-Endpunkt ohne Authentifizierung
@app.route('/admin/users', methods=['GET', 'POST', 'DELETE'])
def admin_users():
    # ANFÄLLIG: Keine Authentifizierungsprüfung
    # Jeder kann auf diese administrative Funktion zugreifen

    if request.method == 'GET':
        return jsonify(get_all_users())

    elif request.method == 'POST':
        # ANFÄLLIG: Admin-Benutzer ohne Auth erstellen
        data = request.json
        create_user(data['username'], data['password'], admin=True)
        return jsonify({'status': 'created'})

    elif request.method == 'DELETE':
        # ANFÄLLIG: Benutzer ohne Autorisierung löschen
        user_id = request.args.get('id')
        delete_user(user_id)
        return jsonify({'status': 'deleted'})

# ANFÄLLIG: Konfigurationsendpunkt offengelegt
@app.route('/admin/config', methods=['GET', 'POST'])
def admin_config():
    # ANFÄLLIG: Systemkonfiguration ohne Schutz
    if request.method == 'GET':
        return jsonify(get_system_config())

    elif request.method == 'POST':
        # ANFÄLLIG: Systemkonfiguration ohne Auth modifizieren
        config = request.json
        update_system_config(config)
        return jsonify({'status': 'updated'})

# ANFÄLLIG: Debug-Endpunkt in Produktion
@app.route('/debug/execute', methods=['POST'])
def debug_execute():
    # ANFÄLLIG: Befehlsausführung ohne Authentifizierung
    command = request.json.get('cmd')
    result = os.popen(command).read()  # Hat auch Command Injection!
    return jsonify({'output': result})
// Anfällig: Java Admin-Schnittstelle ohne Schutz

import javax.servlet.*;
import javax.servlet.http.*;

public class VulnerableAdminServlet extends HttpServlet {

    // ANFÄLLIG: Kein Authentifizierungsfilter
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String action = req.getParameter("action");

        // ANFÄLLIG: Administrative Aktionen ohne Auth-Prüfung
        switch (action) {
            case "listUsers":
                // Gibt alle Benutzerdaten zurück
                resp.getWriter().write(getAllUsers().toString());
                break;

            case "getConfig":
                // ANFÄLLIG: Legt Systemkonfiguration offen
                resp.getWriter().write(getSystemConfig().toString());
                break;

            case "getLogs":
                // ANFÄLLIG: Legt sensible Logs offen
                resp.getWriter().write(getSystemLogs());
                break;
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String action = req.getParameter("action");

        // ANFÄLLIG: Modifizierende Aktionen ohne Autorisierung
        switch (action) {
            case "createAdmin":
                // ANFÄLLIG: Jeder kann Admin-Konten erstellen
                String username = req.getParameter("username");
                String password = req.getParameter("password");
                createAdminUser(username, password);
                break;

            case "updateConfig":
                // ANFÄLLIG: Systemkonfigurationsmodifikation
                String config = req.getParameter("config");
                updateSystemConfig(config);
                break;

            case "shutdown":
                // ANFÄLLIG: System-Shutdown ohne Auth
                System.exit(0);
                break;
        }
    }
}
// Anfällig: Node.js Express Admin-Routen ohne Schutz

const express = require('express');
const app = express();

// ANFÄLLIG: Admin-Router ohne Authentifizierungs-Middleware
const adminRouter = express.Router();

// ANFÄLLIG: Benutzerverwaltung ohne Auth
adminRouter.get('/users', (req, res) => {
    // Gibt alle Benutzer einschließlich Passwörter/Hashes zurück
    res.json(database.getAllUsers());
});

adminRouter.post('/users', (req, res) => {
    // ANFÄLLIG: Benutzer ohne Authentifizierung erstellen
    const { username, password, role } = req.body;
    database.createUser(username, password, role);
    res.json({ success: true });
});

adminRouter.delete('/users/:id', (req, res) => {
    // ANFÄLLIG: Jeden Benutzer löschen
    database.deleteUser(req.params.id);
    res.json({ success: true });
});

// ANFÄLLIG: Systemkonfiguration
adminRouter.get('/config', (req, res) => {
    res.json(systemConfig);  // Enthält Geheimnisse!
});

adminRouter.post('/config', (req, res) => {
    Object.assign(systemConfig, req.body);
    res.json({ success: true });
});

// ANFÄLLIG: Ohne Schutz eingebunden
app.use('/admin', adminRouter);

// ANFÄLLIG: Debug-Endpunkt
app.post('/debug/eval', (req, res) => {
    const result = eval(req.body.code);  // Hat auch Code-Injection!
    res.json({ result });
});

app.listen(8080);

Korrigierter Code

# Korrigiert: Geschützter administrativer Kanal

from flask import Flask, request, jsonify, g
from functools import wraps
import jwt

app = Flask(__name__)

# KORRIGIERT: Authentifizierungs-Decorator
def require_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization', '').replace('Bearer ', '')

        if not token:
            return jsonify({'error': 'Authentifizierung erforderlich'}), 401

        try:
            payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
            g.current_user = payload
        except jwt.InvalidTokenError:
            return jsonify({'error': 'Ungültiges Token'}), 401

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

# KORRIGIERT: Admin-Rollenanforderung
def require_admin(f):
    @wraps(f)
    @require_auth
    def decorated(*args, **kwargs):
        if g.current_user.get('role') != 'admin':
            return jsonify({'error': 'Admin-Zugriff erforderlich'}), 403
        return f(*args, **kwargs)
    return decorated

# KORRIGIERT: Geschützter Admin-Endpunkt
@app.route('/admin/users', methods=['GET', 'POST', 'DELETE'])
@require_admin  # KORRIGIERT: Erfordert Authentifizierung und Admin-Rolle
def admin_users():
    if request.method == 'GET':
        # KORRIGIERT: Audit-Log
        audit_log('user_list', g.current_user['id'])
        return jsonify(get_all_users())

    elif request.method == 'POST':
        data = request.json
        # KORRIGIERT: Audit-Log
        audit_log('user_create', g.current_user['id'], data['username'])
        create_user(data['username'], data['password'], admin=data.get('admin', False))
        return jsonify({'status': 'created'})

    elif request.method == 'DELETE':
        user_id = request.args.get('id')
        # KORRIGIERT: Audit-Log
        audit_log('user_delete', g.current_user['id'], user_id)
        delete_user(user_id)
        return jsonify({'status': 'deleted'})

# KORRIGIERT: Netzwerkebenen-Einschränkung für sensible Endpunkte
@app.before_request
def check_admin_network():
    if request.path.startswith('/admin/'):
        # KORRIGIERT: Nur vom internen Netzwerk erlauben
        client_ip = request.remote_addr
        if not is_internal_network(client_ip):
            return jsonify({'error': 'Zugriff verweigert'}), 403

# KORRIGIERT: Debug-Endpunkte in Produktion entfernen
if not app.debug:
    @app.route('/debug/<path:path>')
    def block_debug(path):
        return jsonify({'error': 'Nicht gefunden'}), 404
// Korrigiert: Java Admin-Schnittstelle mit ordnungsgemäßem Schutz

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebFilter;

// KORRIGIERT: Authentifizierungsfilter für Admin-Pfade
@WebFilter(urlPatterns = {"/admin/*"})
public class AdminAuthFilter implements Filter {

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

        HttpServletRequest httpReq = (HttpServletRequest) req;
        HttpServletResponse httpResp = (HttpServletResponse) resp;

        // KORRIGIERT: Authentifizierung prüfen
        HttpSession session = httpReq.getSession(false);
        if (session == null || session.getAttribute("user") == null) {
            httpResp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }

        // KORRIGIERT: Admin-Rolle prüfen
        User user = (User) session.getAttribute("user");
        if (!user.hasRole("ADMIN")) {
            httpResp.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        // KORRIGIERT: Quell-IP prüfen
        String clientIP = httpReq.getRemoteAddr();
        if (!isAllowedAdminIP(clientIP)) {
            httpResp.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        // KORRIGIERT: Audit-Log
        auditLog(user.getUsername(), httpReq.getRequestURI());

        chain.doFilter(req, resp);
    }
}

// KORRIGIERT: Geschütztes Admin-Servlet
public class SecureAdminServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        // KORRIGIERT: Filter hat bereits Authentifizierung und Autorisierung verifiziert
        User user = (User) req.getSession().getAttribute("user");

        String action = req.getParameter("action");

        switch (action) {
            case "listUsers":
                // KORRIGIERT: Ausgabe bereinigen, keine sensiblen Daten einschließen
                resp.getWriter().write(getSanitizedUserList().toString());
                break;

            case "getConfig":
                // KORRIGIERT: Nur sichere Konfigurationswerte zurückgeben
                resp.getWriter().write(getSafeConfig().toString());
                break;
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        User user = (User) req.getSession().getAttribute("user");
        String action = req.getParameter("action");

        // KORRIGIERT: Zusätzliche Bestätigung für kritische Aktionen
        switch (action) {
            case "createAdmin":
                // KORRIGIERT: Re-Authentifizierung für sensible Ops erfordern
                if (!verifyPassword(user, req.getParameter("currentPassword"))) {
                    resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                    return;
                }

                String username = req.getParameter("username");
                String password = req.getParameter("password");
                createAdminUser(username, password);

                // KORRIGIERT: Audit-Log
                auditLog(user.getUsername(), "created admin: " + username);
                break;
        }
    }
}
// Korrigiert: Node.js mit geschützten Admin-Routen

const express = require('express');
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');

const app = express();

// KORRIGIERT: Authentifizierungs-Middleware
const authenticate = (req, res, next) => {
    const token = req.headers.authorization?.replace('Bearer ', '');

    if (!token) {
        return res.status(401).json({ error: 'Authentifizierung erforderlich' });
    }

    try {
        const payload = jwt.verify(token, process.env.JWT_SECRET);
        req.user = payload;
        next();
    } catch (err) {
        return res.status(401).json({ error: 'Ungültiges Token' });
    }
};

// KORRIGIERT: Admin-Autorisierungs-Middleware
const requireAdmin = (req, res, next) => {
    if (req.user.role !== 'admin') {
        return res.status(403).json({ error: 'Admin-Zugriff erforderlich' });
    }
    next();
};

// KORRIGIERT: IP-Whitelist-Middleware
const adminIPWhitelist = (req, res, next) => {
    const allowedIPs = process.env.ADMIN_IPS?.split(',') || ['127.0.0.1'];
    const clientIP = req.ip || req.connection.remoteAddress;

    if (!allowedIPs.includes(clientIP)) {
        return res.status(403).json({ error: 'Zugriff von dieser IP verweigert' });
    }
    next();
};

// KORRIGIERT: Rate-Limiting für Admin-Routen
const adminRateLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 Minuten
    max: 100,
    message: { error: 'Zu viele Anfragen' }
});

// KORRIGIERT: Geschützter Admin-Router
const adminRouter = express.Router();

// KORRIGIERT: Alle Sicherheits-Middleware anwenden
adminRouter.use(authenticate);
adminRouter.use(requireAdmin);
adminRouter.use(adminIPWhitelist);
adminRouter.use(adminRateLimiter);

// KORRIGIERT: Audit-Logging-Middleware
adminRouter.use((req, res, next) => {
    auditLog({
        user: req.user.id,
        action: req.method + ' ' + req.path,
        ip: req.ip,
        timestamp: new Date()
    });
    next();
});

// KORRIGIERT: Geschützte Endpunkte
adminRouter.get('/users', (req, res) => {
    // KORRIGIERT: Keine sensiblen Daten zurückgeben
    const users = database.getAllUsers().map(u => ({
        id: u.id,
        username: u.username,
        role: u.role,
        // Kein Passwort-Hash!
    }));
    res.json(users);
});

adminRouter.post('/users', (req, res) => {
    const { username, password, role } = req.body;
    // KORRIGIERT: Eingabe validieren
    if (!username || !password) {
        return res.status(400).json({ error: 'Ungültige Eingabe' });
    }
    database.createUser(username, password, role);
    res.json({ success: true });
});

// KORRIGIERT: Mit Schutz einbinden
app.use('/admin', adminRouter);

// KORRIGIERT: Keine Debug-Endpunkte in Produktion
if (process.env.NODE_ENV === 'production') {
    app.use('/debug', (req, res) => {
        res.status(404).json({ error: 'Nicht gefunden' });
    });
}

app.listen(8080);

CVE-Beispiele

  • CVE-2022-24112: Apache APISIX Admin-API ungeschützt, ermöglicht Remote-Codeausführung.
  • CVE-2020-17519: Apache Flink ungeschützte REST-API ermöglicht beliebiges Lesen von Dateien.
  • CVE-2019-0193: Apache Solr ungeschützter DataImportHandler.

Verwandte CWEs

  • CWE-923: Improper Restriction of Communication Channel to Intended Endpoints (Eltern)
  • CWE-306: Missing Authentication for Critical Function (verwandt)
  • CWE-287: Improper Authentication (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-419: Unprotected Primary Channel." https://cwe.mitre.org/data/definitions/419.html
  2. OWASP. "Administrative Interface Security"
  3. NIST. "Security and Privacy Controls for Information Systems"