English Русский 中文 Español 日本語
preview
Erstellen eines Handelsadministrator-Panels in MQL5 Teil IV: Login-Sicherheitsschicht

Erstellen eines Handelsadministrator-Panels in MQL5 Teil IV: Login-Sicherheitsschicht

MetaTrader 5Beispiele | 14 Januar 2025, 09:04
105 0
Clemence Benjamin
Clemence Benjamin

Inhaltsübersicht:


Einführung

Sicherheit ist in jedem Fachgebiet von größter Bedeutung, und wir können es uns nicht leisten, ihre Bedeutung zu übersehen. Angesichts der ständigen Bedrohung durch unbefugten Zugriff ist es wichtig, unser Admin-Panel vor potenziellen Eindringlingen zu schützen. Wenn sich Unbefugte Zugang verschaffen, könnten sie das Panel leicht manipulieren und unsere Kommunikationsbemühungen mit der Rundfunkgemeinschaft gefährden. Der Hauptzweck dieses Systems ist die Erleichterung einer zuverlässigen Kommunikation, und obwohl wir die Funktionalität auf der Ebene des Expert Advisors verbessern können, bleibt das Risiko des Eindringens erheblich.

Ein Angreifer, der auf das Dashboard zugreift, könnte irreführende Nachrichten an unsere Nutzer senden, Verwirrung stiften und den Ruf des Systemadministrators schädigen. Um diese Risiken zu mindern, ist es meiner Meinung nach unerlässlich, eine Sicherheitsebene zu implementieren, die den Zugang zu wichtigen Funktionen ohne die richtigen Anmeldedaten einschränkt. Dieser unkomplizierte Sicherheitsansatz schützt unser Panel und trägt außerdem dazu bei, die Integrität unserer Kommunikation und das Vertrauen unserer Gemeinschaft zu erhalten.

Anmelde-Panel

Anmelde-Panel


Überblick über die Sicherheit in MQL5

MQL5 bietet eine umfassende Reihe von Sicherheitsfunktionen, die sowohl den Quellcode als auch die kompilierten Dateien (EX5) schützen, das geistige Eigentum bewahren und eine unberechtigte Nutzung verhindern. Zu den wichtigsten Mechanismen gehören die Verschlüsselung der kompilierten Dateien, die konto- und zeitbasierte Lizenzierung und die Integration externer DLLs für zusätzlichen Schutz. Die Plattform unterstützt digitale Signaturen zur Überprüfung der Code-Authentizität, während MetaQuotes den Code durch Kompilierung und Verschleierung schützt, um Reverse Engineering zu verhindern. Bei Produkten, die über den MQL5-Markt vertrieben werden, sorgt eine zusätzliche Verschlüsselung dafür, dass nur lizenzierte Nutzer auf die Software zugreifen und sie nutzen können, wodurch ein robuster Sicherheitsrahmen für Entwickler geschaffen wird.

2012 diskutierte Investeo, ein Autor bei MQL5, verschiedene Methoden zur Sicherung von MQL5-Programmen und -Code und gab wertvolle Einblicke in die Implementierung von Techniken wie Passwortschutz, Schlüsselgenerierung, Einzelkonto-Lizenzierung, zeitlich begrenzter Schutz, Fernlizenzen, sichere Lizenzverschlüsselung und fortschrittliche Anti-Dekompilierungsmethoden. Seine Arbeit dient als grundlegende Referenz für die Verbesserung der Programmsicherheit.

Ziel der Diskussion:

Da wir wissen, wie wichtig die Sicherheit ist, wollen wir die Implementierung eines Passwortschutzes für den Zugriff auf die Funktionen des Admin-Panels diskutieren. Wir werden uns mit den Techniken befassen, die verwendet werden, um die in der vorherigen Abbildung gezeigten Ergebnisse zu erzielen, und uns darauf konzentrieren, wie wir den Nutzerzugang wirksam schützen können.

Bereiche mit Sicherheitsbedenken in unserem Admin-Panel:

