(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!


Messagepackをより安全に使う方法【Unity】【Messagepack】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 6000.2.6f2


はじめに

以前、JSONと同じように扱えて、より高速かつコンパクトなMessagePack

Unityに導入する方法と使い方を紹介しました。


今回はそのMessagepackをより安全に使う方法の紹介です!

特にオンラインでデータのやり取りする場合に必要になってくる話です。


UntrustedDataを使う

1つ目はデジリアライズ(復元)時にMessagePackSecurity.UntrustedDataを使う方法です。

これを使うと、過剰なネストや巨大なサイズのデータなど、

悪意あるデータが送られてきた時に復元途中で検出して中断出来ます。

(逆に使わずに悪意あるデータを復元してしまうと、フリーズやクラッシュの原因になります)

//UntrustedDataのオプション作成
var untrustedDataOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData);

//復元時にそのオプションを指定
var restored = MessagePackSerializer.Deserialize<Sample>(bytes, untrustedDataOptions);


なお、復元を中断した際はMessagePackSerializationExceptionという例外をキャッチ出来ます。

try{
  var untrustedDataOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData);
  var restored = MessagePackSerializer.Deserialize<Sample>(bytes, untrustedDataOptions);
  Debug.Log($"Deserialize成功");
}
catch (MessagePackSerializationException e){//不正な深さ/サイズ/形式など → ここで止まる(オブジェクトは生成されない)
  Debug.LogError($"Deserialize失敗: {e.GetType().Name} : {e.Message}");
}
catch (System.Exception e){//念のためその他の例外も捕捉
  Debug.LogError($"Deserialize失敗(その他): {e.GetType().Name} : {e.Message}");
}



Typelessを使わない

2つ目はTypelessを使わないようにするという事です。

MessagepackはTypelessContractlessStandardResolver.Instanceを使う事で、

objectや未知の型をそのまま送って、さらに型を自動復元する事が出来ます。

//objectでインスタンス作る
object player = new Player{ Id = 2 };

//タイプレスのオプション指定して、シリアライズ
var typelessOptions = MessagePackSerializerOptions.Standard.WithResolver(TypelessContractlessStandardResolver.Instance);
var bytes = MessagePackSerializer.Serialize<object>(player, typelessOptions);

//タイプレスのオプション指定して、デシリアライズ
object restoredPlayer = MessagePackSerializer.Deserialize<object>(bytes, typelessOptions);

//型が分かる
Debug.Log($"restoredPlayerのタイプ名 : {restoredPlayer.GetType().Name}");


ただ、これは使ってしまうと攻撃者により「想定外の型」を復元させられる可能性があるため、

基本的には使わないようにしましょう。