SnykのCLIで脆弱性を検出する

# 概要

Snykには脆弱性を検出するCLI（`snyk`コマンド）があるので、何ができるのか紹介します。

![logo-solid-background.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/64402782-2c53-4fb1-b950-d7ce19d3270c.png)

# インストール

Snykの公式ドキュメントの「[Install or update the Snyk CLI](https://docs.snyk.io/snyk-cli/install-or-update-the-snyk-cli)」に記載がある通り、インストールは簡単で、Linuxであれば以下のコマンドを実行して完了です。

```shell-session
$ curl --compressed https://static.snyk.io/cli/latest/snyk-linux -o snyk
$ chmod +x ./snyk
$ sudo mv ./snyk /usr/local/bin/
```

なお、今回の検証ではUbuntu 22.04を使用しましたが、他のOSを使っている場合もほぼ同様で、ファイルの取得先をOSに応じたURL（以下）に変更し、ダウンロードしたコマンドにパスを通すだけです。

* macOS: [https://static.snyk.io/cli/latest/snyk-macos](https://static.snyk.io/cli/latest/snyk-macos)
* Windows: [https://static.snyk.io/cli/latest/snyk-win.exe](https://static.snyk.io/cli/latest/snyk-win.exe)
* Linux/arm64: [https://static.snyk.io/cli/latest/snyk-linux-arm64](https://static.snyk.io/cli/latest/snyk-linux-arm64)
* Alpine: [https://static.snyk.io/cli/latest/snyk-alpine](https://static.snyk.io/cli/latest/snyk-alpine)

以下のコマンドを実行して、バージョンが表示されればインストールできています。

```shell-session
$ snyk --version
```
```
1.1256.0
```

ちなみにアップグレードも前述の3つのコマンドでOKです（ダウンロードして、権限付与後、置換しているだけなので）。`snyk --version`で新しいバージョンになったことが分かります。

```
1.1260.0
```

# 機能の紹介

## `snyk --help`

まずは、以下のコマンドを入力して、何ができるか確認してみましょう。

```shell-session
$ snyk --help
```

以下のとおり、出力されます。

```
CLI help
  Snyk CLI scans and monitors your projects for security vulnerabilities and license issues.

  For more information visit the Snyk website https://snyk.io

  For details see the CLI documentation https://docs.snyk.io/features/snyk-cli

How to get started
  1. Authenticate by running snyk auth.
  2. Test your local project with snyk test.
  3. Get alerted for new vulnerabilities with snyk monitor.

Available commands
  To learn more about each Snyk CLI command, use the --help option, for example, snyk auth --help.

  Note: The help on the docs site is the same as the --help in the CLI.

  snyk auth
    Authenticate Snyk CLI with a Snyk account.

  snyk test
    Test a project for open-source vulnerabilities and license issues.

    Note: Use snyk test --unmanaged to scan all files for known open-source dependencies (C/C++
    only).

  snyk monitor
    Snapshot and continuously monitor a project for open-source vulnerabilities and license issues.

  snyk container
    These commands test and continuously monitor container images for vulnerabilities and generate an
    SBOM for a container image.

  snyk iac
    These commands find and report security issues in Infrastructure as Code files; detect, track,
    and alert on infrastructure drift and unmanaged resources; and create a .driftigore file.

  snyk code
    The snyk code test command finds security issues using Static Code Analysis.

  snyk sbom
    Produce an SBOM for a local software project in an ecosystem supported by Snyk.

  snyk log4shell
    Find Log4Shell vulnerability.

  snyk config
    Manage Snyk CLI configuration.

  snyk policy
    Display the .snyk policy for a package.

  snyk ignore
    Modify the .snyk policy to ignore stated issues.

Debug
  Use -d option to output the debug logs.

Configure the Snyk CLI
  You can use environment variables to configure the Snyk CLI and also set variables to configure the
  Snyk CLI to connect with the Snyk API. See Configure the Snyk CLI 
  https://docs.snyk.io/features/snyk-cli/configure-the-snyk-cli
```

「How to get started」の番号付き箇条書きにある通り、とりあえず始めるには、以下のようにすればいいようです。

  1. `snyk auth`を実行して、Snykのサイトに認証される。
  2. `snyk test`でローカルプロジェクトの脆弱性を検出する。
  3. `snyk monitor`で新しい脆弱性のアラートを受け取れるようにする。


## `snyk auth`

`snyk`コマンドを使用するには、Snykのアカウントを作成し、認証されている（Snyk CLIとSnykアカウントを関連付ける）必要があるようです。未認証で`snyk test`などのコマンドを実行しても、以下のエラーになります。

```shell-session
$ snyk test
```
```
`snyk` requires an authenticated account. Please run `snyk auth` and try again.
```

ということで、`snyk auth`コマンドを実行しましょう。

```shell-session
$ snyk auth
```

このコマンドを実行すると、ブラウザーが起動し、Snykのサイトに誘導されます。

![Screenshot from 2023-11-29 22-53-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/d4f7924c-380e-0730-8f78-c252e9c9616a.png)

ここではGitHubのアカウントでサインインします。

![Screenshot from 2023-11-29 22-53-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/ed7a3389-0cb4-5507-e71a-cb854151e0b2.png)

以下のような画面が表示されるので、Authenticateボタンをクリックします。

![Screenshot from 2023-11-29 22-54-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/14bd7d8c-233b-5d3b-224a-337dcf513e2b.png)

以下の画面が表示されれば、認証済みになります。

![Screenshot from 2023-11-29 23-22-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/d94712d2-0568-7f6c-a02f-926a924292f5.png)

もしくは、Snykの[アカウント設定ページ](https://app.snyk.io/account)からあらかじめトークンを取得しておき、

![Screenshot from 2023-12-04 18-00-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/f1c22b7c-d2af-8ded-8259-a6b3c2a8766c.png)

`snyk auth`コマンドに付加してもOKです。

```shell-session
$ snyk auth c931aedf-89dc-401e-9cbc-c11fc6d6f7ea
```
問題なく認証されれば、以下のメッセージが出力されます。
```
Your account has been authenticated. Snyk is now ready to be used.
```

## `snyk test`

認証が完了したので、アプリケーションの脆弱性チェックをしてみましょう。ここでは、私が開発した[脆弱性だらけのWebアプリケーション「EasyBuggy」のSpring Boot版「EasyBuggy Boot」](https://github.com/k-tamura/easybuggy4sb)をクローンします。

https://github.com/k-tamura/easybuggy4sb
```shell-session
$ git clone https://github.com/k-tamura/easybuggy4sb.git
$ cd easybuggy4sb/
```

では、「How to get started」の2番目のステップである`snyk test`コマンドを実行してみましょう。このコマンドは、`pom.xml`を確認して依存関係をチェックし、OSSのライブラリーの既知の脆弱性を発見します。

```shell-session
$ snyk test
```
```
Testing /home/tamura/git/easybuggy4sb...

Tested 105 dependencies for known issues, found 184 issues, 184 vulnerable paths.


Issues to fix by upgrading:

  Upgrade com.google.api-client:google-api-client-gson@1.30.3 to com.google.api-client:google-api-client-gson@1.33.0 to fix
  ✗ Deserialization of Untrusted Data [Medium Severity][https://security.snyk.io/vuln/SNYK-JAVA-COMGOOGLECODEGSON-1730327] in com.google.code.gson:gson@2.8.1

  ...（長いので省略）...

  ✗ Cross-site Scripting (XSS) [High Severity][https://security.snyk.io/vuln/SNYK-JAVA-ORGOWASPESAPI-6091110] in org.owasp.esapi:esapi@2.1.0.1
    introduced by org.owasp.esapi:esapi@2.1.0.1
  No upgrade or patch available



Organization:      k-tamura
Package manager:   maven
Target file:       pom.xml
Project name:      org.t246osslab:easybuggy4sb
Open source:       no
Project path:      /home/tamura/git/easybuggy4sb
Licenses:          enabled
```

出力された結果は、IntelliJ IDEなどのSnykプラグインでスキャンした結果の「Open Source」のカテゴリーのもの（以下）と同じになるようです。

![oss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/be6d5cf2-98f1-abbc-24e7-c19f363830f8.png)

## `snyk monitor`

「How to get started」の2番目のステップまで終わったので、最後のステップの`snyk monitor`コマンドを試してみましょう。ヘルプでは、このコマンドオプションは、次のように説明されていましたが、これはどのようなことを意味するのでしょうか？

>  snyk monitor
>    　Snapshot and continuously monitor a project for open-source vulnerabilities and license issues.

では、実行してみます。

```shell-session
$ snyk monitor
```

実行すると、URLが出力されました。

```
Monitoring /home/tamura/git/easybuggy4sb (org.t246osslab:easybuggy4sb)...

Explore this snapshot at https://app.snyk.io/org/k-tamura/project/4963a80a-bf4b-4d2d-b658-864cda0e3c24/history/050efd32-0591-4660-9569-ec9e6aa23849

Notifications about newly disclosed issues related to these dependencies will be emailed to you.
```

このURLにアクセスすると、以下のような画面が表示されます。

![Screenshot from 2023-11-30 15-57-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/257f86e8-9566-dd68-2fd4-80e09ccde132.png)

`snyk monitor`したプロジェクト（アプリ）はこのページで確認ができ、アプリに脆弱性の可能性を含む依存関係やコードが、今後追加された場合は、監視結果のメールが送信されてくるようになります。

![Screenshot from 2023-12-01 03-02-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/bb35e7fb-779e-2d75-3e85-931a2b087b99.png)

## `snyk code test`

さらに、`snyk code test`コマンドも実行してみましょう。このコマンドは、ソースコードの静的解析により脆弱性を発見することができます。

```shell-session
$ snyk code test
```
```
Testing /home/tamura/git/easybuggy4sb ...

 ✗ [Low] Trust Boundary Violation 
   Path: src/main/java/org/t246osslab/easybuggy4sb/core/filters/AuthenticationFilter.java, line 57 
   Info: Unsanitized input from the request URL flows into setAttribute where it is used to modify the HTTP session object. This could result in mixing trusted and untrusted data in the same data structure, thus increasing the likelihood to mistakenly trust unvalidated data.

  ...（長いので省略）...

 ✗ [High] Path Traversal 
   Path: src/main/java/org/t246osslab/easybuggy4sb/vulnerabilities/NullByteInjectionController.java, line 38 
   Info: Unsanitized input from an HTTP parameter flows into org.springframework.util.FileCopyUtils.copy, where it is used as a path. This may result in a Path Traversal vulnerability and allow an attacker to read arbitrary files.


✔ Test completed

Organization:      k-tamura
Test type:         Static code analysis
Project path:      /home/tamura/git/easybuggy4sb

Summary:

  28 Code issues found
  15 [High]   7 [Medium]   6 [Low] 
```

得られた結果は、IntelliJ IDEのSnykプラグインがスキャンした結果の「Code Security」のカテゴリーのもの（以下）と同じ結果となるようです。

![cs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/72c2a9ee-5b44-e469-ad8c-c2ac14a7aecf.png)

今回見つかった脆弱性の可能性のある実装の数は、重要度ごとに以下のとおりです。

* 高：15件
* 中： 7件
* 低： 6件

しかしながら、ここで注意すべきことは、**これがこのアプリに存在する脆弱性の全てではない**ということと、28件が**全て脆弱性とは言えない**ということです（当然の話ではありますが...:wink:）。Snykに限らず、どのような脆弱性検出ツールでもそうですが、完ぺきな検出は不可能です。脆弱性のパターンは事実上無限にあり、静的解析ですべて検出することは不可能です。また、検出されたものが実際には脆弱性ではないことも十分にあり得ます。例えば、今回、以下のような脆弱性の疑いがありましたが、実際にはこれは脆弱性とは言えません。

```
 ✗ [Medium] Open Redirect
   Path: src/main/java/org/t246osslab/easybuggy4sb/core/filters/AuthenticationFilter.java, line 59
   Info: Unsanitized input from an HTTP parameter flows into sendRedirect, where it is used as an URL to redirect the user. This may result in an Open Redirect vulnerability.
```

この[`AuthenticationFilter`の59行目](https://github.com/k-tamura/easybuggy4sb/blob/1.0.9/src/main/java/org/t246osslab/easybuggy4sb/core/filters/AuthenticationFilter.java#L59)を見ると、実装は以下のようになっています。

```java
response.sendRedirect(response.encodeRedirectURL("/login" + queryString));
```

`queryString`は空文字か`?`で始まる文字となるような実装になっているので、リダイレクト先の`/login`に何か悪意のある攻撃を仕掛けられない限り、オープンリダイレクトの危険性はありません。とはいえ、アプリ内部のURLである`/login`に、攻撃者がクエリストリングを細工して脆弱性を埋め込むことができない保証は無いので、指摘誤りとは言えませんが...

## `snyk container test`

続いて、`snyk container test`というコマンドを実行してみましょう。このコマンドは、Dockerコンテナイメージの脆弱性を検出することができます。

EasyBuggy Bootは単独で動作するWebアプリケーションですが、以下のような構成で動作するDockerコンテナイメージも含まれており、`docker compose up`で連携して動作することもできます。EasyBuggy Bootコンテナの他に、トラップが仕掛けられた攻撃者のアプリのコンテナや、認証を行うOSSであるKeycloakのコンテナなどが入っていて、認可コードインジェクションなどの脆弱性が体験できるようになっています。

![eb4sb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/631ed7e9-2d55-7a9a-c85d-8582a12c656f.png)

`snyk container test`の次にコンテナのイメージ名を付加する必要があるので、以下のコマンドで確認します。

```shell-session
$ docker ps -a
```
```
CONTAINER ID   IMAGE                              COMMAND                   CREATED         STATUS                      PORTS     NAMES
5a9abf9d9f3a   easybuggy4sb-easybuggy             "java -XX:MaxMetaspa…"   10 hours ago    Exited (143) 10 hours ago             easybuggy
bad11c906d5f   quay.io/keycloak/keycloak:legacy   "/opt/jboss/tools/do…"   10 hours ago    Exited (0) 10 hours ago               keycloak
2901270ee536   easybuggy4sb-attacker_app          "catalina.sh run"        10 hours ago    Exited (143) 10 hours ago             attacker_app
220c6b2c82ec   mysql:8                            "docker-entrypoint.s…"   10 hours ago    Exited (0) 10 hours ago               db
b64b2dd03d9e   python:3                           "python -m smtpd -d …"   10 hours ago    Exited (137) 10 hours ago             mail
```

ここでは、この中のEasyBuggy Bootのコンテナ（`easybuggy4sb-easybuggy`）の脆弱性を検出してみましょう。

```shell-session
$ snyk container test easybuggy4sb-easybuggy
```
```
Testing easybuggy4sb-easybuggy...

✗ Low severity vulnerability found in util-linux/libblkid1
  Description: Information Exposure
  Info: https://security.snyk.io/vuln/SNYK-DEBIAN11-UTILLINUX-2401081
  Introduced through: util-linux/libblkid1@2.36.1-8+deb11u1, e2fsprogs@1.46.2-2, util-linux/libmount1@2.36.1-8+deb11u1, util-linux/mount@2.36.1-8+deb11u1, util-linux/libuuid1@2.36.1-8+deb11u1, util-linux@2.36.1-8+deb11u1, util-linux/bsdutils@1:2.36.1-8+deb11u1, util-linux/libsmartcols1@2.36.1-8+deb11u1
  From: util-linux/libblkid1@2.36.1-8+deb11u1
  From: e2fsprogs@1.46.2-2 > util-linux/libblkid1@2.36.1-8+deb11u1
  From: util-linux/libmount1@2.36.1-8+deb11u1 > util-linux/libblkid1@2.36.1-8+deb11u1
  and 15 more...

  ...（長いので省略）...
  
-------------------------------------------------------

Testing easybuggy4sb-easybuggy...

Organization:      k-tamura
Package manager:   maven
Target file:       /usr/local/openjdk-8/lib
Project name:      easybuggy4sb-easybuggy:latest:/usr/local/openjdk-8/lib
Docker image:      easybuggy4sb-easybuggy
Licenses:          enabled

✔ Tested easybuggy4sb-easybuggy for known issues, no vulnerable paths found.


Tested 28 projects, 2 contained vulnerable paths.
```

長いので省略しましたが、非常に多くの脆弱性に関する情報が出力されました。EasyBuggy Bootの依存ライブラリーの脆弱性の可能性（`snyk test`の結果）の他に、コンテナでEasyBuggy Bootを動かすためのOpenJDKの脆弱性や、コンテナのOSが利用するライブラリーの脆弱性などが多数出力されます。

## `snyk ignore`

先ほど行った`snyk test`では、対応不要と考えていい脆弱性も検出されました。例えば、以下に示す依存ライブラリーの1つであるApache Derbyの旧バージョンの脆弱性です。

```
  Upgrade org.apache.derby:derby@10.13.1.1 to org.apache.derby:derby@10.14.2.0 to fix
  ✗ Security Bypass [Medium Severity][https://security.snyk.io/vuln/SNYK-JAVA-ORGAPACHEDERBY-32274] in org.apache.derby:derby@10.13.1.1
    introduced by org.apache.derby:derby@10.13.1.1
```

しかし、RDBMSとして内部で限定的に使用されているApache Derbyの脆弱性が攻撃される可能性は極めて低いと考えられます（詳しくは調査していませんが、事実上不可能ではないかと推測します）。このような脆弱性を`snyk test`を実行するたびに指摘されるのも困りものです。このようなときに役立つのが`snyk ignore`コマンドです。

このコマンドの`--id`オプションに脆弱性のSnyk ID（`snyk test`で出力された脆弱性の情報ページのURLの`https://security.snyk.io/vuln/`以降）を付加して実行すると、この脆弱性に対する指摘がこれ以降出力されなくなります。

```shell-session
$ snyk ignore --id=SNYK-JAVA-ORGAPACHEDERBY-32274
```

また、コマンドの実行とともに`.snyk`というファイル（ポリシーファイル）が出力されます。ファイルの内容は以下のようになっています。

```yaml
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.25.0
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
ignore:
  SNYK-JAVA-ORGAPACHEDERBY-32274:
    - '*':
        reason: None Given
        expires: 2024-01-05T08:10:30.393Z
        created: 2023-12-06T08:10:30.396Z
patch: {}
```

つまり、このファイルをもとにチェックしない脆弱性をフィルターすることができるようになります。'*'の部分はリソースのパスを記述することができ、特定のパスのみのフィルターすることもできます。詳細については、[このページ](https://docs.snyk.io/manage-risk/policies/the-.snyk-file)を参照してください。

## `snyk policy`

作成した.snyk ポリシーファイルの内容は、`snyk policy`コマンドでも確認できます。

```shell-session
$ snyk policy
```
```
Current Snyk policy, read from .snyk file
Modified: Wed Dec 06 2023 17:10:30 GMT+0900 (GMT+09:00)
Created:  Wed Dec 06 2023 17:10:30 GMT+0900 (GMT+09:00)

#1 Ignore https://security.snyk.io/vuln/SNYK-JAVA-ORGAPACHEDERBY-32274 in the following paths:
*
Reason: None Given
Expires: Fri, 05 Jan 2024 08:10:30 GMT
```

`.snyk`ポリシーファイルより、少し読みやすいでしょうか。

## `snyk log4shell`

コマンドのヘルプには、2021年の年末に大きな話題となっていた脆弱性「Log4shell[^1]」だけをチェックできると思われるコマンドオプションがありました。これも実行してみましょう。

[^1]: https://ja.wikipedia.org/wiki/Log4Shell

```shell-session
$ snyk log4shell
```

```
Please note this command is for already built artifacts. To test source code please use `snyk test`.

Results:
No known vulnerable version of Log4J was detected
```

検出されませんでした。EasyBuggy BootはLog4J2を使っていないので、まあ、結果は分かっていましたが。

ちなみに[Log4shellの問題があるアプリケーション](https://github.com/christophetd/log4shell-vulnerable-app)に対してこのコマンドを実行すると、どうなるか試してみましょう。

```shell-session
$ git clone https://github.com/christophetd/log4shell-vulnerable-app.git
$ snyk log4shell
```

```
Please note this command is for already built artifacts. To test source code please use `snyk test`.

Results:
No known vulnerable version of Log4J was detected
```

あれ？検出されませんね。でも、出力されたメッセージをよく見てください。このコマンドは、ビルド済みのアプリケーション（warファイルなど）にLog4Jのjarファイルが含まれているかどうかをチェックしているということです。`pom.xml`や`build.gradle`などをチェックするのは、あくまでも`snyk test`ということですね。

ということで、ビルドしてからもう一度、`snyk log4shell`を実行してみましょう。

```shell-session
$ gradlew build
$ snyk log4shell
```

```
Please note this command is for already built artifacts. To test source code please use `snyk test`.

Results:
A version of Log4J that is vulnerable to Log4Shell was detected:
	./build/libs/log4shell-vulnerable-app-0.0.1-SNAPSHOT.jar/BOOT-INF/lib/log4j-core-2.14.1.jar

We highly recommend fixing this vulnerability. If it cannot be fixed by upgrading, see mitigation information here:
      	- https://security.snyk.io/vuln/SNYK-JAVA-ORGAPACHELOGGINGLOG4J-2314720
      	- https://snyk.io/blog/log4shell-remediation-cheat-sheet/
```

アプリケーションのjarファイルに含まれるLog4Jのjarファイルを検出できました。

## `snyk iac`

`snyk iac`コマンドは、IaC（Infrastructure as Code）ファイル（例えば、KubernetesのyamlファイルやTerraformのtfファイル）のセキュリティー問題を検出します。`test`、`capture`、`describe`などのサブコマンドがありますが、ここでは`test`を実行してみましょう。

なお、ここまで検証に使ってきたアプリケーションにはIaCファイルが無いので、Keycloak（IAMのOSS）を`git clone`して、検証してみましょう。

```shell-session
$ git clone https://github.com/keycloak/keycloak.git
$ cd keycloak
$ snyk iac test
```
```
Snyk Infrastructure as Code

✔ Test completed.

Issues

Low Severity Issues: 4

  [Low] Container's or Pod's  UID could clash with host's UID
  Info:    `runAsUser` value is set to low UID. UID of the container processes
           could clash with host's UIDs and lead to unintentional authorization
           bypass
  Rule:    https://security.snyk.io/rules/cloud/SNYK-CC-K8S-11
  Path:    [DocId: 0] > input > spec > template > spec >
           containers[postgresql-db] > securityContext > runAsUser
  File:    operator/src/main/resources/example-postgres.yaml
  Resolve: Set `securityContext.runAsUser` value to greater or equal than
           10'000. SecurityContext can be set on both `pod` and `container`
           level. If both are set, then the container level takes precedence

  ...（長いので省略）...

-------------------------------------------------------

Test Summary

  Organization: k-tamura
  Project name: keycloak/keycloak

✔ Files without issues: 22
✗ Files with issues: 2
  Ignored issues: 0
  Total issues: 9 [ 0 critical, 0 high, 5 medium, 4 low ]

Tip: Re-run in debug mode to see more information: DEBUG=*snyk* <COMMAND>
If the issue persists contact support@snyk.io

-------------------------------------------------------

Tip

  New: Share your test results in the Snyk Web UI with the option --report
```

KeycloakにはKubernetesのyamlファイルがいくつか含まれていますが、それに対して中レベル以下の脆弱性の可能性を指摘するレポートが出力されました。

## `snyk sbom`

`snyk sbom`はSBOMファイルを生成します。SBOM（Software Bill Of Materials：ソフトウェア部品表）とは、特定のプロダクトに含まれるすべてのソフトウェア、ライセンス、依存関係などを一覧化したものです。詳しくは、Snyk Advent Calendar 2023 4日目 @Kidapan さんの[「SnykでSBOM生成してみた」](https://dev.classmethod.jp/articles/snyk-sbom-202312-kdpn/)で解説されていますので、ここではコマンドのみを紹介します。以下のように`--format`オプションで`cyclonedx1.4+json`、`cyclonedx1.4+xml`、`spdx2.3+json`のいずれかを指定して、`snyk sbom`を実行すると、SBOMファイルが生成されるようです。

```shell-session
$ snyk sbom --format cyclonedx1.4+json
```

が、Snyk Enterpriseプランを契約していないとダメなようです。

```
Your account is not authorized to perform this action. Please ensure that you belong to the given organization and that the organization is entitled to use the Snyk API. (Org ID: d7de236e-80ce-4e34-add9-970fedf152f2)
```

## `snyk fix`

`snyk --help`では出力されませんでしたが、公式ガイドを見ると、`snyk fix`というプレビュー機能のコマンドオプションがあるようです。これにより、一部の脆弱性を自動的に修正してくれるようです。正しく修正できるのでしょうか？さっそく実行してみましょう。

```shell-session
$ snyk fix
```
```
`snyk fix` is not supported.
See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix
```

サポートされていない？:thinking:うーん、でも有効にすればいいようです。ということで出力されたURLにアクセスすると、`snyk fix`を有効化する手順が記載されているので、

![Screenshot from 2023-11-30 10-20-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/032a8256-fbc0-aa62-68e0-b6238e04951a.png)

それに従い、有効にしてみましょう。

![Screenshot from 2023-11-30 10-21-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/5f34f03e-f139-a567-699f-1247dc347428.png)

では、再度実行してみます。

```shell-session
$ snyk fix
```
```
► Running `snyk test` for /home/tamura/git/easybuggy4sb

 ✖ No successful fixes


Unresolved items:

  pom.xml
  ✖ maven is not supported.

Summary:

  1 items were not fixed

  183 issues: 9 Critical | 97 High | 63 Medium | 14 Low
  178 issues are fixable
  

Tip: Re-run in debug mode to see more information: DEBUG=*snyk* <COMMAND>. If the issue persists contact support@snyk.io
```

あれ:thinking:、

> maven is not supported.

ということなので、Mavenの`pom.xml`の自動修正はまだサポートされていないってことでしょうね。

# Java以外のプロジェクトでテストしてみる

私が開発した脆弱性だらけのWebアプリケーションは、Java版の他にもKotlin（Spring Boot）版やPython（Django）版もあるので、これらのチェックもしてみましょう。

https://github.com/k-tamura/easybuggy4kt

https://github.com/k-tamura/easybuggy4django

## Kotlin版の脆弱性だらけのWebアプリケーションを検証

まずはKotlin版を試してみましょう。以下のコマンドでプロジェクトをクローンします。

```shell-session
$ git clone https://github.com/k-tamura/easybuggy4kt.git
$ cd easybuggy4kt/
```

では、`snyk code test`でソースコードの脆弱性を検出してみましょう。

```shell-session
$ snyk code test
```
```
Testing /home/tamura/git/easybuggy4kt ...

 ✗ [High] Path Traversal 
   Path: src/main/kotlin/org/t246osslab/easybuggy4kt/vulnerabilities/UnrestrictedExtensionUploadController.kt, line 76 
   Info: Unsanitized input from an HTTP parameter flows into javax.imageio.ImageIO.read, where it is used as a path. This may result in a Path Traversal vulnerability and allow an attacker to read arbitrary files.

 ✗ [High] Path Traversal 
   Path: src/main/kotlin/org/t246osslab/easybuggy4kt/vulnerabilities/UnrestrictedSizeUploadController.kt, line 77 
   Info: Unsanitized input from an HTTP parameter flows into javax.imageio.ImageIO.read, where it is used as a path. This may result in a Path Traversal vulnerability and allow an attacker to read arbitrary files.

  ...（長いので省略）...

 ✗ [High] Code Injection 
   Path: src/main/kotlin/org/t246osslab/easybuggy4kt/vulnerabilities/CodeInjectionController.kt, line 37 
   Info: Unsanitized input from an HTTP parameter flows into eval, where it is executed as JavaScript code. This may result in a Code Injection vulnerability.


✔ Test completed

Organization:      k-tamura
Test type:         Static code analysis
Project path:      /home/tamura/git/easybuggy4kt

Summary:

  6 Code issues found
  6 [High] 
```

検出した脆弱性はHighレベルの6件でした。Kotlin版が実装している脆弱性は、Java版とほぼ同じですが、検出件数は28件→6件に減少しています。現状では、Kotlin版の方がSnykの検出能力が低いと考えられます。そうであれば、KotlinからJavaソースコードにデコンパイルしてから、JavaのSnykプラグインで脆弱性を検出するという手もありかもしれません。

## Python版の脆弱性だらけのWebアプリケーションを検証

次に、Python版を試してみましょう。以下のコマンドでプロジェクトをクローンします。

```shell-session
$ git clone https://github.com/k-tamura/easybuggy4django.git
$ cd easybuggy4django/
```

では、`snyk code test`でソースコードの脆弱性を検出してみましょう。

```shell-session
$ snyk code test
```
```
Testing /home/tamura/git/easybuggy4django ...

 ✗ [Medium] Insecure Xml Parser 
   Path: easybuggy/views.py, line 836 
   Info: xml.sax.parseString is considered insecure. Use an analog from the defusedxml package.

 ✗ [Medium] Open Redirect 
   Path: easybuggy/views.py, line 92 
   Info: Unsanitized input from an HTTP parameter flows into django.shortcuts.redirect, where it is used as an URL to redirect the user. This may result in an Open Redirect vulnerability.

  ...（長いので省略）...

 ✗ [High] Command Injection 
   Path: easybuggy/views.py, line 555 
   Info: Unsanitized input from an HTTP parameter flows into os.system, where it is used as a shell command. This may result in a Command Injection vulnerability.


✔ Test completed

Organization:      k-tamura
Test type:         Static code analysis
Project path:      /home/tamura/git/easybuggy4django

Summary:

  12 Code issues found
  4 [High]   8 [Medium] 
```

検出した脆弱性はHighレベルの4件とMediumレベルの8件でした。こちらも実装している脆弱性は、Java版とそれほど変わりませんが、検出件数はJava版より少ないです。ちなみにこの検出結果は、PyCharmのSynkプラグインで検出した結果の「Code Security」のカテゴリーと同じです。

![Screenshot from 2023-12-01 11-29-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43869/232230fb-86d0-813e-b2ba-b9d010fdb306.png)

`snyk test`で依存ライブラリーの脆弱性を検出もしてみましょう。

```shell-session
$ snyk test
```
```
Required packages missing: django, mysql-connector-python, ldap3, validate-email

Please run `pip install -r requirements.txt`. If the issue persists try again with --skip-unresolved.
```

依存ライブラリーが無いので、実行されませんでした。出力されたメッセージに従い、`pip install -r requirements.txt`を実行するか`--skip-unresolved`オプションを付加して再実行する必要があるので、後者の方法で再実行してみましょう。

```shell-session
$ snyk test --skip-unresolved
```
```
Testing /home/tamura/git/easybuggy4django...

Tested 7 dependencies for known issues, found 24 issues, 24 vulnerable paths.


Issues to fix by upgrading dependencies:

  Upgrade django@2.0.3 to django@3.2.23 to fix
  ✗ Directory Traversal [Low Severity][https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-1066259] in django@2.0.3
    introduced by django@2.0.3
  ✗ Directory Traversal [Low Severity][https://security.snyk.io/vuln/SNYK-PYTHON-DJANGO-1279042] in django@2.0.3
    introduced by django@2.0.3

  ...（長いので省略）...

  Upgrade mysql-connector-python@8.0.6 to mysql-connector-python@8.0.14 to fix
  ✗ Improper Access Control [High Severity][https://security.snyk.io/vuln/SNYK-PYTHON-MYSQLCONNECTORPYTHON-173986] in mysql-connector-python@8.0.6
    introduced by mysql-connector-python@8.0.6



Organization:      k-tamura
Package manager:   pip
Target file:       requirements.txt
Project name:      easybuggy4django
Open source:       no
Project path:      /home/tamura/git/easybuggy4django
Licenses:          enabled

Tip: Try `snyk fix` to address these issues.`snyk fix` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems.
See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix
```

と、ここで気になる出力が:no_mouth:。

> Tip: Try `snyk fix` to address these issues.`snyk fix` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems.
See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fi

`snyk fix`コマンドで、`requirements.txt`に対して前述した「自動修正」が適用できそうです。やってみましょう。

```shell-session
$ snyk fix --skip-unresolved
```
```
► Running `snyk test` for /home/tamura/git/easybuggy4django

✔ Looking for supported Python items
✔ Processed 1 requirements.txt items
✔ Done

Successful fixes:

  requirements.txt
  ✔ Pinned certifi from 2022.12.7 to 2023.7.22

Summary:

  1 items were successfully fixed

  6 issues: 2 Critical | 1 High | 3 Medium
  6 issues are fixable
  1 issues were successfully fixed
```

1件だけですが、脆弱性の自動修正ができたようです。`git diff`でどのような修正が行われたか見てみましょう。

```shell-session
$ git diff
```
```diff
diff --git a/requirements.txt b/requirements.txt
index 18e5b6e..0b585af 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,3 +12,4 @@ requests==2.18.4
 urllib3==1.24.2
 ldap3==2.5
 validate_email
+certifi>=2023.7.22 # not directly required, pinned by Snyk to avoid a vulnerability
```

`certifi>=2023.7.22`の1行が、Snykが修正したというコメント付きで`requirements.txt`に追加されていました。certifiのクリティカルな脆弱性「CVE-2023-37920」に対する対策ということですね。

# デバッグするには

`snyk`コマンドを実行した結果、以下のようにエラーとなる場合があります。

```shell-session
$ snyk sbom --format cyclonedx1.4+json
```
```
An error occurred while running the underlying analysis needed to generate the SBOM.
```

このような場合は、`-d`オプションを付加してデバッグモードで実行すると、原因が分かる可能性が高くなります。

```shell-session
$ snyk sbom --format cyclonedx1.4+json -d
```

例えば、コマンドを実行した結果が以下の出力を含んで入れば、内部でMavenのコマンド（`mvn dependency:tree -DoutputType=dot --batch-mode --non-recursive --file="pom.xml"`）を実行して、エラーになっていることが分かるので、「MavenとJavaのバージョンの相性が悪いかも？」というような推測ができます。

```
2023-12-04T07:48:36.740Z snyk-mvn-plugin Maven command: mvn dependency:tree -DoutputType=dot --batch-mode --non-recursive --file="pom.xml"
2023-12-04T07:48:36.740Z snyk-mvn-plugin Maven working directory: /home/tamura/git/easybuggy4sb
2023-12-04T07:48:38.399Z snyk-mvn-plugin Child process exited with code: 1
2023-12-04T07:48:38.399Z snyk-mvn-plugin Child process failed with exit code: 1
2023-12-04T07:48:38.399Z snyk-mvn-plugin ----------------
2023-12-04T07:48:38.399Z snyk-mvn-plugin STDERR:
2023-12-04T07:48:38.399Z snyk-mvn-plugin
2023-12-04T07:48:38.399Z snyk-mvn-plugin ----------------
2023-12-04T07:48:38.400Z snyk-mvn-plugin STDOUT:
2023-12-04T07:48:38.400Z snyk-mvn-plugin [ERROR] Error executing Maven.
[ERROR] java.lang.IllegalStateException: Unable to load cache item
```

# 補足

ちなみに、ここまでの説明では`git clone`コマンドを実行してから`snyk test`コマンドを実行しましたが、`snyk test`コマンドの後にGitHubのプロジェクトのURLを付加すれば、そのプロジェクトの依存ライブラリーの脆弱性チェックをできるようです。

```shell-session
$ snyk test https://github.com/k-tamura/easybuggy4sb
```
```
Testing https://github.com/k-tamura/easybuggy4sb...

✗ Low severity vulnerability found in org.yaml:snakeyaml
  Description: Stack-based Buffer Overflow
  Info: https://security.snyk.io/vuln/SNYK-JAVA-ORGYAML-3016888
  Introduced through: org.springframework.boot:spring-boot-starter-actuator@1.5.6.RELEASE, org.springframework.boot:spring-boot-starter-data-ldap@1.5.6.RELEASE, org.springframework.boot:spring-boot-starter-jdbc@1.5.6.RELEASE, org.springframework.boot:spring-boot-starter-mail@1.5.6.RELEASE, org.springframework.boot:spring-boot-starter-web@1.5.6.RELEASE, org.springframework.boot:spring-boot-starter-thymeleaf@1.5.6.RELEASE

  ...（長いので省略）...

Organization:      k-tamura
Package manager:   maven
Open source:       yes
Project path:      https://github.com/k-tamura/easybuggy4sb

Tested https://github.com/k-tamura/easybuggy4sb for known vulnerabilities, found 107 vulnerabilities, 968 vulnerable paths.
```

`snyk code test`コマンドでもできるのかと思いましたが、それはできませんでした...

```shell-session
$ snyk code test https://github.com/k-tamura/easybuggy4sb
```
```
no such file or directory: https://github.com/k-tamura/easybuggy4sb
An unknown error occurred. Please run with `-d` and include full trace when reporting to Snyk
```

なお、この記事では一部の機能しか紹介できませんでしたが、SnykのCLIには他にも様々な機能があります。興味のある機能があれば、`snyk --help`、`snyk (testなどのオプション) --help`で使い方を調べてみるといいでしょう。

# まとめ

SnykのCLIはインストールが簡単なので、気軽に使えるのがいいと思いました。コマンドなので、様々なタスクに組み込むことができ、応用の幅は広いと言えます。様々な言語に対応している点もいいです。誤った指摘をすることもたまにありますが、思いがけない問題を見つけたりもするので、アプリの検証にSnykを利用しておいて損はないと思いました。

残念な点は、有料プランでなければ、コマンドの利用やコード修正のコントリビュートに制限があるということです。今回の検証で誤った指摘をする箇所があり、その改善のためにソースコード修正のプルリクエストをしようかと考えていましたが、無料プランでは不可能なようでした（脆弱性を検出するロジックが分かるソースコードは公開されていません）。まあ、そういうビジネスモデルなので仕方ありませんが...

最後に、自動修正などのプレビュー機能のエンハンスは難しい課題で現状はまだまだという感じでしたが、今後の楽しみとしておきましょう。

# 参考資料

* [Snyk公式ドキュメント - Snyk CLI](https://docs.snyk.io/snyk-cli)
* [Qiita - Snyk CLI のインストールとアップデート](https://qiita.com/ToshiAizawa/items/c090cbd525e45cc5ae51)