3 Implementierungshandbuch-IIS-PHP-AD
blaerf edited this page 2025-11-16 11:27:27 +01:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Technisches Implementierungshandbuch: PHP-basierte Active Directory-Verwaltung mit IIS auf Windows Server 2025


Zusammenfassung

Dieses Dokument beschreibt die detaillierte, produktionsreife Implementierung einer PHP-Webanwendung auf einem Windows Server 2025 Datacenter, die über die Internet Information Services (IIS) bereitgestellt wird.

Die Anwendung erfüllt folgende hoch privilegierte Aufgaben:

  • Authentifizierung von Administratoren über LDAP
  • Abfrage von Servermetriken über SNMP
  • Erstellung von Active-Directory-(AD)-Benutzern (einzeln und als CSV-Massenimport)

Die AD-Benutzererstellung wird durch die sichere Ausführung von PowerShell-Skripten aus PHP heraus realisiert. Die Skripte verarbeiten sowohl Einzelbenutzer als auch CSV-Massenimporte.

Der Schwerpunkt dieses Handbuchs liegt auf der Konfiguration einer robusten und sicheren Architektur nach dem Least-Privilege-Prinzip, um Risiken durch Web-basierten Zugriff auf AD und Serverdienste zu minimieren.


Teil 1: Einrichtung der Basisinfrastruktur (IIS, PHP & FastCGI)

Dieser Abschnitt legt das Fundament für die Webanwendung durch die Installation und Konfiguration des Webservers und der PHP-Laufzeitumgebung auf einem sauberen Windows Server 2025.

1.1 Installation der IIS-Serverrolle

  1. Öffnen des Server-Managers.
  2. Auswahl von Verwalten → Rollen und Features hinzufügen.
  3. Im Assistenten zur Seite Serverrollen navigieren.
  4. Webserver (IIS) auswählen.
  5. Im erscheinenden Pop-up auf Features hinzufügen klicken.
  6. Zur Seite Rollendienste fortfahren.
  7. Unter Webserver → Anwendungsentwicklung den Knoten erweitern.
  8. Das Kontrollkästchen CGI aktivieren.

Technische Erläuterung:
Die Auswahl von CGI ist entscheidend. Diese Option installiert nicht nur klassisches CGI, sondern auch das moderne FastCGI-Modul, das für die performante und stabile Anbindung von PHP an IIS erforderlich ist. Ohne FastCGI kann IIS nicht mit php-cgi.exe kommunizieren.

  1. Den Assistenten abschließen und die Installation abwarten.

1.2 Installation der PHP-Laufzeitumgebung

Die Installation von PHP erfolgt manuell, da der Web Platform Installer (WPI) nicht mehr unterstützt wird.

Voraussetzung: Visual C++ Redistributable

PHP unter Windows benötigt das Microsoft Visual C++ 20152022 Redistributable (x64).

  1. Neueste x64-Version von Microsoft herunterladen: vc_redist.x64.exe.
  2. Installation ausführen und abschließen.

PHP-Download

  1. Zur offiziellen Download-Seite für PHP unter Windows wechseln: PHP
  2. Die x64 Non-Thread Safe (NTS) Version der gewünschten PHP-Version (z.B. PHP 8.4) im Zip-Format auswählen.

Technische Erläuterung:
Die NTS-Version ist für den Betrieb mit IIS + FastCGI optimiert. FastCGI übernimmt das Prozess-Pooling, daher ist Thread-Safety in PHP selbst nicht erforderlich. Die Verwendung einer Thread-Safe-Version (TS) kann hier zu Performance- und Stabilitätsproblemen führen.

PHP-Installation

  1. Ein Verzeichnis für PHP erstellen, z.B.: C:\PHP
  2. Das heruntergeladene ZIP-Archiv nach C:\PHP entpacken.

1.3 Konfiguration von IIS für PHP (Handler Mapping)

Nun muss IIS angewiesen werden, wie .php-Dateien behandelt werden. Dies erfolgt über eine Handler-Zuordnung.

  1. IIS-Manager starten (inetmgr).

  2. Im linken Bereich Verbindungen den Servernamen (oberste Ebene) auswählen.

  3. Im mittleren Bereich auf Handlerzuordnungen doppelklicken.

  4. Im rechten Bereich unter Aktionen auf Modulzuordnung hinzufügen… klicken.

  5. Felder wie folgt ausfüllen:

    • Anforderungspfad: *.php
    • Modul: FastCgiModule
    • Ausführbare Datei: C:\PHP\php-cgi.exe (Pfad ggf. anpassen)
    • Name: z.B. PHP via FastCGI
  6. Mit OK bestätigen.

  7. Die Nachfrage, ob eine FastCGI-Anwendung angelegt werden soll, mit Ja bestätigen.


