皆さん、こんにちは!今日はMetaTrader 4(MT4)のインジケーターやエキスパートアドバイザー(EA)にパスワード保護を追加する方法を紹介します。この方法を使えば、あなたのコードをしっかり守ることができますよ。
これまでにもコードを保護するための様々な方法が提案されてきましたが、どれも簡単すぎたり(セキュリティが低い)、新しい顧客ごとにコードを再コンパイルする必要があったり(顧客が数人ならまだしも、もっと多くなると大変です)、複雑すぎてクライアント端末の検証が必要だったりと、面倒なことが多かったんですよね。
そこで、ここではMT4の組み込みセキュリティエンジンを利用したシンプルなパスワード検証方式を提案します。これなら、顧客ごとにコードを再コンパイルする必要もなく、DES/ECB暗号化を使用できます。
私自身、カナダのスマートカード関連のプロジェクトに関わった経験があり、金融機関やカード発行者が使用する様々なセキュリティ方式に詳しくなりました。さて、まず考えるべきことは「リスクは何か?」です。プロジェクトを始める際には必ずリスク評価が行われます。もし答えが「何百万ドルものリスクがある」となれば、このセキュリティ方式は向いていません。
逆に、もし「誰かが私のセキュリティをハッキングするのに約1年かかるなら、数ヶ月のコーディングが無駄になるだけだ」と思うなら、この方法がピッタリです。この暗号化方式で使用される単一のDESキーは、あなたのコードを守るには十分なセキュリティを提供します。
便利に使える2つのソースファイルも用意しました。最初のファイル「Password_Check」は、インジケーターやエキスパートアドバイザーに追加するものです。このファイルは、ユーザーが入力した「Password」を検証し、間違っている場合(またはオフラインの場合)には親しみやすいメッセージを表示し、エキスパートを削除し、INIT_FAILEDステータスを返します。
次のファイル「Password_Generate」は、保護したいクライアントの名前と口座番号を入力するために使います。生成されたパスワードが表示されるので、これを顧客に提供できます。もちろん、このコードは最終製品には含めないようにしましょう!
では、始めましょう!まず、インジケーターやエキスパートアドバイザーに入力文字列を定義する必要があります:
//--- 入力パラメータ extern string Password;
次に、init()関数にパスワードを確認し、間違っている場合やオフラインの場合にメッセージを表示するコードを追加します。
//+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int init() { string client = NULL; // クライアントがオンラインであることを確認して、名前と口座番号を取得 if(IsConnected()) client = AccountInfoString(ACCOUNT_NAME) + " / " + DoubleToStr(AccountInfoInteger(ACCOUNT_LOGIN), 0); // クライアントのパスワードを確認 if(!Password_Check(client)) { if(StringLen(Password) != 0) MessageBox("クライアントと口座番号を確認できません!" + (IsConnected() ? "\n正しいパスワードを確認してください。" : "\n\n確認のためにはオンラインである必要があります。"), (IsConnected() ? "無効なパスワード!" : "オフライン!"), MB_OK | MB_ICONSTOP); else MessageBox("登録されていないソフトウェアです。\n\nソフトウェアベンダーに連絡して、\nあなた専用のアクティベーションパスワードを取得してください。" + (StringLen(client) == 0 ? "" : "\n\nあなたの登録情報は:\n\n'"+client+"'"), "未登録", MB_OK | MB_ICONSTOP); // 無効なパスワードまたはユーザーがオフライン。エキスパートを削除し、エラーで終了 ExpertRemove(); return(INIT_FAILED); } // すべて良好... return(INIT_SUCCEEDED); }
さて、ここからが本題です。クライアントの名前と口座番号をDESキーで暗号化し、その結果をBASE64にエンコードして、入力されたパスワードと比較します。結果が一致すれば、顧客は満足です。一致しなければ、ハッカーがDESキーを破ろうとしています。誤ったパスワードが入力されるたびにエキスパートアドバイザーは自動的にアンロードされるので、成功する前にボラボラでリタイアしてしまうかもしれません!
//+------------------------------------------------------------------+ //| クライアントのパスワードを検証 //+------------------------------------------------------------------+ bool Password_Check(string client) { string MasterKey; uchar dst[], src[], key[]; // ここで暗号化キーを定義します。DES/ECB暗号化のために7文字でなければなりません // パスワードは難解にしましょう。苗字は良くありません! // "wLdU&$z"のようなものが良いでしょう。今のところ、簡単なものを使います... MasterKey = "NotDemo"; // MasterKeyを文字配列に変換 StringToCharArray(MasterKey, key); // クライアント文字列がnullでないことを確認 if(StringLen(client) == 0) return(false); // DESキーを使用してクライアントを暗号化 StringToCharArray(client, src); CryptEncode(CRYPT_DES, src, key, dst); // キーをクリアし、BASE64にエンコード ArrayInitialize(key, 0x00); CryptEncode(CRYPT_BASE64, dst, key, src); // パスワードを比較して結果を返す return(CharArrayToString(src) == Password); }
これで、MetaTrader 4のクライアントアカウント名(クライアントの名前)と口座番号を検証できるようになりました。
ライセンスポリシーが単一のクライアントのために複数の口座を許可する場合、'client'文字列から口座番号を削除するだけで済みます。以下のように:
// クライアントの名前を取得するためにクライアントがオンラインであることを確認 if(IsConnected()) client = AccountInfoString(ACCOUNT_NAME);
もちろん、「ブローカー名」、「口座名」、「口座ログイン」を混ぜ合わせることもできます。'client'変数が長くなるほど、暗号化されたパスワードも長くなりますので、その点を考慮しておいてください。
次に「Password_Generate」コードを見てみましょう。やりたいことは「Password_Check」と同じですが、EAにパスワードを入力するのではなく、暗号化するためにクライアント名(またはあなたが選んだブローカー名、口座名、口座ログインの組み合わせ)を入力し、生成されたパスワードを表示します。これが、あなたの素晴らしいインジケーターやエキスパートアドバイザーを購入したクライアントに渡すものです。
再度、init()関数に以下のコードを追加します。
//+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int init() { string Password = NULL; // クライアント入力が空でないことを確認 if(StringLen(Client) != 0) { // クライアントパスワードを生成 Password = Password_Generate(Client); // 生成されたパスワードを出力(コピー&ペーストが簡単) Print("クライアント: '"+Client+"' パスワード: "+Password); // クライアントのために生成されたパスワードを表示 MessageBox("クライアント / 口座のために生成されたパスワード\n\n'"+Client+"' は:\n"+Password, "パスワードジェネレーター", MB_OK | MB_ICONINFORMATION); } else MessageBox("クライアント / 口座番号を指定する必要があります!", "パスワードジェネレーター", MB_OK | MB_ICONSTOP); // すべて良好。エキスパートを削除。 ExpertRemove(); return(INIT_SUCCEEDED); }
次に「Password_Check()」関数を少し修正して、エンコードされたパスワードの文字列を返すようにします。パスワードを両方の関数で同じものにすることを忘れないでください。そうしないと、大変なことになりますから!
//+------------------------------------------------------------------+ //| クライアント情報を暗号化し、パスワードを返す //+------------------------------------------------------------------+ string Password_Generate(string client) { string MasterKey; uchar dst[], src[], key[]; // ここで暗号化キーを定義します。DES/ECB暗号化のために7文字でなければなりません // 'Password_Check()'関数で定義された同じパスワードでなければなりません! // パスワードは難解にしましょう。苗字は良くありません! // "wLdU&$z"のようなものが良いでしょう。今のところ、簡単なものを使います... MasterKey = "NotDemo"; // MasterKeyを文字配列に変換 StringToCharArray(MasterKey, key); // クライアントをDESキーで暗号化 StringToCharArray(client, src); CryptEncode(CRYPT_DES, src, key, dst); // キーをクリアし、BASE64にエンコード ArrayInitialize(key, 0x00); CryptEncode(CRYPT_BASE64, dst, key, src); // 暗号化されたパスワードを返す return(CharArrayToString(src)); }
これで完了です!クライアントから提供された情報を入力し、メールなどの手段でパスワードを送信するだけです。この仕組みの良いところは、ボラボラの自宅からでもできるということです!
このセキュリティ方式は、毎回新しい顧客のためにコードを再コンパイルしたり、サーバー側の検証ホストを設定したりする必要がなく、あなたが作った素晴らしいインジケーターやエキスパートアドバイザーのために、かなり良好なセキュリティを提供します。
それでは、楽しいトレードを!
- クロード