JSDefender 1.x から 2.x へのアップグレード

概要

JSDefender バージョン 2 では、バージョン 1 より高度な JavaScript コードの保護シナリオをサポートしています。また、バージョン 1 のユーザーが注意する必要のある重大な変更がいくつかあります。最も重要な変更点と新機能の概要は次のとおりです。

  • コマンド ライン インターフェイス(CLI)の名前は、pjsd から jsdefender に変わりました。
  • 単一の保護セッションで複数のソース ファイルを保護できるため、ファイルごとに CLI を実行する必要はありません。
  • バージョン 2 には、次のような新しい保護技法が備わっています。
    • 自己防御型:保護された関数をコード改ざんを監視する関数にラップします。ハッカーがコードを変更した場合(たとえば、コードを整形したり、何かを追加または削除したりしようとした場合)、そのコードは正しく実行されなくなります。
    • 式シーケンスの難読化:隣接する割り当て式を式シーケンスに変換します。
    • プロパティの散在化変換:単一のオブジェクト リテラルの割り当てを複数の割り当てに変換することで、コードの読み取りをより困難にします。
    • 変数のグループ化変換:変数の宣言と初期化を分けます。宣言をホストする語彙スコープの最後に宣言を移動します。
  • バージョン 2 は、バンドルとモジュールを認識します。JSDefender はこの情報を使用して、より高度で洗練された方法で変換を実行します。

CLI の変更点

CLI の最も重要な変更点は、その名前です。pjsd ではなく jsdefender を使用して CLI を呼び出す必要があります。そのため、古いバージョンで次のような行を書いていた場合は、

pjsd input.js protected.js

次のように変更する必要があります。

jsdefender input.js protected.js

コマンド ライン オプションを使用し、構成ファイルを使用しない単一ファイルのシナリオの場合は、名前を変更するだけでバージョン 1 から 2 へ移行できます。しかし、pjsd を使用して複数のファイルを保護したり、CLI ツールで構成ファイルを使用したりしていた場合は、より多くの変更に備える必要があります。

削除されたコマンド ライン オプション

バージョン 2 には存在しなくなったコマンド ライン オプションがいくつかあります。

  • --inclusive包含モードを有効にします。このモードは、-s/--scope オプションでマークされたスコープ指定の関数のみを保護します。
  • -s--scope包含モードにある場合は含める対象、そうでない場合は除外する対象となる関数名パターンを指定します。

JSDefender は、これらのスイッチの代わりにインラインの保護ディレクティブを使用して、部分的な保護を設定するようになりました。これらのディレクティブは直接ソース コードに記述されます。コードのどのパーティションが保護され、それに対してどの技法が適用されるかを記述するためのより簡単な方法を提供します。

  • --idprefix:複数ファイルのシナリオを処理するための回避策として、プログラム スコープの宣言に対して識別子プレフィックスを設定します。
  • --id-map--id-map-in--id-map-out:複数ファイルのシナリオを管理するために、複数のセッション間で識別子の宣言情報を保持するためのオプション。

これらのオプションはすべて、pjsd で複数ファイルのシナリオに対応できるようにするための回避策でした。現在、jsdefender は単一のコマンド ライン セッションでの複数ファイルの保護をサポートしているので、これらのオプションはもう必要ありません。

  • --es5:難読化中に使用される ES 2015(以降)の言語機能の使用を無効にします。

pjsd ツールは、いくつかのシナリオで(主に、Internet Explorer の互換性のために)このオプションを使用しました。jsdefender CLI は、ソース コードの ES バージョンを自動的に検出し、適宜保護機能を使用します。何らかの理由で、保護に使用する ES バージョンを今後もより細かく制御する必要がある場合は、jsdefender では --estarget オプションを使用できます。

  • -a- anns-A- annsoff:これらのオプションは、バージョン 1 での将来の拡張のために予約されていました。バージョン 2 では、これらは必要ありません。

変更された既定値