Da sich unser Programm weiterentwickelt und neue Funktionen enthält, sind wir uns der wachsenden Komplexität bewusst, insbesondere für unerfahrene Entwickler. Wir haben mehrere Schlüsselbereiche identifiziert, die für die Sicherheit von Interesse sind:

  • Gesicherter Zugang zum Admin-Panel:

Um sicherzustellen, dass keine unbefugten Nutzer ohne das korrekte Passwort auf das Admin-Panel zugreifen können, implementieren wir einen Passwortschutz. Ein unbefugter Zugriff könnte dazu führen, dass unbeabsichtigte Nachrichten an die Gemeinschaft der Wirtschaftsbeteiligten, die sich auf die Erkenntnisse der Administratoren verlassen, verbreitet werden. Zufällige Klicks auf Schnelltasten könnten ohne echte Absicht erfolgen, weshalb ein sicheres Passwort unerlässlich ist. Während viele Anwendungen die Zwei-Faktor-Authentifizierung (2FA) zur zusätzlichen Verifizierung einsetzen, konzentrieren wir uns derzeit auf die Implementierung grundlegender Sicherheitsfunktionen und planen, im Laufe der Zeit weitere fortschrittliche Optionen einzubauen.

  • Sicherheit von Telegram-API-Nachrichten:

Wir legen auch großen Wert auf die Sicherheit der Kommunikation über die Telegram-API, indem wir die Chat-ID und das Bot-Token beim Programmstart sicher eingeben. Auf diese Weise wird sichergestellt, dass sensible Daten in den Händen des Nutzers geschützt bleiben. Telegram verwendet robuste Sicherheitsfunktionen, um die Kommunikation der Nutzer zu schützen, einschließlich Transport Layer Security durch das MTProto Protokoll für Standard-Chats und Ende-zu-Ende-Verschlüsselung für Secret Chats. Darüber hinaus unterstützt Telegram 2FA, sodass Nutzer aktive Sitzungen verwalten und die Kontosicherheit erhöhen können. Die Sicherheitsprotokolle von Telegram sind zwar stark, aber die Nutzer müssen auch sicherstellen, dass ihre Geräte sicher sind, da kompromittierte Geräte diese Schutzmaßnahmen untergraben können.


Kurze Zusammenfassung von Teil III

In der vorangegangenen Diskussion haben wir uns mit der Einbeziehung von Methoden für das Themenmanagement befasst. Wir haben jedoch mit Dateien gearbeitet, die bei Aktualisierungen der MetaTrader 5-Plattform geändert werden können. Jedes Mal, wenn ein Update veröffentlicht wird, wird es automatisch heruntergeladen und beim erneuten Start installiert. Der folgende Codeausschnitt veranschaulicht die Fehler, die bei der Kompilierung nach den Aktualisierungen auftraten.

'UpdateThemeColors' - undeclared identifier     Admin Panel .mq5        390     16
'darkTheme' - some operator expected    Admin Panel .mq5        390     34
'SetTextColor' - undeclared identifier  Admin Panel .mq5        397     14
'textColor' - some operator expected    Admin Panel .mq5        397     27
'SetBackgroundColor' - undeclared identifier    Admin Panel .mq5        398     14
'bgColor' - some operator expected      Admin Panel .mq5        398     33
'SetBorderColor' - undeclared identifier        Admin Panel .mq5        399     14
'borderColor' - some operator expected  Admin Panel .mq5        399     29
'SetTextColor' - undeclared identifier  Admin Panel .mq5        424     12
'textColor' - some operator expected    Admin Panel .mq5        424     25
'SetBackgroundColor' - undeclared identifier    Admin Panel .mq5        425     12
'bgColor' - some operator expected      Admin Panel .mq5        425     31
'SetBorderColor' - undeclared identifier        Admin Panel .mq5        426     12
'borderColor' - some operator expected  Admin Panel .mq5        426     27
14 errors, 1 warnings           15      2

Vorläufige Lösung

