TomcatのDBアクセスユーザーのパスワードを暗号化する

TomcatでDBにアクセスする場合、server.xmlcontext.xmlResource要素に以下のような設定をします。

<Resource name="jdbc/TestDB" auth="Container"
    type="javax.sql.DataSource"
    maxTotal="100" maxIdle="30" maxWaitMillis="10000"
    username="javauser" password="javadude"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/javatest"/>

この時、password 属性の値には平文のパスワードを書くことになりますが、「これはセキュリティ上良くないのでは?」ということを聞かれて、少し調べてみました。

まず、何よりも先に読むのはユーザーガイドです。

Tomcat 8.5 – JNDI Datasource HOW-TO – Database Connection Pool (DBCP 2) Configurations

ここには、暗号化についての言及はなく、設定例には平文のパスワードが記載されています。

ということで、少し調べてみると、TomcatのWikiの中にそれについて書かれたページがありました。

Tomcat Wiki – Why are plain text passwords in the config files?

この中で、いくつか対策の例が上がっていますが、いずれもパスワードを安全に保持にする方法ではなく、“Security by Obscurity”(隠ぺいによるセキュリティの確保)であり、根本的な対策にはならないと書かれています。むしろ、server.xmlに対する読み取りアクセスをrootユーザーやTomcat実行ユーザーだけに限定することの必要性について言及しています。

このXMLファイルのパスワードを暗号化することにどれだけの効果があるかは分かりません。しかし、それでも、気休め程度でも、平文のパスワードではなく、暗号化されたパスワードを書いておきたい、という方はいるのではないかと思います。そんな方々のために簡単な解決策となるファクトリークラスをつくってみました。これを利用すると、前述のXMLのpassword=”javadude”password=”xe2J0sJ+WlEAX3L4v/EI3A==”のように暗号化されたパスワードを書けます。Tomcat 8.5で動作確認しましたが、他のバージョンでは若干のロジック修正が必要かもしれません(DBCP2のライブラリを使用しているので)。

使用方法

使用方法は以下の通りです。

  1. GitHubからファクトリークラスをgit cloneして下さい。
    $ git clone https://github.com/k-tamura/encrypt-db-password.git
  2. encrypt-db-password/src/main/java/org/t246osslab/tomcat/dbcp/dbcp2の中にあるEncryptionDataSourceFactoryのメソッド encrypt()decrypt() に暗号化、復号化の処理を実装します(実装してありますが、変更して下さい)。:
        public static String encrypt(String source) throws NoSuchAlgorithmException, NoSuchPaddingException,
                InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
            // TODO Remove the following code and write a processing of returning an encrypted string
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(KEY.getBytes(), ALGORITHM));
            return new String(Base64.getEncoder().encode(cipher.doFinal(source.getBytes())));
        }
    
        public static String decrypt(String encryptSource) throws NoSuchAlgorithmException, NoSuchPaddingException,
                InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
            // TODO Remove the following code and write a processing of returning an decrypted string
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), ALGORITHM));
            return new String(cipher.doFinal(Base64.getDecoder().decode(encryptSource.getBytes())));
        }
    
  1. mvnコマンドでビルドします。
    $ mvn clean package
  2. 生成した依存ライブラリを含むjarで平文のパスワードを暗号化します。
    $ java -jar target/encrypt-db-password-1.0.0-jar-with-dependencies.jar \
     -e [平文のパスワード]
  3. 以下のようにデータソースの定義(server.xmlなど)を編集します:
  4. <Resource name="jdbc/TestDB" auth="Container"
        ・・・
        password="[暗号化したパスワード]"
        factory="org.t246osslab.tomcat.dbcp.dbcp2.EncryptionDataSourceFactory" 
        ・・・
        url="jdbc:mysql://localhost:3306/javatest"/>   
    
  1. 依存ライブラリを含まないjarをTomcatのlibディレクトリにコピーします。
    $ cp target/encrypt-db-password-1.0.0.jar $CATALINA_HOME/lib/
  2. Tomcatを起動します。

Tomcatのバージョンによって、若干の変更が必要かもしれませんが、こんな手順でいいはずです。

広告

TomcatのsafeToDelete.tmpの謎を追う

「TomcatのtempディレクトリにあるsafeToDelete.tmpというファイルは何ですか?」

こんな質問をされたので、少し調べてみました。

※大げさなタイトルですが、超小ネタです。

ぱっと手元にあるTomcatを確認したところ、確かに、tempディレクトリの下にはsafeToDelete.tmpという空のファイルができています。バージョン6.0でも7.0でも8.0でもこの空のファイルがあります。保存されているディレクトリ名とファイル名から判断すると、削除したところで問題が無いことは推測できるのですが、これは一体??

ということで、まずは”safeToDelete.tmp”でググってみました。が、イマイチそれらしい答えが見つからず。

まあ、Tomcatのガイドに書いてあるだろうと、今後は「safeToDelete.tmp site:tomcat.apache.org」とサイト内検索でググってみましたが、結果はゼロ。

こうなると、ソースコードを調べた方が速そうなので、「safeToDelete」でソースコード全体をgrep。すると、ヒットはしたのですが、dist.xmlに以下の1行があるだけ…

<touch file="${tomcat.dist}/temp/safeToDelete.tmp" />

dist.xmlはantでTomcatをビルドする際に読み込まれるファイルで、これをもとにantは空のファイル(safeToDelete.tmp)を作成(touch)しているだけです。作成しているものの、どこからも参照されていないこのファイルに何の意味があるのでしょうか。このファイルが作成されるようになった過去の経緯を知らないと、存在意義は分からなそうです。

ということで、いつからのこのファイルがあるのか調べてみると、Tomcat 5.0.28には入っていませんでした。Tomcat 5.5.36を調べてみると、bugzilla37035-safeToDelete.tmpというファイルがありました…あ、そゆこと…

ということで、bugzillaでid=37035を検索すると、ありました。
https://bz.apache.org/bugzilla/show_bug.cgi?id=37035

Windowsの解凍ツールWinZIPでTomcatのtar.zpファイルを解凍したときに、もともとあった空のtempディレクトリが消えてしまう、というバグ(?)でした…

WinZIPの問題であって、対策すべきではないのでは?対策の仕方も…

そして、次の疑問が。logsやworkなどの空ディレクトリはなぜ、この対策をしなかったのか?tempディレクトリはサーブレットの仕様で規定されているから?深追いするような問題では無いので、この辺りで調査は切り上げます。