Back to "Εφαρμογή Demo: Μια Trivial Απόδειξη της Έννοιας"

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

Εφαρμογή Demo: Μια Trivial Απόδειξη της Έννοιας

Thursday, 20 November 2025

Για να δείξω αυτές τις έννοιες σε δράση, δημιούργησα ένα σχέδιο επίδειξης που δείχνει πώς ένα τέτοιο σύστημα μπορεί να λειτουργήσει. Πρόκειται για μια ασήμαντη εφαρμογή μόνο για εκπαιδευτικούς σκοπούς και σκόπιμα περιλαμβάνει ελάχιστη ασφάλεια για να κρατήσει τον κώδικα ευανάγνωστο και κατανοητό.

Κρίσιμη Προειδοποίηση για το Demo

Ο κωδικός demo έχει πολλές αδυναμίες ασφαλείας και δεν είναι κατάλληλος για χρήση σε πραγματικό κόσμο. Έχει σχεδιαστεί για να επιδεικνύει έννοιες, δεν πρέπει να αναπτυχθεί. Δείτε την πλήρη λίστα των θεμάτων ασφαλείας στο README του demo.

Δομή έργου επίδειξης

Το demo είναι ένα ξεχωριστό έργο ASP.NET Core 9.0 στο αποθετήριο στο Mostlylucid.SecureChat.Demo/ με τα ακόλουθα συστατικά μέρη:

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

Πώς να Εκτελέσετε το Demo

  1. Κλείστε το αποθετήριο και περιηγηθείτε στο Mostlylucid.SecureChat.Demo
  2. Τρέξε. dotnet build && dotnet run
  3. Άνοιγμα προγράμματος περιήγησης σε http://localhost:5000/Demo/Company
  4. Προσθήκη παραμέτρου ενεργοποίησης: ?ref=newsletter_2025_jan
  5. Εισάγετε κωδικό όταν σας ζητηθεί: SAFE2025
  6. Σε άλλη καρτέλα, ανοιχτή /Demo/Support να ανταποκριθεί ως προσωπικό υποστήριξης

Το Μικροσκοπικό Σενάριο Σκανδάλης

Εδώ είναι ο πραγματικός κωδικός από compatibility-shim1.js - σημειώστε πόσο μικρό και αβλαβές είναι:

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

Αυτό το σενάριο είναι μόνο ~1KB και κάνει δύο νόμιμα πράγματα (ελέγχων συμβατότητας browser) πριν από τον έλεγχο για τη σκανδάλη.

Το πλήκτρο Signer

Το backend χρησιμοποιεί το SignalR για αμφίδρομη επικοινωνία σε πραγματικό χρόνο. Εδώ είναι η απλοποιημένη δομή κόμβου:

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

The Client-Side Chat

Όταν ενεργοποιείται, η μονάδα συνομιλίας δημιουργεί ένα παράθυρο τρόπου λειτουργίας με αντίστροφη μέτρηση ταυτότητας 30 δευτερολέπτων:

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

Εάν αποτύχει η ταυτοποίηση ή φορές έξω, το σύστημα ανακατευθύνει σε ένα URL οπισθοδρόμησης (αποθηκευμένο σε μια κρυφή ετικέτα meta στη σελίδα):

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

Τι Δείχνει το Demo

Core Concepts Illustrated:

  1. Κρυφό ΤρίγκερCity name (optional, probably does not need a translation): παράμετρος URL ?ref=newsletter_2025_jan Μοιάζει με ανίχνευση μάρκετινγκ.
  2. Δυναμική φόρτωση: Η μονάδα συνομιλίας φορτώνει μόνο όταν ενεργοποιείται, κρατώντας το αρχικό ωφέλιμο φορτίο μικροσκοπικό
  3. Χρονοκατοικημένη Auth: 30-δευτερόλεπτο παράθυρο αποτρέπει την αόριστη εξέταση
  4. Πιθανή Αποτυχία: Αποτυχημένο auth μοιάζει με ένα σπασμένο widget υποστήριξης
  5. Επικοινωνία σε πραγματικό χρόνο: SignalR επιτρέπει αμφίδρομη συνομιλία
  6. Διαχωρισμός των Ανησυχιών: Η διεπαφή προσωπικού υποστήριξης είναι εντελώς ξεχωριστή

Τι δεν δείχνει το Demo:

Το σύστημα παραγωγής είχε πολύ πιο εξελιγμένα χαρακτηριστικά που δεν περιλαμβάνονται στο demo:

  • Πραγματική κρυπτογράφηση (μηνύματα που αποστέλλονται με απλό κείμενο σε demo)
  • Αδιευκρίνιστος/εμπλουτισμένος κωδικός (ο κωδικός δαίμονας είναι ευανάγνωστος)
  • Τυχαιοποίηση της κυκλοφορίας και του συγχρονισμού
  • Ασφαλή βασικά πρωτόκολλα ανταλλαγής
  • Περιστροφή σημειώματος συνεδρίας
  • Ποσοστό περιορισμού και πρόληψης κατάχρησης
  • Πλήρης καταγραφή του ελέγχου
  • Μέτρα κατά της Σήμανσης
  • Και δεκάδες άλλα στρώματα ασφαλείας...

Το Σύστημα Κατασκευής: Παρακώλυση και Μίμηση