Um das Problem zu lösen, muss man zunächst die Ursache des Problems verstehen. Wie bereits erläutert, werden durch die Plattformaktualisierung die von uns verwendeten Bibliotheken auf ihren Standardzustand zurückgesetzt. Folglich sind die Methoden, die wir für die Themenverwaltung implementiert haben, nicht mehr gültig, weshalb wir jetzt auf Fehler stoßen. Um dies zu beheben, müssen wir die aktualisierten Dateien (Dialog.mqh, Edit.mqh und Button.mqh) mit den erweiterten Versionen überschreiben, die ich im vorherigen Artikel angefügt habe. Sie können den Ordner für die Include-Dateien wie in der folgenden Abbildung gezeigt finden.

Den Stammordner für Include-Dateien finden

Einfaches Auffinden des Stammordners dialog.mqh

Dauerhafte Lösung:

Sie können die Datei Dialog.mqh und andere zugehörige Dateien bei der Verwendung in Extended_Dialog.mqh umbenennen und unseren Code entsprechend anpassen, aber stellen Sie sicher, dass alle #include-Anweisungen, die auf den alten Dateinamen verweisen, auf den neuen Namen aktualisiert werden. Außerdem müssen wir prüfen, ob es andere Abhängigkeiten gibt, die darauf verweisen, und diese bei Bedarf aktualisieren. Nachdem wir diese Änderungen vorgenommen haben, kompilieren wir unser Projekt neu, um mögliche Fehler zu erkennen, und testen die Funktionalität gründlich, um sicherzustellen, dass alles korrekt funktioniert. Dadurch wird sie separat unter dem neuen Namen gespeichert, die Originaldatei bleibt jedoch erhalten.

Wenn wir zum Beispiel die Datei bereits als Extended_Dialog.mqh gespeichert haben, können wir zu unserem Admin-Panel navigieren und den Code wie folgt anpassen:

#include <Controls\Extended_Dialog.mqh>
#include <Controls\Extended_Button.mqh>
#include <Controls\Extended_Edit.mqh>
#include <Controls\Label.mqh>

Vorteile des Speicherns unter einem anderen Namen

Sie bietet die Möglichkeit, die Funktionalität speziell auf Ihre Bedürfnisse zuzuschneiden, indem sie Funktionen hinzufügt oder anpasst, die in der integrierten Version nicht vorhanden sind. Diese Anpassung ermöglicht es Ihnen, eine einzigartige Schnittstelle zu schaffen, die Ihren Anforderungen entspricht. Außerdem lassen sich durch die Verwendung nutzerdefinierter Dateinamen Konflikte mit integrierten Bibliotheken oder Bibliotheken von Drittanbietern vermeiden, wodurch das Risiko unerwarteter Verhaltensweisen aufgrund von Namensüberschneidungen verringert wird. Die Isolierung Ihrer Erweiterungen in einer umbenannten Datei schützt Ihre Anpassungen davor, von anderen eingebauten Funktionen, die den ursprünglichen Dialog verwenden könnten, beeinträchtigt zu werden, und gewährleistet, dass Sie Ihr Projekt ohne Beeinträchtigung durch externe Änderungen entwickeln und pflegen können.


Integration eines Passwortschutzes in das Admin-Panel

In diesem Projekt werden wir einen bedingten Passwortschutz implementieren, bei dem ein Passwort vom Typ string verwendet wird, das sowohl Buchstaben als auch Zahlen enthalten kann, was die Komplexität erhöht. Eine vierstellige PIN mag zwar einfach erscheinen, ist aber dennoch schwer zu erraten. Im Admin-Panel verwenden wir die Klasse Dialog, um den Nutzer bei der Anmeldung zur Eingabe eines Passworts aufzufordern, wobei die Bedingungen so festgelegt sind, dass die Hauptfunktionen des Panels erst nach erfolgreicher Passworteingabe angezeigt werden.

Bei der weiteren Entwicklung des Admin-Panel-Programms liegt unser Hauptaugenmerk auf der Einrichtung einer soliden Anmeldesicherheit, um sicherzustellen, dass nur autorisierte Nutzer auf sensible Verwaltungsfunktionen zugreifen können. Wir haben erkannt, wie wichtig es ist, unser System vor unbefugtem Zugriff zu schützen, und diskutieren, wie wir MQL5 zur Sicherung unserer Produkte einsetzen können.

Mechanismus zur Authentifizierung

