npmパッケージマネージャーの安全でないデフォルト設定を悪用し、macOSのキーボードショートカットを盗む
2023年6月28日
0 分で読めます悪意のあるnpmパッケージとその危険性は、これまでたびたび話題になってきました。数百ものコマンド&コントロール型Cobalt Strikeマルウェアパッケージ、タイポスクワッティング、npmレジストリ(PyPIなどを含む)に公開された一般的なマルウェアなど、その例はさまざまです。こうしたセキュリティリスクから開発者やメンテナーを守るため、Snykはnpmセキュリティのベストプラクティスガイドを公開しました。
そうした中で、長年のメンテナーにYagiz Nizipliが注意を促した今回の攻撃範囲と、現実に起こり得るデータ侵害のリスクは、npmのpostinstallライフサイクルフックなど、パッケージマネージャーによる任意のコマンド実行リスクを最小限に抑えることがいかに重要かを示す好例です。
npmのライフサイクルスクリプト
Node Package Manager(npm)は、パッケージのライフサイクルイベントを管理するためのスクリプトを開発者やパッケージメンテナーに提供します。これらのスクリプトを使えば、パッケージのインストール時にさまざまなタスクや設定を実行できるため、開発者にとって大きな価値があります。たとえばpostinstallスクリプトを使って、アセットのビルド、環境変数の設定、マイグレーションの実行など、自動化可能なタスクを実行できます。
scriptsファイルのpackage.jsonプロパティには、パッケージのライフサイクルや開発中のパッケージの依存関係に応じて実行されるコマンドを定義します。現在、npmではpackage.jsonファイルのscriptsプロパティで限られた数のライフサイクルスクリプトを利用できます。
ここからは簡潔にするため、postinstallコマンドに焦点を当てます。ただし、この記事で説明する内容は、ほかのライフサイクル操作にも当てはまります。
過去のセキュリティインシデント
JavaScript開発者に現実の影響を及ぼした、大きく報道されたインシデントがいくつも発生しています。たとえば、次のようなものがあります。
Oscar Bolmstenが発見したcross-envのセキュリティインシデント。
暗号資産アプリの開発者を狙ったevent-streamを起点とする攻撃。
そのほか多くのJavaScriptおよびNode.jsのセキュリティインシデントが、Awesome Node.js Securityリポジトリにまとめられています。
保存データのセキュリティ
セキュリティの専門家は、データの転送中や処理中ではなく、保存中の資産を保護することをData-at-restのセキュリティと定義しています。データベース、ファイルシステム、永続ストレージに保存された機密情報の保護に重点を置きます。保存データのセキュリティは、データが使われていない間の不正アクセス、漏えい、改ざんを防ぐことを目的としています。これを実現するため、次のようなさまざまな対策があります。
必要なときだけ復号:現在のタスクに必要なデータのみを復号し、それ以外のデータは暗号化したまま保存して、不正アクセスを防ぎます。
アクセス制御ロジック:パスワード、二要素認証、OSが提供する生体認証(Face IDなど)といった仕組みでリクエスト元の身元を確認し、望ましくない相手にリソースがさらされるのを防ぎます。
開発者を取り巻く攻撃対象領域
業界のベストプラクティスに従ってアプリケーションを開発することが求められます。異なるチームや開発者と連携する際に多くのメリットをもたらす一方で、攻撃対象領域も広げてしまいます。
開発者のマシンには、どのようなデータが暗号化されずに残っているのでしょうか?
.envなどのプレーンテキストファイルに保存された環境変数(dotenvパッケージで利用可能)。config.jsonなど、JSONファイルとして保存されたプロジェクトの設定ファイル。Github/Gitlabへのアクセスに使うSSHキー(
~/.sshフォルダー内に保存)。そして……macOSのキーボードショートカットです!
macOSのテキスト置換
macOSには標準でText Replacementsという機能があり、システム設定アプリの中にあります。この機能を使うと、ある単語を別の単語にすばやく置き換えられます。つい最近、ある有名企業の開発者が、@cardというキーワードをクレジットカード情報に置き換えるテキスト置換を使っていると知りました。有効期限やCVVを含まないカード番号だけなら第三者に知られても金銭的な被害には直結しませんが、悪用される可能性のある攻撃対象領域を増やすことになります。

キーボードのテキスト置換データを外部に持ち出す
キーボードショートカットはdefaultsに保存されます。これはローカルフォルダー内のどこかにある、ファイルシステム上の.plistファイルに対応しています。次のコマンドを実行すると、設定済みのテキスト置換を取得できます。システム設定アプリからも確認できます。
次のコードの実行にsudo権限は必要ありません。コンピューター上のどのプロセスからでも実行できます。
同じコマンドはNode.jsのexecSyncから実行して簡単に解析できます。また、npmパッケージマネージャーがサポートするpostinstallライフサイクル操作を通じても実行できます。
以下は、悪意のある攻撃者がmacOSのテキスト置換データにアクセスし、機密情報を外部に持ち出すために利用できるNode.jsスクリプトの例です。
パッケージのインストール時に上記のコードが実行されるよう、次のようにpackage.jsonのマニフェストファイルを更新します。
npm経由で配布され、開発者がダウンロードすると、このライブラリはカスタムスクリプトを直接実行して、キーボードの置換データを取得・処理します。注意していないと、> node ./retrieve.jsの行を見落としがちです。
対策
開発者として、悪意のあるnpmパッケージのセキュリティリスクや、依存関係ツリー内のパッケージによる任意のコマンド実行など、一般的なセキュリティ上の懸念を軽減するにはどうすればよいでしょうか?
npmパッケージのインストール時にスクリプトを無効化する
postinstallスクリプトを利用するパッケージから身を守る方法があります。npmでは、パッケージのインストール時に--ignore-scriptsを指定できます。
npmの安全なデフォルト設定を使う
npmパッケージマネージャーには、.npmrcという設定ファイルもあります。安全なデフォルト設定を適用するには、npm CLIを使って既定の設定を変更できます。
安全な保管
何より重要なのは、機密情報をプレーンテキストで保存しないことです。要件上、どうしてもプレーンテキストで保存する必要がある場合は、多要素認証を通じてのみアクセスできるようにしてください。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。



