見出し画像

MT4 自動売買EA最強の口座認証を構築その6最終

少しづつ分割して書いてきたのでだいぶ長くなってしまいました。
スキ欲しいです!!よろしくお願いします!!
このシリーズもその6で完成となります。この記事の続きです。


最後はMT4のプログラムを書いていきます。
MetaEditorを開いて新規作成→エキスパートアドバイザーでMQLファイルを作成して下さい。ファイル名はお好きにどうぞ。

1.通信周りのプログラム

まずは、FastAPIサーバーと通信するwininet周りを書いていきます。FastAPIの認証サーバーURLは一応わかりづらい通信方式です。URLがバレちゃうあたりはココあたりに記載しています。

account変数は、MT4でログインしている口座番号です。
auth_url変数は、FastAPIサーバーのURLにaccount変数をくっつけてURLを生成しています。wininet.dllをインポートして通信するプログラムがそれ以下です。http://***.**.***.***:8000をご自分の環境に合わせて変更してください。

string account = IntegerToString(AccountNumber());
string auth_url = "http://***.**.***.***:8000/?account="+account;
 #import   "wininet.dll"
int InternetOpenW(string agent, int accessType, string proxyName, string proxyByPass, int flags);
int InternetOpenUrlW(int internetSession, string url, string header, int headerLength, int flags, int context);
int InternetReadFile(int, uchar &arr[], int, int &byte);
int InternetCloseHandle(int winINet); #import  

string ReadInternet(string url, int cp){
   int inet = InternetOpenW("MetaTrader", 0, "0", "0", 0);
   if(inet == 0)
     {
      return("MetaTrader Error");
     }
   else
     {
      int handle = InternetOpenUrlW(inet, url, NULL, 0, 0, 0);
      string text = "";
      int    byteSize = 0;
      uchar  receive[1024];
      while(InternetReadFile(handle, receive, 1024, byteSize))
        {
         if(byteSize <= 0)
            break;
         text += CharArrayToString(receive, 0, byteSize, cp);
        }
      InternetCloseHandle(handle);
      InternetCloseHandle(inet);
      return(text);
     }
   return("Error");
}

2.認証の基本的なプログラム

次に、エキスパートアドバイザーで認証を行う基本的な部分を書いていきます。今回は、OnInit()に書きますので、エキスパートアドバイザーがセットされた瞬間に口座認証が走ることになります。

int OnInit(){
  Comment("");
  //DLLの使用が許可されているかを確認する
  if(!MQLInfoInteger(MQL_DLLS_ALLOWED)){
    Comment("DLLの使用が許可されていません");
    return INIT_FAILED;
  }
  //認証サーバーに問い合わせ
  string response = ReadInternet(auth_url, CP_UTF8);
  StringReplace(response,"\"","");
  
  // 検証用。プログラム完成時に削除//////////////
  Print(response+":認証サーバーからのレスポンス");
  /////////////////////////////////////
  
  if(response!="Error"){
    if(auth(response)){
      Comment("口座番号",account,"認証OK");
      return INIT_SUCCEEDED;
    } else {
      Comment("口座番号",account,"認証NG");
      return INIT_FAILED;
    }
  } else {
    Comment("口座番号",account,"認証NG");
    return INIT_FAILED;
  }
}

wininet.dllの使用が許可されているかを確認します。wininet.dllを使うにはDLLの使用を許可するにチェックが入っていないと通信ができません。

上記で作成したReadInternet関数にauth_url変数を渡し、FastAPIサーバーに口座番号を投げかけます。その5で作成した暗号化ハッシュ応答がresponseに返ってきます。返ってきたハッシュの前後に「"」がついているので取り除きます。

responseがエラー出なかったら

