
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil V): Zwei-Faktoren-Authentifizierung (2FA)
Inhalt:
- Einführung
- Was ist die Zwei-Faktoren-Authentifizierung (2FA)?
- Implementierung der Zwei-Faktor-Authentifizierung (2FA) im Verwaltungsbereich mit MQL5
- Implementierung von GUI-Elementen für die Passworteingabe und 2FA-Code-Validierung
- Algorithmus zur Erzeugung von Verifizierungscodes
- Verstehen der Funktion MathRand()
- Telegram API für 2FA-Verifizierung
- Tests und Ergebnisse
- Schlussfolgerung
Einführung
Zuvor haben wir uns mit der Implementierung der Passwort-Authentifizierung im Admin-Panel befasst, die einen wichtigen ersten Schritt zur Sicherung der Kommunikation zwischen Administratoren und Händlern darstellt. Diese grundlegende Form der Sicherheit ist zwar für den anfänglichen Schutz unerlässlich, kann diese Systeme jedoch aufgrund der Abhängigkeit von einem einzigen Überprüfungsfaktor potenziell angreifbar machen. Die Integration der Zwei-Faktor-Authentifizierung (2FA) wird zu einem wichtigen Upgrade, das einen robusteren Sicherheitsrahmen für unsere Anwendung bietet.
Dieser Ansatz mindert das Risiko eines unbefugten Zugriffs erheblich, da er neben der Kenntnis des Kennworts auch den Zugriff auf die sekundäre Überprüfungsmethode erfordert. 2FA stellt sicher, dass die gesamte Kommunikation aus legitimen Quellen stammt, und schützt so vor den potenziellen Folgen von kompromittierten Daten, Fehlinformationen und Marktmanipulation.
Durch die Integration von 2FA in unser Admin-Panel können wir den Nutzern ein höheres Maß an Vertrauen und Sicherheit bieten. Dieses doppelte Authentifizierungssystem wirkt als wirksame Abschreckung gegen potenzielle Verstöße und gibt sowohl Administratoren als auch Händlern die Sicherheit, in einer dynamischen Finanzlandschaft zu agieren. Heute werden wir ein Konzept diskutieren, das ich erfolgreich in eine funktionierende Lösung umgewandelt habe. Mit dieser Initiative wurde die Sicherheit unseres Admin-Panels als Reaktion auf die Schwachstellen im Zusammenhang mit der im vorigen Artikel der Serie implementierten Passcode-Sicherheit verstärkt.
Was ist Zwei-Faktor-Authentifizierung?
Die Zwei-Faktor-Authentifizierung (2FA) ist ein Sicherheitsmechanismus, der zwei verschiedene Formen der Verifizierung erfordert, bevor der Zugriff auf ein Konto oder System gewährt wird. Sie ist eine Untergruppe der Multifaktor-Authentifizierung (MFA), die zwei oder mehr Verifizierungsfaktoren umfassen kann. Das Hauptziel von 2FA ist es, neben dem Nutzernamen und dem Kennwort eine weitere Sicherheitsebene hinzuzufügen, die es unbefugten Nutzern erschwert, Zugang zu erhalten.
Einigen Quellen zufolge umfasst 2FA in der Regel zwei der folgenden drei Kategorien von Authentifizierungsfaktoren:
- Etwas, das Sie wissen (Wissensfaktor): Dabei handelt es sich in der Regel um ein Passwort oder eine PIN, die der Nutzer eingeben muss, um auf sein Konto zuzugreifen. Sie dient als erste Verteidigungslinie.
- Etwas, das Sie haben (Besitzfaktor): Dabei handelt es sich um ein physisches Gerät oder ein Token, das der Nutzer besitzt, z. B. ein Sicherheits-Token, eine Smartcard oder ein Mobiltelefon. Viele Systeme verwenden Anwendungen wie Google Authenticator oder Authy, um Einmal-Passwörter (OTPs) zu generieren, die in der Regel nur für einen kurzen Zeitraum (in der Regel 15 Minuten) gültig sind.
- Etwas, das Sie sind (biometrischer Faktor): Dieser Aspekt kann die Erkennung von Fingerabdrücken, Gesichtern oder anderen biometrischen Daten umfassen. Biometrie wird zwar nicht immer zusammen mit den ersten beiden Faktoren für 2FA verwendet, kann aber eine zusätzliche Sicherheitsebene bieten.
Implementierung der Zwei-Faktor-Authentifizierung (2FA) im Verwaltungsbereich mit MQL5
Durch die Integration von 2FA gehen wir über die herkömmliche Ein-Faktor-Authentifizierung (SFA) hinaus, die sich in der Regel ausschließlich auf Nutzernamen und Passwörter stützt. Dieser Wandel ist von entscheidender Bedeutung, da Passwörter zwar nach wie vor die gängigste Form der anfänglichen Sicherheit darstellen, aber von Natur aus anfällig für verschiedene Arten von Angriffen sind, darunter Social Engineering, Brute-Force- und Wörterbuchangriffe. Der Multifaktor-Ansatz der 2FA mindert diese Risiken wirksam, indem er von den Nutzern zwei verschiedene Formen der Authentifizierung verlangt, die zu unterschiedlichen Kategorien gehören, wodurch das Vertrauen gestärkt wird, dass der Zugang wirklich nur legitimen Nutzern gewährt wird.
Um 2FA in unserem Admin-Panel-Projekt zu implementieren, habe ich die Dialog-Bibliothek genutzt, die es uns ermöglicht, mehrere Fensterebenen zu erstellen, die durch eine bestimmte Logik gesteuert werden. Zu Beginn dieser Serie haben wir die Telegram-Kommunikation integriert, wobei wir uns in erster Linie auf die Übermittlung von Nachrichten aus dem Admin-Panel an Nutzerkanäle oder Gruppen auf Telegram konzentriert haben. Sein Potenzial geht jedoch darüber hinaus; wir wollen es auch für die OTP-Übermittlung nutzen.
In diesem Projekt werden wir unseren Code so anpassen, dass er einen zufälligen sechsstelligen Code generiert, den das Programm sicher speichert und anschließend zur Überprüfung an Telegram des Administrators sendet. Mir ist aufgefallen, dass viele Unternehmen Telegram für die Verifizierung nutzen, wenn auch mit anderen Ansätzen als denen, die wir hier umsetzen werden. In der Abbildung unten sehen Sie beispielsweise den MQL5 Überprüfungsbot, der uns als Beispiel für eine solche Verwendung dient.
MQL5-Überprüfungsbot
Implementierung von GUI-Elementen für die Passworteingabe und 2FA-Code-Validierung
Bei der Implementierung des Kennworteingabe-Dialogs beginnen wir mit der Definition der Funktion ShowAuthenticationPrompt(), die alle erforderlichen Schritte zur Erstellung einer Nutzeroberfläche für die Kennworteingabe kapselt. Der Prozess beginnt mit der Instanziierung des Authentifizierungsdialogs mit der Methode Create(), wobei die Abmessungen und die Position im Chart angegeben werden. Für die Nutzereingabe erstellen wir passwordInputBox, um das Passwort des Nutzers sicher zu erfassen. Anschließend wird passwordPromptLabelhinzugefügt, um dem Nutzer klare Anweisungen zu geben und ihn über den Zweck des Dialogs zu informieren. Um Nutzerrückmeldungen, insbesondere bei fehlerhaften Eingaben, zu verarbeiten, wurde ein feedbackLabel implementiert, bei dem Fehlermeldungen in roter Schrift angezeigt werden, damit der Nutzer besser versteht, was falsch gelaufen ist. Als Nächstes richten wir zwei Schaltflächen ein:
- einen loginButton, auf den der Nutzer klicken kann, um sein Passwort zur Authentifizierung zu übermitteln, und
- eine closeAuthButton, die es ihm ermöglicht, das Dialogfeld zu verlassen, wenn er nicht fortfahren möchten.
Schließlich rufen wir show() für den Authentifizierungsdialog auf, um ihn dem Nutzer zu präsentieren, und rufen ChartRedraw() auf, um sicherzustellen, dass alle Komponenten korrekt auf dem Bildschirm dargestellt werden. Dieser systematische Ansatz gewährleistet eine sichere und nutzerfreundliche Schnittstelle für die Passworteingabe im Admin Panel. Siehe den nächsten Codeschnipsel.
Erstellung eines Dialogs zur Passworteingabe
// Show authentication input dialog bool ShowAuthenticationPrompt() { if (!authentication.Create(ChartID(), "Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create authentication dialog"); return false; } // Create password input box if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95)) { Print("Failed to create password input box"); return false; } authentication.Add(passwordInputBox); // Create password prompt label if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 40)) { Print("Failed to create password prompt label"); return false; } passwordPromptLabel.Text("Enter password: Access Admin Panel"); authentication.Add(passwordPromptLabel); // Create feedback label for wrong attempts if (!feedbackLabel.Create(ChartID(), "FeedbackLabel", 0, 20, 140, 380, 40)) { Print("Failed to create feedback label"); return false; } feedbackLabel.Text(""); feedbackLabel.Color(clrRed); // Set color for feedback authentication.Add(feedbackLabel); // Create login button if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 40)) { Print("Failed to create login button"); return false; } loginButton.Text("Login"); authentication.Add(loginButton); // Create close button for authentication dialog if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 40)) { Print("Failed to create close button for authentication"); return false; } closeAuthButton.Text("Close"); authentication.Add(closeAuthButton); authentication.Show(); ChartRedraw(); return true; }
Erstellung eines Dialogs zur Validierung des 2FA-Codes
Um den 2FA-Code-Validierungsdialog zu erstellen, definieren wir die Funktion ShowTwoFactorAuthPrompt(), die alle für die Überprüfung des Zwei-Faktor-Authentifizierungscodes des Nutzers erforderlichen Komponenten verarbeitet.
Wir beginnen mit der Erstellung des Dialogfelds twoFactorAuth und verwenden wiederum die Methode Create(), um seine Eigenschaften festzulegen. Die erste hinzugefügte Komponente ist twoFACodeInput, ein Eingabefeld zur sicheren Erfassung des 2FA-Codes, der an Telegram des Nutzers gesendet wird.
Um den Nutzer zu führen, implementieren wir ein twoFAPromptLabel, das ihn eindeutig anweist, den erhaltenen 2FA-Code einzugeben. Um die Nutzerfreundlichkeit weiter zu verbessern, wird twoFAFeedbackLabel zur Anzeige von Echtzeit-Rückmeldungen eingefügt. Es zeigt Meldungen in Rot an, wenn der eingegebene Code nicht mit dem erwarteten Wert übereinstimmt, und informiert den Nutzer so über falsche Eingaben.
Für die Übermittlung wird twoFALoginButton erstellt, der es dem Nutzer ermöglicht, seinen Code zu verifizieren, während der close2FAButton zum Verlassen des Dialogs vorgesehen ist, falls erforderlich. Sobald die Komponenten eingerichtet sind, rufen wir Show() für das Dialogfeld twoFactorAuth auf, um es für den Nutzer sichtbar zu machen, und rufen ChartRedraw() auf, um die Schnittstelle zu aktualisieren.
Dieser strukturierte Ansatz gewährleistet eine sichere Methode zur Validierung von 2FA-Codes und eine optimierte Nutzerinteraktion im Verwaltungsbereich. Zum besseren Verständnis finden Sie nachstehend einen Codeausschnitt.
// Show two-factor authentication input dialog void ShowTwoFactorAuthPrompt() { if (!twoFactorAuth.Create(ChartID(), "Two-Factor Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create 2FA dialog"); return; } // Create input box for 2FA code if (!twoFACodeInput.Create(ChartID(), "TwoFACodeInput", 0, 20, 70, 260, 95)) { Print("Failed to create 2FA code input box"); return; } twoFactorAuth.Add(twoFACodeInput); // Create prompt label for 2FA if (!twoFAPromptLabel.Create(ChartID(), "TwoFAPromptLabel", 0, 20, 20, 380, 40)) { Print("Failed to create 2FA prompt label"); return; } twoFAPromptLabel.Text("Enter the 2FA code sent to your Telegram:"); twoFactorAuth.Add(twoFAPromptLabel); // Create feedback label for wrong attempts if (!twoFAFeedbackLabel.Create(ChartID(), "TwoFAFeedbackLabel", 0, 20, 140, 380, 40)) { Print("Failed to create 2FA feedback label"); return; } twoFAFeedbackLabel.Text(""); twoFAFeedbackLabel.Color(clrRed); // Set color for feedback twoFactorAuth.Add(twoFAFeedbackLabel); // Create login button for 2FA code submission if (!twoFALoginButton.Create(ChartID(), "TwoFALoginButton", 0, 20, 120, 100, 40)) { Print("Failed to create 2FA login button"); return; } twoFALoginButton.Text("Verify"); twoFactorAuth.Add(twoFALoginButton); // Create close button for 2FA dialog if (!close2FAButton.Create(ChartID(), "Close2FAButton", 0, 120, 120, 200, 40)) { Print("Failed to create close button for 2FA"); return; } close2FAButton.Text("Close"); twoFactorAuth.Add(close2FAButton); twoFactorAuth.Show(); ChartRedraw(); }
Algorithmus zur Erzeugung von Verifizierungscodes
Nach der erfolgreichen Eingabe des Passworts für den Zugang zum Admin-Panel haben wir eine zweite Schutzebene eingerichtet, die die Generierung eines OTP-Codes beinhaltet. Dieser Code wird sicher gespeichert und an eine eindeutige, fest codierte Chat-ID weitergeleitet, die mit der Telegram-App verknüpft ist, entweder auf dem Mobiltelefon oder auf dem Desktop, wo der rechtmäßige Besitzer ihn für die weitere Eingabe in die Eingabeaufforderung abrufen kann. Wenn der eingegebene Code übereinstimmt, gewährt die Anwendung Zugriff auf alle Funktionen des Admin-Panels für Operationen und Kommunikation.
Was den Algorithmus zur Codegenerierung betrifft, so werde ich die verschiedenen Komponenten in den folgenden Codeschnipseln erläutern:
Die unten stehende Codezeile dient als wichtige Variablendeklaration für die Verwaltung der Zwei-Faktor-Authentifizierung (2FA) in unserem Programm.
string twoFACode = "";
Diese Zeile initialisiert die Variable twoFACode als leere Zeichenkette, die zum Speichern eines zufällig generierten 6-stelligen Codes für die zweistufige Authentifizierung verwendet wird. Während des gesamten Authentifizierungsprozesses spielt diese Variable eine wichtige Rolle, da sie den tatsächlichen Code enthält, der dem Nutzer über Telegram zugesandt wird, nachdem er erfolgreich das richtige Passwort für den Zugriff auf das Admin Panel eingegeben hat.
Wenn der Nutzer die anfängliche Kennwortprüfung besteht, wird die Variable twoFACode mit einem neuen Wert gefüllt, der von der Funktion GenerateRandom6DigitCode() erzeugt wird, die eine 6-stellige numerische Zeichenfolge erzeugt. Dieser Wert wird dann mit der Funktion SendMessageToTelegram() an Telegram des Nutzers gesendet.
Wenn der Nutzer später aufgefordert wird, seinen 2FA-Code einzugeben, vergleicht das Programm die Eingabe des Nutzers mit diesem in twoFACode gespeicherten Wert. Wenn die Eingabe des Nutzers mit dem Wert in twoFACode übereinstimmt, wird der Zugang zum Admin-Panel gewährt; andernfalls wird eine Fehlermeldung angezeigt.
1. Passwort-Authentifizierung:
string Password = "2024"; // Hardcoded password // Handle login button click void OnLoginButtonClick() { string enteredPassword = passwordInputBox.Text(); if (enteredPassword == Password) { twoFACode = GenerateRandom6DigitCode(); SendMessageToTelegram("Your 2FA code is: " + twoFACode, Hardcoded2FAChatId, Hardcoded2FABotToken); authentication.Destroy(); ShowTwoFactorAuthPrompt(); Print("Password authentication successful. A 2FA code has been sent to your Telegram."); } else { feedbackLabel.Text("Wrong password. Try again."); passwordInputBox.Text(""); } }
Ein fest codiertes Passwort (2024) dient als Zugangskontrolle für das Admin Panel. Wenn der Nutzer das eingegebene Kennwort in das dafür vorgesehene Eingabefeld eingibt, prüft der Code, ob die Eingabe mit dem fest codierten Kennwort übereinstimmt. Wenn er übereinstimmt, wird mit der Funktion GenerateRandom6DigitCode() ein zufälliger 6-stelliger Code generiert und über die Funktion SendMessageToTelegram()an Telegram des Nutzers gesendet. Dies zeigt eine erfolgreiche Authentifizierung an und fordert die Anwendung auf, zur Zwei-Faktor-Authentifizierung überzugehen. Wenn das Passwort falsch ist, wird der Nutzer durch eine Fehlermeldung aufgefordert, es erneut zu versuchen.
2. Generierung und Übermittlung von Zwei-Faktor-Authentifizierungscodes:
// Generate a random 6-digit code for 2FA string GenerateRandom6DigitCode() { int code = MathRand() % 1000000; // Produces a 6-digit number return StringFormat("%06d", code); // Ensures leading zeros } // Handle 2FA login button click void OnTwoFALoginButtonClick() { string enteredCode = twoFACodeInput.Text(); if (enteredCode == twoFACode) { twoFactorAuth.Destroy(); adminPanel.Show(); Print("2FA authentication successful."); } else { twoFAFeedbackLabel.Text("Wrong code. Try again."); twoFACodeInput.Text(""); } }
Dieser Bereich verwaltet die Zwei-Faktor-Authentifizierung (2FA), indem er einen eindeutigen 6-stelligen Code generiert und die Nutzereingaben anhand dieses Codes überprüft. Die Funktion GenerateRandom6DigitCode() generiert mit Hilfe der Funktion MathRand() eine 6-stellige Zahl, wobei sichergestellt wird, dass sie auch bei führenden Nullen das erforderliche Format beibehält. Nach der Überprüfung des Anfangspassworts wird dieser 6-stellige Code über Telegram an den angegebenen Chat des Nutzers gesendet, um die Sicherheit zu erhöhen. In der folgenden Funktion OnTwoFALoginButtonClick() werden die Eingaben des Nutzers mit dem generierten Code verglichen. Wenn der eingegebene Code mit dem an Telegram gesendeten Code übereinstimmt, wird der Zugang zum Verwaltungsbereich gewährt; andernfalls wird der Nutzer über den falschen Code informiert und aufgefordert, es erneut zu versuchen
Die Funktion MathRand()
Diese Funktion in MQL5 wird verwendet, um eine pseudo-zufällige Ganzzahl zu erzeugen. Im Falle unseres Projekts erzeugt die Funktion MathRand() eine zufällige Ganzzahl im Bereich von 0 bis MathRandMax(), der normalerweise als 0 bis 32767 definiert ist.
Um eine 6-stellige Zufallszahl zu erzeugen, können Sie die Ausgabe mit dem Modulo-Operator (%) begrenzen. Dieser Operator berechnet den Rest einer Division und ermöglicht es Ihnen, den Bereich der Zufallszahlen so einzuschränken, dass er zu den gültigen 6-stelligen Werten passt, die von 000000 (0) bis 999999 reichen.
Insbesondere die Verwendung des Ausdrucks MathRand() % 1000000 ergibt ein Ergebnis zwischen 0 und 999999, wodurch sichergestellt wird, dass alle möglichen 6-stelligen Kombinationen, einschließlich derer mit führenden Nullen, abgedeckt sind.
Telegram API für 2FA-Verifizierung
Die Funktion SendMessageToTelegram() ist wichtig, um sicherzustellen, dass unsere 2FA-Codes und andere Nachrichten sicher an den Telegram-Chat des Nutzers übermittelt werden. Diese Funktion erstellt eine HTTP-POST-Anfrage an die Telegram Bot API, einschließlich des Bot-Tokens und der Ziel-Chat-ID. Die Nachricht wird in JSON formatiert, um die Anforderungen der API zu erfüllen.
Die Funktion WebRequest() führt die Anfrage mit einer bestimmten Zeitüberschreitung aus, und die Funktion prüft den Antwortcode, um zu bestätigen, dass die Nachricht erfolgreich gesendet wurde (HTTP-Code 200).
Wenn die Nachrichtenübermittlung fehlschlägt, protokolliert die Funktion einen Fehler, einschließlich des Antwortcodes, der Fehlermeldung und des relevanten Antwortinhalts, um mögliche Probleme beim Senden von Nachrichten für weitere Diagnosen zu identifizieren.
Um mehr über die Telegram API zu erfahren, können Sie deren Website besuchen und einige frühere Artikel lesen, in denen wir sie erklärt haben.
bool SendMessageToTelegram(string message, string chatId, string botToken) { string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; char postData[]; ArrayResize(postData, StringToCharArray(jsonMessage, postData) - 1); int timeout = 5000; char result[]; string responseHeaders; int responseCode = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, postData, result, responseHeaders); if (responseCode == 200) { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", responseCode, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } }
Als Teil der Telegram-API haben wir die folgenden Konstanten in unser Projekt integriert, um den Prozess der Zwei-Faktor-Authentifizierung (2FA) über Telegram zu erleichtern.
// Constants for 2FA const string Hardcoded2FAChatId = "REPLACE WITH YOUR CHAT ID"; const string Hardcoded2FABotToken = "REPLACE WITH YOUR ACTUAL BOT TOKEN";
In diesem Teil des Codes stellt die Variable Hardcoded2FAChatId den eindeutigen Chat-ID für den Telegram-Chat dar, an den die Authentifizierungsnachrichten gesendet werden, während Hardcoded2FABotToken das Token für den Telegram-Bot enthält, der zum Senden der Nachrichten verwendet wird.
Das Bot-Token ist wichtig für die Authentifizierung von Anfragen an die Telegram-API und stellt sicher, dass nur ein legitimer Bot mit den richtigen Berechtigungen Nachrichten an den angegebenen Chat senden kann. Durch die Festcodierung dieser Konstanten rationalisiert das Programm den Prozess der Übermittlung von 2FA-Codes, da jedes Mal dieselbe Chat-ID und dasselbe Bot-Token verwendet werden, ohne dass eine Nutzereingabe oder Konfiguration erforderlich ist.
Es ist jedoch zu beachten, dass das Festcodieren sensibler Informationen wie Bot-Tokens ein Sicherheitsrisiko darstellen kann, wenn der Code offengelegt wird, weshalb für Produktionsumgebungen alternative sichere Speichermethoden in Betracht gezogen werden sollten.
Der Gesamtcode wird hier vorgestellt, und wir können feststellen, dass er mit der Implementierung neuer Funktionen erheblich erweitert wird.
//+------------------------------------------------------------------+ //| Admin Panel.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property description "A secure and responsive Admin Panel. Send messages to your telegram clients without leaving MT5" #property version "1.20" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> #include <Controls\Label.mqh> // Input parameters for quick messages input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "YOUR_CHAT_ID"; input string InputBotToken = "YOUR_BOT_TOKEN"; // Constants for 2FA const string Hardcoded2FAChatId = "ENTER YOUR REAL CHAT ID"; const string Hardcoded2FABotToken = "ENTER YOUR Telegram Bot Token"; // Global variables CDialog adminPanel; CDialog authentication, twoFactorAuth; CButton sendButton, clearButton, changeFontButton, toggleThemeButton; CButton loginButton, closeAuthButton, twoFALoginButton, close2FAButton; CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton; CEdit inputBox, passwordInputBox, twoFACodeInput; CLabel charCounter, passwordPromptLabel, feedbackLabel, twoFAPromptLabel, twoFAFeedbackLabel; bool minimized = false; bool darkTheme = false; int MAX_MESSAGE_LENGTH = 4096; string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman" }; int currentFontIndex = 0; string Password = "2024"; // Hardcoded password string twoFACode = ""; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminPanel.Create(ChartID(), "Admin Panel", 0, 30, 30, 500, 500)) { Print("Failed to create admin panel dialog"); return INIT_FAILED; } if (!CreateControls()) { Print("Control creation failed"); return INIT_FAILED; } adminPanel.Hide(); Print("Initialization complete"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Show authentication input dialog | //+------------------------------------------------------------------+ bool ShowAuthenticationPrompt() { if (!authentication.Create(ChartID(), "Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create authentication dialog"); return false; } if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95)) { Print("Failed to create password input box"); return false; } authentication.Add(passwordInputBox); if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 40)) { Print("Failed to create password prompt label"); return false; } passwordPromptLabel.Text("Enter password: Access Admin Panel"); authentication.Add(passwordPromptLabel); if (!feedbackLabel.Create(ChartID(), "FeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create feedback label"); return false; } feedbackLabel.Text(""); feedbackLabel.Color(clrRed); // Red color for incorrect attempts authentication.Add(feedbackLabel); if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create login button"); return false; } loginButton.Text("Login"); authentication.Add(loginButton); if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for authentication"); return false; } closeAuthButton.Text("Close"); authentication.Add(closeAuthButton); authentication.Show(); ChartRedraw(); return true; } //+------------------------------------------------------------------+ //| Show two-factor authentication input dialog | //+------------------------------------------------------------------+ void ShowTwoFactorAuthPrompt() { if (!twoFactorAuth.Create(ChartID(), "Two-Factor Authentication", 0, 100, 100, 500, 300)) { Print("Failed to create 2FA dialog"); return; } if (!twoFACodeInput.Create(ChartID(), "TwoFACodeInput", 0, 20, 70, 260, 95)) { Print("Failed to create 2FA code input box"); return; } twoFactorAuth.Add(twoFACodeInput); if (!twoFAPromptLabel.Create(ChartID(), "TwoFAPromptLabel", 0, 20, 20, 380, 40)) { Print("Failed to create 2FA prompt label"); return; } twoFAPromptLabel.Text("Enter the 2FA code sent to your Telegram:"); twoFactorAuth.Add(twoFAPromptLabel); if (!twoFAFeedbackLabel.Create(ChartID(), "TwoFAFeedbackLabel", 0, 20, 140, 380, 160)) { Print("Failed to create 2FA feedback label"); return; } twoFAFeedbackLabel.Text(""); twoFAFeedbackLabel.Color(clrRed); // Red color for incorrect 2FA attempts twoFactorAuth.Add(twoFAFeedbackLabel); if (!twoFALoginButton.Create(ChartID(), "TwoFALoginButton", 0, 20, 120, 100, 140)) { Print("Failed to create 2FA login button"); return; } twoFALoginButton.Text("Verify"); twoFactorAuth.Add(twoFALoginButton); if (!close2FAButton.Create(ChartID(), "Close2FAButton", 0, 120, 120, 200, 140)) { Print("Failed to create close button for 2FA"); return; } close2FAButton.Text("Close"); twoFactorAuth.Add(close2FAButton); twoFactorAuth.Show(); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } //+------------------------------------------------------------------+ //| Handle login button click | //+------------------------------------------------------------------+ void OnLoginButtonClick() { string enteredPassword = passwordInputBox.Text(); if (enteredPassword == Password) { twoFACode = GenerateRandom6DigitCode(); SendMessageToTelegram("A login attempt was made on the Admin Panel. Please use this code to verify your identity. " + twoFACode, Hardcoded2FAChatId, Hardcoded2FABotToken); authentication.Destroy(); ShowTwoFactorAuthPrompt(); Print("Password authentication successful. A 2FA code has been sent to your Telegram."); } else { feedbackLabel.Text("Wrong password. Try again."); passwordInputBox.Text(""); } } //+------------------------------------------------------------------+ //| Handle 2FA login button click | //+------------------------------------------------------------------+ void OnTwoFALoginButtonClick() { string enteredCode = twoFACodeInput.Text(); if (enteredCode == twoFACode) { twoFactorAuth.Destroy(); adminPanel.Show(); Print("2FA authentication successful."); } else { twoFAFeedbackLabel.Text("Wrong code. Try again."); twoFACodeInput.Text(""); } } //+------------------------------------------------------------------+ //| Handle close button for authentication | //+------------------------------------------------------------------+ void OnCloseAuthButtonClick() { authentication.Destroy(); ExpertRemove(); // Exit the expert Print("Authentication dialog closed."); } //+------------------------------------------------------------------+ //| Handle close button for 2FA | //+------------------------------------------------------------------+ void OnClose2FAButtonClick() { twoFactorAuth.Destroy(); ExpertRemove(); Print("2FA dialog closed."); } //+------------------------------------------------------------------+ //| Create necessary UI controls | //+------------------------------------------------------------------+ bool CreateControls() { long chart_id = ChartID(); if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95)) { Print("Failed to create input box"); return false; } adminPanel.Add(inputBox); if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 5, 460, 25)) { Print("Failed to create character counter"); return false; } charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH)); adminPanel.Add(charCounter); if (!clearButton.Create(chart_id, "ClearButton", 0, 235, 95, 345, 125)) { Print("Failed to create clear button"); return false; } clearButton.Text("Clear"); adminPanel.Add(clearButton); if (!sendButton.Create(chart_id, "SendButton", 0, 350, 95, 460, 125)) { Print("Failed to create send button"); return false; } sendButton.Text("Send"); adminPanel.Add(sendButton); if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115)) { Print("Failed to create change font button"); return false; } changeFontButton.Text("Font<>"); adminPanel.Add(changeFontButton); if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115)) { Print("Failed to create toggle theme button"); return false; } toggleThemeButton.Text("Theme<>"); adminPanel.Add(toggleThemeButton); if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); adminPanel.Add(maximizeButton); if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); adminPanel.Add(closeButton); return CreateQuickMessageButtons(); } //+------------------------------------------------------------------+ //| Create quick message buttons | //+------------------------------------------------------------------+ bool CreateQuickMessageButtons() { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; for (int i = 0; i < ArraySize(quickMessages); i++) { bool created = quickMessageButtons[i].Create(ChartID(), "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height); if (!created) { Print("Failed to create quick message button ", i + 1); return false; } quickMessageButtons[i].Text(quickMessages[i]); adminPanel.Add(quickMessageButtons[i]); } return true; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { adminPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (StringLen(message) > 0) { if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Handle clear button click | //+------------------------------------------------------------------+ void OnClearButtonClick() { inputBox.Text(""); OnInputChange(); Print("Input box cleared."); } //+------------------------------------------------------------------+ //| Handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick(long index) { string quickMessages[] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; string message = quickMessages[(int)index]; if (SendMessageToTelegram(message, InputChatId, InputBotToken)) Print("Quick message sent: ", message); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Update character counter | //+------------------------------------------------------------------+ void OnInputChange() { int currentLength = StringLen(inputBox.Text()); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle toggle theme button click | //+------------------------------------------------------------------+ void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); } //+------------------------------------------------------------------+ //| Update theme colors for the panel | //+------------------------------------------------------------------+ void UpdateThemeColors() { color textColor = darkTheme ? clrWhite : clrBlack; color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro; color borderColor = darkTheme ? clrSlateGray : clrGray; color bgColor = darkTheme ? clrDarkBlue : clrWhite; UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(maximizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor); } ChartRedraw(); } //+------------------------------------------------------------------+ //| Apply theme settings to a button | //+------------------------------------------------------------------+ void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); } //+------------------------------------------------------------------+ //| Handle change font button click | //+------------------------------------------------------------------+ void OnChangeFontButtonClick() { currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts); SetFontForAll(availableFonts[currentFontIndex]); Print("Font changed to: ", availableFonts[currentFontIndex]); ChartRedraw(); } //+------------------------------------------------------------------+ //| Set font for all input boxes and buttons | //+------------------------------------------------------------------+ void SetFontForAll(string fontName) { inputBox.Font(fontName); clearButton.Font(fontName); sendButton.Font(fontName); toggleThemeButton.Font(fontName); changeFontButton.Font(fontName); minimizeButton.Font(fontName); maximizeButton.Font(fontName); closeButton.Font(fontName); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { quickMessageButtons[i].Font(fontName); } } //+------------------------------------------------------------------+ //| Generate a random 6-digit code for 2FA | //+------------------------------------------------------------------+ string GenerateRandom6DigitCode() { int code = MathRand() % 1000000; // Produces a 6-digit number return StringFormat("%06d", code); // Ensures leading zeros } //+------------------------------------------------------------------+ //| Handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { minimized = true; adminPanel.Hide(); minimizeButton.Hide(); maximizeButton.Show(); closeButton.Show(); Print("Panel minimized."); } //+------------------------------------------------------------------+ //| Handle maximize button click | //+------------------------------------------------------------------+ void OnMaximizeButtonClick() { if (minimized) { adminPanel.Show(); minimizeButton.Show(); maximizeButton.Hide(); closeButton.Hide(); minimized = false; Print("Panel maximized."); } } //+------------------------------------------------------------------+ //| Handle close button click for admin panel | //+------------------------------------------------------------------+ void OnCloseButtonClick() { ExpertRemove(); Print("Admin panel closed."); } //+------------------------------------------------------------------+ //| Send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message, string chatId, string botToken) { string url = "https://api.telegram.org/bot" + botToken + "/sendMessage"; string jsonMessage = "{\"chat_id\":\"" + chatId + "\", \"text\":\"" + message + "\"}"; char postData[]; ArrayResize(postData, StringToCharArray(jsonMessage, postData) - 1); int timeout = 5000; char result[]; string responseHeaders; int responseCode = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, postData, result, responseHeaders); if (responseCode == 200) { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", responseCode, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } } //+------------------------------------------------------------------+
Tests und Ergebnisse
Schließlich haben wir erfolgreich eine robuste Passwortsicherheit und Zwei-Faktor-Authentifizierung (2FA) für das Admin-Panel implementiert. Nachstehend finden Sie Bilder, die die Antworten veranschaulichen.
Versuch mit falschem Passwort
Falscher Verifizierungscode-Versuch
Die folgende Abbildung veranschaulicht den gesamten Anmelde- und Verifizierungsprozess. Es ist uns auch gelungen, die Telegram-App mit dem Anmeldevorgang zu synchronisieren, um die Übermittlung des Verifizierungscodes zu erfassen.
Gültige Anmeldung mit Testpasswort und 2FA.
Übermittlung des 2FA-Codes über Telegram für den oben genannten Anmeldeversuch.
Schlussfolgerung
Durch die Integration von Zwei-Faktor-Authentifizierungsfunktionen (2FA) in dieses MQL5-Projekt wurde die Sicherheit des Admin-Panels erheblich verbessert, indem eine entscheidende Verifizierungsebene für den Nutzerzugriff hinzugefügt wurde. Durch die Nutzung von Telegram für die Übermittlung des Codes wurde sichergestellt, dass die Nutzer in Echtzeit benachrichtigt werden. Die Implementierung umfasst eine Fehlerbehandlung für fehlerhafte Eingaben, bei der die Nutzer aufgefordert werden, die Eingabe ihrer Passwörter oder 2FA-Codes zu wiederholen, was den unbefugten Zugriff minimiert und die Nutzer gleichzeitig über etwaige Fehler informiert.
Es ist jedoch wichtig, sich bewusst zu machen, dass weiterhin Risiken bestehen, insbesondere wenn die Telegram-Anwendung auf demselben gefährdeten Computer installiert und eingeloggt ist. Ein Eindringling kann Schwachstellen in solchen Konfigurationen ausnutzen, insbesondere wenn das Gerät kompromittiert wird oder wenn nicht autorisierte Nutzer Zugriff auf das Telefon erhalten, das der Systemadministrator für Telegram verwendet. Daher ist die Einhaltung strikter Sicherheitspraktiken practices — wie z. B. das Abmelden von der App, wenn sie nicht verwendet wird, und die Gewährleistung, dass die Geräte sicher sind practices — für den Schutz sensibler Daten und Kommunikationen von größter Bedeutung.
Ich hoffe, Sie haben wertvolle Erkenntnisse über die Implementierung von MQL5 für 2FA gewonnen, insbesondere im Zusammenhang mit der Codegenerierung in Echtzeit und dem sicheren Messaging. Das Verständnis dieser Konzepte wird die Sicherheit Ihrer Anwendungen verbessern und auch die Bedeutung proaktiver Maßnahmen zum Schutz Ihrer Anwendungen vor potenziellen Bedrohungen hervorheben. Im Anhang finden Sie das fertige Werk. Viel Spaß beim Entwickeln! Händler.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16142





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.