1.4 Konfiguration der „Default Web Site“

  1. Im IIS-Manager im linken Bereich Websites erweitern.
  2. Rechtsklick auf Default Web SiteVerwalten der Website → Erweiterte Einstellungen…
  3. Die Eigenschaft Physischer Pfad suchen.
  4. Den Standardpfad (z.B. %SystemDrive%\inetpub\wwwroot) ändern auf den public-Ordner des Projekts, z.B.:
    C:\Web\AdAdminPanel\public
  5. Mit OK bestätigen.

Ab jetzt leitet IIS Anfragen an http://localhost/ in das Verzeichnis C:\Web\AdAdminPanel\public.


1.5 Validierung der Basisinstallation

  1. Eine neue Textdatei phpinfo.php in
    C:\Web\AdAdminPanel\public erstellen.

  2. Folgenden Inhalt einfügen:

    <?php
    phpinfo();
    
  3. Im Browser http://localhost/phpinfo.php aufrufen.

Wenn alles korrekt ist, erscheint die PHP-Info-Seite mit allen Konfigurationsdetails.

Wichtig:
Den Wert bei Loaded Configuration File (php.ini) Path notieren. Dieser Pfad ist wichtig für die Konfiguration in Teil 3.

Sicherheit:
Die Datei phpinfo.php nach der Validierung wieder löschen.


Teil 2: Konfiguration der Host-Dienste (SNMP & Active Directory)

Bevor die PHP-Anwendung konfiguriert wird, müssen die Zieldienste auf dem Server (SNMP) und in der Domäne (Active Directory) vorbereitet werden.

2.1 Aktivierung und Konfiguration des SNMP-Dienstes

Installation des SNMP-Dienstes

Unter Windows Server 2025 erfolgt die Installation bevorzugt über PowerShell:

Install-WindowsFeature SNMP-Service,SNMP-WMI-Provider -IncludeManagementTools

Konfiguration des SNMP-Dienstes

  1. services.msc öffnen.
  2. Den Dienst SNMP Service suchen und Eigenschaften öffnen.

Registerkarte „Agent“:

  • Optional Kontakt und Standort eintragen.
  • Unter Dienst passende Kategorien aktivieren (z.B. Physisch, Anwendungen, Internet).

Registerkarte „Sicherheit“ (kritischer Schritt):

  • Unter Akzeptierte CommunitynamenHinzufügen…
    • Rechte: SCHREIBGESCHÜTZT (READ ONLY)
    • Community-Name, z.B. public_ro (nicht public verwenden).
  • Unter SNMP-Pakete von diesen Hosts annehmenHinzufügen…
    • 127.0.0.1 eintragen.

Technische Erläuterung:
Die Beschränkung auf 127.0.0.1 stellt sicher, dass nur lokale Prozesse (z.B. PHP) den SNMP-Dienst abfragen können. Anfragen anderer Hosts werden verworfen.

Den SNMP-Dienst nach der Konfiguration neu starten.


2.2 Vorbereitung von Active Directory (OU und Dienstkonto)

Organisationseinheit (OU) erstellen

  1. Active Directory-Benutzer und -Computer (dsa.msc) öffnen.
  2. Rechtsklick auf die Domäne → Neu → Organisationseinheit.
  3. Namen vergeben, z.B. WebAppUsers.

Diese OU dient als isolierter Container für alle Benutzer, die über die PHP-Anwendung erstellt werden. Dort wird später die Rechte-Delegierung vorgenommen.

Dienstkonto (Service Account) erstellen

  1. Einen neuen Standard-Domänenbenutzer erstellen, z.B.:
    • Benutzername: svc_iis_php_ad
  2. Keiner administrativen Gruppe (z.B. Domänen-Admins) hinzufügen.
  3. Ein langes, komplexes Kennwort vergeben (25+ Zeichen).
  4. Kontooptionen:
    • Kennwort läuft nie ab aktivieren.
    • Benutzer kann Kennwort nicht ändern aktivieren.
    • Benutzer muss Kennwort bei der nächsten Anmeldung ändern deaktivieren.

Dieses Konto wird später als Identität des IIS-Anwendungspools verwendet.


Teil 3: Konfiguration von Secure LDAP (LDAPS) auf dem Domänencontroller

