Back to "Demogenomförande: ett trefaldigt bevis på konceptet"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

History JavaScript Security

Demogenomförande: ett trefaldigt bevis på konceptet

Thursday, 20 November 2025

För att illustrera dessa koncept i handling har jag skapat ett demonstrationsprojekt som visar hur ett sådant system kan fungera. Detta är ett trivialt genomförande endast för utbildningsändamål och avsiktligt innehåller minimal säkerhet för att hålla koden läsbar och förståelig.

Kritisk varning om demo

Demokoden har MÅNGA säkerhetssvagheter och är INTE lämplig för någon verklig användning. Den är utformad för att demonstrera koncept, inte för att användas. Se hela listan över säkerhetsfrågor i demo README.

Demoprojektets struktur

Demo är ett separat ASP.NET Core 9,0 projekt i arkivet på Mostlylucid.SecureChat.Demo/ med följande komponenter:

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

Hur man styr demo

  1. Klonera arkivet och navigera till Mostlylucid.SecureChat.Demo
  2. Kör dotnet build && dotnet run
  3. Öppna webbläsare till http://localhost:5000/Demo/Company
  4. Lägg till utlösande parameter: ?ref=newsletter_2025_jan
  5. Ange kodord när du blir tillfrågad: SAFE2025
  6. Öppna under en annan flik /Demo/Support att svara som stödpersonal

Det lilla triggerskriptet

Här är den faktiska koden från compatibility-shim1.js - Notera hur liten och ofarlig den är:

(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();
    }
})();

Detta skript är bara ~1KB och gör två legitima saker (browser kompatibilitet kontroller) innan du kontrollerar efter utlösaren. För alla som inspekterar koden, ser det ut som en vanlig polyfill helper.

Signalcentralen

Backend använder SignalR för dubbelriktad kommunikation i realtid. Här är den förenklade navstrukturen:

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.
}

Chatt på klientsidan

När chattmodulen aktiveras skapar den ett modalfönster med en nedräkning av 30 sekunders behörighetskontroll:

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);
}

Om behörighetskontroll misslyckas eller tider ut, omdirigeras systemet till en reservwebbadress (lagras i en dold metatagg på sidan):

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);
}

Vad demonen visar

Kärnbegreppen illustreras:

  1. Dold trigger: Webbadressparameter ?ref=newsletter_2025_jan ser ut som marknadsföring spårning
  2. Dynamisk laddning: Chattmodulen laddas endast när den aktiveras, vilket håller den initiala nyttolasten liten
  3. Tidsbegränsad behörighet: 30-sekunders fönster förhindrar obestämd undersökning
  4. Osannolika misslyckanden: Misslyckades auth ser ut som en trasig stödkomponent
  5. Kommunikation i realtid: SignalR möjliggör dubbelriktad chatt
  6. Åtskillnad mellan olika intressen: Supportpersonalens gränssnitt är helt separat

Vad Demo inte visar:

Produktionssystemet hade betydligt mer sofistikerade funktioner som inte ingick i demo:

  • Faktisk kryptering (meddelanden som skickas i klartext i demo)
  • Obfuskerad/minifierad kod (demokod är läsbar)
  • Trafik stoppning och tids randomisering
  • Säkra viktiga utbytesprotokoll
  • Sessionssymbolens rotation
  • Bedrägeribegränsning och förebyggande av missbruk
  • Omfattande granskningsloggning
  • Åtgärder mot kriminalteknik
  • Och dussintals andra säkerhetslager...

Byggsystemet: Hindring och förfining

En kritisk aspekt av steganografiska system är att göra koden svår att analysera. Demo innehåller ett enkelt byggsystem som visar grundläggande obfuscation tekniker.

Från källkod till distribuerat skript

Här är omvandlingsprocessen:

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

Källkod (läsbar)

Källan är ren och förståelig:

// 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);
}

Föråldrad version (utarbetad)

Efter obfuscation, strängar delas och kodas:

!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)}}();

Meddelande:

  • 'ref' blir String.fromCharCode(114,101,102)
  • /^newsletter_\d{4}_[a-z]+$/i blir en teckenuppsättning
  • 'script' blir String.fromCharCode(115,99,114,105,112,116)
  • Alla blanktecken borttagna, variabelnamn förkortade

Bygg processflöde

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

Förvirringsteknik som demonstrerats

1. Strängkodning

// 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. Strängdelning

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-kodning (Enkel)

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)})";
}

Vad skulle produktionen lägga till?

De verkliga produktionssystemen skulle omfatta följande:

  1. Anpassade krypteringsscheman

    • Domänlåsta dekrypteringsnycklar
    • Tidsbaserad viktig härledning
    • Miljöspecifik kryptering
  2. Kontrollflödesobfuscation

    • Platta styrstrukturer
    • Ersätt if/else med uppslagstabeller
    • Lägg till falska villkorade filialer
  3. AST-manipulering

    • Omstrukturerad kod på syntaxträdsnivå
    • Omvandla uttryck till likvärdiga former
    • Injicera död kod som ser legitim ut
  4. Anti-debuggning

    • Upptäck felsökningsnärvaro
    • Tidskontroller för att upptäcka enstaka steg
    • Självmodifierande kod
    • Miljöns fingeravtryck
  5. Trafikförsämring

    • Pad-meddelanden till fasta storlekar
    • Slumpmässiga tidsfördröjningar
    • Dummy trafikgenerering
    • Förlaga till protokoll

Konfigurering och flexibilitet

Demon är utformad för att vara konfigurerbar för olika gränssnitt:

// 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)

I HTML (som ser ut som standardmetadata):

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

Detta gör det möjligt för samma klientkod att arbeta med olika gränssnittsimplementationer utan ändring.

Fullständig flödesdiagram

Här är hur alla bitar fungerar tillsammans:

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

Försök själv

Den fullständiga demokoden finns i arkivet. Läs README noggrant för den fullständiga listan över säkerhetsvarningar. Koden kommenteras kraftigt för att förklara varje koncept.

Nyckelfiler att undersöka:

JavaScript (Källa vs. obfuscated):

  • wwwroot/js/dev/compatibility-shim1.src.js - Avläsningsbart triggerskript
  • wwwroot/js/compatibility-shim1.js - Obfuskerad utlösare (~400 byte)
  • wwwroot/js/dev/secure-chat.src.js - Läsbart chattprogram
  • wwwroot/js/secure-chat.js - Minifierat chattprogram (~5KB)

Bakgrund:

  • Hubs/SecureChatHub.cs - SignalR-nav för chatt i realtid
  • Controllers/DemoController.cs - Page routing

Gränssnitt:

  • Views/Demo/Company.cshtml - "Företagets webbplats" med dold inställning
  • Views/Demo/Support.cshtml - Stödpersonals gränssnitt

Byggsystem:

  • Build/JsObfuscator.cs - Strängförångningsverktyg
  • Build/BuildObfuscated.cs - Bygga verktyg för att skapa minifierade versioner
  • build.sh - Shell manus för att bygga

Kom ihåg: Detta är en trivialt genomförande av konceptet. – Det visar på idéer, inte produktionsklar säkerhet.

logo

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