[Gradle] SpringBootの組み込まれてるTomcatのバージョンを変更したい
こむろ@札幌です。
小ネタです。1月前ほどにTomcatの脆弱性がアナウンスされてました。それも相当広いバージョンで。
JVNVU#90211511 Apache Tomcat の複数の脆弱性に対するアップデート
- Apache Tomcat 9.0.0.M1 から 9.0.0.M18 まで
- Apache Tomcat 8.5.0 から 8.5.12 まで
- Apache Tomcat 8.0.0.RC1 から 8.0.42 まで
- Apache Tomcat 7.0.0 から 7.0.76 まで
- Apache Tomcat 6.0.0 から 6.0.52 まで
SpringBootで組んだWebアプリケーションは、開発時のバージョンのまま止まっていることが多く、こういった脆弱性が発見されたりした時には、すでに現行と2バージョンも違うなんていうこともザラです。 本来FrameworkのバージョンアップでサクッとMigrationできれば問題ないんでしょうけど、なかなかそううまくはいきません。 1バージョン新しくなった時に非推奨となったクラスが、2バージョンあとでは跡形もなく消えているなんてこともよくあります。例: SpringApplicationConfiguration
さて自分が担当していたシステムのSpringBootのバージョンはと言うと1.3.2.RELEASE
確実に対象だろうな、と思いながらも一抹の希望を捨てずに組み込まれているTomcatのバージョンを確認します。 (/ω・\)チラッ
Spring Boot Reference Guide - Appendix E. Dependency versions
GroupId | Artifact Id | Version |
---|---|---|
org.apache.tomcat.embed | tomcat-embed-core | 8.0.30 |
対象でした。無念。対応としてTomcatを以下のバージョンへアップデートする必要があります。
- Apache Tomcat 9.0.0.M19
- Apache Tomcat 8.5.13
- Apache Tomcat 8.0.43
- Apache Tomcat 7.0.77
- Apache Tomcat 6.0.53
対応としてすぐ考えられるのはSpringBootのバージョンアップです。フレームワークごとバージョンアップしてしまえば中に組み込まれているTomcatもバージョンアップしているはずなので、当然の結果です。それぞれのフレームワークに組み込まれているTomcatのバージョンは以下のリンクで確認できます。
各種SpringBootのTomcatバージョンを確認
現行バージョンまでの組み込みTomcatのバージョンを確認します。以下のとおりです。
SpringBoot 1.3.2
GroupId | Artifact Id | Version |
---|---|---|
org.apache.tomcat | tomcat-jdbc | 8.0.30 |
org.apache.tomcat | tomcat-jsp-api | 8.0.30 |
org.apache.tomcat.embed | tomcat-embed-core | 8.0.30 |
org.apache.tomcat.embed | tomcat-embed-el | 8.0.30 |
org.apache.tomcat.embed | tomcat-embed-jasper | 8.0.30 |
org.apache.tomcat.embed | tomcat-embed-logging-juli | 8.0.30 |
org.apache.tomcat.embed | tomcat-embed-websocket | 8.0.30 |
1.3.2 Appendix Dependency versions
SpringBoot 1.3.8
GroupId | Artifact Id | Version |
---|---|---|
org.apache.tomcat | tomcat-jdbc | 8.0.37 |
org.apache.tomcat | tomcat-jsp-api | 8.0.37 |
org.apache.tomcat.embed | tomcat-embed-core | 8.0.37 |
org.apache.tomcat.embed | tomcat-embed-el | 8.0.37 |
org.apache.tomcat.embed | tomcat-embed-jasper | 8.0.37 |
org.apache.tomcat.embed | tomcat-embed-logging-juli | 8.0.37 |
org.apache.tomcat.embed | tomcat-embed-websocket | 8.0.37 |
1.3.8 Appendix Dependency versions
SpringBoot 1.4.6
GroupId | Artifact Id | Version |
---|---|---|
org.apache.tomcat | tomcat-jdbc | 8.5.13 |
org.apache.tomcat | tomcat-jsp-api | 8.5.13 |
org.apache.tomcat.embed | tomcat-embed-core | 8.5.13 |
org.apache.tomcat.embed | tomcat-embed-el | 8.5.13 |
org.apache.tomcat.embed | tomcat-embed-jasper | 8.5.13 |
org.apache.tomcat.embed | tomcat-embed-websocket | 8.5.13 |
1.4.6 Appendix Dependency versions
SpringBoot 1.5.3
GroupId | Artifact Id | Version |
---|---|---|
org.apache.tomcat | tomcat-jdbc | 8.5.14 |
org.apache.tomcat | tomcat-jsp-api | 8.5.14 |
org.apache.tomcat.embed | tomcat-embed-core | 8.5.14 |
org.apache.tomcat.embed | tomcat-embed-el | 8.5.14 |
org.apache.tomcat.embed | tomcat-embed-jasper | 8.5.14 |
org.apache.tomcat.embed | tomcat-embed-websocket | 8.5.14 |
1.5.3 Appendix Dependency versions
Tomcat8.0系は8.0.43以降へのバージョンアップを推奨しています。そのため、SpringBoot1.3.2を1.3.8に変更するだけでは修正にならないようです。実際このフレームワークのバージョンアップを検討したのですが、大量のテストコードの修正や実装コードの修正、特にパッケージの移動が発生しているクラスなどがあり、そこそこの実装の修正量になります。また1.3系から1.5系へのバージョンアップを行う場合、テストケースを大幅に修正する必要があり、なかなかの労力が必要です。
SpringBootのバージョンアップをせずにTomcatだけ更新する
そこで、ひとまず脆弱性のあるTomcatのみは急ぎでバージョンアップを検討します。これは結構簡単で、gradleファイルで依存しているTomcatのモジュール設定を上書きすることで実現が可能です。
環境
- Java 1.8.0_91
- SpringBoot 1.4.6.RELEASE
SpringBootのアプリケーションを作成します。今回はGradleで作成しますが、mavenでも同じ設定が有効です。
build.gradle
Spring Initializrで作成できる素の雛形そのものです。
buildscript { ext { springBootVersion = '1.4.6.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') }
Application
@SpringBootApplication public class TomcatVersionupDemoApplication { public static void main(String[] args) { SpringApplication.run(TomcatVersionupDemoApplication.class, args); } }
実行結果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.4.6.RELEASE) 2017-05-17 15:55:19.416 INFO 6072 --- [ main] j.c.s.d.TomcatVersionupDemoApplication : Starting TomcatVersionupDemoApplication on komuroMBA.local with PID 6072 (/Users/komurohiraku/Develop/spring/Tomcatversionup/build/classes/main started by komurohiraku in /Users/komurohiraku/Develop/spring/Tomcatversionup) 2017-05-17 15:55:19.419 INFO 6072 --- [ main] j.c.s.d.TomcatVersionupDemoApplication : No active profile set, falling back to default profiles: default 2017-05-17 15:55:19.532 INFO 6072 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6b53e23f: startup date [Wed May 17 15:55:19 JST 2017]; root of context hierarchy 2017-05-17 15:55:20.937 INFO 6072 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2017-05-17 15:55:20.944 INFO 6072 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat 2017-05-17 15:55:20.944 INFO 6072 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.13
SpringBoot1.4.6なので組み込まれているTomcatは Apache Tomcat/8.5.13
です。これを 8.5.15
に変更してみます。
build.gradle修正
組み込まれているTomcatのバージョンをDependenciesの設定の中で上書きします。
buildscript { ext { springBootVersion = '1.4.6.RELEASE' tomcatVersion = '8.5.15' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } tomcatVersion = '8.5.15' dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') compile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}") compile("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") compile("org.apache.tomcat.embed:tomcat-embed-el:${tomcatVersion}") compile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}") }
実行結果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.4.6.RELEASE) 2017-05-17 16:56:35.541 INFO 8065 --- [ main] j.c.s.d.TomcatVersionupDemoApplication : Starting TomcatVersionupDemoApplication on komuroMBA.local with PID 8065 (/Users/komurohiraku/Develop/spring/Tomcatversionup/build/classes/main started by komurohiraku in /Users/komurohiraku/Develop/spring/Tomcatversionup) 2017-05-17 16:56:35.546 INFO 8065 --- [ main] j.c.s.d.TomcatVersionupDemoApplication : No active profile set, falling back to default profiles: default 2017-05-17 16:56:35.687 INFO 8065 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3b2c72c2: startup date [Wed May 17 16:56:35 JST 2017]; root of context hierarchy 2017-05-17 16:56:37.323 INFO 8065 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http) 2017-05-17 16:56:37.332 INFO 8065 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2017-05-17 16:56:37.333 INFO 8065 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.15
はい。これでSpringBootのバージョンはそのままに、Tomcatのみを Apache Tomcat/8.5.15
に変更しました。
おまけ
compile
で指定するとjarの中に組み込まれてしまいます。他のjarに組み込まれるライブラリなどは、Compileのときのみ取り込まれjarには含まれない provided
を利用したいところですが、あいにくgradleにはデフォルトで providedスコープがありません。そこでプラグインで解決します。
repositoriesの追加
repositories以下に設定を追加します。
maven { url 'http://repo.spring.io/plugins-release' }
buildscript.dependenciesの追加
classpath 'org.springframework.build.gradle:propdeps-plugin:0.0.7'
apply plugin
apply plugin: 'propdeps'
変更したファイル
build.gradleは以下のようになります。
buildscript { ext { springBootVersion = '1.4.6.RELEASE' tomcatVersion = '8.5.15' } repositories { mavenCentral() maven { url 'http://repo.spring.io/plugins-release' } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") classpath 'org.springframework.build.gradle:propdeps-plugin:0.0.7' } } apply plugin: 'propdeps' (snip) dependencies { (snip) provided("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}") provided("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") provided("org.apache.tomcat.embed:tomcat-embed-el:${tomcatVersion}") provided("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}") }
これでprovided指定ができるようになりました。よかったですね。