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
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Umfang: Zugriffskontrolle Privilegien erlangen oder Identität annehmen - Angreifer können Privilegien durch ungeschützte administrative Kanäle eskalieren. |
| Autorisierung | Umfang: 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
- MITRE Corporation. "CWE-419: Unprotected Primary Channel." https://cwe.mitre.org/data/definitions/419.html
- OWASP. "Administrative Interface Security"
- NIST. "Security and Privacy Controls for Information Systems"