最近 Spring Framework / Boot エコシステムを1ヶ月ほど触り、今までで最も期待を感じるJavaフレームワークだ!と胸をときめかせつつあるのですが、OGNLを使ったばかりにRCEだらけのStruts2が頭をよぎり、「そういやSpring製品の脆弱性報告傾向ってどうなんだ?」と焦って軽くググッたメモです。
先に結論だけ書くと、数は少ないもののRCEやSQLインジェクションが見つかってますので、「Springだから安全」と言える状況ではなく、継続的にSpring製品の脆弱性情報をモニタリングし、適切なタイミングでバージョンアップに追従していく必要があります。
まず https://www.cvedetails.com/ でざっくりとCVE-ID発行状況を見てみます。
ここで罠だったのが、Spring って最初はSpringSourceで開発されてて、その後Pivotalに移ったんですよね。しかもサイト上は vendor名が "Pivotal" と "Pivotal Software" の2種類が登録されてた ので、最初それに気づかず、「なんだめっちゃCVE少ないじゃん、これなら安心安全(●´ω`●)」となった貴重な一瞬を返してください。
- "SpringSource" 時代
- https://www.cvedetails.com/vendor/9664/Springsource.html
- 2009~2014年までこちらで報告されてるのがあり、全体で11件、RCE(Remove Code Execution) は1件だけ。
- "Pivotal" ベンダー名義
- https://www.cvedetails.com/vendor/14939/Pivotal.html
- 2014~2016年までですが、こちら名義で報告されてるのは全部で5件。Directory TraversalやGain Informationと穏やかな傾向です。
- "Pivotal Software" ベンダー名義
- https://www.cvedetails.com/vendor/15183/Pivotal-Software.html
- 2015~最新で、こちらは現時点で全部で29件とようやく本気になった感じです。Code Executionは3件です。
では、Strutsはどうかというと・・・
-
https://www.cvedetails.com/product/6117/Apache-Struts.html?vendor_id=45
- Struts1/2 両方合わせて56件、うち Code Execution がStruts2で多数発見されて全部で18件です。
ということで、現時点ではSpringの方が全部合わせても45件、しかもCode Executionは4件とStrutsより大分安全な印象を受けます。
そもそもMVCパターンのWebアプリケーションフレームワークだけに絞ったStrutsに対して、SpringはDI, AOP, MVC, JPA, e.t.c と非常に広範囲をカバーする製品群です。
その点を考慮すると、やはりSpringの方をwinnerとしたくなる衝動を抑えきれません。
しかしセキュリティについては恋愛感情と盛り上がり重視の情動に身を任せてエモーションするのではなく一歩引いて考える我々の理性に判断を委ねるべきです。
つまり、**「単にSpringが攻撃者から狙われていないだけ・脆弱性が見つかっていないだけ」**という可能性に怯えるのを我々は忘れてはなりません。
今の時点では比較的安全な状態だったとしても、将来の機能拡張による設計レベルでのイケてなさにより、クリティカルな脆弱性のもぐら叩きになる未来はいつだってあり得るのです(Struts2がそうであったように)。
実際 Spring にも Spring Expression Language (SpEL) があり、OWASPで SpEL によるインジェクションが解説されています。
EL式(とか最近だとシリアライズデータ)をユーザ入力で渡すのは可能な限り避けたい、というか個人的には絶対やりたくない類のアプローチです。
個人的には、上記OWASPのページで解説されてるエラーコードをエラーページに渡してEL式としてメッセージ文字列を取ってくる処理は、Flashスコープ使ってセッション変数で渡すべきかなぁ~と思いましたん。
実際に、Spring 2/3 時代にEL式が原因のRCEが報告されてます。
それは昔の話だろうう、今はSpring Frameworkも4系だよ・・・と言ってスルーできれば良いのですが、そう楽観的にもなれないようです。
こちらはPivotal製品の脆弱性(恐らくCVE-IDが発番されたもの)の一覧ですが、2016年にもいくつかCode Injection/Remote Code Executionが報告されています。
- https://pivotal.io/security/cve-2016-6656 : "Pivotal Greenplum" DB製品が使うGPHDFS protocolにコマンドインジェクションの脆弱性
- https://pivotal.io/security/cve-2016-4977 : Spring Security OAuth で response_type がSpELとして実行されていたため、RCEの脆弱性。
- https://pivotal.io/security/cve-2016-2173 : Spring AMQP で通信データのデシリアライズに org.springframework.core.serializer.DefaultDeserializer を使っていたことによる RCE の脆弱性。
また、一見SQLを直接扱わないのでSQLインジェクションの心配が無さそうなJPAですが、ORDER BY を制御するSortインスタンスでBlind SQL Injectionの問題がSpring Data JPAで報告されてます。
以上のように「Strutsとは違うのだよ、Strutsとは!」と若さゆえの過ちで脆弱性情報の確認を怠っていると、Spring使ってても気がついたら攻撃されてた、なんて可能性はまだまだありそうです。
以下は時間があれば後日見てみたいトピック:
- なぜStrutsよりはRCEの報告が少ないのか?パラメータをJava Beanに反映するのはSpring Frameworkでも行われているが、StrutsでのOGNLを使った方式とはどこが違うのか?
- 実際にHTTPのヘッダやパラメータをEL式として扱う箇所は、どれくらいSpring Frameworkに潜んでいるのか?静的解析などでトレースして確認してみたくはある。
- SpEL の実装では、classloaderなどStruts2 + OGNLで狙われやすいプロパティや式表現について、なにか対策をしているのか?
などなど。