Standard-LDAP (Port 389) überträgt Anmeldeinformationen unverschlüsselt. Für eine Produktionsumgebung ist die Aktivierung von LDAPS (LDAP über SSL, Port 636) zwingend erforderlich.

  1. Voraussetzung: SSL-Zertifikat
    LDAPS funktioniert nur, wenn der Domänencontroller (DC) ein gültiges SSL-Zertifikat besitzt. Dieses Zertifikat muss für den Zweck "Serverauthentifizierung" ausgestellt sein und der FQDN des Domänencontrollers (z. B. dc01.yourdomain.com) muss im Antragstellernamen (Subject Name) oder Alternativen Antragstellernamen (SAN) enthalten sein.
  2. Empfohlene Methode: Active Directory-Zertifikatdienste (AD CS)
    Die einfachste und robusteste Methode zur Bereitstellung dieses Zertifikats ist die Installation der Active Directory-Zertifikatdienste (AD CS)-Rolle auf dem Server.
    • Den Server-Manager auf dem DC öffnen.
    • Verwalten > Rollen und Features hinzufügen auswählen.
    • In der Rollenauswahl Active Directory-Zertifikatdienste anklicken.
    • Im Assistenten für Rollendienste mindestens Zertifizierungsstelle aktivieren.
    • Abschluss der Installation und die anschließende Konfiguration der Rolle abwarten ("Unternehmens-CA" auswählen).
    • Nach der Installation und Konfiguration erhält der Domänencontroller (oder alle DCs in der Domäne, abhängig von der Konfiguration) automatisch ein gültiges Zertifikat von der neuen internen Zertifizierungsstelle.
  3. Automatische Aktivierung von LDAPS
    Sobald ein gültiges Zertifikat im persönlichen Zertifikatspeicher des Domänencontrollers vorhanden ist, beginnt der AD-Dienst (LSASS.exe) automatisch, auf den LDAPS-Ports zu lauschen:
    • TCP 636 (für LDAPS)
    • TCP 3269 (für LDAPS zum globalen Katalog)
  4. Verifizierung der LDAPS-Verbindung (auf dem DC)
    • ldp.exe starten (ein AD-Verwaltungstool).
    • Danach Verbindung > Verbinden... auswählen.
    • Server: FQDN des DCs eingeben (z. B. dc01.yourdomain.com).
    • Port: 636
    • Kontrollkästchen SSL aktivieren.
    • Auf OK klicken.
    • Wenn die Verbindung erfolgreich ist, werden die RootDSE-Informationen im rechten Fensterbereich angezeigt. Dies bestätigt, dass der Server LDAPS-Verbindungen akzeptiert.

Teil 4: Erweiterte PHP-Konfiguration (LDAP und SNMP aktivieren)

Nun werden die PHP-Erweiterungen aktiviert, die für LDAP-Authentifizierung und SNMP-Abfragen benötigt werden.

4.1 Bearbeitung der php.ini

  1. Zum PHP-Installationsverzeichnis wechseln, z.B. C:\PHP.
  2. Falls keine php.ini existiert:
    • php.ini-production nach php.ini kopieren.
  3. php.ini mit einem Editor (z.B. Notepad++ als Administrator) öffnen.

4.2 Aktivierung der PHP-Erweiterungen

  1. In der php.ini nach extension_dir suchen und sicherstellen, dass es auf das ext-Verzeichnis zeigt:

    extension_dir = "ext"
    
  2. Folgende Zeilen aktivieren (Semikolon am Zeilenanfang entfernen):

    extension=ldap
    extension=snmp
    extension=openssl
    
  • ldap: für Administrator-Authentifizierung via LDAP
  • snmp: für SNMP-Abfragen (Servermetriken)
  • openssl: u.a. für LDAPS (LDAP über SSL/TLS)

4.3 Behebung von Windows-spezifischen DLL-Abhängigkeiten

Erweiterungen wie php_ldap.dll benötigen zusätzliche DLLs (z.B. libsasl.dll, libcrypto-*.dll, libssl-*.dll), die sich im PHP-Stammverzeichnis befinden.

Typische Symptome:

  • In phpinfo() fehlen die Sektionen ldap oder snmp.
  • In der Ereignisanzeige oder in IIS-Logs erscheinen PHP-Startwarnungen.

Lösung (Best Practice):

  1. Systemsteuerung → System → Erweiterte Systemeinstellungen.
  2. Umgebungsvariablen… öffnen.
  3. Unter Systemvariablen die Variable Path bearbeiten.
  4. Neu: C:\PHP hinzufügen.
  5. Alle Fenster mit OK schließen.

