LASSIC Media らしくメディア
Struts脆弱性を解消、Spring Boot移行を外注
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- Struts1は2013年4月にEOLとなり、Struts2も2.3.x系は2019年5月、2.5.x系は2024年4月に相次いでEOLを迎えています。
- S2-045(CVE-2017-5638)やS2-066(CVE-2023-50164)など、認証不要で実行できる深刻な脆弱性がStruts2でも繰り返し報告されています。
- 移行はActionクラスやstruts.xmlの資産調査から始まり、全面リライトと段階移行(ストラングラーパターン)のどちらを選ぶかが実務の分かれ目です。
目次
- Struts1は2013年にEOL、Struts2も2.3.x・2.5.xが順次EOL——古いStrutsで動くシステムの実態
- OGNLを突いた深刻な脆弱性——S2-045(CVE-2017-5638)とS2-066(CVE-2023-50164)
- なぜ脆弱性が積み重なるのか——OGNLの仕組みとEOLによるパッチ停止
- 移行先の中心はSpring Boot——全面リライトか段階移行(ストラングラーパターン)か
- 移行の実務——Actionクラス・struts.xml・JSPタグライブラリの置き換えとテスト戦略
- 内製と外注の分かれ目——資産調査・脆弱性優先度付け・並行稼働
- まとめ:Struts移行で押さえる3つの判断軸
- よくある質問
Struts1は2013年にEOL、Struts2も2.3.x・2.5.xが順次EOL——古いStrutsで動くシステムの実態
Apache Struts1は2013年4月5日、公式にEOL(End Of Life。サポート終了)が発表されたフレームワークです*1。最終リリースであるバージョン1.3.10は2008年12月に公開されたまま更新が止まっており、Apache Struts Teamは新規プロジェクトでの採用を推奨しないと明言しています*1。この発表では後継としてStruts2、あるいはSpring Web MVCなどの別フレームワークへの移行が示されました*1。
「Struts2に上げてあれば問題ない」という理解は、実務では成立しません。Struts2自体もバージョン系列ごとにEOLが順次訪れています。2018年11月14日の発表により、Struts2.3.x系は6ヶ月後の2019年5月14日にEOLを迎えました*2。続いて2023年10月30日の発表で、Struts2.5.x系も2024年4月30日にEOLとなっています*3。
つまり2026年現在、Struts1はもちろん、Struts2の2.3.x系・2.5.x系で稼働しているシステムも、公式サポートの対象外という状態です。現行でサポートされているのはStruts6.x系・7.x系に限られます。古いStrutsで動く業務システムを保守している企業にとって、これは「いつか対応すればよい」話ではなく、すでに支援の切れた基盤の上でシステムを動かしているという現実を意味します。
OGNLを突いた深刻な脆弱性——S2-045(CVE-2017-5638)とS2-066(CVE-2023-50164)
StrutsのEOLが厄介なのは、単に新機能が提供されなくなるだけでなく、過去に繰り返し重大な脆弱性が発覚してきた経緯があるためです。代表例がS2-045(CVE-2017-5638)です。JPCERT/CCは2017年3月9日、この脆弱性に関する注意喚起を発表しました*4。Jakarta Multipartパーサーを利用したファイルアップロード処理において、リクエストのContent-Typeヘッダーの解析に不備があり、認証なしで任意のコードを実行できる問題でした*5。影響を受けるのはStruts2.3.5〜2.3.31、および2.5〜2.5.10で、修正版は2.3.32と2.5.10.1として公開されています*5。この脆弱性は米国の大手信用情報機関で発生した大規模な情報漏えい事件との関連が広く報じられ、パッチ未適用のまま運用を続ける危険性を世界的に知らしめました。
もう一つの代表例がS2-066(CVE-2023-50164)です。JVN(Japan Vulnerability Notes)は2023年12月8日、外部からアクセス可能なファイルの脆弱性としてこの問題を公開しました*6。ファイルアップロード時のパラメータを操作することでパストラバーサル(意図しない上位ディレクトリへのアクセス)が発生し、悪意あるファイルの配置からリモートコード実行につながる恐れがあると説明されています*7。影響範囲はStruts2.0.0〜2.3.37、2.5.0〜2.5.32、6.0.0〜6.3.0と広く、修正版は2.5.33および6.3.0.2以降です*7。公表から数日のうちに実証コードが公開され、悪用の試みが観測された点も、対応の速さが問われる脆弱性だったことを示しています。
この二つの事例が示すのは、Struts2であっても油断はできないという点です。EOLを迎えたバージョン系列では、こうした脆弱性が新たに見つかっても修正版は提供されません。ファイルアップロード機能を持つ業務システムは特に、影響範囲の確認が欠かせないところです。
なぜ脆弱性が積み重なるのか——OGNLの仕組みとEOLによるパッチ停止
S2-045とS2-066には、いずれもOGNL(Object-Graph Navigation Language。Struts2が画面とActionクラスのプロパティを結びつけるために使う式言語)が関わっています。Struts2は、リクエストパラメータやエラーメッセージの組み立てなど、内部の多くの処理でOGNL式を評価する仕組みを採用しているのが実情です。入力値の検証が不十分な箇所にOGNL式の評価が及ぶと、攻撃者が用意した式がサーバー側でそのまま実行されてしまう構造的なリスクが生まれます。
S2-045では、リクエストヘッダーの値が例外処理を通じてOGNLの評価対象に渡る経路が問題視されました*5。S2-066では、ファイルアップロード時のパラメータ名の扱いに不備があり、パス操作を経由して任意の場所にファイルを配置できる状態になっていました*7。原因は異なりますが、いずれも「便利さのために内部処理を柔軟にした結果、想定外の入力を防ぎきれなかった」という共通点があります。
ここに輪をかけて厳しいのがEOLです。Apache Struts Teamは各バージョン系列のEOL発表時、発表日からEOL日までの期間はセキュリティ脆弱性のみ対応を続けるとしていますが*2*3、EOL日を過ぎればその対応も終わります。新しいOGNL関連の問題が見つかったとしても、EOL済みの系列には修正パッチが来ません。放置すればするほど、既知・未知の脆弱性を抱えたまま公開システムを稼働させ続けることになります。
移行先の中心はSpring Boot——全面リライトか段階移行(ストラングラーパターン)か
Java系Webシステムの移行先として広く選ばれているのがSpring Bootです。Spring公式は、スタンドアロンで実行できる本番レベルのSpringベースアプリケーションを最小限の手間で作成できるフレームワークと説明しています*8。TomcatやJettyといったサーバーを組み込んで動かせるため、WARファイルを別途デプロイする手順が不要になる点も特徴です*8。加えて、Springや主要な3rd Partyライブラリの設定を自動化する仕組みと、ビルド設定を簡素化する「opinionated」なスターター依存関係を備えています*8。ヘルスチェックや外部化設定など、本番運用を見据えた機能もあらかじめ用意されています*8。
移行アプローチは大きく三つに分かれます。一つ目は全面リライトです。既存のActionクラスやstruts.xmlの設計を踏襲せず、業務要件を洗い出したうえでSpring Bootベースで作り直す方法です。設計の刷新にはつながりますが、対象範囲が広い場合はテスト工数と移行期間がふくらみやすくなります。
二つ目は段階移行です。業務単位・画面単位でStrutsからSpring Bootへ徐々に置き換え、両方のフレームワークが一定期間並行稼働する形をとります。三つ目はストラングラーパターン(Strangler Fig Pattern。既存システムの外側にプロキシ層を置き、機能ごとに新システムへ徐々に処理を移していく設計手法)の考え方を取り入れる方法です。リバースプロキシやAPI Gatewayで振り分け先を切り替えながら、旧Strutsの領域を少しずつ縮小させていきます。対象システムの利用状況や停止できない業務の有無によって、どの方式が適しているかは変わります。
移行の実務——Actionクラス・struts.xml・JSPタグライブラリの置き換えとテスト戦略
実際の移行作業では、Struts2の構成要素をSpring Bootのどの仕組みに対応させるかを一つずつ確認していく作業が欠かせません。主な対応関係は次の通りです。
| Struts2の構成要素 | Spring Bootでの対応先 |
|---|---|
| Actionクラス(executeメソッド) | @Controller/@RestControllerのハンドラーメソッド |
| struts.xml(action要素によるマッピング) | @RequestMapping・@GetMapping等のアノテーション |
| ActionForm・validation.xmlによる入力値検証 | Bean Validation(@Valid、@NotNull等) |
| JSP+Strutsタグライブラリ(<s:…>) | Thymeleaf等のテンプレートエンジン、または移行中はJSP継続 |
| Interceptor(struts.xmlのinterceptor-ref) | Spring InterceptorやAOPによる横断処理 |
| web.xmlのFilterDispatcher設定 | 組み込みサーバーとDispatcherServletの自動設定 |
Struts2の系列内で見ても、この対応関係は一枚岩ではありません。Struts2.5から6.0.0への移行では、内部パッケージがcom.opensymphony.xwork2からorg.apache.struts2へ名称変更されており、参照箇所の一括置き換えが必要になります*9。さらにStruts6系から7系では、サーブレットAPIの名前空間がjavax.servletからjakarta.servletへ切り替わるため、対応するサーブレットコンテナのバージョンも合わせて見直す必要があります*9。Struts2内での延命だけでも相応の改修が伴うことがわかります。
JSPについては、一度にすべてを置き換える必要はありません。段階移行を選ぶ場合、Spring MVCもJSPをビューとして利用できるため、まずはコントローラー層とルーティングをSpring Boot側に寄せ、画面の刷新は後回しにするという順序も選べます。逆に全面リライトを選ぶ場合は、画面設計そのものを見直す機会として、テンプレートエンジンへの置き換えを併せて検討する企業も少なくないところです。
テスト戦略では、移行前に既存の挙動を固定するキャラクタリゼーションテスト(現状の入出力を正解として記録し、リグレッションを検知するテスト)を用意しておくことが土台になります。加えて、旧Strutsと新Spring Bootを同一環境で並行稼働させ、同じ入力に対する応答を比較する検証期間を設けておくと、移行後の不具合を抑えやすくなります。業務システムでは利用者への影響が大きいため、テストの網羅性を移行スケジュールより優先させる判断が求められる場面もあります。
内製と外注の分かれ目——資産調査・脆弱性優先度付け・並行稼働
移行の初期段階で必要になるのが資産調査です。現行システムに存在するActionクラスの数、struts.xmlに定義されたマッピングの数、JSPファイルの数を洗い出し、どこにOGNL式が使われているか、どの機能が外部公開されファイルアップロードを受け付けているかを把握します。この調査範囲が広い場合、既存の運用担当者が通常業務と並行して対応するのは負荷が大きい作業です。
調査の結果は、脆弱性の優先度付けにも直結します。認証不要でアクセスできるエンドポイントやファイルアップロード機能は、S2-045・S2-066のような脆弱性が突かれた際の影響が大きいため、移行順序を検討する際に優先度を上げる対象です。すべての機能を一律に扱うのではなく、公開範囲とリスクの大きさに応じて着手順を決めることが実務的です。
外注を検討する場合は、資産調査から移行方式の選定支援、段階移行時の並行稼働環境の構築までを一括して依頼できるかどうかが選定の分かれ目になります。移行対象の技術がStruts1・Struts2という組み合わせの企業では、双方の知見を持つ技術者を確保しにくいことも少なくありません。元請(プライムベンダー)として要件整理から移行後の運用まで一貫して対応できる体制かどうかも、契約前に確認しておきたい点です。移行対象の規模や業務要件の複雑さによって必要な工数は変わってくるため、現状の構成を診断したうえで内製・外注の切り分けを検討することが現実的な進め方です。
まとめ:Struts移行で押さえる3つの判断軸
本稿ではStruts移行の背景と実務を、Apache Struts公式やJPCERT/CC・JVNの情報をもとに整理しました。要点は3つに集約できます。第一に、Struts1は2013年、Struts2の2.3.x系・2.5.x系も2019年・2024年にそれぞれEOLを迎えており、Struts2だからといってリスクがないとは言い切れません*1*2*3。第二に、S2-045やS2-066のように認証不要で実行できる深刻な脆弱性がStruts2でも繰り返し報告されており、EOL後はこうした問題への修正パッチが提供されなくなります*5*7。第三に、移行はActionクラスやstruts.xmlの資産調査から始まり、全面リライトと段階移行のどちらを選ぶか、そして内製と外注のどちらで進めるかが、実務上の判断軸になります。
よくある質問
Struts1とStruts2の両方が社内システムに残っている場合、どちらを先に移行すべきですか。
Struts1は2013年にEOLとなってから長期間パッチが提供されていないため、外部公開の有無やアクセス範囲を確認したうえで優先度を検討します*1。Struts2側もバージョンが2.3.x・2.5.x系のままEOL済みであれば、同様に脆弱性対応が止まっている状態です*2*3。どちらを先に着手するかは、外部からアクセスできる機能の有無や利用者数など、リスクの大きさで判断するのが実務的です。
移行は全面リライトと段階移行、どちらを選ぶべきですか。
対象システムの規模や、業務を止められる時間の有無によって適した方式は変わります。小規模で影響範囲が把握しやすい場合は、全面リライトで設計を刷新しやすい点がメリットです。一方、規模が大きく利用者への影響を抑えたい場合は、ストラングラーパターンのような段階移行を選び、機能単位でSpring Boot側へ徐々に処理を移していく進め方が検討されます。
JSPは移行時にすべて置き換える必要がありますか。
一度にすべてを置き換える必要はありません。Spring MVCもJSPをビューとして利用できるため、段階移行ではコントローラー層の刷新を先に進め、画面のテンプレートエンジンへの置き換えは後の工程に回すという順序も選べます。
移行にはどのくらいの期間がかかりますか。
対象となるActionクラスの数やstruts.xmlのマッピング数、JSPの数、業務要件の複雑さによって必要な期間は大きく変わるため、一律の目安を示すことは適切ではありません。まず資産調査を行い、移行対象の規模を把握したうえで、全面リライトか段階移行かに応じた計画を立てることが現実的な進め方です。
移行作業を外部に委託する場合、契約前に何を確認すればよいですか。
資産調査の進め方、脆弱性の優先度付けの基準、全面リライトと段階移行のどちらに対応できるか、並行稼働環境の構築を含めた検証範囲を確認します。加えて、Struts特有のOGNLやタグライブラリの知見を持つ技術者が対応できるかどうかも、委託先を選ぶうえで確認しておきたい点です。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Apache Struts「Apache Struts 1 End-Of-Life (EOL) Announcement」(2013年4月5日)(https://struts.apache.org/struts1eol-announcement.html)
- *2 出典:Apache Struts「Apache Struts 2.3.x End-Of-Life (EOL) Announcement」(2018年11月14日)(https://struts.apache.org/struts23-eol-announcement)
- *3 出典:Apache Struts「Apache Struts 2.5.x End-Of-Life (EOL) Announcement」(2023年10月30日)(https://struts.apache.org/struts25-eol-announcement)
- *4 出典:JPCERT/CC「Apache Struts 2 の脆弱性 (S2-045) に関する注意喚起」(2017年3月9日)(https://www.jpcert.or.jp/at/2017/at170009.html)
- *5 出典:Apache Struts「S2-045」セキュリティ情報(CVE-2017-5638)(https://cwiki.apache.org/confluence/display/WW/S2-045)
- *6 出典:JVN「JVNVU#96961218:Apache Struts 2における外部からアクセス可能なファイルの脆弱性(S2-066)」(2023年12月8日)(https://jvn.jp/vu/JVNVU96961218/)
- *7 出典:Apache Struts「S2-066」セキュリティ情報(CVE-2023-50164)(https://cwiki.apache.org/confluence/display/WW/S2-066)
- *8 出典:Spring「Spring Boot」公式プロジェクトページ(https://spring.io/projects/spring-boot)
- *9 出典:Apache Struts Wiki「Struts 2.5 to 6.0.0 migration」(https://cwiki.apache.org/confluence/display/WW/Struts+2.5+to+6.0.0+migration)