まったり技術ブログ

Webエンジニアのセキュリティブログ

CodeQLで遊ぶ ~ ローカル環境で試す『静的アプリケーション・セキュリティ・テスト』 ~

はじめに

 本記事でやること。

  • CodeQL を導入
  • 脆弱なアプリケーションに対してのセキュリティテスト(XXEを検出)
  • 検出結果を見てみる

CodeQL とは

 CodeQL は SAST(Static application security testing) というセキュリティテスト手法を実現するためのツールです。

 本ブログで何度か取りあげた GitHub Code Scanning も SAST に属しているセキュリティテスト手法です。
GitHubのCode Scanningを使ってみるGitHubのCode Scanningを使ってみる パート2

 そして GitHub Code Scanning は CodeQLの技術が利用されています。

github.blog

Code Scanningの実行画面。CodeQLが利用されていることが確認できます。

 CodeQL を使うメリットとしてはローカルPCに導入して利用することができるため、GitHubなどで管理していないソースコードに対してもセキュリティテストを実施することができます

 本記事では CodeQL をローカルPC上に導入し、脆弱性を含んだサンプルアプリケーションに対してセキュリティテストを行うまでを紹介します。

※本記事の情報は2021年2月時点のものです。

サポート言語

 本記事では Javaで作成したアプリケーションを対象にセキュリティテストを実施しますが、CodeQL でサポートされている言語は以下の通りです。

  • C/C++
  • C#
  • Golang
  • Java
  • JavaScript
  • Python
  • TypeScript

 バージョンによってはサポート外のものもありますので詳細は公式ドキュメント(Supported languages and frameworks — CodeQL)をご覧ください。

準備

検証環境

  • MacOS 10.15.7
  • Java (AdoptOpenJDK) 11

 本記事では以下のツールを導入して検証していきます。

ツール・アプリケーション 簡単な説明
CodeQL CLI CodeQL のコマンドラインツールです。
バージョン: 2.3.4
CodeQL query セキュリティテストに必要なクエリが保存されています。
バージョン: 1.26.0
検査対象アプリケーション XXE の脆弱性を含んでいる Spring Boot 製のアプリケーションです。
motikan2010/GitHub-code-scanning-Test

 私の環境では CodeQL CLI 2.4.3 を使った場合に "CodeQLデータベースの生成" が上手くいかなかったので、少し古いバージョンを利用しています。

検証環境の構築

 検証に使うツールは全て GitHub にありますので、それらをダウンロードしていきます。

■ 作業用ディレクトリを作成
$ mkdir codeql_work
$ cd codeql_work/

■ 検査対象アプリケーションのダウンロード
$ git clone -b feature/xml-external-entity git@github.com:motikan2010/GitHub-code-scanning-Test.git

■ CodeQL CLI のダウンロード (v2.3.4 リリース日:2020/12/17)
$ wget https://github.com/github/codeql-cli-binaries/releases/download/v2.3.4/codeql-osx64.zip
$ unzip codeql-osx64.zip
$ rm -f codeql-osx64.zip

■ CodeQL のダウンロード (v1.26.0 リリース日:2020/12/17)
$ git clone -b v1.26.0 https://github.com/github/codeql.git ql

■ 作業用ディレクトリの状態
~/Desktop/codeql_work
$ ll
total 0
drwxr-xr-x  12 motikan2010  staff  384  2  7 14:58 GitHub-code-scanning-Test
drwxr-xr-x  18 motikan2010  staff  576 12 16 01:15 codeql
drwxr-xr-x  25 motikan2010  staff  800  2  7 15:01 ql

CodeQL CLI の動作確認 (バージョンの表示)

 CodeQL CLI が正常に動作するかバージョンを表示するコマンドを実行します。

$ cd codeql
$ ./codeql version --format=json
{
  "productName" : "CodeQL",
  "vendor" : "GitHub",
  "version" : "2.3.4",
  "sha" : "ff8bc627f2f24adc6ea19c838237d80a8f24a41f",
  "branches" : [
    "codeql-cli-2.3.4"
  ],
  "copyright" : "Copyright (C) 2019-2020 GitHub, Inc.",
  "unpackedLocation" : "/Users/motikan2010/Desktop/codeql_work/codeql"
}

動作確認

 スキャンは3ステップで行えます。

  1. スキャン対象のソースコードを元に CodeQLデータベースの生成
  2. 「1.」 のデータベースに対して CodeQLクエリの実行
  3. スキャン結果の表示

CodeQLデータベースの生成

 CodeQLデータベースの生成は codeql database create コマンドで実行できます。

Creating CodeQL databases — CodeQL

$ ./codeql database create -l=java -s ../GitHub-code-scanning-Test codeql_db

 コマンド実行時の出力です。テスト対象のアプリケーションをビルドしているようです。