Zur Absicherung des Admin-Panels implementieren wir einen einfachen, passwortbasierten Authentifizierungsmechanismus, der die Nutzer zur Eingabe eines Passworts auffordert, bevor der Zugriff auf Funktionen gewährt wird. Diese Entscheidung spiegelt unser Engagement für die Überprüfung der Nutzeridentität als Voraussetzung für den Zugriff auf wichtige Komponenten des Programms wider.

// Show authentication input dialog
bool ShowAuthenticationPrompt()
{
    if (!authentication.Create(ChartID(), "Authentication", 0, 100, 100, 500, 300))
    {
        Print("Failed to create authentication dialog");
        return false;
    }
   
}

Mit der Funktion ShowAuthenticationPrompt entwerfen wir eine nutzerfreundliche Oberfläche, die unsere Nutzer effektiv durch den Authentifizierungsprozess führt. Durch die Einrichtung eines speziellen Dialogs für die Passworteingabe stellen wir sicher, dass der primäre Zugangspunkt zum Verwaltungsbereich sicher und gleichzeitig intuitiv bleibt.

Zum besseren Verständnis habe ich den Code für die Erstellung von Dialogen im folgenden Ausschnitt dargestellt und mit Kommentaren versehen, um die Funktionsweise zu erklären. Wenn Sie Ihr Wissen über Achsen und Koordinaten auffrischen möchten, lesen Sie bitte Teil I.  

// This condition checks if the authentication object is created successfully
if (!authentication.Create(          // Function call to create authentication
    ChartID(),                       // Retrieve the ID of the current chart
    "Authentication",                // Label of the dialog window in this case it is 'Authentication'
    0,                               // Initial X position on the chart also X_1
    100,                             // Initial Y position on the chart also Y_1
    500,                             // Width of the authentication window also X_2
    300                              // Height of the authentication window also Y_2
))

Nachdem wir den Authentifizierungsdialog eingerichtet haben, ordnen wir die anderen Elemente der Nutzeroberfläche ähnlich an, wenn auch mit anderen Werten. Der Prozess beginnt mit der Erstellung eines Passwort-Eingabefelds, in das die Nutzer ihre Anmeldedaten eingeben können, gefolgt von wichtigen Schaltflächen. Wir konzentrieren uns insbesondere auf zwei Hauptschaltflächen: die Schaltfläche „Anmelden“ und die Schaltfläche „Schließen“. Die Schaltfläche „Login“ dient zur Übermittlung des eingegebenen Passworts, während die Schaltfläche „Close“ dem Nutzer die Möglichkeit bietet, den Dialog zu verlassen, wenn er das Passwort nicht kennt. Nachfolgend finden Sie einen Codeausschnitt, der die Logik für die Erstellung dieser Schaltflächen und die Beschriftung der Kennwortaufforderung veranschaulicht.

 // Create password input
    if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95))
    {
        Print("Failed to create password input box");
        return false;
    }
    authentication.Add(passwordInputBox);

    // Create prompt label
    if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 20))
    {
        Print("Failed to create password prompt label");
        return false;
    }
    passwordPromptLabel.Text("Enter password: Access Admin Panel");
    authentication.Add(passwordPromptLabel);

    // Create login button
    if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 140))
    {
        Print("Failed to create login button");
        return false;
    }
    loginButton.Text("Login");
    authentication.Add(loginButton);

    // Create close button for authentication
    if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 140)) // Adjusted position
    {
        Print("Failed to create close button for authentication");
        return false;
    }
    closeAuthButton.Text("Close");
    authentication.Add(closeAuthButton);

    authentication.Show(); // Show the authentication dialog
    ChartRedraw(); // Redraw the chart to reflect changes

    return true; // Prompt shown successfully
}

Passwortverwaltung

Zurzeit verwenden wir für erste Tests ein einfaches, fest kodiertes Kennwort, mit dem wir die Funktionalität schnell testen können. Wir sind uns jedoch darüber im Klaren, dass dieser Ansatz Risiken birgt, z. B. die Anfälligkeit für Brute-Force-Angriffe, wenn der Code kompromittiert wird.

// Default password for authentication
string Password = "2024";

