🔥

NPMプロジェクトにおける脆弱性の姑息的解決法(override)

2023/11/25に公開

はじめに

仕事で、Snykが検出した脆弱性に対処する機会があったので、ベストプラクティスとは言い難いが、npmのoverrideについて検証する。ちなみに、Javaのgradle関してはdependency constraintがある。

検証環境

検証した環境は以下のとおりだが、nodeとnpmのバージョンには注意してほしい。
overrideの機能はnpm v8.3.0から導入されたものであるのと同時に、バージョンが低いとlockfileが更新されなかったり、破損してしまい、npm ciがうまく動かなかったりするようだ。

詳しくは、このissueを参照してほしい。

OS Arch Linux 6.6.1-arch1-1
node v18.18.2
npm 10.2.3

事前準備

脆弱性を含むプロジェクトを再現してみる

# 質問にはテキトーに答える
$ npx create-react-app my-app

以下のようにNPMからも脆弱性を指摘してくれている

added 1460 packages, and audited 1461 packages in 1m

242 packages are looking for funding
  run `npm fund` for details

8 vulnerabilities (2 moderate, 6 high)

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

ここで、本来であればnpm audit fix --forceを行って、直接依存のパッケージを更新することにより、解決を試みるが、今回は最新版のreact-create-appで行っているのでこれ以上メジャーバージョンを上げることはできない。
また、react-create-appに関しても、最近では脆弱性が放置され気味のようだ。

Snykスキャン

スキャンの仕方についてはここでは、省略する。

一旦、Snykでこのプロジェクトのスキャン結果を見てみる。複数の脆弱性を確認できるが、
High Severityのものを1つ抜粋すると

Regular Expression Denial of Service (ReDoS) (High Severity)
Package Manager: npm
Vulnerable module: nth-check
Paths : react-scripts@5.0.1 › @svgr/webpack@5.5.0 › @svgr/plugin-svgo@5.5.0 › svgo@1.3.2 › css-select@2.1.0
› nth-check@1.0.2

どうやら、Snykによる指摘のPathsを見ると明らかだが、間接的に依存しているnth-check@1.0.2に脆弱性が出ているようだ。

$ npm ls nth-check
my-app@0.1.0 /home/chiiko/github.com/NaGaii1994/fix_vulnerability_npm/my-app
└─┬ react-scripts@5.0.1
  ├─┬ @svgr/webpack@5.5.0
  │ └─┬ @svgr/plugin-svgo@5.5.0
  │   └─┬ svgo@1.3.2
  │     └─┬ css-select@2.1.0
  │       └── nth-check@1.0.2 # ←間接的依存関係の末端に脆弱性を含むパッケージが存在
  └─┬ html-webpack-plugin@5.5.3
    └─┬ pretty-error@4.0.0
      └─┬ renderkid@3.0.0
        └─┬ css-select@4.3.0
          └── nth-check@2.1.1

remediationとしてはnth-checkのバージョンを2.1.1以上に上げる必要があるので、それをnpmのoverrideを用いて行ってみる。

以下のようにpackage.jsonを修正した。

package.json
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
+  "overrides": {
+    "nth-check": "2.1.1"
+  },

パッケージを更新

$ npm install

up to date, audited 1531 packages in 4s

246 packages are looking for funding
  run `npm fund` for details

3 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

どうやら、修正されたらしく6個あった high vulnerabilitiesが消えている。
また、修正後の依存関係ツリーを表示すると以下のように間接依存のnth-checkのバージョンを上書きできたことがわかる。

$ npm ls nth-check
my-app@0.1.0 /home/chiiko/github.com/NaGaii1994/fix_vulnerability_npm/my-app
└─┬ react-scripts@5.0.1
  ├─┬ @svgr/webpack@5.5.0
  │ └─┬ @svgr/plugin-svgo@5.5.0
  │   └─┬ svgo@1.3.2
  │     └─┬ css-select@2.1.0
- │       └── nth-check@1.0.2
+ │       └── nth-check@2.1.1 overridden
  └─┬ html-webpack-plugin@5.5.3
    └─┬ pretty-error@4.0.0
      └─┬ renderkid@3.0.0
        └─┬ css-select@4.3.0
-         └── nth-check@2.1.1
+         └── nth-check@2.1.1 deduped

npm ci

私が仕事で使用している環境では、nodeとnpmのバージョンが古く動作しなかったため、念の為検証する。

$ rm -rf node_modules
$ npm ci
npm WARN deprecated @babel/plugin-proposal-numeric-separator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.
npm WARN deprecated @babel/plugin-proposal-class-properties@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.
npm WARN deprecated @babel/plugin-proposal-private-methods@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.
npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
npm WARN deprecated @babel/plugin-proposal-nullish-coalescing-operator@7.18.6: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
npm WARN deprecated rollup-plugin-terser@7.0.2: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
npm WARN deprecated @babel/plugin-proposal-optional-chaining@7.21.0: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
npm WARN deprecated w3c-hr-time@1.0.2: Use your platform's native performance.now() and performance.timeOrigin.
npm WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
npm WARN deprecated workbox-cacheable-response@6.6.0: workbox-background-sync@6.6.0
npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.

added 1530 packages, and audited 1531 packages in 22s

246 packages are looking for funding
  run `npm fund` for details

3 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

lockfileは破損おらず、正常にnpm ciできているようだ。

Discussion