Open14

GitLab SASTでSpring Bootプロジェクトに脆弱性が混入したケースを検出して修正するまで試す (GitLab Ultimate trial)

daylightdaylight

glabを入れてログインの準備

$ mise install glab
$ mise use --global glab@latest
$ glab auth login

cloneする

$ ghq get https://gitlab.com/daylight551/gitlab-sast-test.git
daylightdaylight

折角なのでAdvanced SASTも設定しておく。
設定方法はUltimateプランであればCI Variablesで以下を設定するだけ。

include:
  - template: Jobs/SAST.gitlab-ci.yml

variables:
  GITLAB_ADVANCED_SAST_ENABLED: 'true'

参考: https://docs.gitlab.com/ee/user/application_security/sast/gitlab_advanced_sast.html#enable-advanced-sast-scanning

下記MRで設定
https://gitlab.com/daylight551/gitlab-sast-test/-/merge_requests/3

先ほどの通常SASTと実行ログを比較してみる。

使用されるルール数もパッと見同じだから、違いがわからない・・・。

daylightdaylight

Advanced SASTが機能してなさげ?
Semgrepとは別のアナライザーが動くため、Advanced SAST用の新たなJobが出来るのが正しい動き。

daylightdaylight

修正: Spring Bootが起動するようコード修正

肝心のSpring bootの起動確認がまだだったので確認しておく。

Java/Maven/Gradleをインストール

$ mise install java@17
$ mise install maven
$ mise install gradle
$ mise use --global java@17
$ mise use --global gradle@latest
$ mise use --global maven@latest

GradleでSpring Boot起動

$ gradle bootRun

以下ログになるだけでサーバー起動しているように見えない。。。

2024-11-12T23:09:37.893+09:00  INFO 78199 --- [demo] [main] com.example.demo.DemoApplicationKt       : Starting DemoApplicationKt using Java 17.0.2 with PID 78199 (/Users/tanimura/dev/ghq/gitlab.com/daylight551/gitlab-sast-test/build/classes/kotlin/main started by tanimura in /Users/tanimura/dev/ghq/gitlab.com/daylight551/gitlab-sast-test)
2024-11-12T23:09:37.894+09:00 DEBUG 78199 --- [demo] [main] com.example.demo.DemoApplicationKt       : Running with Spring Boot v3.3.5, Spring v6.1.14
2024-11-12T23:09:37.894+09:00  INFO 78199 --- [demo] [main] com.example.demo.DemoApplicationKt       : The following 1 profile is active: "default"

どうやらSpring Initializerのデフォルトで生成されるコードではサーバーは起動しないよう。

以下を参考に修正する。
https://qiita.com/shupeluter/items/59fdfddaed25759c2661

実際に修正したMR
https://gitlab.com/daylight551/gitlab-sast-test/-/merge_requests/4

$ gradle bootRun

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.5)

2024-11-12T23:45:12.364+09:00  INFO 11509 --- [demo] [           main] com.example.demo.DemoApplicationKt       : Starting DemoApplicationKt using Java 17.0.2 with PID 11509 (/Users/tanimura/dev/ghq/gitlab.com/daylight551/gitlab-sast-test/build/classes/kotlin/main started by tanimura in /Users/tanimura/dev/ghq/gitlab.com/daylight551/gitlab-sast-test)
2024-11-12T23:45:12.366+09:00 DEBUG 11509 --- [demo] [           main] com.example.demo.DemoApplicationKt       : Running with Spring Boot v3.3.5, Spring v6.1.14
2024-11-12T23:45:12.366+09:00  INFO 11509 --- [demo] [           main] com.example.demo.DemoApplicationKt       : The following 1 profile is active: "default"
2024-11-12T23:45:12.711+09:00  INFO 11509 --- [demo] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2024-11-12T23:45:12.718+09:00  INFO 11509 --- [demo] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-11-12T23:45:12.719+09:00  INFO 11509 --- [demo] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.31]
2024-11-12T23:45:12.744+09:00  INFO 11509 --- [demo] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-11-12T23:45:12.744+09:00  INFO 11509 --- [demo] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 349 ms
2024-11-12T23:45:12.869+09:00  INFO 11509 --- [demo] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path '/'
2024-11-12T23:45:12.874+09:00  INFO 11509 --- [demo] [           main] com.example.demo.DemoApplicationKt       : Started DemoApplicationKt in 0.696 seconds (process running for 0.824)
2024-11-12T23:46:12.514+09:00  INFO 11509 --- [demo] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-11-12T23:46:12.514+09:00  INFO 11509 --- [demo] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-11-12T23:46:12.515+09:00  INFO 11509 --- [demo] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
<===========--> 85% EXECUTING [3m 21s]
> :bootRun

http://localhost:8080 でHello Worldの表示を確認

daylightdaylight

脆弱性コードの混入: SQL Injection/RCE/XSS

脆弱性の例はGitLab SASTが検出できればなんでも良い。
Perplexity(Claude 3 Ops)に作成したサンプルコードを渡して、脆弱性を含むコードを生成してもらう。
https://www.perplexity.ai/search/konokotonigitlab-sastkajian-ch-8WSZ3AZeQt.giT7BBdyBeg

例として出てきたコードは以下。

DemoApplication.kt
package com.example.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import java.sql.DriverManager
import javax.script.ScriptEngineManager

@RestController
@SpringBootApplication
class DemoApplication {
    @GetMapping("/")
    fun home() = "Hello World!"

    // SQL インジェクションの脆弱性
    @GetMapping("/user")
    fun getUserById(@RequestParam id: String): String {
        val connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password")
        val statement = connection.createStatement()
        val query = "SELECT * FROM users WHERE id = '$id'"
        val resultSet = statement.executeQuery(query)
        return if (resultSet.next()) resultSet.getString("name") else "User not found"
    }

    // リモートコード実行の脆弱性
    @GetMapping("/eval")
    fun evaluateExpression(@RequestParam expression: String): String {
        val scriptEngine = ScriptEngineManager().getEngineByName("JavaScript")
        return scriptEngine.eval(expression).toString()
    }

    // クロスサイトスクリプティング (XSS) の脆弱性
    @GetMapping("/greet")
    fun greet(@RequestParam name: String): String {
        return "<h1>Welcome, $name!</h1>"
    }
}

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

脆弱性の意図は以下の通り。
userはDB起動が必要なため動作確認はスルー。
/evalは任意のJavaScriptコード
/greetは軽く試せた。

  1. SQLインジェクション: /user エンドポイントで、ユーザー入力を直接SQLクエリに挿入しており、攻撃者が任意のSQLを実行できる可能性があります。
  2. リモートコード実行(RCE): /eval エンドポイントで、ScriptEngineManagerを使用して任意のJavaScriptコードを実行できます。これは深刻なセキュリティリスクとなります。
  3. クロスサイトスクリプティング (XSS): /greet エンドポイントで、ユーザー入力を直接HTMLに挿入しており、悪意のあるスクリプトを注入される可能性があります。
daylightdaylight

SASTの脆弱性検出

脆弱性コードを追加したMR
https://gitlab.com/daylight551/gitlab-sast-test/-/merge_requests/5

意外なところが検出されたw

追加した脆弱性は検出されていない。。。
生成AI出力そのままを使ったから怪しいのはある。
しかしsemgrepのルールがそもそも弱い説?

daylightdaylight

KotlinはSemgrep Analyzerの対象外だった。
Advanced SASTでも未サポートのため、検出されないのは正しい。

daylightdaylight

明日脆弱性修正から検証の続きを開始する。