One IT Thing

IT業界で飯を食う為の学習系雑記

database java maven security

H2 Databaseで生成したSHA256値をJavaで生成したSHA256値と比較してみる

投稿日:2020年8月15日 更新日:

ファイル、サーバ、メモリ、様々な動作形態がとれてプロトタイピングや、配布アプリの組み込みDBとして便利に使えるPure Javaデータベースの「H2」。

  1. zipファイルでWin10にインストール。
  2. H2 Databaseコンソール(Webブラウザ)起動。
  3. H2にユーザ情報テーブル作成。
  4. データ追加。(パスワードはH2のSHA256ハッシュ関数で保存)
  5. JDBCでH2に接続、平文パスワードをJavaでSHA256化した値と比較。

こんな感じのことを試してみようと思います。

環境

  • Windows10
  • Java 8(Eclipse同梱ではなくOSにインストール)
  • Eclipse 202003(Java11)
  • H2 Database ver 1.4.199

H2はJavaで作られていて、コマンドプロンプトから実行します。
コマンドプロンプトからJVMを起動できるよう、OSにJDKをインストールしてjavaコマンドを実行出来るようにしておきます。

(*)2020/08時点でH2の最新は1.4.200ですが、私の環境だとDBファイルを作る際に以下のエラーに遭遇しました。

一般エラー: "java.lang.IllegalStateException: Unable to read the page at position 1967576057930752 [1.4.200/6]"
General error: "java.lang.IllegalStateException: Unable to read the page at position 1967576057930752 [1.4.200/6]" [50000-200] HY000/50000 (ヘルプ)

githubのissueを見るとOpenなままです。

この為、一つ下のバージョン1.4.199を使用します。(調査するのがめんどくさい)

H2 Databaseの構築

インストールからデータ追加まで。

Windows10にインストール

インストーラ形式とzipファイル形式があります。
今回はAll Platform用のzipファイルを解凍してC:\opt\h2に置きました。

C:\opt\h2>dir
2020/08/14  23:45    <DIR>          bin
2019/03/13  14:58               385 build.bat
2019/03/13  14:58               546 build.sh
2020/08/14  23:45    <DIR>          docs
2020/08/14  23:45    <DIR>          service
2020/08/14  23:45    <DIR>          src

コンソール(Webブラウザ)起動

binディレクトリに入り、h2.batを実行。

C:\opt\h2>cd bin
C:\opt\h2\bin>h2.bat

ブラウザが起動し、8082ポートでコンソール開始画面が開きます。
今回はHDDに作成されるDBファイルにTCP接続するサーバモードで使います。

「接続」するとホームディレクトリ直下にtest.mv.dbファイルが出来上がり、SQLを実行できる画面に遷移します。

SQL編集画面からテーブルを作成

表示されたSQL編集画面で以下のテーブルを作成してみます。

  • users:ユーザ情報(メール、パスワードハッシュ、権限)
  • role:権限マスタ
/* 権限マスタ */
create table role(
    id int primary key,
    name varchar(50)
);

/* ユーザ情報 */
create table users(
    mail varchar(255) primary key,
    name varchar(255),
    password varchar(255),
    role int,
    foreign key(role) references role(id)
);

作成したテーブルにデータを追加

roleテーブル:1:user(一般利用者)、2:admin(管理者)
usersテーブル:パスワードはH2のhash関数でSHA256ハッシュ化

H2の関数詳細は公式を参照。

insert into role values(1, 'user');
insert into role values(2, 'admin');

insert into users
values(
    'yamada@hoge.com',
    '山田太郎',
    hash('sha256', stringtoutf8('password1')),
    1
);

insert into users
values(
    'suzuki@foo.com',
    '鈴木一郎',
    hash('sha256', stringtoutf8('password2')),
    2
)
;

selectして追加されたか確認。
一般利用者の山田さん、管理者の鈴木さんが登録されました。

山田さんのパスワードは「password1」、鈴木さんのパスワードは「password2」でしたがハッシュ化されてシステム側では元のパスワードがなんだったのか分からなくなっています。

EclipseからJDBCでH2に接続

H2側のデータが整ったのでJavaプログラムから接続してみます。

mavenプロジェクトを作ってH2の依存を追加

(gradleでもいいですが)EclipseでMavenプロジェクトを作成。
mvnrepositoryからH2のドライバを含むjarを探し、pom.xmlに追加します。