Erforderlicher Schritt:

  • Vollständigen Neustart des Servers durchführen
    oder zumindest die Dienste W3SVC und WAS neu starten, damit der IIS-Prozess w3wp.exe den aktualisierten PATH übernimmt.

4.4 Konfiguration von PHP für LDAPS-Vertrauensstellung

Das Aktivieren von extension=ldap allein reicht nicht aus, um LDAPS mit einer internen Zertifizierungsstelle zu verwenden. Hintergrund ist, dass PHP unter Windows nicht auf den Windows-Zertifikatspeicher zugreift. Ohne zusätzliche Konfiguration führt dies bei LDAPS-Verbindungen zu dem Fehler „Unknown CA“. Damit PHP der internen Zertifizierungsstelle vertraut, muss das Root-Zertifikat manuell in einer separaten OpenLDAP-Konfigurationsstruktur hinterlegt werden.

Schritt 1: Root-CA-Zertifikat exportieren

  1. Auf einem beliebigen domänenangehörigen System mmc.exe starten.
  2. Datei → Snap-In hinzufügen/entfernen… auswählen.
  3. Zertifikate hinzufügen → ComputerkontoLokaler Computer.
  4. Zu Vertrauenswürdige Stammzertifizierungsstellen → Zertifikate navigieren.
  5. Das Stammzertifikat der internen CA auswählen.
  6. Rechtsklick → Alle Aufgaben → Exportieren….
  7. Format Base-64-codiert X.509 (.CER) wählen.
  8. Das Zertifikat z. B. als C:\InternalRootCA.cer speichern.

Schritt 2: OpenLDAP-Konfigurationsverzeichnis erstellen

  1. Auf dem IIS-Server das folgende Verzeichnis anlegen:
    C:\openldap\sysconf\
  2. Die exportierte Datei InternalRootCA.cer in dieses Verzeichnis kopieren.
  3. Im selben Verzeichnis eine Datei ldap.conf anlegen.

Schritt 3: ldap.conf konfigurieren

  1. C:\openldap\sysconf\ldap.conf mit einem Editor öffnen.
  2. Folgende Zeile eintragen (Dateiname ggf. anpassen):

4.5 Überprüfung der geladenen Module

  • phpinfo.php erneut aufrufen.
  • Mit Strg+F nach ldap und snmp suchen.

Sind separate Konfigurationsblöcke für ldap und snmp sichtbar, wurden die Module korrekt geladen.

Tabelle 1: Erforderliche PHP-Erweiterungen und Abhängigkeiten

Erweiterung php.ini-Eintrag Wichtige DLLs (im PHP-Stammverzeichnis) Zweck
LDAP extension=ldap libsasl.dll, libcrypto-*.dll, libssl-*.dll Administrator-Authentifizierung (Login)
SNMP extension=snmp (i.d.R. keine zusätzlichen DLLs) Abfrage von Serverinformationen (CPU, RAM, Uptime)
OpenSSL extension=openssl libcrypto-*.dll, libssl-*.dll LDAPS/HTTPS-Funktionalität

Teil 5: Die PowerShell-Automatisierungsebene

Die AD-Operationen werden über PowerShell-Skripte ausgeführt, die als sichere, parametrisierte Schnittstelle zwischen PHP und Active Directory dienen.

Pfad für Skripte:
C:\Web\AdAdminPanel\scripts\powershell\

5.1 Skript für einzelne Benutzererstellung (Create-ADUser.ps1)

# C:\Web\AdAdminPanel\scripts\powershell\Create-ADUser.ps1

param(
    [Parameter(Mandatory=$true)][string]$Username,
    [Parameter(Mandatory=$true)][string]$Password,
    [Parameter(Mandatory=$true)][string]$GivenName,
    [Parameter(Mandatory=$true)][string]$Surname,
    [Parameter(Mandatory=$true)][string]$OUPath
)

try {
    Import-Module ActiveDirectory -ErrorAction Stop

    # Kritisch: Konvertierung des Klartext-Passworts in einen SecureString
    $SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

    $userParams = @{
        Name                  = "$GivenName $Surname"
        GivenName             = $GivenName
        Surname               = $Surname
        SamAccountName        = $Username
        UserPrincipalName     = "$Username@yourdomain.com" # "yourdomain.com" anpassen
        AccountPassword       = $SecurePassword
        Path                  = $OUPath
        Enabled               = $true
        ChangePasswordAtLogon = $true
    }

    New-ADUser @userParams

    Write-Output "Erfolg: Benutzer $Username wurde in der OU $OUPath erstellt."
}
catch {
    Write-Error "Fehler bei der Benutzererstellung für $Username: $($_.Exception.Message)"
    exit 1
}