Μια κρίσιμη πτυχή των στεγανογραφικών συστημάτων δυσκολεύει την ανάλυση του κώδικα. Το demo περιλαμβάνει ένα απλό σύστημα κατασκευής που δείχνει βασικές τεχνικές άμβλωσης.

Από την Πηγή στο Απασχολημένο Σενάριο

Εδώ είναι η διαδικασία μεταμόρφωσης:

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

Πηγαίος κώδικας (Readable)

Η πηγή είναι καθαρή και κατανοητή:

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

Επηρεασμένη έκδοση (απασχολούμενη)

Μετά την αποσύνθεση, οι χορδές χωρίζονται και κωδικοποιούνται:

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

Ειδοποίηση:

  • 'ref' γίνεται String.fromCharCode(114,101,102)
  • /^newsletter_\d{4}_[a-z]+$/i γίνεται μια σειρά χαρακτήρων
  • 'script' γίνεται String.fromCharCode(115,99,114,105,112,116)
  • Απομακρύνθηκε όλος ο λευκός χώρος, συντομεύτηκε η μεταβλητή ονομασία

Κατασκευή ροής διαδικασίας

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

Επιδειγμένες τεχνικές διαβρώσεως

1. Κωδικοποίηση συμβολοσειρών

// 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. Διαχωρισμός χορδών

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 (Απλό)

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

Τι θα πρόσθετε η Παραγωγή

Τα πραγματικά συστήματα παραγωγής θα περιλαμβάνουν:

  1. Προσαρμοσμένα σχήματα κρυπτογράφησης

    • Κλειδωμένα στον τομέα κλειδιά αποκρυπτογράφησης
    • Προθεσμιακή βασική παραγωγή
    • Κρυπτογράφηση ειδικού για το περιβάλλον
  2. Παρακώλυση ροής ελέγχου

    • Επιπεδωμένες δομές ελέγχου
    • Αντικατάσταση if/else με πίνακες αναζήτησης
    • Προσθήκη ψεύτικων κλαδιών υπό όρους
  3. Χειρισμός AST

    • Κωδικός αναδόμησης σε επίπεδο δέντρου σύνταξης
    • Μεταμορφώστε εκφράσεις σε ισοδύναμες μορφές
    • Ένεση νεκρού κώδικα που φαίνεται νόμιμο
  4. Κατά της αποσφαλμάτωσης

    • Ανίχνευση παρουσίας αποσφαλματωτή
    • Έλεγχος συγχρονισμού για την ανίχνευση μονοβήματος
    • Αυτοτροποποιητής κωδικός
    • Περιβαλ λοντική λήψη δακτυλικών αποτυπωμάτων
  5. Εμπόδιση της κυκλοφορίας

    • Μήνυμα pad σε σταθερά μεγέθη
    • Τυχαία καθυστέρηση χρόνου
    • Χαζή παραγωγή κίνησης
    • Μιμητισμός πρωτοκόλλου

Διαμόρφωση και ευελιξία

Το demo έχει σχεδιαστεί για να είναι ρυθμιζόμενο για διαφορετικά backends:

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

Στο HTML (μοιάζει με τυποποιημένα μεταδεδομένα):

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

Αυτό επιτρέπει στον ίδιο κωδικό πελάτη να λειτουργεί με διαφορετικές εφαρμογές backend χωρίς τροποποίηση.

Πλήρες διάγραμμα ροής

Εδώ είναι πώς όλα τα κομμάτια λειτουργούν μαζί:

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

Δοκίμασέ το μόνος σου.

Ο πλήρης κωδικός επίδειξης βρίσκεται στο αποθετήριο. Διαβάστε προσεκτικά το README για την πλήρη λίστα προειδοποιήσεων ασφαλείας. Ο κώδικας σχολιάζεται πολύ για να εξηγήσει κάθε έννοια.

Βασικά αρχεία για την εξέταση:

JavaScript (Πηγή εναντίον Εμπρησμού):

  • wwwroot/js/dev/compatibility-shim1.src.js - Readable script σκανδάλης
  • wwwroot/js/compatibility-shim1.js - Αδιευκρίνιστη σκανδάλη (~400 ψηφιολέξεις)
  • wwwroot/js/dev/secure-chat.src.js - Αναγνωστή εφαρμογή συνομιλίας
  • wwwroot/js/secure-chat.js - Μινοποιημένη εφαρμογή συνομιλίας (~5KB)

Σύστημα υποστήριξης:

  • Hubs/SecureChatHub.cs - SignalR hub for real-time chat
  • Controllers/DemoController.cs - Ροή σελίδας

Frontend:

  • Views/Demo/Company.cshtml - Η "εταιρεία ιστοσελίδα" με κρυφό config
  • Views/Demo/Support.cshtml - Διεπαφή προσωπικού υποστήριξης

Σύστημα κατασκευής:

  • Build/JsObfuscator.cs - Βοηθητικά προγράμματα για την αφαίρεση των χορδών
  • Build/BuildObfuscated.cs - Εργαλείο κατασκευής για τη δημιουργία εμπλουτισμένων εκδόσεων
  • build.sh - Shell script for building

Να θυμάστε: ασήμαντη εφαρμογή της έννοιαςΔείχνει ιδέες, όχι την ασφάλεια της παραγωγής.

logo

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