Slide 1

Slide 1 text

Deno のセキュリティに関する仕組みの 紹介 (toranoana.deno #23)

Slide 2

Slide 2 text

今日話すこと 最近、npm パッケージに関するサプライチェーン攻撃などのセキュリ ティに関する話題が盛んです。 最近のアップデートも踏まえつつ、Deno におけるセキュリティ関連の 仕組みについて紹介していきます。

Slide 3

Slide 3 text

自己紹介 @uki00a deno-weekly というWeb サ イトを運営しています RevComm Inc.

Slide 4

Slide 4 text

Deno におけるセキュリティ関連の仕組み 1. 悪意のあるパッケージの導入を防止する仕組み 2. セキュリティ上の被害・リスクを緩和する仕組み 3. 悪意のあるパッケージや挙動を検出する仕組み

Slide 5

Slide 5 text

1. 悪意のあるパッケージの導入を防止する仕組 み deno.lock minimumDependencyAge

Slide 6

Slide 6 text

deno.lock 依存関係の追加・更新時などに自動で更新されます。 インストールされるパッケージのバージョンを固定することによっ て、意図せぬバージョンのパッケージがインストールされることを 防止できます。 チェックサムの検証によるパッケージの改ざん検知も可能 可能な限り、バージョン管理に含めることを推奨します $ git add deno.lock

Slide 7

Slide 7 text

minimumDependencyAge pnpm におけるminimumReleaseAge に相当する仕組みです (Deno v2.5.5 で導入) { "minimumDependencyAge": { // 公開されてから最低でも1 日 (=1440 分) 以上経過しているバージョンのみをインストールします "age": 1440, // `minimumDependencyAge` の適用を除外したいパッケージを指定します "exclude": ["npm:@my-company/some-package"] } }

Slide 8

Slide 8 text

2. セキュリティ上の被害・リスクを緩和する仕 組み パーミッションシステム deno approve-scripts プロトタイプ汚染攻撃への対策

Slide 9

Slide 9 text

前提 ここで紹介する内容はあくまで被害を軽減するための仕組みであ り、リスクを完全になくすことはできません。 前提としてもし悪意のあるパッケージの導入が発覚した場合は、速 やかに関係各所への通知や相談を行い、公式などの信頼性の高い情報 源を参照しつつ被害や影響範囲の確認をし、各種クレデンシャルの無 効化・再発行や悪意のあるパッケージの削除などの対応を進めるべき であると思います。

Slide 10

Slide 10 text

パーミッションシステム # (1) あらゆる処理を許可 - セキュリティの観点では推奨されない $ deno run -A main.ts # (2) 一部の処理を許可 $ deno run --allow-net --allow-read --allow-env main.ts # (3) allowlist によりアクセス対象のリソースを限定 $ deno run --allow-net=127.0.0.1 \ --allow-read=data,config \ --allow-env=FOO,BAR \ main.ts

Slide 11

Slide 11 text

パーミッションセット deno.json 内でパーミッションのセットを定義できます (Deno v2.5 で 追加) { "permissions": { "default": { "net": true }, "benchmark": { "net": ["127.0.0.1:6379"], "env": { "ignore": true }, "write": ["tmp"] } } }

Slide 12

Slide 12 text

パーミッションセット 定義したパーミッションセットは --permission-set ( -P ) オプション によって適用できます。 # (1) `permissions.default` を適用します $ deno run --permission-set server.ts # (2) こちらも同様に`permissions.default` を適用します $ deno run -P worker.ts # (3) `permissions.benchmark` を適用します $ deno run --permission-set=benchmark benchmark.ts

Slide 13

Slide 13 text

--ignore-* Deno v2.6 で --ignore-read と --ignore-env オプションが追加 $ cat main.js console.info("HOME", Deno.env.get("HOME")); console.info("FOO", Deno.env.get("FOO")); $ FOO=1 deno run --allow-env --ignore-env=HOME main.js HOME undefined FOO 1 $ FOO=1 deno run --ignore-env main.js HOME undefined FOO undefined

Slide 14

Slide 14 text

deno approve-scripts pnpm における pnpm approve-builds 相当のコマンド (Deno v2.6 で追加) # (1) ライフサイクルスクリプトを提供するパッケージをインストール $ deno install npm:[email protected] npm:[email protected] ... ╭ Warning │ │ Ignored build scripts for packages: │ npm:[email protected] │ │ Run "deno approve-scripts" to run build scripts. ╰─ # (2) ライフサイクルスクリプトの実行を許可するパッケージを指定 $ deno approve-scripts ? Select which packages to approve lifecycle scripts for ( to select, ..., enter to accept, to cancel) ❯ ● npm:[email protected] ○ npm:[email protected]

Slide 15

Slide 15 text

deno approve-scripts deno approve-scripts を実行すると、 allowScripts が更新されます。 # (3) `deno approve-scripts` によって`deno.json` が更新されます $ cat deno.json | jq 'pick(.allowScripts)' { "allowScripts": { "allow": [ "npm:[email protected]" ], "deny": [ "npm:[email protected]" ] } }

Slide 16

Slide 16 text

プロトタイプ汚染攻撃への対策 Deno はデフォルトで Object.prototype.__proto__ を削除しています delete Object.prototype.__proto__; この挙動は --unstable-unsafe-proto オプションによって無効化できま す ( 特別な理由がない限りはこのオプションの指定は推奨されませ ん)

Slide 17

Slide 17 text

3. 悪意のあるパッケージや挙動を検出する仕組 み deno audit DENO_AUDIT_PERMISSIONS

Slide 18

Slide 18 text

deno audit v2.5.5 で導入された npm audit 相当のコマンドです。 $ deno audit

Slide 19

Slide 19 text

deno audit --socket @socketsecurity/bun-security-scanner と同様の仕組みで検査が行わ れます (Deno v2.6 でサポート) # `socket.dev` を使用してパッケージを検査する $ deno audit --socket

Slide 20

Slide 20 text

DENO_AUDIT_PERMISSIONS アプリケーションが要求したパーミッションの一覧がJSON Lines 形式 で指定したファイルへ記録されます (Deno v2.5 で追加) # (1) `DENO_AUDIT_PERMISSIONS` にパスを指定してDeno を実行 $ DENO_AUDIT_PERMISSIONS=permissions.jsonl deno run -A main.js # (2) 指定されたパスに要求されたパーミッション情報が記録されます $ jq 'pick(.permission, .value)' --compact-output permissions.jsonl {"permission":"read","value":"README.md"} {"permission":"write","value":"README.md"} {"permission":"read","value":"Makefile"} {"permission":"write","value":"Makefile"}

Slide 21

Slide 21 text

まとめ ここ一年でセキュリティ関連 ( 特にサプライチェーン攻撃向け) の 様々な仕組みが追加されています。 パーミッションの指定が面倒な問題はパーミッションセットや --ignore-* オプションを使うと緩和できそうです。 minimumDependencyAge などは比較的簡単に導入できるので、設定を おすすめします。

Slide 22

Slide 22 text

おまけ deno.json の設定は難しい... パーミッションフラグの安全な指定方法 ( --allow-all は避ける、極 力 allowlist を指定する、など) minimumDependencyAge の設定がまだあまり認知されていなさそう deno.lock の無効化は避けた方が良い ( "lock": false )

Slide 23

Slide 23 text

おまけ deno.json の Linter を作ってみました (jsr:@uki00a/deno-json-lint) $ deno run --allow-read=deno.json jsr:@uki00a/deno-json-lint deno.json: [require-minimum-dependency-age] `minimumDependencyAge` should be configured deno.json:2:11: [require-lockfile] A lockfile should be enabled deno.json:4:23: [ban-allow-all] --allow-all/-A should not be used deno.json:5:27: [require-allow-list] An allow list should be specified for --allow-read deno.json:8:32: [ban-allow-all] `all: true` should not be used もしご興味があればぜひ試してみてください!