(ついでにJava11でビルドされるようにmaven-compiler-pluginも設定してます)

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

        (snip)

    <!-- java11でコンパイル -->
    <build>
        <finalName>h2</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <!-- H2のJDBCドライバorg.h2.Driverクラスを含むjarファイル -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
        </dependency>

        (snip)

    </dependencies>
</project>

DBハッシュ値とJavaでSHA256化した値を比較

単純なJDBCプログラムでH2から山田さんのハッシュされたパスワードを取得、Javaでハッシュしたパスワードと比較してみます。

package sample.h2;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) throws SQLException, NoSuchAlgorithmException {
		String jdbcUrl = "jdbc:h2:tcp://localhost/~/test";
		String jdbcUser = "sa";
		String jdbcPassword = "";

		// DB値と比較するyamadaの平文パスワード
		String userPassword = "password1";

		// 1.usersテーブルからyamadaのレコードを取得
		try (Connection conn = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword)) {
			conn.setAutoCommit(false);

			String sql = "select * from users, role where users.role = role.id and users.mail = 'yamada@hoge.com'";

			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);

			String mail = null;
			String name = null;
			String password = null;
			while (rs.next()) {
				mail = rs.getString(1);
				name = rs.getString(2);
				password = rs.getString(3);
				System.out.println(mail + " | " + name + " | " + password);
			}

			// 2.yamadaの平文パスワードをsha256ハッシュ、16進文字列化。
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			md.update(userPassword.getBytes());
			byte[] sha256 = md.digest();
			StringBuilder sb = new StringBuilder(2 * sha256.length);
			for (byte b : sha256) {
				sb.append(String.format("%02x", b & 0xff));
			}
			System.out.println("yamadaのパスワードハッシュ = " + sb);

			// 1と2が等しいか調べる
			if (sb.toString().equals(password)) {
				System.out.println("パスワードは等しい");
			} else {
				System.out.println("パスワードは等しくない");
			}

			stmt.close();
		}
	}
}

実行結果

平文「password1」をH2でハッシュ化、Javaでハッシュ化した結果が等しいと分かりました。

yamada@hoge.com | 山田太郎 | 0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e
yamadaのパスワードハッシュ = 0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e
パスワードは等しい

まとめ

AP、DBどちらでハッシュ化しても同じ結果になることが分かりました。

お仕事で実戦投入する際はハッシュする担当はAPかDBに統一しますし、より強度を高める為にソルトを使ったり、暗号化したり、keycloakやopenstack-keystone他外部の認証トークン生成ツールを使うなどすると思います。

実践向きの検証ではないですが、どちらでハッシュ化しても同じ結果になることを知っておくのは運用面を考えると良いことかな、と。

可搬性にも優れていますし、試作の時点ではH2でも十分代替が効きそうです。

-database, java, maven, security
-, ,

執筆者:

関連記事

Chrome76でシークレットモード非検知を実現出来なかった件の検証

2019/07/30にChrome76がリリースされました。 76では以前からGoogleが問題視していた「閲覧者がシークレットモードでみているかどうか運営側が分かってしまう」が解決されるはずでした。 …

Stripe+Java+Payment Request APIでApple Pay、Google Payを使ったテストWeb決済をしてみる

自分で作ったサービスを運用してチャリンチャリンしたい・・・エンジニアならこんな夢、一度は見たことがあるんじゃないでしょうか。 夢を実現する為、以前Stripeのcheckout.jsを使ったテストWe …

SNS他Webサービスの情報流出、セキュリティ事故に巻き込まれたかどうか調べる

FaceBookやCapital Oneなど、サービスに登録されたユーザ情報が漏洩する事件が日々取り沙汰されています。 「もしかしたら自分が登録した情報も漏れてるかもしれない」 そう思って気になったら …

Spring&JSPの検証環境を速攻で作る

2019年現在、オワコン風潮の強いJSPですが使っているプロジェクトもまだまだあり、枯れた技術を好む官公庁系のプロジェクトでは根強いシェアを誇っています。実装検証をする為に環境を作る機会があったりする …

ブラウザでRSA暗号化したデータをサーバで復号する(Angular + JSEncrypt、Spring MVC)【後編】

前回の続きです。 One IT ThingブラウザでRSA暗号化したデータをサーバで復号する(Angular + JSEncrypt、Spring …https://one-it-thi …

 

shingo.nakanishi
 

東京在勤、職歴20年越え中年ITエンジニアです。まだ開発現場で頑張っています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけどフリーランスで孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。