Wir sind uns zwar bewusst, dass die Verwendung eines hart kodierten Passworts unsere Entwicklung beschleunigt, aber wir müssen in zukünftigen Updates zu einer sichereren Lösung übergehen, d. h. verschlüsselte Konfigurationsdateien implementieren oder ein ausgefeilteres System zur Verwaltung von Nutzerkonten verwenden, um die Sicherheit zu erhöhen.

Umgang mit Nutzereingaben

Um die Sicherheit zu erhöhen, müssen wir sicherstellen, dass das Passwort-Eingabefeld im Authentifizierungsdialog klar definiert ist. Indem wir die Nutzer zur Eingabe ihrer Passwörter anleiten und diese Eingaben mit dem gespeicherten Passwort abgleichen, sorgen wir für ein nahtloses und sicheres Anmeldeerlebnis.
// Handle login button click
void OnLoginButtonClick()
{
    string enteredPassword = passwordInputBox.Text();
    if (enteredPassword == Password) // Check the entered password
    {
        authentication.Destroy(); // Hide the authentication dialog
        Print("Authentication successful.");
        adminPanel.Show(); // Show the admin panel after successful authentication
    }
    else
    {
        Print("Incorrect password. Please try again.");
        passwordInputBox.Text(""); // Clear the password input
    }
}

In der Funktion OnLoginButtonClick prüft das Programm, ob das eingegebene Passwort mit dem gespeicherten Passwort übereinstimmt. Nach erfolgreicher Eingabe wird der Authentifizierungsdialog ausgeblendet und dem Nutzer das Verwaltungsfenster angezeigt. Wenn das Kennwort falsch ist, wird das Eingabefeld gelöscht und der Nutzer aufgefordert, es erneut zu versuchen, um sicherzustellen, dass er den Vorgang versteht und sich bei der Anmeldung sicher fühlt.

Wir haben auch eine Ereignisbehandlung für die Schaltfläche „Close“, der für die Exit-Logik verantwortlich ist. Wenn diese Schaltfläche angeklickt wird, wird der Authentifizierungsdialog geschlossen und der Experte vollständig aus dem Chart entfernt, sodass kein Zugriff auf die Verwaltungsfunktionen mehr möglich ist. Diese Maßnahme erhöht die Sicherheit und bietet einen klaren Ausstiegsweg für Nutzer, die sich gegen eine weitere Authentifizierung entscheiden. So wird die Ereignisbehandlung definiert:

//+------------------------------------------------------------------+
//| Handle close button click for authentication                     |
//+------------------------------------------------------------------+
void OnCloseAuthButtonClick()
{
    authentication.Destroy();
    ExpertRemove(); // Remove the expert if user closes the authentication dialog
    Print("Authentication dialog closed.");
}

Das schließt die Authentifizierung. Destroy() schließt den Dialog effektiv, während ExpertRemove() sicherstellt, dass der Expert Advisor vollständig aus dem Chart entfernt wird, was die Sicherheit der Anwendung insgesamt erhöht

Vollständig in das Hauptprogramm integriert:

//+------------------------------------------------------------------+
//|                                             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 version   "1.19"

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>

// Input parameters
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 = "Enter Chat ID from Telegram bot API";
input string InputBotToken = "Enter BOT TOKEN from your Telegram bot";

// Global variables
CDialog adminPanel;
CDialog authentication; // Renamed from passwordPanel 
CButton sendButton, clearButton, changeFontButton, toggleThemeButton, loginButton, closeAuthButton;
CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton;
CEdit inputBox, passwordInputBox;
CLabel charCounter, passwordPromptLabel;
bool minimized = false;
bool darkTheme = false;
int MAX_MESSAGE_LENGTH = 4096;
string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman", "Britannic Bold", "Dubai Medium", "Impact", "Ink Tree", "Brush Script MT"};
int currentFontIndex = 0;

