エラー スクリプト
ドメイン ロック、日付ロック、自己防御型の保護といったいくつかの変換は、チェックに応えてコードを実行することができるランタイム チェックです。これらの変換にはすべて任意の構成プロパティ errorScript
があり、このプロパティで、ランタイム チェックがトリガーされたときに実行するスクリプトを提供できます。このセクションでは、保護されるコードにエラー スクリプトを追加する方法を学習します。
構成オプション errorScript
を指定せずに JSDefender を実行する方法
構成プロパティ errorScript
を使用しない場合は、JSDefender により既定の保護が適用されます。
変換 | 既定の保護 |
---|---|
ドメイン ロック | RangeError: Maximum call stack size exceeded (呼び出しスタックの最大サイズを超えました) エラー メッセージを発行します。 |
日付ロック | RangeError: Maximum call stack size exceeded (呼び出しスタックの最大サイズを超えました) エラー メッセージを発行します。 |
自己防御型の保護 | メッセージ SyntaxError を発行します。 |
SyntaxError
です。コードをランダムに変換すると、その他のエラー メッセージが発行される場合もあります。
JSDefender がエラー スクリプトを使用する方法
保護エンジンは、構成プロパティ errorScript
の文字列値をそのままコードに差し込みます。それでも、保護エンジンは、各エラー スクリプトが JavaScript ブロック ステートメント内で実行されるように管理します。次のエラー処理スニペットがあるとします。
const myMessage = "I got you!";
alert(myMessage);
このスニペットは、次のような記述としてコードに差し込まれ、定数変数 myMessage
には別のスコープが提供されます。
{
const myMessage = "I got you!";
alert(myMessage);
}
Error: the code has been tampered!
(エラー: コードが改ざんされています!) メッセージが表示されます。
エラー スクリプトが差し込まれる場所
エンジンは、ドメイン ロック変換および日付ロック変換のエラー スクリプトを 1 回のみ、保護されたコードに差し込みます。JSDefender Runtime という十分に保護されたセクションは、ロックの検証で違反が検出された場合、このエラー ハンドラーを呼び出します。複数のファイルを保護している場合、このコードは必ず最初に保護されたファイルに差し込まれます。バンドルされたモジュールまたは Web チャンクを使用している場合、JSDefender はエラー ハンドラー コードを複数のファイルへ差し込みます。JSDefender はスクリプトを差し込むファイルと同じ設定でエラー ハンドラー スクリプトを保護します。
これに対し、自己防御型の変換では、保護されたすべての関数にエラー スクリプトが差し込まれます。JSDefender では部分的構成がサポートされているので、保護される複数の関数に異なるエラー スクリプトを割り当てることもできます。
エラー スクリプトで実行できること
JSDefender バージョン 2.2 以前では、以下の操作を実行できました。
- 追加操作を行った後、JSDefender にエラー メッセージを発行させる。
- 追加操作を行い、違反が起きていないかのようにコードを実行できるようにする。
バージョン 2.3 では、2 番目のオプションが使用できなくなりました。このオプションが削除された理由は、攻撃者が日付ロックやドメインロックの保護をより簡単に迂回できるような構成だからです。
エラー スクリプトの作成
エラー スクリプトを作成する場合、以下の機能を含め、JavaScript のツールセット全体を使用できます。
- 変数、関数、クラスの宣言
- ステートメント
- グローバル関数の呼び出し
- 例外処理(
try..catch..finally
)
ただし、以下の事項に注意する必要があります。
- できれば、コード内で
with
ステートメントやeval
関数を使用しないでください。これらにより、コードが保護の実行後に失敗する可能性があります。 var
宣言は、コードの他の語彙スコープ内の識別子と競合する可能性があるため、慎重に処理してください。- エラー スクリプトのコードにモジュールをインポートしないでください。関数やクラス メソッドを呼び出す必要がある場合は、グローバルな変数またはオブジェクトを介してそれらにアクセスしてください。
async
とawait
を使って非同期コードを使用することもできますが、エラー ハンドラーは同期的に実行されます。
var
宣言の使用
ES 2015 の let
および const
変数のみを使用することをお勧めします。なんらかの理由で var
宣言を使用する必要がある場合に、var
宣言が他の変数名と(偶々)競合する可能性があります。競合した場合は、エラー ハンドラーが失敗します。そのような場合には、即時関数を使用して JavaScript モジュール パターンを使用してください。たとえば、次のスクリプトは使用しないでください。
var myMessage = "I got you!";
alert(myMessage);
代わりに、以下を差し込んでください。
!(function () {
var myMessage = "I got you!";
alert(myMessage);
})();
グローバル関数の呼び出し
JavaScript のグローバル スコープの変数にアクセスできるほか、そこで宣言された関数(JavaScript のグローバル関数を含む)を呼び出すことができます。このため、myDateViolationHandler
というグローバル関数がある場合は、次の errorScript
を適用することができます。
myDateViolationHandler("violated");
myDateViolationHandler
の宣言とその参照の名前変更をエラー ハンドラー スクリプトで管理します。
async
コードの使用
エラー ハンドラーは同期的に実行されます。エラー ハンドラーに async
コードを追加することはできますが、違反があるにもかかわらずアプリケーション コードの実行を許可するのか、それとも停止するのかを決める関数の結果を await
(待機)させることはできません。
次のコードを見てください。
function timeout(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
(async () => {
await timeout(2000);
alert("Invalid date");
return;
})();
一見したところ、このコードには return
があるため、"Invalid date" メッセージが表示された後もアプリケーションの実行を続行できると考えられるかもしれません。しかし、その return は非同期の即時関数から戻るものです。戻るまでに、メッセージが表示されてユーザーに確認されます(2 秒の遅延があることが示されています)。保護エンジンは既定の操作を実行し、ReferenceError
メッセージを表示して停止します。
違反があるにもかかわらずコードの実行を許可するには、次のようにコードに締めくくりの return を追加する必要があります。
function timeout(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
(async () => {
await timeout(2000);
alert("Invalid date");
return;
})();
return; // --- 違反が行われた場合でも続行します
追跡すべきエラー ハンドラー パターン
優れたエラー処理スクリプトを作成するために踏襲すべきシンプルなパターンがあります。その方法をこのセクションで学習できます。
JSDefender は、元のコードの 1 行目よりも前に、ドメインと日付をチェックする保護が実行されるように管理します。このパターンを使用すると、日付違反の結果を格納できます。もちろん、ドメイン違反を管理するのにも類似のパターンを使用することができます。
次のコードをプログラムの先頭に追加します。
let dateViolated;
function signDateViolation() {
dateViolated = true;
}
if (dateViolated) {
// アプリの中止、ユーザーのログアウトなど、
// 日付違反時のロジックをここに追加します
}
// このコードが実行されるのは、制御フローがこのポイントまで到達した場合です
doMyJob();
dateLock
構成に次の errorScript
を追加します。
"dateLock": {
"startDate": "<開始日>",
"endDate": "<終了日>",
"errorScript": "signDateViolation(); return;"
}
エラー ハンドラーは return
ステートメントで終わっているため、日付違反が発生した場合でも、JSDefender はプログラムの流れを続行します。JSDefender は let dateViolated
宣言に到達する前に日付チェック ロジックを実行するので、if
ステートメントが日付条件を評価するまでに dateViolated
変数が正しく設定されることが保証されます。