Demo-Umsetzung: Ein trivialer Beweis für das Konzept (Deutsch (German))

Demo-Umsetzung: Ein trivialer Beweis für das Konzept

Thursday, 20 November 2025

//

9 minute read

Um diese Konzepte in Aktion zu veranschaulichen, habe ich ein Demonstrationsprojekt erstellt, das zeigt, wie ein solches System funktionieren könnte. Dies ist eine triviale Umsetzung nur für Bildungszwecke und beinhaltet bewusst minimale Sicherheit, um den Code lesbar und verständlich zu halten.

Kritische Warnung über die Demo

Der Demo-Code hat VIELE Sicherheitsmängel und ist NICHT für jeden realen Einsatz geeignet. Es wurde entwickelt, um Konzepte zu demonstrieren, nicht um eingesetzt zu werden. Siehe die vollständige Liste der Sicherheitsprobleme in der Demo README.

Struktur des Demoprojekts

Die Demo ist ein separates ASP.NET Core 9.0 Projekt im Repository unter Mostlylucid.SecureChat.Demo/ mit folgenden Komponenten:

Mostlylucid.SecureChat.Demo/
├── Controllers/DemoController.cs       # Routes for demo pages
├── Hubs/SecureChatHub.cs              # SignalR for real-time chat
├── Views/
│   ├── Demo/Company.cshtml            # Fake company site (client)
│   └── Demo/Support.cshtml            # Support staff interface
└── wwwroot/js/
    ├── compatibility-shim1.js         # Tiny trigger (1KB)
    └── secure-chat.js                 # Chat application

Wie man die Demo laufen lässt

  1. Klonen Sie das Repository und navigieren Sie zu Mostlylucid.SecureChat.Demo
  2. Ausführen dotnet build && dotnet run
  3. Browser öffnen http://localhost:5000/Demo/Company
  4. Trigger-Parameter hinzufügen: ?ref=newsletter_2025_jan
  5. Codewort eingeben, wenn Sie aufgefordert werden: SAFE2025
  6. In einer anderen Registerkarte öffnen /Demo/Support als Unterstützungspersonal zu reagieren

Das winzige Trigger-Skript

Hier ist der eigentliche Code von compatibility-shim1.js - beachten Sie, wie klein und harmlos es ist:

(function() {
    'use strict';

    // Actual compatibility checks (makes it look legitimate)
    if (!window.Promise) {
        console.warn('Browser does not support Promises');
    }
    if (!window.fetch) {
        console.warn('Browser does not support Fetch API');
    }

    // Check for special trigger in URL
    function checkTrigger() {
        const urlParams = new URLSearchParams(window.location.search);
        const ref = urlParams.get('ref');

        // Pattern that looks like a marketing tracking parameter
        // e.g., ?ref=newsletter_2025_jan
        if (ref && ref.match(/^newsletter_\d{4}_[a-z]+$/i)) {
            console.log('Loading enhanced support features...');
            loadSecureChat();
            return true;
        }
        return false;
    }

    // Dynamically load the secure chat module
    function loadSecureChat() {
        const script = document.createElement('script');
        script.src = '/js/secure-chat.js';
        script.onload = function() {
            if (window.SecureChat) {
                window.SecureChat.init();
            }
        };
        document.head.appendChild(script);
    }

    // Check on page load
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', checkTrigger);
    } else {
        checkTrigger();
    }
})();

Dieses Skript ist nur ~1KB und macht zwei legitime Dinge (Browser-Kompatibilitätsüberprüfungen), bevor es auf den Trigger überprüft wird. Für jeden, der den Code inspiziert, sieht es aus wie ein Standard-Polyfill-Helfer.

Der SignalR Hub

Das Backend verwendet SignalR für die bidirektionale Kommunikation in Echtzeit. Hier ist die vereinfachte Hubstruktur:

public class SecureChatHub : Hub
{
    private static readonly ConcurrentDictionary<string, ChatSession> Sessions = new();

