GitLab SASTでSpring Bootプロジェクトに脆弱性が混入したケースを検出して修正するまで試す (GitLab Ultimate trial)
GitLab SAST検証用のグループ/プロジェクトを作成。
Ultimate Planでの見え方が気になるので、UltimateもTrialで契約。
(Trial時に企業名を聞かれますが、仮でも良いみたいです。)
glab
を入れてログインの準備
$ mise install glab
$ mise use --global glab@latest
$ glab auth login
cloneする
$ ghq get https://gitlab.com/daylight551/gitlab-sast-test.git
Spring Initializerを使ってSpring bootの初期ソースコードを生成
ポリシーで設定しても良いが、簡易検証なのでプロジェクトのSecurity設定画面でSASTを有効にする。
SAST有効化のMRをマージ
デフォルト定義で生成されたPipelineが失敗していたが、無視してマージした。
Pipelineが失敗していたのはソースコードが空であったためのよう。
コード追加とSAST有効化の順番を逆にすればよかった。
折角なのでAdvanced SASTも設定しておく。
設定方法はUltimateプランであればCI Variablesで以下を設定するだけ。
include:
- template: Jobs/SAST.gitlab-ci.yml
variables:
GITLAB_ADVANCED_SAST_ENABLED: 'true'
下記MRで設定
先ほどの通常SASTと実行ログを比較してみる。
使用されるルール数もパッと見同じだから、違いがわからない・・・。
Advanced SASTが機能してなさげ?
Semgrepとは別のアナライザーが動くため、Advanced SAST用の新たなJobが出来るのが正しい動き。
修正: 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のデフォルトで生成されるコードではサーバーは起動しないよう。
以下を参考に修正する。
実際に修正したMR
$ 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の表示を確認
脆弱性コードの混入: SQL Injection/RCE/XSS
脆弱性の例はGitLab SASTが検出できればなんでも良い。
Perplexity(Claude 3 Ops)に作成したサンプルコードを渡して、脆弱性を含むコードを生成してもらう。
例として出てきたコードは以下。
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
は軽く試せた。
- SQLインジェクション: /user エンドポイントで、ユーザー入力を直接SQLクエリに挿入しており、攻撃者が任意のSQLを実行できる可能性があります。
- リモートコード実行(RCE): /eval エンドポイントで、ScriptEngineManagerを使用して任意のJavaScriptコードを実行できます。これは深刻なセキュリティリスクとなります。
- クロスサイトスクリプティング (XSS): /greet エンドポイントで、ユーザー入力を直接HTMLに挿入しており、悪意のあるスクリプトを注入される可能性があります。
SASTの脆弱性検出
脆弱性コードを追加したMR
意外なところが検出されたw
追加した脆弱性は検出されていない。。。
生成AI出力そのままを使ったから怪しいのはある。
しかしsemgrepのルールがそもそも弱い説?
KotlinはSemgrep Analyzerの対象外だった。
Advanced SASTでも未サポートのため、検出されないのは正しい。
明日脆弱性修正から検証の続きを開始する。