Snykを使ってPython Webアプリを脆弱性診断してみた

## はじめに

この記事は[Qiita Engineer Festa 2022](https://qiita.com/official-campaigns/engineer-festa/2022)への参加記事です。

Snykの脆弱性診断機能を用いて、Pythonで書かれたWebアプリを診断してみました。
診断対象に、良いコード/悪いコードを比較するためのWebアプリ[vulpy](https://github.com/fportantier/vulpy)を使用します。

## Snyk(スニーク)とは

- 安全で迅速な開発を支援する、デベロッパーファーストのセキュリティプラットフォーム
- コードの依存OSSやコンテナ/IaC(Infrastructure as Code)における脆弱性を見つけ、優先順位をつけ自動修正
- Gitや統合開発環境(IDE)、CI/CDパイプラインに直接組み込めるため、デベロッパーが簡単に使用可能

※ 引用元: https://go.snyk.io/jp.html

## Snyk提唱のPythonセキュリティのベストプラクティス

安全なPythonコードを書くための、チートシートが公開されていました。

- 外部データは常にサニタイズ
- コードをスキャン
- パッケージのダウンロードに注意
- 依存パッケージのライセンスを確認
- OS付属のPythonを使用しない
- Python仮想環境向けの機能を使用
- 本番ではDEBUGをFalseに
- 文字列の書式指定を慎重に
- デシリアライズを慎重に
- Python型アノテーションを使用

※ 引用元: [Python Security Best Practices Cheat Sheet](https://snyk.io/wp-content/uploads/cheat-sheet-python-security-2021.pdf)

## vulpyとは(Web Application Security Lab)

- Python/Flask/SQLiteで開発された、2つの側面を持つWebアプリ
    - GOODコード: 安全なコーディングのベストプラクティスに準拠
        - [OWASP Application Security Verification Standard](https://owasp.org/www-project-application-security-verification-standard/)
    - BADコード: セキュリティが考慮されていないコード

- アプリの機能
    - ログイン/ログアウト
    - 他のユーザーの投稿を読む
    - 投稿を公開
    - 多要素認証(MFA)
    - 投稿の読み取り/書き込み用API
    - コンテンツセキュリティポリシー(CSP)
    - SSL/TLSサーバー

- BADバージョンに仕掛けられた脆弱性
    - クロスサイトスクリプティング(XSS)
    - SQLインジェクション(SQLi)
    - クロスサイトリクエストフォージェリ(CSRF)
    - セッションのなりすまし(Impersonation)
    - 安全でないデシリアライズ(Deserialize)
    - 認証ブルートフォース(Bruteforce)
    - 認証バイパス(Bypass)
    - ※ 注: GOODバージョンも対応中で、脆弱性が含まれている可能性あり

## Snykを使って脆弱性診断

### Snykにサインアップ

- [Snyk Webサイト](https://snyk.io)の画面右上から`Sign up`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/9a6226ca-a2a6-f1c3-380b-ce2bb74b5d99.png)

- GitHubやGoogleアカウントを用いて、サインアップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/a8d55876-ce5a-7971-d003-40ae3033f987.png)

## vulpyをインストール

- vulpyリポジトリをcloneし、インストール
```
C:\snyk>git clone https://github.com/fportantier/vulpy
C:\snyk>cd vulpy
C:\snyk\vulpy>pip3 install --user -r requirements.txt
```

## `snyk test`で依存関係の脆弱性とライセンスを診断

```
C:\snyk\vulpy>snyk test

Testing C:\snyk\vulpy...

Tested 29 dependencies for known issues, found 2 issues, 3 vulnerable paths.

Issues with no direct upgrade or patch:
  ✗ Denial of Service (DoS) [Low Severity][https://snyk.io/vuln/SNYK-PYTHON-AIOHTTP-2934978] in aiohttp@3.8.1  
    introduced by geoip2@4.6.0 > aiohttp@3.8.1
  No upgrade or patch available

License issues:

  ✗ MPL-2.0 license (new) [Medium Severity][https://snyk.io/vuln/snyk:lic:pip:certifi:MPL-2.0] in certifi@2022.5.18.1
    introduced by requests@2.27.1 > certifi@2022.5.18.1 and 1 other path(s)

Organization:      mingchun.zhao
Package manager:   pip
Target file:       requirements.txt
Project name:      vulpy
Open source:       no
Project path:      C:\snyk\vulpy
Licenses:          enabled
```

### 考察

- [重要度低] Denial of Service(DoS)
    - `aiohttp`から検知されたようです
- [重要度中] MPL-2.0 licenseの問題
    - `certifi`から検知されたようです

## `snyk code test`でPythonコードの脆弱性を診断

```
C:\snyk\vulpy>snyk code test 

Testing C:\snyk\vulpy ...

 ✗ [Medium] RunWithDebugTrue
     Path: good/vulpy.py, line 53
     Info: Running the application in debug mode (debug flag is set to True in run) is a security risk if the application is accessible by untrusted parties.

 ✗ [Medium] RunWithDebugTrue
     Path: good/vulpy-ssl.py, line 29
     Info: Running the application in debug mode (debug flag is set to True in run) is a security risk if the application is accessible by untrusted parties.

 ✗ [Medium] RunWithDebugTrue
     Path: bad/vulpy-ssl.py, line 29
     Info: Running the application in debug mode (debug flag is set to True in run) is a security risk if the application is accessible by untrusted parties.

 ✗ [Medium] RunWithDebugTrue
     Path: bad/vulpy.py, line 55
     Info: Running the application in debug mode (debug flag is set to True in run) is a security risk if the application is accessible by untrusted parties.

 ✗ [High] Cross-site Scripting (XSS)
     Path: good/mod_user.py, line 34
     Info: Unsanitized input from a web form flows into the return value of _, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).

 ✗ [High] Cross-site Scripting (XSS)
     Path: bad/mod_user.py, line 33
     Info: Unsanitized input from a web form flows into the return value of _, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).

 ✗ [High] SQL Injection
     Path: bad/mod_user.py, line 20
     Info: Unsanitized input from a web form flows into execute, where it is used in an SQL query. This may result in an SQL Injection vulnerability.

 ✗ [High] SQL Injection
     Path: bad/mod_user.py, line 52
     Info: Unsanitized input from a web form flows into execute, where it is used in an SQL query. This may result in an SQL Injection vulnerability.

 ✗ [High] SQL Injection
     Path: bad/mod_user.py, line 80
     Info: Unsanitized input from a web form flows into execute, where it is used in an SQL query. This may result in an SQL Injection vulnerability.

 ✗ [High] Use of Hardcoded Cryptographic Key
     Path: good/libsession.py, line 9
     Info: A hardcoded string value is used as a cipher key in cryptography.fernet.Fernet. Generate the value with a cryptographically strong random number generator instead.


✔ Test completed

Organization:      mingchun.zhao
Test type:         Static code analysis
Project path:      C:\snyk\vulpy

10 Code issues found
6 [High]  4 [Medium]
```

### 考察

脆弱性問題が10個指摘されています。
分類すると、

- [重要度高] SQL Injection
    - フォームからの入力データに対し、サニタイズが施されていない
- [重要度高] Cross-site Scripting (XSS)
    - フォームからの入力データに対し、サニタイズが施されていない
- [重要度高] 暗号化キーのハードコーディング
    - 強力な乱数生成器を暗号化に使用してください、とのこと

## おわりに

Snykを使って、Python Webアプリの脆弱性診断を行ってみました。
Snykの[Pythonセキュリティチートシート](https://snyk.io/wp-content/uploads/cheat-sheet-python-security-2021.pdf)を眺めながら、開発したいものです。