jsdefender では、-m--mapout オプションは既定で有効に設定されます。コマンド ラインに -m off または --mapout off オプションを追加しない限り、CLI は maps.txt ファイルを語彙スコープの階層マップと一緒に、現在の作業フォルダーに生成します。ファイルの形式については、ユーザー ガイドの語彙割り当てセクションを参照してください。

新しいコマンド ライン オプションとスイッチ

jsdefender ツールには、pjsd では利用できなかった新しいコマンド ライン オプションがあります。新しいオプションは、新しい保護技法を定義します。

  • --constarg--constargoff定数引数の保護を有効または無効にします。
  • --datelock:ソース コードを特定の日付(および時刻)の範囲にロックできます。
  • --exprseq--exprseqoff式シーケンス変換の保護を有効または無効にします。
  • --propsparsing--propsparsingoffプロパティの散在化の保護を有効または無効にします。
  • --selfdefend--selfdefendoff自己防御型の保護を有効または無効にします。
  • --vargroup--vargroupoff変数のグループ化による保護を有効または無効にします。

CLI は、別の新しいオプションを提供します。

  • --estarget:保護されるコードの ES ターゲットを定義できます。既定では、ツールがソース ファイルの解析中に検出する、最新の ES バージョンが使用されます。
  • --randomseed:乱数生成に使用するシード値(32 ビットの数値)を定義できます。同じ値を使用すると、JSDefender は同じコマンド ライン オプションで実行されたときに、同じ乱数を生成できます。このオプションは、トラブルシューティングに役立ちます。
  • --ignore-unsafe:保護の変換は、保護した後にコードを失敗させる可能性がある安全でない構成(変数名を変更する JavaScript の with ステートメントなど)の入力コードを調べます。既定では、ツールは安全でないコードの保護を中止します。しかし、このオプションを使用すれば、安全でない要素がある場合でもコードの保護を続行できます。
  • --disable-inline:このオプションを使用すると、インラインの保護ディレクティブの使用を無効にし、ディレクティブがコードに書き込まれていないかのようにすることができます。

暗黙の構成ファイル

jsdefender CLI は、jsdefender.config.json という名前の構成ファイルが存在するかどうか現在の作業ディレクトリを自動的に調べます。そのファイルが存在する場合、CLI は自動的にそれを読み込んで使用します。したがって、現在の作業フォルダーに該当ファイルがあれば、引数を何も指定せずに CLI を呼び出すことができます(つまり、jsdefender を実行するだけです)。別の構成を使用したい場合は、-c または --config オプションで構成ファイル名を使用します。

jsdefender -c myconfig.json
jsdefender --config myconfig.json
メモ: この例では、現在の作業フォルダーに jsdefender.config.json ファイルが存在していた場合でも、JSDefender ではそのファイルを無視して、myconfig.json を適用します。

構成ファイルの簡易な使用法

典型的なシナリオでは、jsdefender は次のように構成ファイルのみを指定して実行します。

jsdefender --config superheavy.config.json

これをさらに簡潔にすることができます。ファイル名の引数が 1 つだけである場合、jsdefender はそれを構成ファイルの名前と見なします。したがって、次のコマンド ラインは前のコマンド ラインと同等です。

jsdefender superheavy.config.json

単一ファイルの保護

構成ファイルの指定がないコマンド ラインの移行

単一ファイルを保護する場合、コマンド ライン オプションを介してのみ構成する(つまり、構成ファイルがない)のであれば、pjsd で使用したコマンド ライン オプションと同じオプションを jsdefender で使用できます。たとえば、次のような実行するバージョン 1 のコマンド ラインがあるとします。

pjsd input.js protected.js -b -i -names sequential

バージョン 2 で必要なのは、CLI の名前を変更することだけです。

jsdefender input.js protected.js -b -i -names sequential

pjsd--inclusive または -s/--scope オプションを使用していた場合、jsdefender で部分的な保護を設定するには、ソース コードにインラインの保護ディレクティブを追加する必要があります。ユーザー ガイドのインライン構成セクションを参照してください。

今後、--es5 オプションを使用することはできません。代わりに、--estarget es5 に変更してください。Internet Explorer 準拠のコードを作成するための次のコマンド ラインがあるとします。