if(response!="Error"){

レスポンスを下記で作成するauth関数に渡します。

if(auth(response)){

その結果、auth関数からtrueが返ってきたらコメントで認証OKとチャート左上に表示しINIT_SUCCEEDED初期化成功となります

      Comment("口座番号",account,"認証OK");
      return INIT_SUCCEEDED;

もし、auth関数からfalseが返ってきたら認証NGと表示し、INIT_FAILEDとしチャートからエキスパートアドバイザーが削除され自動売買EAを動かすことが出来ない仕組みになります。

  } else {
    Comment("口座番号",account,"認証NG");
    return INIT_FAILED;

下記は、検証用です。MT4のターミナルにあるエキスパートタブに認証サーバーからのレスポンスを確認するためです。wininetで通信がうまくいっていれば、ハッシュ化された口座番号のレスポンスが表示されます。この表示はユーザーに見られたくないのでプログラム完成後に削除してください。

  // 検証用。プログラム完成時に削除//////////////
  Print(response+":認証サーバーからのレスポンス");
  /////////////////////////////////////

3.口座番号照合プログラム

FastAPIから受け取ったハッシュ化された口座番号とMT4でログインしている口座番号を照合するauth関数を書いていきます。string key = "AAA";はFastAPIサーバー側に記載したキーと合わせてください。

string key = "AAA";

bool auth(string hash_sha256){
  string text = account + key;
  uchar src[],dst[],k[];
  // 暗号文をバイナリにデコード
  StringToCharArray(text,src,0,StringLen(text));

  int result=CryptEncode(CRYPT_HASH_SHA256,src,k,dst);
  if(result>0){
  
    // 検証用。プログラム完成時に削除//////////////
    Print(ArrayToHex(dst)+":内部生成ハッシュ");
    /////////////////////////////////////
    
    if( hash_sha256 == ArrayToHex(dst)){
      return true;
    } else {
      Print("口座認証エラー");
      return false;
    }
  } else {
    Print("エンコードエラー。 エラーコード =",GetLastError());
    return false;
  }
}

string ArrayToHex( uchar &arr[] , int count=-1 )
{
    string res = "";
    //--- arr配列サイズ確認
    if( count < 0 || count > ArraySize(arr)) {
        count = ArraySize(arr);
    }
    //--- arr配列のデータから文字列(16進数表示)を作成
    for( int i=0; i < count; i++) {
        //Print(StringFormat("%.2X",arr[i]),":",arr[i]);
        res += StringFormat("%.2X",arr[i]);
    }
    return( res );
}

account変数にキーをくっつけたtext変数を作ります。text変数は12345AAAといった形になります。

text = account + key;

text変数をハッシュ化します。ハッシュ化されdst変数に格納されます。

  uchar src[],dst[],k[];
  // 暗号文をバイナリにデコード
  StringToCharArray(text,src,0,StringLen(text));

  int result=CryptEncode(CRYPT_HASH_SHA256,src,k,dst);

dst変数をArrayToHex関数に渡し、文字列として見えるようにしMT4のターミナルにあるエキスパートタブに表示するようにします。ここも同じようにユーザーには見せたくないのでプログラム完成後に削除してください。

    // 検証用。プログラム完成時に削除//////////////
    Print(ArrayToHex(dst)+":内部生成ハッシュ");
    /////////////////////////////////////

FastAPIからのレスポンスとMT4内で生成したハッシュが2行に渡って表示されるはずです。

この2行のハッシュが同じであればtrueを返します。

    if( hash_sha256 == ArrayToHex(dst)){
      return true;

ハッシュが違えば、falseを返します。

    } else {
      Print("口座認証エラー");
      return false;
    }

4.口座認証の仕組み

内部生成ハッシュ(口座番号+キー)はユーザー側で操作することはできません。FastAPI側から返ってくる認証サーバーからのレスポンスハッシュ(口座番号+キー)はスプレッドシートに口座番号がなければ生成されません。
内部生成ハッシュと認証サーバーからのレスポンスハッシュが同じであれば、口座認証OKという仕組みにしています。
 口座番号だけをハッシュ化すると誰でも自分の口座番号をハッシュ化しサーバーからのレスポンスを書き換えることで口座認証を騙すことが出来ます.
騙し方はココ辺りに書いています。
口座番号+キーをハッシュ化することでキーを知らなけれは自分の口座をハッシュ化することはかなり難しくなります。

5.最後に

口座認証をなるべく複雑にする方法を記事にしてきました。この方法でも破ることは可能ですが、簡単に破れるユーザーは数少ないという前提で書いています。
 今回はOnInit()関数にプログラムを書いていきましたがログインが遅れると認証NGになる可能性もあるので多少の工夫が必要だと思います。
 FastAPI側とMT4側を多少改造すれば、最低運用証拠金なども認証の条件に含むこともできますので是非いろいろ試してみてください。
 認証サーバーのFastAPIを自動起動する設定も必要です。

6.サポート

わからないことがあれば、X(旧twitter)でお気軽に問い合わせください。また、この方式の設置代行も致しますのでお気軽にご相談ください。

全ソースコード

上記プログラムと同じソースを記載しています。

ここから先は

3,318字

¥ 1,980

期間限定 PayPay支払いすると抽選でお得に!

この記事が参加している募集

#スキしてみて

525,791件

この記事が気に入ったらサポートをしてみませんか?