// Default password for authentication
string Password = "2024";

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    if (!ShowAuthenticationPrompt())
    {
        Print("Authorization failed. Exiting...");
        return INIT_FAILED; // Exit if the authorization fails
    }

    // Initialize the main admin panel
    if (!adminPanel.Create(ChartID(), "Admin Panel", 0, 30, 30, 500, 500))
    {
        Print("Failed to create admin panel dialog");
        return INIT_FAILED;
    }

    // Create controls for the admin panel
    if (!CreateControls())
    {
        Print("Control creation failed");
        return INIT_FAILED;
    }

    // Initially hide the admin panel
    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;
    }

    // Create password input
    if (!passwordInputBox.Create(ChartID(), "PasswordInputBox", 0, 20, 70, 260, 95))
    {
        Print("Failed to create password input box");
        return false;
    }
    authentication.Add(passwordInputBox);

    // Create prompt label
    if (!passwordPromptLabel.Create(ChartID(), "PasswordPromptLabel", 0, 20, 20, 260, 20))
    {
        Print("Failed to create password prompt label");
        return false;
    }
    passwordPromptLabel.Text("Enter password: Access Admin Panel");
    authentication.Add(passwordPromptLabel);

    // Create login button
    if (!loginButton.Create(ChartID(), "LoginButton", 0, 20, 120, 100, 140))
    {
        Print("Failed to create login button");
        return false;
    }
    loginButton.Text("Login");
    authentication.Add(loginButton);

    // Create close button for authentication
    if (!closeAuthButton.Create(ChartID(), "CloseAuthButton", 0, 120, 120, 200, 140)) // Adjusted position
    {
        Print("Failed to create close button for authentication");
        return false;
    }
    closeAuthButton.Text("Close");
    authentication.Add(closeAuthButton);

    authentication.Show(); // Show the authentication dialog
    ChartRedraw(); // Redraw the chart to reflect changes

    return true; // Prompt shown successfully
}

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
    if (id == CHARTEVENT_OBJECT_CLICK)
    {
        // Handle button clicks inside the authentication dialog
        if (sparam == "LoginButton")
        {
            OnLoginButtonClick(); // Call the login button handler
        }
        else if (sparam == "CloseAuthButton") // Made sure this matches the ID
        {
            OnCloseAuthButtonClick(); // Call the close button handler
        }
        
        
    }
    
    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) // Check the entered password
    {
        authentication.Destroy(); // Hide the authentication dialog
        Print("Authentication successful.");
        adminPanel.Show(); // Show the admin panel after successful authentication
    }
    else
    {
        Print("Incorrect password. Please try again.");
        passwordInputBox.Text(""); // Clear the password input
    }
}

//+------------------------------------------------------------------+
//| Handle close button click for authentication                     |
//+------------------------------------------------------------------+
void OnCloseAuthButtonClick()
{
    authentication.Destroy();
    ExpertRemove(); // Remove the expert if user closes the authentication dialog
    Print("Authentication dialog closed.");
}

//+------------------------------------------------------------------+
//| Create necessary UI controls                                     |
//+------------------------------------------------------------------+
bool CreateControls()
{
    long chart_id = ChartID();

    // Create the input box
    if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95))
    {
        Print("Failed to create input box");
        return false;
    }
    adminPanel.Add(inputBox);

    // Character counter
    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);

    // Clear button
    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);

    // Send button
    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);

    // Change font button
    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);

    // Toggle theme button
    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);

    // Minimize button
    if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) // Adjusted Y-coordinate for visibility
    {
        Print("Failed to create minimize button");
        return false;
    }
    minimizeButton.Text("_");
    adminPanel.Add(minimizeButton);

    // Maximize button
    if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) // Adjusted Y-coordinate for visibility
    {
        Print("Failed to create maximize button");
        return false;
    }
    maximizeButton.Text("[ ]");
    adminPanel.Add(maximizeButton);

    // Close button for admin panel
    if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) // Adjusted Y-coordinate for visibility
    {
        Print("Failed to create close button");
        return false;
    }
    closeButton.Text("X");
    adminPanel.Add(closeButton);

    // Quick messages
    return CreateQuickMessageButtons();
}