pjsd input.js protected.js --es5

jsdefender では、次のように実行する必要があります。

jsdefender input.js protected.js --estarget es5

PJSD 構成ファイルの移行

pjsd で構成ファイルを使用していた場合、それを jsdefender で使用できるようにするには、新しいファイル形式に移行する必要があります。新しいファイル形式は、多くの新しいオプションによって古い形式を拡張します。

  • 複数のソース ファイルおよび出力ファイルを定義できます。
  • ソース コードと出力のフォルダーを設定するオプションがあります。
  • 名前付きの構成セットを作成できます。
メモ: 新しいファイル形式の詳細については、User Guide の構成ファイルの形式セクションを参照してください。

保護技法

単一ファイルのシナリオの場合、構成ファイルの移行は簡単です。pjsd では、JSON 構成オブジェクトに保護技法を設定するための以下のプロパティがあります。

  • booleanLiterals
  • integerLiterals
  • stringLiterals
  • domainLock
  • propertyIndirection
  • localDeclarations
  • debuggerRemoval
  • controlFlow
  • functionReorder

jsdefender では、これらのプロパティを値とともに使用できます。ただし、それらを新しいオブジェクト名 settings で囲む必要があります。次の pjsd 構成があるとします。

{
  "domainLock": {
    "domainPattern": "mysuperapp.azurewebsites.net"
  },
  "stringLiterals": true,
  "localDeclarations": {
    "nameMangling": "base62"
  }
}

jsdefender で使用するには、次のようにして構成をアップグレードする必要があります。

{
  "settings": {
    "domainLock": {
      "domainPattern": "mysuperapp.azurewebsites.net"
    },
    "stringLiterals": true,
    "localDeclarations": {
      "nameMangling": "base62"
    }
  }
}

部分的な保護

pjsd CLI で部分的な保護を設定するには、構成ファイルで localContext プロパティを使用しました。このプロパティは jsdefender では使用できないため、移行された構成ファイルから削除する必要があります。部分的な保護を利用するための詳細については、ユーザー ガイドのインライン構成セクションを参照してください。

ES5 モードの設定

pjsd では次の例のように、es5Mode プロパティ(ブール値を受け入れる)により保護対象を ES5 に設定することができます。

{
  "es5Mode": true,
  "stringLiterals": true,
  "localDeclarations": {
    "nameMangling": "base62"
  }
}

jsdefender では、同じ目的のために esTarget 構成プロパティを使用して es5 値を指定します。したがって、上記の構成の移行バージョンは次のようになります。

{
  "esTarget": "es5",
  "settings": {
    "stringLiterals": true,
    "localDeclarations": {
      "nameMangling": "base62"
    }
  }
}

idPrefix の使用

pjsdidPrefix オプションは、複数ファイルの保護を複数の CLI セッションを介して管理する方法を提供するための回避策です。単一ファイルの保護の場合、このオプションはまったく必要ありません。jsdefender にこの構成オプションは存在しません。pjsd 構成ファイルにこのオプションが見つかった場合は、誤ってそこに残されているか、または複数ファイルの保護を使用しているかのいずれかです。前者の場合は、このオプションを削除できます。後者の場合は、複数ファイルでの作業セクションをお読みください。

license の使用

保護セッションに使用するライセンス キーの設定には、今後も license プロパティを使用できます。次のような、ライセンス情報を含む pjsd 構成ファイルがあるとします。

{
  "license": "MYLICENSE1234",
  "stringLiterals": true,
  "localDeclarations": {
    "nameMangling": "base62"
  }
}

jsdefenderでは、次の構成形式を使用します。

{
  "license": "MYLICENSE1234",
  "settings": {
    "stringLiterals": true,
    "localDeclarations": {
      "nameMangling": "base62"
    }
  }
}

複数ファイルでの作業

新しいバージョンの JSDefender では、複数ファイルのシナリオをそのまま処理することができます。複数の pjsd セッションを実行する必要はありません。代わりに、単一の jsdefender CLI 呼び出しで保護を実行できます。

