Back to "Implementazione demo: una prova triviale del concetto"

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

Implementazione demo: una prova triviale del concetto

Thursday, 20 November 2025

Per illustrare questi concetti in azione, ho creato un progetto dimostrativo che mostra come un tale sistema potrebbe funzionare. Si tratta di un'attuazione banale solo a fini educativi e include deliberatamente la minima sicurezza per mantenere il codice leggibile e comprensibile.

Avvertimento critico sulla demo

Il codice demo ha MOLTI punti deboli di sicurezza ed è NON adatto a qualsiasi uso del mondo reale. E 'disegnato per dimostrare i concetti, non per essere implementato. Vedi l'elenco completo dei problemi di sicurezza nel demo README.

Struttura del progetto demo

La demo è un progetto separato ASP.NET Core 9.0 nel repository a Mostlylucid.SecureChat.Demo/ con i seguenti componenti:

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

Come eseguire la demo

  1. Clonare il repository e navigare su Mostlylucid.SecureChat.Demo
  2. Esegui dotnet build && dotnet run
  3. Apri browser a http://localhost:5000/Demo/Company
  4. Aggiungi parametro di trigger: ?ref=newsletter_2025_jan
  5. Inserire la parola in codice quando richiesto: SAFE2025
  6. In un'altra scheda, aprire /Demo/Support rispondere come personale di supporto

Il piccolo script trigger

Ecco il codice reale da compatibility-shim1.js - notare quanto sia piccolo e innocuo:

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

Questo script è solo ~1KB e fa due cose legittime (controlli di compatibilità del browser) prima di controllare il trigger. A chiunque controlli il codice, sembra un aiutante di polifill standard.

Il Mozzo SignalR

Il backend utilizza SignalR per la comunicazione bidirezionale in tempo reale. Ecco la struttura dell'hub semplificata:

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

La chat Client-Side

Quando attivato, il modulo di chat crea una finestra modale con un conto alla rovescia di autenticazione di 30 secondi:

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

Se l'autenticazione fallisce o si spegne, il sistema reindirizza ad un URL di ripiego (registrato in un meta tag nascosto sulla pagina):

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

Cosa mostra la demo

Concetti principali illustrati:

  1. Trigger nascosto: parametro URL ?ref=newsletter_2025_jan sembra un tracking marketing
  2. Caricamento dinamico: Modulo di chat carica solo quando attivato, mantenendo il carico iniziale minimo
  3. Auth a tempo limitato: La finestra di 30 secondi impedisce l'analisi indefinita
  4. Fallimento plausibile: Auth non riuscito sembra un widget di supporto rotto
  5. Comunicazione in tempo reale: SignalR permette la chat bidirezionale
  6. Separazione delle preoccupazioni: L'interfaccia del personale di supporto è completamente separata

Che cosa la demo non mostra:

Il sistema di produzione aveva caratteristiche molto più sofisticate non incluse nella demo:

  • Cifratura effettiva (messaggi inviati in chiaro in demo)
  • Codice obfusivo/minificato (il codice demo è leggibile)
  • Imbottitura del traffico e randomizzazione dei tempi
  • Protocolli di scambio chiave sicuri
  • Rotazione token di sessione
  • Limitazioni delle tariffe e prevenzione degli abusi
  • Registrazione completa dell'audit
  • Misure antiforensi
  • E dozzine di altri livelli di sicurezza...

Il sistema di costruzione: obfuscation e minification

Un aspetto critico dei sistemi steganografici sta rendendo il codice difficile da analizzare. La demo include un semplice sistema di costruzione che dimostra tecniche di offuscamento di base.

Da sorgente a script dislocato

Ecco il processo di trasformazione:

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

Codice sorgente (Readable)

La fonte è pulita e comprensibile:

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

Versione offuscata (distribuita)

Dopo l'offuscazione, le stringhe vengono divise e codificate:

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

Avviso:

  • 'ref' diventa String.fromCharCode(114,101,102)
  • /^newsletter_\d{4}_[a-z]+$/i diventa un array di caratteri
  • 'script' diventa String.fromCharCode(115,99,114,105,112,116)
  • Tutto lo spazio bianco rimosso, i nomi delle variabili accorciati

Genera flusso di processo

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

Tecniche di Obfuscation Dimostrate

1. Codifica stringa

// 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. Dividere le stringhe

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. Codifica XOR (semplice)

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

Che cosa aggiungerebbe la produzione

I sistemi di produzione reali comprenderebbero:

  1. Schemi di cifratura personalizzati

    • Chiavi di decrittazione bloccate a dominio
    • Derivazione della chiave basata sul tempo
    • Cifratura specifica per l'ambiente
  2. Obfuscazione del flusso di controllo

    • Strutture di controllo appiattite
    • Sostituire if/else con tabelle di ricerca
    • Aggiungi rami condizionali fasulli
  3. Manipolazione AST

    • Ristrutturare il codice a livello dell'albero di sintassi
    • Trasforma le espressioni in forme equivalenti
    • Inietta codice morto che sembra legittimo
  4. Anti-debug

    • Rileva la presenza del debug
    • Verifica dei tempi per rilevare un singolo passo
    • Codice automodificante
    • Impronte digitali ambientali
  5. Obfuscation del traffico

    • Pad messaggi a dimensioni fisse
    • Ritardi nei tempi casuali
    • Generazione del traffico idiota
    • Mimetismo del protocollo

Configurazione e flessibilità

La demo è progettata per essere configurabile per diversi backend:

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

Nell'HTML (sembrano metadati standard):

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

Questo permette allo stesso codice client di lavorare con diverse implementazioni di backend senza modifiche.

Schema di flusso completo

Ecco come funzionano tutti i pezzi insieme:

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

Provalo da solo.

Il codice demo completo è nel repository. Leggi attentamente il README per l'elenco completo degli avvisi di sicurezza. Il codice è fortemente commentato per spiegare ogni concetto.

File chiave da esaminare:

JavaScript (Fonte vs. Obfuscated):

  • wwwroot/js/dev/compatibility-shim1.src.js - Script di trigger leggibile
  • wwwroot/js/compatibility-shim1.js - Trigger offuscato (~400 byte)
  • wwwroot/js/dev/secure-chat.src.js - Applicazione di chat leggibile
  • wwwroot/js/secure-chat.js - Applicazione di chat ridotta (~5KB)

Backend:

  • Hubs/SecureChatHub.cs - Mozzo SignalR per chat in tempo reale
  • Controllers/DemoController.cs - Instradamento pagina

Frontend:

  • Views/Demo/Company.cshtml - Il "sito dell'azienda" con configurazione nascosta
  • Views/Demo/Support.cshtml - Interfaccia personale di supporto

Sistema di generazione:

  • Build/JsObfuscator.cs - Utilità di oscuramento delle corde
  • Build/BuildObfuscated.cs - Strumento di creazione per la creazione di versioni minified
  • build.sh - Script di shell per la costruzione

Ricorda: questo è un applicazione banale del concettoDimostra le idee, non la sicurezza pronta alla produzione.

logo

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