SpringBatchのプロジェクトにおいて、JdbcTemplateを使ってDBアクセス処理を書いていた際、「これってちゃんとSQLインジェクション対策できてるの?」という問いが生まれました。
公式を読んでみても「出来てるよ!」という明言が見つからなかったため、ライブラリの中身まで確認し、調査してみました。
想定読者
- JdbcTemplateってSQLインジェクションされてるのか不安な人
- SpringBatch実装したことがある人
- 検証にはSpringBatchプロジェクトを利用しています。ステップやジョブの概念など、細かいものは省きます。
そもそもSQLインジェクションってなんだっけ、と言う人向け
以下サイトを参考にしてみてください!
結論
JdbcTemplateはSQLインジェクション出来てると思って問題ないと思います。検証に利用したバージョンとメソッドは以下。
※調査内容が膨大になるので、今回一つのSELECT系メソッドのみで検証しました。
※鵜呑みにはせず、ご自身のプロジェクト内で議論/検討/判断のうえ利用するようにしてくださいね。
Version
spring-boot-starter-batch:2.7.0を利用しています。
内部的にはspring-jdbc:5.3.23が呼ばれてるようです。
検証したメソッド
queryForObject
※JavaDoc
https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html#queryForObject-
java.lang.String-org.springframework.jdbc.core.RowMapper-java.lang.Object..
なぜ出来てると言えるのか
プレースホルダ(=「?」)使いつつ、内部的にPreparedStatementで型チェックされてるから、です。具体的には以下。
実験
検証用リポジトリで遊んでみました。
https://github.com/kannna5296/jdbctemlate_example
検証ソースの軽い仕様説明
上記ソースは、バッチに引数TASK_ID
を与えて実行することで利用します。
TASK
テーブルのID
カラムの値が、与えた引数TASK_ID
と一致していた場合、検索に成功しタスク名を標準出力するようなものです。
TASK_ID=1
と引数を与えれば、以下のようにタスク名を出力してくれます。
インジェクションしようとしてみる
https://marunouchi-tech.i-studio.co.jp/2056/
↑このサイトを参考に、' OR 1=1--
という変な引数(※)を与えて実行してみます。
※単純な文字列結合でSQL生成していた場合(ダメな例)には、生成されるSQLが ...WHERE id = '' OR 1 = 1 --
となり、全件抜き出しを許してしまうような引数です。
データ変換でバッチが落ちてくれました。対策できてそうです。
参考
公式JavaDoc
公式チュートリアル「Spring JDBC JdbcTemplate で SQL 発行」
https://spring.pleiades.io/guides/gs/relational-data-access/