jsdefender では、単一ファイルのシナリオの場合にのみ、コマンド ライン オプションでファイル名を設定できます。複数ファイルを用いる場合、入力と出力に名前を付けるには、構成ファイルを使用する必要があります。これらのシナリオ用の設定方法については、ユーザー ガイドの複数ファイルの保護セクションを参照してください。

JSDefender Webpack プラグインの使用

新しいバージョンの JSDefender Webpack プラグインは、以下に挙げる事項を除き、以前のバージョンと同様に機能します。

パッケージ名の変更

パッケージの名前は @preemptive/pjsd-webpack-plugin から @preemptive/jsdefender-webpack-plugin に変更されました。そのため、package.json 内のパッケージ名と同様に、webpack.config.js 内のパッケージ名も変更する必要があります。

const {
  JSDefenderWebpackPlugin,
} = require("@preemptive/jsdefender-webpack-plugin");

名前を提供しない暗黙の構成ファイル

プラグインは CLI と同様、既定では、暗黙の構成ファイル jsdefender.config.json が存在するかどうかプロジェクトのルート ディレクトリを探します。つまり、構成ファイルの名前が jsdefender.config.json である場合は、プラグイン オプションでその名前を提供する必要はありません。もちろん、別の名前の構成を提供することは可能です。

new JSDefenderWebpackPlugin({
  includeChunks: ["main", "child"],
});
new JSDefenderWebpackPlugin({
  configurationFile: "jsdefender.config.json",
  includeChunks: ["main", "child"],
});
// 上記の 2 つの構成は、プロジェクト ルートに `jsdefender.config.json` ファイルがある場合は同一です

構成形式

このガイドの PJSD 構成ファイルの移行セクションで述べたように、構成形式が新しい形式に変更されました。これは、プラグインのコンストラクター オプションや構成ファイル(ある場合)にも当てはまります。

new JSDefenderWebpackPlugin({
  // 以下のプラグイン オプションは変更されていません
  configurationFile: "my-jsdefender-config.json", // 明示的または既定(`jsdefender.config.json`)の構成ファイルの形式も変更する必要があります
  includeChunks: [],
  excludeChunks: [],
  quietMode: true,
  // 非本番モードで保護を有効にするための、新しいオプションが追加されました
  enableInDevelopmentMode: true,
  // プラグインのコンストラクターで提供されたインライン保護構成は、構成ルートで提供するのではなく、`settings` キーの下に移動させる必要があります
  settings: {
    // `booleanLiterals`、`integerLiterals` などのインライン保護構成
  },
});

非本番モードでのプラグインの実行

以前のバージョンでは、プラグインはすべての Webpack モードに対して保護を実行していました。今後、既定では、mode という Webpack 構成が production に設定されていなければ、保護はスキップされます。Webpack ドキュメントによると、既定値は production なので、設定を変更しない限り、保護は実行されます。非本番モードで保護を実行するためには、JSDefender Webpack プラグインの enableInDevelopmentMode オプションを true に設定します。

構成のマージ方法

構成のマージ方法が変更されました。以前のバージョンでは、configurationFile で提供された保護構成は、new PjsdWebpackPlugin() コンストラクターで直接提供された保護構成によって上書きされました。新しいバージョンでは、コンストラクターの構成は、明示的または暗示的(jsdefender.config.json)構成ファイルで提供された構成がある場合、その構成を上書きします。

jsdefender.config.json

{
  "settings": {
    "booleanLiterals": true
  }
}

webpack.config.js

  ...
  new JSDefenderWebpackPlugin({
    settings: {
      booleanLiterals: false
    }
  })
  ...

上記の場合、booleanLiterals オプションの最終的な値は false になります。

既定の構成

プラグインは CLI と同様、既定の構成を使用します。これは、プラグインに明示的に構成を指定することによって上書きできます。

JSDefender Metro プラグインの使用

新しいバージョンの JSDefender Metro プラグインは、以下に挙げる事項を除き、以前のバージョンと同様に機能します。

パッケージ名の変更

