
MQL5で取引管理者パネルを作成する(第7回):信頼できるユーザー、回復、暗号化
内容
はじめに
MQL5マーケットは、配布された製品のセキュリティを確保する上でデバイスIDが重要であることを示しています。今回の調査は、安全な管理パネルの運用において直面した課題をきっかけに始まりました。強化されたセキュリティ対策を導入して以来、端末上でのファイルコンパイルや機能テストのたびにログインプロンプトや認証要求が発生し、開発・テストプロセスの遅延が生じています。この追加のセキュリティ層は必要不可欠ですが、ワークフローに支障をきたす要因となっています。
新しい製品を公開する際、マーケットの最初のページには以下の警告が表示されます。これは、MQL5が開発者とユーザーの両方を保護するために、堅牢なセキュリティ対策を優先していることを示しています。マーケットで販売されるすべてのプログラムは、不正使用を防ぐため、特別なキーで暗号化されています。この暗号化キーは購入者ごとに固有であり、購入者のコンピュータに紐付けられるため、マーケット内のすべての製品には自動コピー保護機能が備わっています。
購入した製品は最低でも5回アクティベーションが可能です。これにより、買い手と売り手双方の利益のバランスが確保されます。アクティベーションの上限回数は販売者によって設定されます。
多くのアプリケーションやWebサービスでは、セキュリティ対策の一環として、第二層の認証を選択的に適用しています。たとえば、匿名IPの使用、新しいデバイスからのログイン、複数回のログイン失敗といった「疑わしいアクティビティ」が検出された場合のみ、追加の認証が求められます。このアプローチにより、セキュリティを維持しつつ、ユーザーの利便性を損なうことなく運用が可能になります。
しかし、私たちの環境では、開発中のテスト作業において頻繁にパスワード入力やTelegramアプリでの6桁コード確認が求められることが、大きな負担となっています。特に、端末のアクティビティが変化するたびに認証が求められると、開発プロセスがスムーズに進まなくなります。以下のような操作が発生するたびに、デバイスの再初期化が行われ、再ログインが求められます。
- 通貨ペアの変更
- 時間枠の切り替え
- 端末の再起動
特定のシナリオでは、プログラムが何度も再初期化されることが避けられません。技術的・運用上の理由から、このプロセスを完全に排除することは困難ですが、最適化することは可能です。現在、ユーザー認証アルゴリズムはプログラムの初期化関数内の最初のステップとして組み込まれており、この認証を通過しなければ処理を続行できません。しかし、ここにバイパスメカニズムを導入することで、開発プロセスをより円滑に進めることができます。提案するバイパスアルゴリズムでは、ログイン試行回数を監視し、一定の条件下で2FA(二要素認証)を省略します。
パスワード入力の失敗回数が設定上限を超えた場合、不審なアクセスの可能性があるため、通常通りの認証プロセスを適用します。一方、3回以内に正しいパスワードを入力すると、2FAがインテリジェントにバイパスされ、Telegramベースの認証を繰り返す必要がなくなるため、時間を大幅に節約できます。このアプローチにより、特に集中的な開発およびテスト段階で、セキュリティと効率の両方が向上します。
以下の画像は、アプリ開発中にTelegramへ多数の認証メッセージが送信される様子を示しており、本アルゴリズムの必要性を明確に示しています。
管理パネル:個人用Telegram 2FAコード配信ボット
以前は、プログラムの初期化のたびにパスワードと2FA認証の両方が繰り返し求められ、プロセスに多大な時間がかかっていました。そこで、開発時間を短縮するために、Telegramに送信される6桁の認証コードを端末の[エキスパート]ログに直接出力するコードを追加しました。この変更により、アプリのテスト中にTelegramアプリを開くことなく、ログから認証コードをすばやく取得できるようになり、作業効率が大幅に向上しました。
このコードスニペットは、Telegramメッセージを送信する関数の一部です。その中に、利便性のために送信メッセージを操作ログへ記録する機能を追加しました。しかし、開発段階を過ぎた今後のバージョンでは、セキュリティ強化のためにこの機能を削除する予定です。認証コードのような機密情報をログに残したままにすると、不正アクセスが発生した際にセキュリティリスクとなる可能性があります。この変更は、開発プロセスの効率化と機密データの保護という、両者のバランスを考慮したものです。
以下のコードスニペットは、送信されたメッセージを出力する行を示しています。
//+------------------------------------------------------------------+ //| 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); //This line prints the message in journal,thus a security leak that I used to bypass telegram during app tests. return true; } else { Print("Failed to send message. HTTP code: ", responseCode, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } }
以下に強調表示されているのは、認証コードを含むTelegramに送信されたメッセージです。このアプローチは、開発中にTelegramでコードを確認する手間を省くための便利な方法でした。しかし、この機能をそのまま残しておくと、権限のない第三者がTelegramにアクセスせずとも端末上で直接コードを取得できる可能性があり、重大なセキュリティリスクとなります。 なお、このテキストは通常、端末の[エキスパート]タブに出力されます。
ディスカッションの目標2024.11.22 08:44:47.980 Admin Panel V1.22 (Volatility 75 (1s) Index,M1) Message sent successfully: A login attempt was made on the Admin Panel. Please use this code to verify your identity: 028901 2024.11.22 08:44:48.040 Admin Panel V1.22 (Volatility 75 (1s) Index,M1) Password authentication successful. A 2FA code has been sent to your Telegram.
このディスカッションの目的は、ログインと2FAプロセスを合理化するための信頼できるユーザー認識システムを統合することです。ユーザーが3回以内に正しいパスワードを入力すれば、2FAをスキップできますが、制限を超えた場合は2FAがトリガーされ、Telegram経由で送信されたコードとハードコードされたパスワードを入力する必要があります。このシステムは、総当たり攻撃を防ぐために試行回数を制限しつつ、スムーズな認証プロセスを実現することで、利便性とセキュリティのバランスを取っています。信頼はセッションごとに適用され、新しいログインのたびに再検証が必要です。次のセクションでは、総当たり攻撃に対処するための具体的な対策についてさらに詳しく説明します。
総当たり攻撃について
総当たり攻撃とは、攻撃者が正しいパスワード、暗号化キー、または資格情報のあらゆる組み合わせを体系的に試し、アカウント、システム、または暗号化されたデータに不正アクセスを試みる手法です。このアプローチは、システム自体の脆弱性を悪用するのではなく、計算能力と試行回数に依存します。
以下は、総当たり攻撃の主な特徴です。
- 試行錯誤:攻撃者は、アクセスできるまでさまざまな文字の組み合わせを繰り返し試行します。
- 自動化:多くの場合、専用ツールやスクリプトを使用してプロセスを自動化し、短時間で数千回、あるいは数百万回の試行が可能になります。
- 時間のかかる作業:攻撃にかかる時間は、ターゲットのパスワードやキーの複雑さによって異なります。文字数が多く、組み合わせの種類が豊富な強力なパスワードほど、解読には長い時間がかかります。
総当たり攻撃の種類
- シンプルな総当たり攻撃:あらゆる可能な文字の組み合わせを試します。
- 辞書攻撃:よく使用されるパスワードのリスト(例:「123456」、「password」、「qwerty」)を使用してアクセスを試みます。
- クレデンシャルスタッフィング:過去のデータ漏洩で流出したユーザー名とパスワードの組み合わせを使用し、他のプラットフォームでの不正アクセスを試みます。
防止
- ログイン試行回数を制限します。
- 強力なパスワードの使用を強制します(長さが十分で、大文字・小文字・数字・記号を含むもの)。
- 二要素認証(2FA)を導入することで、セキュリティ層を追加します。
Panel Accessの現在のセキュリティは、これらの攻撃に対して脆弱です。ログイン試行回数を制限することは重要な防御策ですが、一方で時間の節約のため、Telegramを介した頻繁な認証を回避する必要もあります。検証コードを送信することで、不正アクセスの防止だけでなく、パネル上での潜在的な悪意のある活動を管理者に警告する役割も果たします。万が一、管理者がセキュリティ侵害に気付いていない場合でも、警告機能として有効に機能します。
管理パネルでの信頼できるユーザーの実装
管理パネルに新機能を実装するため、セキュリティとEAプログラムの初期化に関連するソースコードの一部のみを変更しました。このアプローチにより、プログラムのその他の部分には影響を与えず、大規模なコードを管理する際のエラー発生リスクを最小限に抑えることができます。ここではログインハンドラ関数に焦点を当てており、次のコードスニペットで宣言される新しい変数を導入しています。
int failedAttempts = 0; // Counter for failed login attempts bool isTrustedUser = false; // Flag for trusted users
グローバル変数failedAttemptsとisTrustedUserは、新機能の実装において重要な役割を果たします。failedAttemptsは、誤ったパスワード入力の回数を監視し、2FAを適用すべきタイミングを判断するために使用されます。isTrustedUserフラグは、許可された試行回数内に正常にログインしたユーザーを識別し、これらのユーザーに対して2FAプロセスをスキップします。OnLoginButtonClick関数内でこれらの変数を適切にリセットすることで、システムは認証フローを動的に制御し、柔軟性とセキュリティを両立させることができます。
新機能に対応したログイン機能の強化
OnLoginButtonClick関数は、failedAttemptsカウンタでログイン試行回数を追跡し、isTrustedUserフラグで信頼できるユーザーを識別 することで、新機能を統合します。正しいパスワードが入力された場合、失敗した試行回数が3回未満であるかをチェックし、ユーザーが信頼できると判断されれば、2FAをスキップして管理者ホームパネル(Admin Home Panel)へ直接進めます。失敗した試行回数が制限を超えた場合、関数は2FAコードを生成し、回復用のハードコードされたパスワードとともにTelegram経由でユーザーに送信、さらに2FA認証プロンプトを表示します。この仕組みにより、信頼できるユーザーには利便性を提供しつつ、失敗時にはセキュリティを強化する というバランスを確保できます。
//+------------------------------------------------------------------+ //| Handle login button click | //+------------------------------------------------------------------+ void OnLoginButtonClick() { string enteredPassword = passwordInputBox.Text(); if (enteredPassword == Password) { failedAttempts = 0; // Reset attempts on successful login isTrustedUser = true; if (failedAttempts <= 3) // Skip 2FA for trusted users { authentication.Destroy(); adminHomePanel.Show(); Print("Login successful. 2FA skipped for trusted user."); } else { } } else { failedAttempts++; feedbackLabel.Text("Wrong password. Try again."); passwordInputBox.Text(""); if (failedAttempts >= 3) { Print("Too many failed attempts. 2FA will be required."); twoFACode = GenerateRandom6DigitCode(); SendMessageToTelegram( "A login attempt was made on the Admin Panel.\n" + "Use this code to verify your identity: " + twoFACode + "\n" + "Reminder: Your admin password is: " + Password, Hardcoded2FAChatId, Hardcoded2FABotToken ); authentication.Destroy(); ShowTwoFactorAuthPrompt(); Print("Password authentication successful. A 2FA code has been sent to your Telegram."); failedAttempts = 0; // Reset attempts after requiring 2FA } } }
プログラム初期化中の5つのインスタンス
ShowAuthenticationPrompt()関数は、ログインインターフェイスを表示し、OnLoginButtonClickハンドラを[Login]ボタンにリンクするため、2FAスキップ機能を含む認証プロセスはプログラムの初期化時に有効になります。以下に、その流れを説明します。
- 認証プロンプトのトリガー:OnInit()関数内で、最初にShowAuthenticationPrompt()が呼び出されます。この関数は、パスワード入力フィールドと[Login]ボタンを含む認証ダイアログを作成・表示します。ユーザーがダイアログに対話するまで、プログラムはそれ以上の処理を停止します。
- ログイン試行の処理:ユーザーが[Login]ボタンをクリックすると、OnLoginButtonClick関数が実行されます。この関数では、入力されたパスワードをチェックし、failedAttemptsカウンタを更新したうえで、失敗回数に応じてアクセスを許可するか、2FAを適用するかを決定します。
- 認証成功後の処理:ログインが成功し、ユーザーが信頼できると判断された場合(失敗回数が3回未満)、認証ダイアログが破棄され、管理者ホームパネルが即座に表示されます。これにより、信頼できるユーザーの2FAがバイパスされます。
- 必要に応じた2FAの要求: 許容される失敗回数を超えた場合、プログラムは2FAを強制します。6桁の認証コードが生成され、Telegramを通じてユーザーに送信 され、さらにShowTwoFactorAuthPrompt()関数を使用して2FA認証ダイアログが表示されます。認証コードを生成する関数(赤字で強調表示されているもの)を忘れずに確認してください。
//+------------------------------------------------------------------+ //| Generate a random 6-digit code for 2FA | //+------------------------------------------------------------------+ string GenerateRandom6DigitCode() { int code = MathRand() % 1000000; // Generate a 6-digit number return StringFormat("%06d", code); // Ensure leading zeros }
5. さらなる初期化: ユーザーが認証されると(信頼できるログインまたは2FA認証が成功した場合)、残りのパネル(管理ホームパネル、コミュニケーションパネル(Communications Panel)、取引管理パネル(Trade Management Panel)はバックグラウンドで初期化されますが、ナビゲーション中に明示的に表示されるまでは非表示のままになります。
初期化関数のコードスニペットは次のとおりです。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 30, 30, 500, 500)) { Print("Failed to create Communications panel dialog"); return INIT_FAILED; } if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0,260, 30, 1040, 170)) { Print("Failed to create Trade Management panel dialog"); return INIT_FAILED; } if (!CreateControls()) { Print("Control creation failed"); return INIT_FAILED; } if (!CreateTradeManagementControls()) { Print("Trade management control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization communicationsPanel.Hide(); // Hide the Communications Panel tradeManagementPanel.Hide(); // Hide the Trade Management Panel return INIT_SUCCEEDED; }
管理パネルでの暗号化とアプリケーションの例
MQL5の暗号化では、パスワード、メッセージ、認証コードなどの機密データを保護するためのアルゴリズムや方法が使用されます。
以下は、管理パネルでこの概念を適用する4つの方法です。
1.パスワードのハッシュ化
- HashPassword関数は、CRYPT_HASH_SHA256アルゴリズムを使用したCryptEncode関数を使用して、入力パスワードをハッシュ化します。ハッシュ化された結果は、保存または比較のためにCharArrayToHexを使って16進文字列に変換されます。VerifyPassword関数では、入力されたパスワードがハッシュ化され、保存されているハッシュと比較されることで、プレーンテキストのパスワードが保存されたり処理されたりしないようにします。
- ハッシュ化されたパスワードを保存することで、保存されたデータにアクセスされた場合でも、実際のパスワードは安全に保たれます。ハッシュ化は一方向のプロセスであり、ハッシュから元のパスワードを導き出すことはできないため、認証において重要なセキュリティ層を追加します。
// Example for storing our hard-coded password string HashPassword(string password) { uchar hash[]; CryptEncode(CRYPT_HASH_SHA256, password, hash); return CharArrayToHex(hash); } // Usage string PasswordHash = HashPassword("2024"); // Store this instead of plaintext bool VerifyPassword(string enteredPassword) { return HashPassword(enteredPassword) == PasswordHash; }
2.機密データの暗号化
- EncryptData関数は、AES-256アルゴリズム(CRYPT_AES256)を使用して、2FAコードなどの機密情報を安全な暗号化キーで暗号化します。DecryptData関数はこのプロセスを逆にして、データを元の形式に復号化します。このプロセスでは、暗号化と復号化の際に一致する必要があるため、キーが非常に重要です。
- 暗号化は、保存中または送信中の機密データを保護します。たとえば、通信中に2FAコードが傍受された場合でも、暗号化されたバージョンにより、正しいキーがなければ権限のないユーザーが2FAコードを解読できないようになります。
//Example for encryption of our 2FA verification code string EncryptData(string data, string key) { uchar encrypted[]; CryptEncode(CRYPT_AES256, data, encrypted, StringToCharArray(key)); return CharArrayToHex(encrypted); } string DecryptData(string encryptedData, string key) { uchar decrypted[]; uchar input[]; StringToCharArray(encryptedData, input); CryptDecode(CRYPT_AES256, input, decrypted, StringToCharArray(key)); return CharArrayToString(decrypted); } // Usage string key = "StrongEncryptionKey123"; // Use a secure key string encrypted2FA = EncryptData(twoFACode, key); Print("Encrypted 2FA code: ", encrypted2FA);
3.2FAのための安全な乱数生成
- GenerateSecureRandom6DigitCode関数は、CryptEncode関数とCRYPT_HASH_SHA256アルゴリズムを使用して、暗号的に安全なランダムシーケンスを生成します。その結果は、モジュラー演算とフォーマットを用いて6桁の数字に変換されます。
- MathRandのような標準的なランダム関数は疑似ランダムであり、予測可能です。暗号的なランダム性を使用することで、2FAコードの安全性が高まり、予測攻撃や総当たり攻撃に対する耐性が強化され、認証プロセス全体のセキュリティが向上します。
// Example for generating a secure verification code string GenerateSecureRandom6DigitCode() { uchar randomBytes[3]; CryptEncode(CRYPT_HASH_SHA256, MathRand(), randomBytes); // Use CryptEncode for randomness int randomValue = (randomBytes[0] << 16) | (randomBytes[1] << 8) | randomBytes[2]; randomValue = MathAbs(randomValue % 1000000); // Ensure 6 digits return StringFormat("%06d", randomValue); }
4. Telegramによる安全な通信
- SendEncryptedMessageToTelegram関数は、SendMessageToTelegram関数を使用して Telegram サーバーに送信する前に、EncryptData関数を用いてメッセージを暗号化します。暗号化されたメッセージは、正しい復号化キーを持つ者のみが復号できます。
- 通信を暗号化することで、たとえ送信が傍受されても、2FAコードなどの機密情報の機密性が保護されます。これは、データが完全に安全でない可能性があるサードパーティの通信プラットフォームを使用する際に特に重要です。
//Example of the securely sending to Telegram bool SendEncryptedMessageToTelegram(string message, string chatId, string botToken, string key) { string encryptedMessage = EncryptData(message, key); return SendMessageToTelegram(encryptedMessage, chatId, botToken); } // Usage string key = "StrongEncryptionKey123"; SendEncryptedMessageToTelegram("Your 2FA code is: " + twoFACode, Hardcoded2FAChatId, Hardcoded2FABotToken, key);
テスト
この段階で、管理パネルへのセキュリティ強化結果を提示します。このアップデートにより、信頼できるユーザーはログインプロセスが簡素化され、迅速にパネルにアクセスできるようになります。一方、信頼できないユーザーは、本人確認のために二次認証を受ける必要があります。もしユーザーがパスワードを忘れた場合、認証プロセスを通じてパスワードを回復できます。
以下のエキスパートログでは、失敗したログイン試行を示すとともに、ログインフローを示す画像も紹介しています。
2024.11.22 03:53:59.675 Admin Panel V1.23 (Volatility 75 (1s) Index,M2) Too many failed attempts. 2FA will be required. 2024.11.22 03:54:00.643 Admin Panel V1.23 (Volatility 75 (1s) Index,M2) Message sent successfully: Check your telegram for verification code and Password 2024.11.22 03:54:00.646 Admin Panel V1.23 (Volatility 75 (1s) Index,M2) Password authentication successful. A 2FA code has been sent to your Telegram. 2024.11.22 03:54:22.946 Admin Panel V1.23 (Volatility 75 (1s) Index,M2) 2FA authentication successful. Access granted to Admin Home Panel.
検証のために送信されたTelegramメッセージ
管理パネル:失敗したログイン試行
信頼できるユーザーの場合、ログインプロセスは簡単です。二次認証手順を省略し、管理パネルへのアクセスを効率化できます。以下は、信頼できるユーザーがログインに成功したことを示すエキスパートログです。その後、正しいパスワードを入力したユーザーの簡単なログインプロセスを示す画像が続きます。2024.11.22 03:57:41.563 Admin Panel V1.23 (Volatility 75 (1s) Index,M2) Login successful. 2FA skipped for trusted user.
管理パネル:信頼できるユーザーパスワードでログインに成功
結論
管理パネルの強化に関する今回のディスカッションでは、機能性とセキュリティの両面で大きな進展を遂げました。信頼できるユーザー機能の導入により、ログイン試行回数を3回に制限し、この範囲内で認証が成功した場合、2FAをバイパスすることで、既知のユーザーにとってスムーズかつ効率的なログイン体験を提供します。このアプローチは、セキュリティと使いやすさのバランスを取るとともに、信頼できない試行に対しては厳格なアクセス制御を維持し、正当なユーザーに対する摩擦を減らします。
また、パネルのセキュリティ強化のために暗号技術を活用する可能性についても探りました。パスワードのハッシュ化、機密データの暗号化、2FAコードの安全な乱数生成を取り入れることで、重要な情報の整合性と機密性を保護しました。ハッシュ化は保存されたパスワードを不正アクセスから守り、暗号化は送信中および保存中の機密データを保護します。さらに、暗号的に安全なランダム性を使用することで、生成されたコードの予測不可能性が確保され、総当たり攻撃に対する防御層を強化しました。
これらの進展により、取引コミュニケーションおよび操作を管理するための、ユーザーフレンドリーで安全な管理ツールが実現しました。機能性とセキュリティの両方に配慮することで、今後のワークフローの効率化と、最高基準のデータ保護を遵守するための基盤が整いました。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16339





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索