//+------------------------------------------------------------------+
//| Create quick message buttons                                     |
//+------------------------------------------------------------------+
bool CreateQuickMessageButtons()
{
    string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 };
    int startX = 5, startY = 160, width = 222, height = 65, spacing = 5;

    for (int i = 0; i < 8; i++)
    {
        if (!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))
        {
            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 (message != "")
    {
        if (SendMessageToTelegram(message))
            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(int index)
{
    string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 };
    string message = quickMessages[index];

    if (SendMessageToTelegram(message))
        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()
{
    // Use the dialog's theme update method as a placeholder.
    adminPanel.UpdateThemeColors(darkTheme);

    color textColor = darkTheme ? clrWhite : clrBlack;
    color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro;
    color borderColor = darkTheme ? clrSlateGray : clrGray;
    color bgColor     = darkTheme ? clrDarkBlue : clrWhite;

    inputBox.SetTextColor(textColor);
    inputBox.SetBackgroundColor(bgColor);
    inputBox.SetBorderColor(borderColor);

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

    charCounter.Color(textColor);

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

    inputBox.Font(availableFonts[currentFontIndex]);
    clearButton.Font(availableFonts[currentFontIndex]);
    sendButton.Font(availableFonts[currentFontIndex]);
    toggleThemeButton.Font(availableFonts[currentFontIndex]);
    changeFontButton.Font(availableFonts[currentFontIndex]);

    for (int i = 0; i < ArraySize(quickMessageButtons); i++)
    {
        quickMessageButtons[i].Font(availableFonts[currentFontIndex]);
    }

    Print("Font changed to: ", availableFonts[currentFontIndex]);
    ChartRedraw();
}

//+------------------------------------------------------------------+
//| 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();
        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 url = "https://api.telegram.org/bot" + InputBotToken + "/sendMessage";
    string jsonMessage = "{\"chat_id\":\"" + InputChatId + "\", \"text\":\"" + message + "\"}";
    char post_data[];
    ArrayResize(post_data, StringToCharArray(jsonMessage, post_data, 0, WHOLE_ARRAY) - 1);

    int timeout = 5000;
    char result[];
    string responseHeaders;

    int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders);

    if (res == 200)
    {
        Print("Message sent successfully: ", message);
        return true;
    }
    else
    {
        Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError());
        Print("Response: ", CharArrayToString(result));
        return false;
    }
}


Tests und Ergebnisse

Unser Code wurde erfolgreich kompiliert, und beim Starten der Anwendung stellten wir fest, dass die vollständigen Funktionen des Panels unzugänglich bleiben, bis die richtige PIN eingegeben wird. Dieses Verhalten stellt sicher, dass nur autorisierte Nutzer auf die Verwaltungsfunktionen zugreifen können. In diesem Stadium sind wir stolz auf unsere Fortschritte, doch wir sind uns bewusst, dass wir die Grenzen unserer Entwicklung noch nicht erreicht haben. Wir sind uns bewusst, dass unsere Sicherheitsmaßnahmen noch verbessert werden müssen, da sie für fortgeschrittene Hacker anfällig sein können. Wir wissen, dass jeder Schritt, den wir unternehmen, eine Gelegenheit ist, mehr über die Implementierung der MQL5-Sprache zu lernen, und je weiter wir unsere Fähigkeiten ausbauen, desto stabilere Sicherheitsstufen können wir erreichen. Unten sehen Sie ein Bild, das den Start der Anwendung zusammen mit dem gewünschten Ergebnis zeigt.

Sicheres Admin-Panel

Start des Panels



Schlussfolgerung

In diesem Projekt wurde durch die Implementierung eines Login-Authentifizierungsmechanismus die Sicherheit des Admin-Panels erheblich verbessert, was für den Schutz sensibler Funktionen unerlässlich ist. Da für den Zugriff auf die Verwaltungsfunktionen ein Kennwort erforderlich ist, verhindert das Programm eine unbefugte Nutzung und stellt sicher, dass nur verifizierte Nutzer wichtige Einstellungen und Vorgänge verwalten können. Das Design wird durch ein klar definiertes globales Passwort und eine nutzerfreundliche Schnittstelle für die Eingabe von Anmeldeinformationen verstärkt.

Bei der Weiterentwicklung unseres Admin-Panels werden wir uns auf wichtige Verbesserungen konzentrieren, wie z. B. die Umstellung von hart kodierten Passwörtern auf sicher verwaltete Anmeldedaten, um Schwachstellen zu vermeiden, die Integration von Mehrfaktor-Authentifizierung für zusätzliche Sicherheit und die kontinuierliche Optimierung der Anmeldefunktion.