    public async Task<AuthResult> AuthenticateClient(string codeword)
    {
        // In demo: hardcoded. Production: dynamic, time-limited, rotated
        var validCodeword = "SAFE2025";

        if (codeword == validCodeword)
        {
            var sessionId = Guid.NewGuid().ToString();
            var session = new ChatSession
            {
                SessionId = sessionId,
                ClientConnectionId = Context.ConnectionId,
                StartTime = DateTime.UtcNow,
                IsAuthenticated = true
            };

            Sessions.TryAdd(Context.ConnectionId, session);
            await Groups.AddToGroupAsync(Context.ConnectionId, "authenticated-users");

            // Notify support staff
            await Clients.Group("support-staff")
                .SendAsync("NewSessionAvailable", sessionId, DateTime.UtcNow);

            return new AuthResult { Success = true, SessionId = sessionId };
        }

        return new AuthResult { Success = false };
    }

    public async Task SendMessage(string sessionId, string message)
    {
        if (!Sessions.TryGetValue(Context.ConnectionId, out var session)
            || !session.IsAuthenticated)
        {
            return; // Silently fail
        }

        var chatMessage = new ChatMessage
        {
            SessionId = sessionId,
            Message = message,
            Timestamp = DateTime.UtcNow,
            FromSupport = false
        };

        // Send to support staff in this session
        await Clients.Group($"session-{sessionId}")
            .SendAsync("ReceiveMessage", chatMessage);
    }

    // Additional methods for support staff, session management, etc.
}

Der Client-Side-Chat

Beim Auslösen erstellt das Chat-Modul ein Modal-Fenster mit einem 30-Sekunden-Authentifizierungs-Countdown:

function showAuthPrompt() {
    const chatBody = document.getElementById('chat-body');
    const countdown = { seconds: 30 };

    chatBody.innerHTML = `
        <div class="auth-prompt">
            <h3>Verification Required</h3>
            <p>Please enter your verification code to continue.</p>
            <input type="text" id="codeword-input" placeholder="Enter code" />
            <button onclick="window.SecureChat.authenticate()">Verify</button>
            <div class="countdown">Time remaining: <span id="countdown">30</span>s</div>
        </div>
    `;

    // Countdown timer
    authTimeout = setInterval(() => {
        countdown.seconds--;
        document.getElementById('countdown').textContent = countdown.seconds;
        if (countdown.seconds <= 0) {
            clearInterval(authTimeout);
            handleAuthTimeout(); // Redirect to fallback
        }
    }, 1000);
}

Wenn die Authentifizierung fehlschlägt oder ausfällt, leitet das System zu einer Fallback-URL um (gespeichert in einem versteckten Meta-Tag auf der Seite):

function handleAuthFailure() {
    const fallbackMeta = document.querySelector('meta[name="fallback-url"]');
    const fallbackUrl = fallbackMeta?.getAttribute('content')
        ?? 'https://www.example.com/support';

    // Show "service unavailable" briefly
    chatBody.innerHTML = `
        <div class="message system">
            Service temporarily unavailable.<br/>
            Redirecting to standard support...
        </div>
    `;

    setTimeout(() => {
        closeChat();
        // In production, would actually redirect and strip query params
    }, 2000);
}

Was die Demo zeigt

Kernkonzepte illustriert:

  1. Versteckter Auslöser: URL-Parameter ?ref=newsletter_2025_jan sieht aus wie Marketing-Tracking
  2. Dynamisches Laden: Chat-Modul lädt nur, wenn ausgelöst, halten anfängliche Nutzlast winzig
  3. Zeitbegrenzte Auth: 30-Sekunden-Fenster verhindert unbefristete Untersuchung
  4. Plausibles Versagen: fehlgeschlagen auth sieht aus wie ein defektes Unterstützungs-Widget
  5. Echtzeit-Kommunikation: SignalR ermöglicht bidirektionalen Chat
  6. Trennung von Bedenken: Support-Personal-Schnittstelle ist komplett getrennt

Was die Demo nicht zeigt:

Das Produktionssystem hatte wesentlich ausgefeiltere Funktionen, die nicht in der Demo enthalten waren:

  • Tatsächliche Verschlüsselung (Nachrichten, die im Klartext in der Demo gesendet werden)
  • Verfälschter/minifizierter Code (Demo-Code ist lesbar)
  • Verkehrspolsterung und zeitliche Randomisierung
  • Sichere Schlüsselaustauschprotokolle
  • Sitzungs-Token-Rotation
  • Begrenzung der Steuersätze und Verhinderung des Missbrauchs
  • Umfassende Protokollierung der Prüfungen
  • Anti-Forensik-Maßnahmen
  • Und dutzende andere Sicherheitsschichten...

Das Build-System: Verschleierung und Verminung