パッケージの名前は @preemptive/pjsd-metro-plugin から @preemptive/jsdefender-metro-plugin に変更されました。そのため、package.json 内のパッケージ名と同様に、metro.config.js 内のパッケージ名も変更する必要があります。

const jsdefenderMetroPlugin = require("@preemptive/jsdefender-metro-plugin")({...}, {...});
module.exports = jsdefenderMetroPlugin;

名前を提供しない暗黙の構成ファイル

プラグインは CLI と同様、既定では、暗黙の構成ファイル jsdefender.config.json が存在するかどうかプロジェクトのルート ディレクトリを探します。つまり、構成ファイルの名前が jsdefender.config.json である場合は、プラグイン オプションでその名前を提供する必要はありません。もちろん、別の名前の構成を提供することは可能です。

const jsdefenderMetroPlugin = require("@preemptive/jsdefender-metro-plugin")(
  {},
  {}
);
const jsdefenderMetroPlugin = require("@preemptive/jsdefender-metro-plugin")(
  { configurationFile: "jsdefender.config.json" },
  {}
);
// 上記の 2 つの構成は、プロジェクト ルートに `jsdefender.config.json` ファイルがある場合は同一です

構成形式

このガイドの PJSD 構成ファイルの移行セクションで述べたように、構成形式が新しい形式に変更されました。これは、プラグインの関数パラメーターを介して提供されるオプションや構成ファイル(ある場合)にも当てはまります。

const jsdefenderMetroPlugin = require("@preemptive/jsdefender-metro-plugin")(
  {
    // 以下のプラグイン オプションは変更されていません
    configurationFile: "my-jsdefender-config.json", // 明示的または既定(`jsdefender.config.json`)の構成ファイルの形式も変更する必要があります
    quietMode: false,
    protectUserModulesOnly: false,  
    // 非本番モードで保護を有効にするための、新しいオプションが追加されました
    enableInDevelopmentMode: true,
    // プラグインのコンストラクターで提供されたインライン保護構成は、構成ルートで提供するのではなく、`settings` キーの下に移動させる必要があります
    settings: {
      // `booleanLiterals`、`integerLiterals` などのインライン保護構成
    },
  },
  {}
);

開発モードでのプラグインの実行

以前のバージョンでは、プラグインは本番ビルドと開発ビルドの両方で保護を実行していました。今後、既定では、開発ビルドの場合、つまり react-native bundle コマンドに --dev false 引数が指定されていない場合には、保護はスキップされます。Metro ドキュメントによると、既定値は --dev true なので、設定を変更しない場合や bundle コマンドに --dev true を渡している場合には、保護はスキップされます。開発モードで保護を実行するためには、JSDefender Metro プラグインの enableInDevelopmentMode オプションを true に設定します。

enableInDevelopmentMode オプションが true に設定されている場合には、react-native run-android コマンドや react-native run-ios コマンドは、Release 引数が指定されていないと失敗します。これらのコマンドが失敗しないようにするには、それぞれ react-native run-android --variant=release コマンドまたは react-native run-ios --configuration Release コマンドを実行してリリース ビルドを実行するか、あるいは enableInDevelopmentMode オプションを false に設定します。

構成のマージ方法

構成のマージ方法が変更されました。以前のバージョンでは、configurationFile で提供された保護構成は、プラグインの関数パラメーターとして直接提供された保護構成によって上書きされました。新しいバージョンでは、プラグインの関数パラメーターの構成は、明示的または暗示的(jsdefender.config.json)構成ファイルで提供された構成がある場合、その構成を上書きします。

jsdefender.config.json

{
  "settings": {
    "booleanLiterals": true
  }
}

metro.config.js

...
const jsdefenderMetroPlugin = require("@preemptive/jsdefender-metro-plugin")(
  {
    settings: {
      booleanLiterals: false
    }
  },
  {
    ...
  }
);
...

上記の場合、booleanLiterals オプションの最終的な値は false になります。

既定の構成

プラグインは CLI と同様、既定の構成を使用します。これは、プラグインに明示的に構成を指定することによって上書きできます。

PreEmptive Protection™ JSDefender™ Copyright 2020 PreEmptive Solutions, LLC