5.2 Skript für CSV-Massenimport (Bulk-Create-ADUsers.ps1)

# C:\Web\AdAdminPanel\scripts\powershell\Bulk-Create-ADUsers.ps1

param(
    [Parameter(Mandatory=$true)][string]$CsvPath,
    [Parameter(Mandatory=$true)][string]$OUPath
)

$domainSuffix = "@yourdomain.com" # Anpassen

try {
    Import-Module ActiveDirectory -ErrorAction Stop

    # Erwartete Spalten: SamAccountName, GivenName, Surname, Password
    $users = Import-Csv -Path $CsvPath

    if ($null -eq $users) {
        Write-Warning "Die CSV-Datei unter $CsvPath ist leer oder konnte nicht gelesen werden."
        exit 0
    }

    foreach ($user in $users) {
        try {
            $SecurePassword = ConvertTo-SecureString -String $user.Password -AsPlainText -Force

            $userParams = @{
                Name                  = "$($user.GivenName) $($user.Surname)"
                GivenName             = $user.GivenName
                Surname               = $user.Surname
                SamAccountName        = $user.SamAccountName
                UserPrincipalName     = "$($user.SamAccountName)$domainSuffix"
                AccountPassword       = $SecurePassword
                Path                  = $OUPath
                Enabled               = $true
                ChangePasswordAtLogon = $true
            }

            New-ADUser @userParams
            Write-Output "Erfolg (Bulk): Benutzer $($user.SamAccountName) wurde erstellt."
        }
        catch {
            Write-Warning "Fehler bei Benutzer $($user.SamAccountName): $($_.Exception.Message)"
        }
    }

    Write-Output "Massenimport abgeschlossen."
}
catch {
    Write-Error "Schwerwiegender Fehler beim Massenimport: $($_.Exception.Message)"
    exit 1
}

Teil 6: Sicherheitsarchitektur (IIS, PHP und PowerShell)

Die größte Herausforderung ist die sichere Verbindung zwischen der IIS-Webanwendung (niedrige Vertrauensstellung) und Active Directory (hohe Vertrauensstellung).

6.1 Analyse des Sicherheitsproblems

shell_exec() in PHP wird im Sicherheitskontext des IIS-Anwendungspool-Benutzers ausgeführt. Standardmäßig ist dies ein virtuelles Konto wie IIS APPPOOL\DefaultAppPool mit sehr wenigen Rechten. Dieses Konto darf weder:

  • das AD-PowerShell-Modul nutzen,
  • noch AD-Objekte erstellen,
  • noch sich an Domänencontrollern authentifizieren.

Falsche Lösung: Dem AppPool Domänen-Admin-Rechte geben → massive Sicherheitslücke.

Korrekte Lösung: Verwendung des dedizierten Dienstkontos svc_iis_php_ad (Least Privilege) und gezielte Rechte-Delegierung.


6.2 Konfiguration der IIS-Anwendungspool-Identität

  1. IIS-Manager öffnen.
  2. Anwendungspools auswählen.
  3. Rechtsklick → Anwendungspool hinzufügen…
    • Name: PHP_AD_AppPool
    • .NET CLR-Version: Kein verwalteter Code
  4. Auf die Website (z.B. Default Web Site) wechseln → Basis-Einstellungen… bzw. Standardeinstellungen… und den Anwendungspool auf PHP_AD_AppPool umstellen.
  5. In der Liste der Anwendungspools:
    • PHP_AD_AppPool markieren → Erweiterte Einstellungen…
    • Unter Prozessmodell → IdentitätBenutzerdefiniertes Konto auswählen.
    • Festlegen… → Anmeldeinformationen für IHREDOMÄNE\svc_iis_php_ad eintragen.

Ab jetzt läuft der AppPool im Kontext des Dienstkontos.


6.3 Delegierung von AD-Berechtigungen

  1. Auf einem Domänencontroller dsa.msc öffnen.
  2. Rechtsklick auf OU WebAppUsersObjektverwaltung zuweisen…
  3. Im Assistenten:
    • WeiterHinzufügen… → Konto svc_iis_php_ad auswählen.
    • WeiterEine benutzerdefinierte Aufgabe zum Zuweisen erstellen.
    • Objekttyp: Nur die folgenden Objekttypen im OrdnerBenutzerobjekte aktivieren.
    • Berechtigungen:
      • Diese Objekte im Ordner erstellen (ggf. auch löschen).
      • Alle Eigenschaften schreiben
      • Kennwort zurücksetzen
      • Kennwort ändern