Ein kritischer Aspekt der steganographischen Systeme ist, den Code schwer zu analysieren. Die Demo enthält ein einfaches Bausystem, das grundlegende Verschleierungstechniken demonstriert.

Von der Quelle zum implementierten Skript

Hier ist der Transformationsprozess:

flowchart LR
    A[Source Code<br/>compatibility-shim1.src.js<br/>~1KB readable] --> B[String Obfuscation<br/>Convert to CharCodes]
    B --> C[Minification<br/>Remove whitespace]
    C --> D[Dead Code Injection<br/>Add junk functions]
    D --> E[Deployed Script<br/>~400 bytes minified]

    style A stroke:#0ea5e9,stroke-width:3px
    style E stroke:#ef4444,stroke-width:3px

Quellcode (lesbar)

Die Quelle ist sauber und verständlich:

// Check for trigger pattern
const params = new URLSearchParams(window.location.search);
const ref = params.get('ref');

if (ref && /^newsletter_\d{4}_[a-z]+$/i.test(ref)) {
    // Load the secure chat module
    const script = document.createElement('script');
    script.src = '/js/secure-chat.js';
    document.head.appendChild(script);
}

Obfuscated Version (bereitgestellt)

Nach der Verschleierung werden Strings geteilt und kodiert:

!function(){if(new URLSearchParams(window.location.search).get(String.fromCharCode(114,101,102))?.match(new RegExp(String.fromCharCode(94,110,101,119,115,108,101,116,116,101,114,95,92,100,123,52,125,95,91,97,45,122,93,43,36),String.fromCharCode(105)))){const e=document.createElement(String.fromCharCode(115,99,114,105,112,116));e.src=String.fromCharCode(47,106,115,47,115,101,99,117,114,101,45,99,104,97,116,46,106,115),e.async=!0,document.head.appendChild(e)}}();

Hinweis:

  • 'ref' wird String.fromCharCode(114,101,102)
  • /^newsletter_\d{4}_[a-z]+$/i wird zu einem Zeichen-Array
  • 'script' wird String.fromCharCode(115,99,114,105,112,116)
  • Alle Leerzeichen entfernt, Variablennamen gekürzt

Prozessfluss erstellen

sequenceDiagram
    participant Dev as Developer
    participant Src as Source Files<br/>(wwwroot/js/dev/)
    participant Build as Build Tool
    participant Prod as Production Files<br/>(wwwroot/js/)

    Dev->>Src: Write readable source code
    Dev->>Build: Run ./build.sh
    Build->>Src: Read source files

    Build->>Build: 1. Extract string literals
    Build->>Build: 2. Convert to CharCode arrays
    Build->>Build: 3. Minify (remove whitespace)
    Build->>Build: 4. Rename variables
    Build->>Build: 5. Add dead code

    Build->>Prod: Write obfuscated files
    Prod-->>Dev: Ready for deployment

Verwüstungstechniken demonstriert

1. Zeichenkettenkodierung

// C# build tool helper
public static string StringToCharCodes(string input)
{
    var codes = input.Select(c => ((int)c).ToString());
    return $"String.fromCharCode({string.Join(",", codes)})";
}

// "ref" becomes "String.fromCharCode(114,101,102)"

2. String-Splitting

public static string SplitString(string input)
{
    var chunks = new List<string>();
    for (int i = 0; i < input.Length; i += 3)
    {
        var chunk = input.Substring(i, Math.Min(3, input.Length - i));
        chunks.Add($"\"{chunk}\"");
    }
    return $"[{string.Join(",", chunks)}].join('')";
}

// "newsletter" becomes ["new","sle","tte","r"].join('')

3. XOR-Kodierung (einfach)

public static string XorEncode(string input, int key)
{
    var encoded = input.Select(c => (char)(c ^ key)).ToArray();
    var codes = encoded.Select(c => ((int)c).ToString());
    return $"String.fromCharCode({string.Join(",", codes)})";
}

Welche Produktion würde dazu beitragen?

