Flashから送信される値を途中で改ざんしにくくする

改ざんしにくくしたゲーム作ってみました。→くりっくなう(スコア送信バシバシどぞ♪)

実際に、スコアを暗号化して送信しています。ポンクソフトさんFlashを元に作成させていただきましたです。

なんも考えないでFlashのゲームを作ると、スコアランキングを作るときに、スコアをそのままベタな平文で送ってしまいがちです。そうすると、ProxyでHTTPリクエストをインターセプトして書き換えてってことをカンタンにされちゃいます。(星野君連載第5話参照)

さて、そうされないようにはどうすればいいか。

とりあえず、Rijndael(AES暗号)で暗号化してみましょう。但し、この方法はswfファイルの逆コンパイルには耐性がありません。より、イタズラできる人の範囲を少なくするといった効果です。


-----------------------

調べたけど、Flashは通信路でリクエストを書き換えられることを意識していないのか、暗号系の関数がみあたらず。。。

そこで、そんな不満を持った人が作ってくれたモジュールを拝借します♪Meychiさん多謝♪

Meychiさんのページ(英語)→http://www.meychi.com/archive/000021.php

ここから、ASCrypt library extensionを落としてきて、Rijndealを使えるようにするのです。

Flash(ActionScript)側の記述はこうなります。わからない場合は付属のサンプルflaファイルを実行してみるとよいでしょう(いやらしい人は逆コンパイルするのでキーは見えても困らない程度のものを設定するべき) 。サンプルがそうなってたので、ECBモードで記述しています。

//インポート宣言 
import com.meychi.ascrypt.*; 

var rijndael_test:Rijndael = new Rijndael(192, 128); 
var rijndael_text:String = "ココに暗号化したい文字列"; 
var rijndael_key:String = "ココに暗号化キー"; 
var rijndael_hash:String = rijndael_test.encrypt(rijndael_text, rijndael_key, "ECB"); 
//デバッグ用には↓で見るといいかも 
//trace("Rijndael encrypted: "+rijndael_hash); 
//trace("Rijndael decrypted: "+rijndael_test.decrypt(rijndael_hash, rijndael_key, "ECB")); 

これでFlash側での暗号化は完了です。rijndael_hashの文字列を思う存分サーバに投げつけてあげましょう。

さて、サーバ側では、ちゃんと受け取ってあげなければいけません。以下はPerlで受け取る例です。

use CGI; 
use Crypt::Rijndael; 
my $query = CGI->new(); 
my $cipher = new Crypt::Rijndael "ココにFlash側で使った暗号化キー", Crypt::Rijndael::MODE_ECB; 
my $crypted = $query->param('AES');#ココで暗号化された文字列を受け取る。 
$crypted =~ s/([0-9A-Fa-f][0-9A-Fa-f])/pack("H2", $1 )/eg;#16進数で渡されるので戻してあげる。 
my $plaintext = $cipher->decrypt($crypted); 
$plaintext =~ s/\00//eg;#パディング除去 

そんな感じでデータの受け渡しをすれば、きっと途中で書き換えられ放題なんて間抜けなことにはなりません。

ただ、swfファイルを逆コンパイルされるとね。。。それって対策できるのかな?ま、そこは難しいから考えません。あは。

FlashのActionScriptを難読化

↓のツールを使ったりすると読みにくくなります。

actionscript obfuscator :http://www.genable.com/asolite.html

だた、関数名、変数名を読みにくくするものなため、暗号キーのような値は難読化できないみたいですにぇ。あと、処理のどこで暗号化しているかとかがわかりにくいような構成にしないとダメなようです。何でもかんでも難読化すると、誤動作するみたいなので、なかなか難しいですね。

難読化してみたのはこれ。最初っからこうなってると逆コンパイルしても読みにくそう。

http://sagittarius.dip.jp/~toshi/flash/iraira_harupu_obfuscation.php


難読化後はこんな感じ。頑張ればもうちょっとできるかも。

var eval ("aso#73613") = (new com.meychi.ascrypt.eval ("aso#48265")(192, 128));
var eval ("aso#04950") = t.toString();
var eval ("aso#36287") = _root.eval ("aso#10939");
var eval ("aso#42276") = eval ("aso#73613").encrypt(eval ("aso#04950"), eval ("aso#36287"), "aso#67624");


6/12追記:ちゃんとやったら暗号化部分ってわかんなそうな感じになった。飛ばし先URLも変数定義をどっかに飛ばしておけばわかりづらくていけっかな?(難読化のテーブルとかどっかに保持されてんのかなぁ?

var eval ("aso#92972") = (new eval ("aso#73613").eval ("aso#36287").eval ("aso#28906").eval ("aso#67624")(192, 128)); 
var eval ("aso#24309") = t.toString(); 
var eval ("aso#55646") = _root.eval ("aso#30298"); 
var eval ("aso#61635") = eval ("aso#92972").eval ("aso#04950")(eval ("aso#24309"), eval ("aso#55646"), "aso#18320"); 
lv.load((("iraira_harupu_obfuscation.cgi?name=" + escape(name)) + "&time=") + eval ("aso#61635"));