Ergebnis:
svc_iis_php_ad kann nur Benutzerobjekte innerhalb der OU WebAppUsers erstellen/ändern und sonst nichts.


6.4 PowerShell-Ausführungsrichtlinie

Standardmäßig gilt Restricted. Statt die Richtlinie global zu ändern, wird sie pro Aufruf übergangen mit:

-ExecutionPolicy ByPass -NoProfile

Dies wird in den PHP-Skripten beim Aufruf von powershell.exe verwendet.


6.5 Dateisystemberechtigungen (NTFS)

Dem Dienstkonto svc_iis_php_ad werden nur die minimal erforderlichen NTFS-Rechte gewährt:

  • C:\PHP → Lesen & Ausführen
  • C:\Web\AdAdminPanel\public → Lesen
  • C:\Web\AdAdminPanel\scripts\powershell → Lesen & Ausführen
  • C:\Web\AdAdminPanel\storage\uploads → Ändern/Schreiben (für CSV-Uploads)
  • C:\openldap\sysconf → Lesen (damit es die ldap.conf und die .cer-Datei lesen kann)

Teil 7: Implementierung der PHP-Anwendungslogik

Die folgenden PHP-Dateien liegen im Web-Stammverzeichnis, z.B.:
C:\Web\AdAdminPanel\public

7.1 Modul 1: Administrator-Authentifizierung (LDAP-Login)

Datei: login.php

<?php
// login.php
session_start();
$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Domänencontroller und Domäne anpassen
    $ldap_server = "ldap://dc01.yourdomain.com";
    $domain      = "@yourdomain.com";

    // Anmeldung mit UPN
    $ldap_user_dn = $_POST['username'] . $domain;
    $ldap_pass    = $_POST['password'];

    $ldap_conn = ldap_connect($ldap_server);
    if (!$ldap_conn) {
        $error = "Fehler: Verbindung zum LDAP-Server fehlgeschlagen.";
    } else {
        ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
        ldap_set_option($ldap_conn, LDAP_OPT_REFERRALS, 0);

        // @ unterdrückt Warnungen bei fehlerhaftem Login
        if (@ldap_bind($ldap_conn, $ldap_user_dn, $ldap_pass)) {
            $_SESSION['admin_user'] = $ldap_user_dn;
            header("Location: dashboard.php");
            exit;
        } else {
            $error = "LDAP-Bind fehlgeschlagen: Ungültiger Benutzername oder Passwort.";
        }

        ldap_close($ldap_conn);
    }
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>Admin Login</title>
</head>
<body>
    <h2>Admin Login</h2>
    <?php if ($error): ?>
        <p style="color:red;"><?php echo htmlspecialchars($error); ?></p>
    <?php endif; ?>
    <form method="post" action="login.php">
        Benutzername: <input type="text" name="username"><br>
        Passwort: <input type="password" name="password"><br>
        <input type="submit" value="Anmelden">
    </form>
</body>
</html>

7.2 Modul 2: Server-Monitoring (SNMP)

Diese Seite (dashboard.php) zeigt die Serverinformationen an, die über die in Teil 4 aktivierte SNMP-Erweiterung und den in Teil 2 konfigurierten Dienst abgerufen werden.

Tabelle 2: Wichtige SNMP-OIDs für die Windows Server-Überwachung

Metrik OID Beschreibung
CPU-Last .1.3.6.1.2.1.25.3.3.1.2 (HOST-RESOURCES-MIB) Durchschnittliche CPU-Auslastung der letzten Minute (pro CPU-Kern). Dies ist eine Tabelle; ein snmpwalk ist erforderlich, um alle Kerne zu erhalten.59
Gesamter RAM .1.3.6.1.2.1.25.2.3.1.5 (hrStorageSize) Größe der Speichereinheiten. Muss mit hrStorageDescr (z. B. "Physical Memory") korreliert werden.63
Genutzter RAM .1.3.6.1.2.1.25.2.3.1.6 (hrStorageUsed) Genutzte Speichereinheiten. Muss ebenfalls korreliert werden.63
System Uptime .1.3.6.1.2.1.25.1.1.0 hrSystemUptime (in Timeticks).

Datei: dashboard.php