Initializing database at /Users/motikan2010/Desktop/codeql_work/codeql/codeql_db.
Running command [/Users/motikan2010/Desktop/codeql_work/codeql/java/tools/autobuild.sh] in /Users/motikan2010/Desktop/codeql_work/GitHub-code-scanning-Test.
[2021-02-07 15:19:30] [build] [2021-02-07 15:19:30] Build directory is /Users/motikan2010/Desktop/codeql_work/GitHub-code-scanning-Test/.
[2021-02-07 15:19:30] [build] [2021-02-07 15:19:30] [autobuild] > chmod +x gradlew
[2021-02-07 15:19:30] [build] [2021-02-07 15:19:30] [autobuild] > ./gradlew -Dorg.gradle.caching=false --no-daemon -S clean
[2021-02-07 15:19:34] [build] [2021-02-07 15:19:34] [autobuild] To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/6.6.1/userguide/gradle_daemon.html.
[2021-02-07 15:19:36] [build] [2021-02-07 15:19:36] [autobuild] Daemon will be stopped at the end of the build stopping after processing
[2021-02-07 15:19:41] [build] [2021-02-07 15:19:41] [autobuild] > Task :clean UP-TO-DATE
[2021-02-07 15:19:41] [build] [2021-02-07 15:19:41] [autobuild] BUILD SUCCESSFUL in 8s
[2021-02-07 15:19:41] [build] [2021-02-07 15:19:41] [autobuild] 1 actionable task: 1 up-to-date
[2021-02-07 15:19:41] [build] [2021-02-07 15:19:41] [autobuild] > ./gradlew -Dorg.gradle.caching=false --no-daemon -S testClasses
[2021-02-07 15:19:43] [build] [2021-02-07 15:19:43] [autobuild] To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/6.6.1/userguide/gradle_daemon.html.
[2021-02-07 15:19:45] [build] [2021-02-07 15:19:45] [autobuild] Daemon will be stopped at the end of the build stopping after processing
[2021-02-07 15:20:02] [build] [2021-02-07 15:20:02] [autobuild] > Task :compileJava
[2021-02-07 15:20:02] [build] [2021-02-07 15:20:02] [autobuild] > Task :processResources
[2021-02-07 15:20:02] [build] [2021-02-07 15:20:02] [autobuild] > Task :classes
[2021-02-07 15:20:06] [build] [2021-02-07 15:20:06] [autobuild] > Task :compileTestJava
[2021-02-07 15:20:06] [build] [2021-02-07 15:20:06] [autobuild] > Task :processTestResources NO-SOURCE
[2021-02-07 15:20:06] [build] [2021-02-07 15:20:06] [autobuild] > Task :testClasses
[2021-02-07 15:20:07] [build] [2021-02-07 15:20:07] [autobuild] BUILD SUCCESSFUL in 24s
[2021-02-07 15:20:07] [build] [2021-02-07 15:20:07] [autobuild] 3 actionable tasks: 3 executed
Finalizing database at /Users/motikan2010/Desktop/codeql_work/codeql/codeql_db.
[2021-02-07 15:20:09] [build-err] Scanning for files in /Users/motikan2010/Desktop/codeql_work/GitHub-code-scanning-Test...
Successfully created database at /Users/motikan2010/Desktop/codeql_work/codeql/codeql_db.

 コマンド実行後、"codeql_db"というディレクトリが作成されます。 CodeQLデータベースの作成が正常に行われた場合のディレクトリの中身は以下の通りです。

$ ls -l codeql_db
total 16
-rw-r--r--   1 motikan2010  staff   136  2  7 15:20 codeql-database.yml
drwxr-xr-x   5 motikan2010  staff   160  2  7 15:20 db-java
drwxr-xr-x  15 motikan2010  staff   480  2  7 15:24 log
drwxr-xr-x   3 motikan2010  staff    96  2  7 15:23 results
-rw-------   1 motikan2010  staff  2172  2  7 15:20 src.zip

脆弱性の検出

 スキャンは codeql database analyze コマンドで実行できます。(database analyze — CLI manual)

 検出対象の脆弱性は以下の通りです。

codeql/java/ql/src/Security/CWE at main · github/codeql