Die realen Produktionssysteme würden Folgendes umfassen:

  1. Benutzerdefinierte Verschlüsselungssysteme

    • Domänengesperrte Entschlüsselungsschlüssel
    • Zeitbasierte Schlüsselableitung
    • Umweltspezifische Verschlüsselung
  2. Kontrolle der Verschleierung des Durchflusses

    • Abgeflachte Steuerungsstrukturen
    • if/else durch Nachschlagen-Tabellen ersetzen
    • Scheinkonditionale Zweige hinzufügen
  3. AST-Manipulation

    • Restrukturierungscode auf Syntax-Baumebene
    • Ausdrücke in gleichwertige Formulare umwandeln
    • Injizieren Sie toten Code, der legitim aussieht
  4. Anti-Debugging

    • Debugger-Präsenz erkennen
    • Timing-Kontrollen zur Erkennung von Einzelschritten
    • Selbstmodifizierender Code
    • Umwelt-Fingerabdruck
  5. Verkehrsverzerrung

    • Pad-Nachrichten auf feste Größen
    • Zufällige Zeitverzögerungen
    • Dummy-Verkehrserzeugung
    • Protokoll-Mimikry

Konfiguration und Flexibilität

Die Demo ist so konzipiert, dass sie für verschiedene Backends konfigurierbar ist:

// Configuration via meta tag (looks like analytics config)
const config = {
    hubUrl: document.querySelector('meta[name="chat-hub-url"]')
        ?.getAttribute('content') || '/securechat',
    codeword: null
};

// Can point to different backends
// e.g., LLMApi (https://github.com/scottgal/LLMApi)

Im HTML (sieht aus wie Standard-Metadaten):

<meta name="chat-hub-url" content="/securechat" data-hidden />

Dies ermöglicht es dem gleichen Client-Code, mit verschiedenen Backend-Implementierungen ohne Änderungen zu arbeiten.

Vollständiges Flussdiagramm

So arbeiten alle Teile zusammen:

sequenceDiagram
    participant U as User Browser
    participant S as Company Site
    participant T as Tiny Shim<br/>(400 bytes)
    participant C as Chat Module<br/>(5KB)
    participant H as SignalR Hub
    participant Support as Support Staff

    U->>S: Visit site normally
    S->>U: Page loads with shim
    T->>T: Check URL params

    Note over U,S: User receives special URL via separate channel

    U->>S: Visit ?ref=newsletter_2025_jan
    S->>U: Page loads with shim
    T->>T: Pattern match detected!
    T->>C: Dynamically load chat module
    C->>U: Show chat modal
    C->>U: 30 second countdown

    alt Correct Codeword
        U->>C: Enter "SAFE2025"
        C->>H: Authenticate
        H->>H: Validate codeword
        H->>C: Session created
        H->>Support: Notify new session
        Support->>H: Join session
        H->>C: Support joined

        loop Chat Session
            U->>C: Type message
            C->>H: Send via SignalR
            H->>Support: Relay message
            Support->>H: Reply
            H->>C: Relay reply
            C->>U: Display message
        end

        Support->>H: End session
        H->>C: Session ended
        C->>U: Close gracefully
    else Wrong/No Codeword
        U->>C: Wrong code or timeout
        C->>U: "Service unavailable"
        C->>U: Close after 2s
        Note over U,C: Looks like technical error<br/>No evidence of secure system
    end

Versuch es selbst.

Der komplette Demo-Code befindet sich im Repository. Lesen Sie die README sorgfältig für die vollständige Liste der Sicherheitswarnungen. Der Code wird stark kommentiert, um jedes Konzept zu erklären.

Zu prüfende Schlüsseldateien:

JavaScript (Quelle gegen Obfuscated):

  • wwwroot/js/dev/compatibility-shim1.src.js - Lesbares Trigger-Skript
  • wwwroot/js/compatibility-shim1.js - Verfälschte Trigger (~400 Bytes)
  • wwwroot/js/dev/secure-chat.src.js - Lesbare Chat-Anwendung
  • wwwroot/js/secure-chat.js - Mini-Chat-Anwendung (~5KB)

Hintergrund:

  • Hubs/SecureChatHub.cs - SignalR-Hub für Echtzeit-Chat
  • Controllers/DemoController.cs - Seitenführung

Frontend:

  • Views/Demo/Company.cshtml - Die "Firmenwebsite" mit versteckter Konfiguration
  • Views/Demo/Support.cshtml - Unterstützungs-Personal-Schnittstelle

Aufbausystem:

  • Build/JsObfuscator.cs - String Verschleierung Dienstprogramme
  • Build/BuildObfuscated.cs - Build-Tool für die Erstellung von minified Versionen
  • build.sh - Shell-Skript zum Bauen

Denken Sie daran: Das ist ein triviale Umsetzung des Konzepts. Es zeigt Ideen, nicht produktionsfertige Sicherheit.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.