Andererseits wissen wir, dass es für jeden, der keinen Zugang zum Quellcode hat, schwierig wird, sich Zugang zu verschaffen, sobald der Code kompiliert ist, dank der von MQL5 gebotenen Sicherheitsfunktionen gegen Dekompilierung. Dieser zusätzliche Schutz trägt dazu bei, unsere Anwendung vor unbefugtem Zugriff und Reverse Engineering zu schützen.

Bitte zögern Sie nicht, es in Ihren Projekten auszuprobieren! Ich freue mich über Kommentare und Rückmeldungen, denn Ihre Erkenntnisse können uns helfen, unsere Arbeit zu verbessern und zu verfeinern. Ihre Ansichten sind für uns sehr wertvoll, da wir unsere Anwendungen weiter entwickeln und verbessern wollen. Sehen Sie sich den Anhang unten an.

Zurück zur Inhaltsseite

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16079

Beigefügte Dateien |
Admin_Panel_.mq5 (18.66 KB)
Erstellen eines MQL5 Expert Advisors basierend auf der Strategie „Daily Range Breakout“ Erstellen eines MQL5 Expert Advisors basierend auf der Strategie „Daily Range Breakout“
In diesem Artikel erstellen wir einen MQL5 Expert Advisor auf Basis der Daily Range Breakout Strategie. Wir behandeln die wichtigsten Konzepte der Strategie, entwerfen den EA-Blaupause, und implementieren die Breakout-Logik in MQL5. Schließlich werden Techniken für das Backtesting und die Optimierung des EA erforscht, um seine Effektivität zu maximieren.
MQL5 Handels-Toolkit (Teil 3): Entwicklung einer EX5-Bibliothek zur Verwaltung schwebenden Aufträge MQL5 Handels-Toolkit (Teil 3): Entwicklung einer EX5-Bibliothek zur Verwaltung schwebenden Aufträge
Lernen Sie, wie Sie eine umfassende EX5-Bibliothek für schwebende Aufträge in Ihrem MQL5-Code oder Ihren Projekten entwickeln und implementieren. Dieser Artikel zeigt Ihnen, wie Sie eine umfangreiche EX5-Bibliothek für die Verwaltung schwebender Aufträge erstellen können, und führt Sie durch den Import und die Implementierung dieser Bibliothek, indem er ein Handels-Panel oder eine grafische Nutzeroberfläche (GUI) erstellt. Das Expert Advisor-Order-Panel ermöglicht es den Nutzern, schwebende Aufträge, die mit einer bestimmten magischen Zahl verknüpft sind, direkt über die grafische Oberfläche im Chartfenster zu öffnen, zu überwachen und zu löschen.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 43): Reinforcement Learning mit SARSA MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 43): Reinforcement Learning mit SARSA
SARSA, eine Abkürzung für State-Action-Reward-State-Action, ist ein weiterer Algorithmus, der bei der Implementierung von Reinforcement Learning verwendet werden kann. Wie bei Q-Learning und DQN haben wir also untersucht, wie dies als unabhängiges Modell und nicht nur als Trainingsmechanismus in assistentengestützten Expert Advisors implementiert werden kann.
Klassische Strategien neu interpretieren (Teil X): Kann KI den MACD verbessern? Klassische Strategien neu interpretieren (Teil X): Kann KI den MACD verbessern?
Begleiten Sie uns bei der empirischen Analyse des MACD-Indikators, um zu testen, ob die Anwendung von KI auf eine Strategie, die den Indikator mit einbezieht, unsere Prognosegenauigkeit für den EURUSD verbessern würde. Gleichzeitig haben wir geprüft, ob der Indikator selbst leichter vorhersagbar ist als der Preis, und ob der Wert des Indikators das künftige Preisniveau vorhersagt. Wir geben Ihnen die Informationen an die Hand, die Sie benötigen, um zu entscheiden, ob Sie Ihre Zeit in die Integration des MACD in Ihre AI-Handelsstrategien investieren sollten.