CWE 識別子 概要 (JVN iPedia)
CWE-20 不適切な入力確認
CWE-22 パス・トラバーサル
CWE-78 OSコマンドインジェクション
CWE-79 クロスサイトスクリプティング
CWE-89 SQLインジェクション
CWE-90 LDAP インジェクション
CWE-94 コード・インジェクション
CWE-113 HTTP レスポンスの分割
CWE-129 配列インデックスの不適切な検証
CWE-134 書式文字列の問題
CWE-190 整数オーバーフローまたはラップアラウンド
CWE-209 エラーメッセージによる情報漏えい
CWE-312 重要な情報の平文保存
CWE-319 重要な情報の平文での送信
CWE-327 不完全、または危険な暗号アルゴリズムの使用
CWE-335 PRNG におけるシードの不正な使用
CWE-338 暗号における脆弱な PRNG の使用
CWE-352 クロスサイトリクエストフォージェリ
CWE-367 Time-of-check Time-of-use (TOCTOU) 競合状態
CWE-421 Race Condition During Access to Alternate Channel (by MITRE)
CWE-502 信頼できないデータのデシリアライゼーション
CWE-601 オープンリダイレクト
CWE-611 XML 外部エンティティ参照の不適切な制限
CWE-614 Sensitive Cookie in HTTPS Session Without 'Secure' Attribute (by MITRE)
CWE-676 Use of Potentially Dangerous Function (by MITRE)
CWE-681 数値型間の変換の誤り
CWE-732 重要なリソースに対する不適切なパーミッションの割り当て
CWE-798 ハードコードされた認証情報の使用
CWE-807 Reliance on Untrusted Inputs in a Security Decision (by MITRE)
CWE-829 信頼性のない制御領域からの機能の組み込み
CWE-833 Deadlock (by MITRE)
CWE-835 無限ループ

XXE の検査 ~ 検出されることの確認 ~

 全ての脆弱性を検査対象にすると時間が掛かってしまうため、今回は「XXE攻撃(XML eXternal Entity attack)」のみを対象に検査します。
(全てを検査対象にした場合、10分ほど時間が掛かりました。)

検査の実施 ~ CSV形式で出力 ~

 テスト結果はファイルに出力されるようになっています。ファイル形式は --format で指定します。

CSV形式で出力した例です。

■ 検査の実行
$ ./codeql database analyze "codeql_db" \
../ql/java/ql/src/Security/CWE/CWE-611/ \
--format csv --output xxe_result.csv

■ 検査結果の表示
$ cat xxe_result.csv
"Resolving XML external entity in user-controlled data","Parsing user-controlled XML documents and allowing expansion of external entity references may lead to disclosure of confidential data or denial of service.","error","Unsafe parsing of XML file from [[""user input""|""relative:///src/main/java/com/motikan2010/github_code_scanning_test/controller/XxeController.java:26:52:26:92""]].","/src/main/java/com/motikan2010/github_code_scanning_test/controller/XxeController.java","29","41","29","79"

 1行のCSVファイルとして結果が出力されました。
少々見づらいですが結果内容に脆弱性が見つかったファイルや行数の記載がされていることが確認できます。

検査の実施 ~ SARIFで出力 ~

 次は SARIFで出力してみます。

SARIFという単語は馴染みありませんが「Static Analysis Results Interchange Format」の略称であり、

SARIF 標準は、静的分析ツールが結果を共有する方法を合理化するために使用されます。

とのことです。
(当初私は SARIF"形式"と書いていましたが、「Format」の"F"なので明らかな誤りですね...)

 SARIF の見方は下のドキュメントが参考になります。
docs.github.com

■ 検査の実行
$ ./codeql database analyze "codeql_db" \
../ql/java/ql/src/Security/CWE/CWE-611/ \
--format=sarif-latest --sarif-multicause-markdown --output=xxe_result.sarif --no-sarif-add-snippets

 中身はJSON形式のようです。

$ cat xxe_result.sarif | jq .

 結果を見てみると以下のような記載があります。

"locations": [
  {
    "physicalLocation": {
      "artifactLocation": {
        "uri": "src/main/java/com/motikan2010/github_code_scanning_test/controller/XxeController.java",
        "uriBaseId": "%SRCROOT%",
        "index": 0
      },
      "region": {
        "startLine": 29,
        "startColumn": 41,
        "endColumn": 80
      }
    }
  }
],

これはソースコード上で脆弱性を存在している部分を示しています。

 指摘されたソースコードは下の画像です。

指摘されたソースコード

 確かに脆弱性となっている部分です。

RCE の検査 ~ 検出されないことの確認 ~

 次は RCE を検査し、脆弱性が検出されないことを確認します。

■ 検査の実行
$ ./codeql database analyze "codeql_db" \
../ql/java/ql/src/Security/CWE/CWE-078/ \
--format csv --output rce_result.csv

■ 検査結果の表示
$ cat rce_result.csv
(出力なし)

 脆弱性が検出されなかったので、検査結果が格納されるファイルは空となりました。
(ツール使用当初は検査が失敗しているのではと疑っていました・・・)

まとめ

 CodeQL。簡単。無料。 楽しい。

 お金ないけどプライベートリポジトリに対して SAST したいよという方にはオススメです。

参考

更新履歴

  • 2021年2月7日 新規作成
  • 2021年2月8日 CWE記載など