<?php
// dashboard.php
session_start();
if (!isset($_SESSION['admin_user'])) {
    header("Location: login.php");
    exit;
}

// SNMP-Konfiguration
$community = 'public_ro';
$host      = '127.0.0.1';

snmp_set_quick_print(true);
snmp_set_oid_output_format(SNMP_OID_OUTPUT_NUMERIC);

// CPU-Last (erster Kern, Beispiel)
$cpu_oid  = '.1.3.6.1.2.1.25.3.3.1.2.1';
$cpu_load = @snmpget($host, $community, $cpu_oid, 1000000, 2);

// System Uptime
$uptime_oid = '.1.3.6.1.2.1.25.1.1.0';
$uptime_raw = @snmpget($host, $community, $uptime_oid);
$uptime     = $uptime_raw ? ($uptime_raw / (100 * 60 * 60 * 24)) . " Tage" : "Fehler";

// RAM (statisches Beispiel mit Index 5)
$ram_total_oid       = '.1.3.6.1.2.1.25.2.3.1.5.5';
$ram_used_oid        = '.1.3.6.1.2.1.25.2.3.1.6.5';
$ram_alloc_units_oid = '.1.3.6.1.2.1.25.2.3.1.4.5';

$ram_total_raw = @snmpget($host, $community, $ram_total_oid);
$ram_used_raw  = @snmpget($host, $community, $ram_used_oid);
$ram_units     = @snmpget($host, $community, $ram_alloc_units_oid);

if ($ram_total_raw && $ram_used_raw && $ram_units) {
    $ram_total_gb = ($ram_total_raw * $ram_units) / (1024 ** 3);
    $ram_used_gb  = ($ram_used_raw  * $ram_units) / (1024 ** 3);
    $ram_percent  = ($ram_used_gb / $ram_total_gb) * 100;
}
?>
<h2>Admin Dashboard</h2>
<p>Angemeldet als: <?php echo htmlspecialchars($_SESSION['admin_user']); ?></p>

<h3>Server-Status (SNMP)</h3>
<p>CPU-Last (Kern 1): <?php echo $cpu_load ?: "Fehler bei Abfrage"; ?>%</p>
<p>System Uptime: <?php echo $uptime; ?></p>
<p>RAM-Auslastung:
    <?php echo isset($ram_percent) ? number_format($ram_percent, 2) . "%" : "Fehler bei Abfrage"; ?>
</p>

<hr>
<p><a href="create_single_user.php">Einzelnen Benutzer erstellen</a></p>
<p><a href="bulk_create_users.php">Benutzer per CSV importieren</a></p>

7.3 Modul 3: Einzelne Benutzererstellung

Datei: create_single_user.php

<?php
// create_single_user.php
session_start();
if (!isset($_SESSION['admin_user'])) {
    header("Location: login.php");
    exit;
}

$output = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $ps_script = 'C:\\Web\\AdAdminPanel\\scripts\\powershell\\Create-ADUser.ps1';

    if (empty($_POST['username']) || empty($_POST['password'])) {
        $output = "Fehler: Benutzername und Passwort sind erforderlich.";
    } else {
        // Kritisch: Maskierung aller Shell-Argumente (Schutz vor Command Injection)
        $username  = escapeshellarg($_POST['username']);
        $password  = escapeshellarg($_POST['password']);
        $givenname = escapeshellarg($_POST['givenname']);
        $surname   = escapeshellarg($_POST['surname']);
        $oupath    = escapeshellarg("OU=WebAppUsers,DC=yourdomain,DC=com");

        $command = "powershell.exe -ExecutionPolicy ByPass -NoProfile -File $ps_script " .
                   "-Username $username -Password $password -GivenName $givenname " .
                   "-Surname $surname -OUPath $oupath";

        // STDERR nach STDOUT umleiten (2>&1)
        $output = shell_exec($command . " 2>&1");
    }
}
?>
<h2>Neuen AD-Benutzer erstellen</h2>
<form method="post" action="create_single_user.php">
    Benutzername (SamAccountName): <input type="text" name="username"><br>
    Temporäres Passwort: <input type="text" name="password"><br>
    Vorname: <input type="text" name="givenname"><br>
    Nachname: <input type="text" name="surname"><br>
    <input type="submit" value="Benutzer erstellen">
</form>

<?php if ($output): ?>
    <h3>Ausgabe:</h3>
    <pre><?php echo htmlspecialchars($output); ?></pre>
<?php endif; ?>

7.4 Modul 4: CSV-Massenimport

Datei: bulk_create_users.php

