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
Thursday, 20 November 2025
Για να δείξω αυτές τις έννοιες σε δράση, δημιούργησα ένα σχέδιο επίδειξης που δείχνει πώς ένα τέτοιο σύστημα μπορεί να λειτουργήσει. Πρόκειται για μια ασήμαντη εφαρμογή μόνο για εκπαιδευτικούς σκοπούς και σκόπιμα περιλαμβάνει ελάχιστη ασφάλεια για να κρατήσει τον κώδικα ευανάγνωστο και κατανοητό.
Ο κωδικός 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
Mostlylucid.SecureChat.Demodotnet build && dotnet runhttp://localhost:5000/Demo/Company?ref=newsletter_2025_janSAFE2025/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) πριν από τον έλεγχο για τη σκανδάλη.
Το 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.
}
Όταν ενεργοποιείται, η μονάδα συνομιλίας δημιουργεί ένα παράθυρο τρόπου λειτουργίας με αντίστροφη μέτρηση ταυτότητας 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);
}
Core Concepts Illustrated:
?ref=newsletter_2025_jan Μοιάζει με ανίχνευση μάρκετινγκ.Τι δεν δείχνει το 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
Η πηγή είναι καθαρή και κατανοητή:
// 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)})";
}
Τα πραγματικά συστήματα παραγωγής θα περιλαμβάνουν:
Προσαρμοσμένα σχήματα κρυπτογράφησης
Παρακώλυση ροής ελέγχου
Χειρισμός AST
Κατά της αποσφαλμάτωσης
Εμπόδιση της κυκλοφορίας
Το 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 chatControllers/DemoController.cs - Ροή σελίδαςFrontend:
Views/Demo/Company.cshtml - Η "εταιρεία ιστοσελίδα" με κρυφό configViews/Demo/Support.cshtml - Διεπαφή προσωπικού υποστήριξηςΣύστημα κατασκευής:
Build/JsObfuscator.cs - Βοηθητικά προγράμματα για την αφαίρεση των χορδώνBuild/BuildObfuscated.cs - Εργαλείο κατασκευής για τη δημιουργία εμπλουτισμένων εκδόσεωνbuild.sh - Shell script for buildingΝα θυμάστε: ασήμαντη εφαρμογή της έννοιαςΔείχνει ιδέες, όχι την ασφάλεια της παραγωγής.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.