地獄のNPM

前から分かってたことではあるけど、JavaScriptのパッケージって依存関係多すぎやしないか?

node_modulesひたすら長いし、たった1つのパッケージ入れただけでも100パッケージほど生えるとかざら。

この中にマルウェアが紛れ込んでないって確証を得るの難しすぎる。


OSSのセキュリティは「Given enough eyeballs, all bugs are shallow」の精神で保たれてるけど、最終的にそのパッケージを含めてリリースする責任は我々個人・組織にあるわけで、何でもかんでもパッケージを追加したくない。


とりわけ、NPMの`postinstall`が怖い。これは、 npm install した際に、パッケージをダウンロードする後にスクリプトを走らせられる機能で、例えば、ネイティブモジュールが必要なパッケージなどで、環境ごとにコンパイルを走らせたり、バイナリをダウンロードさせたり、package.jsonにプロパティを生やせたりする。


つまるところ、パッケージをダウンロードした際に任意のプログラムを実行させることができるということ。


なんてマルウェアに優しい仕様でしょう。https://security.snyk.io/vuln/npm/


実際に、今までも何度も、そして、今もなおマルウェアなパッケージは登録されています。


npm postinstallに相当する機能はNuGetをはじめパッケージマネージャにとってはよくある機能で、npmだけの問題ではないけれど、それでも、npmで配布されているパッケージたちの依存関係がかなり深いので、それだけにアタックポイントも多いし、よく知らない誰かのパッケージを参照している。


ignore-scriptsとNode Permissionsを設定してみる

npmにはpostinstallを実行させない、ignore-scriptsというオプションがある。

npm install --ignore-scripts <package>のように使えるが、これだと自分しか守れず、他メンバーPCやCI環境で実行されてしまう。

<project dir>/.npmrcに設定しておけば、CI含めプロジェクトメンバー全体で共有できる。


Node Permissionsはdenoのpermissionsモデルが輸入された機能で、アクセスできるディレクトリやファイルを制限したり、子プロセスの生成やワーカーの生成を制限できる。


制限したディレクトリやファイルアクセスは子プロセスには引き継がれないそうなので、全然穴ぼこだけれどもないよりは良い。できればdenoみたいにアクセス可能な通信先も許可リスト制にできれば直良なんだけど、今のところ、そういうのはない。

engine-strict=true
ignore-scripts=true
node-options=--experimental-permission --allow-fs-read=${PWD} --allow-fs-write=${PWD}

.npmrcファイルでignore-scriptsオプションを設定してみることにする。


しかし、問題発生。storybookが動かない。もうstorybook捨てるかあ。