<?php
// bulk_create_users.php
session_start();
if (!isset($_SESSION['admin_user'])) {
    header("Location: login.php");
    exit;
}

$output = '';

if (isset($_FILES['user_csv'])) {
    $upload_dir    = 'C:\\Web\\AdAdminPanel\\storage\\uploads\\';
    $temp_csv_path = $upload_dir . uniqid('users_') . '.csv';

    if (move_uploaded_file($_FILES['user_csv']['tmp_name'], $temp_csv_path)) {
        $ps_script   = 'C:\\Web\\AdAdminPanel\\scripts\\powershell\\Bulk-Create-ADUsers.ps1';
        $csv_path_arg = escapeshellarg($temp_csv_path);
        $oupath_arg   = escapeshellarg("OU=WebAppUsers,DC=yourdomain,DC=com");

        $command = "powershell.exe -ExecutionPolicy ByPass -NoProfile -File $ps_script " .
                   "-CsvPath $csv_path_arg -OUPath $oupath_arg";

        $output = shell_exec($command . " 2>&1");

        // Temporäre CSV mit Klartext-Passwörtern löschen
        unlink($temp_csv_path);
    } else {
        $output = "Fehler beim Hochladen der Datei.";
    }
}
?>
<h2>AD-Benutzer per CSV-Massenimport erstellen</h2>
<p>Die CSV-Datei muss die Spaltenüberschriften <code>SamAccountName</code>, <code>GivenName</code>, <code>Surname</code> und <code>Password</code> enthalten.</p>

<form method="post" action="bulk_create_users.php" enctype="multipart/form-data">
    CSV-Datei auswählen: <input type="file" name="user_csv" accept=".csv"><br>
    <input type="submit" value="Import starten">
</form>

<?php if ($output): ?>
    <h3>Import-Ergebnis:</h3>
    <pre><?php echo htmlspecialchars($output); ?></pre>
<?php endif; ?>

Teil 8: Abschließendes Sicherheits-Audit und Risikobewertung

Die Lösung ist mächtig, aber sensibel, da sie eine Brücke zwischen Web und Active Directory bildet. Die folgenden Risiken und Gegenmaßnahmen sind zentral:

Risiko: Command Injection

Beschreibung:
Ein Angreifer könnte versuchen, über Formulare Befehle einzuschleusen, z.B.:
username; Remove-ADUser -Identity 'Administrator'

Gegenmaßnahme:

  • Konsequente Verwendung von escapeshellarg() für alle Parameter, die an powershell.exe übergeben werden.
  • Dadurch werden Eingaben als einzelne, harmlose Zeichenkette behandelt und nicht als eigenständiger Befehl interpretiert.

Risiko: Eskalation von Berechtigungen

Beschreibung:
Eine Schwachstelle in der PHP-Anwendung könnte genutzt werden, um die Rechte des Webserverkontos zu missbrauchen.

Gegenmaßnahme:

  • AppPool läuft als svc_iis_php_ad mit minimal notwendigen Rechten.
  • AD-Delegierung beschränkt das Konto auf das Erstellen/Ändern von Benutzern in der OU WebAppUsers.
  • Keine Mitgliedschaft in administrativen Gruppen, kein Zugriff auf andere OUs oder Systeme.

Risiko: Klartext-Passwörter

Beschreibung:

  • Passwörter liegen im Klartext in Formularen und CSV-Dateien vor.
  • Übergabe an PowerShell erfolgt im Klartext.
  • Temporäre CSV-Dateien enthalten Klartext-Passwörter auf der Festplatte.

Gegenmaßnahmen:

  • HTTPS erzwingen: Die gesamte Weboberfläche muss über TLS gesichert werden.
  • Schnelle Konvertierung: PowerShell wandelt Klartext-Passwörter sofort in SecureString um.
  • Löschung der CSV-Dateien: Temporäre CSV-Dateien werden nach der Verarbeitung gelöscht (unlink()).
  • Passwortwechsel erzwingen: ChangePasswordAtLogon = $true zwingt Benutzer zur Passwortänderung bei der ersten Anmeldung.

Risiko: Fehlende Fehlerbehandlung

Beschreibung:

  • PowerShell-Fehler (z.B. Kennwort-Komplexität) landen auf STDERR, das von shell_exec() standardmäßig ignoriert wird.

Gegenmaßnahme:

  • Anhängen von 2>&1 an alle Befehle im shell_exec()-Kontext, damit Fehlermeldungen im $output-String landen und im Webinterface angezeigt werden können.

Ende des Dokuments