# PHC 形式でのパスワードハッシュのエクスポート

**URL:** https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805
**Category:** Self-Hosting
**Tags:** how-to
**Created:** [2019 年 11 月 19 日午後 3:38 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805 "2019-11-19T15:38:49Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [2019 年 11 月 19 日午後 3:38 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/1 "2019-11-19T15:38:49Z")

</div>

Discourse のパスワード保存システムに関する現在の詳細は、[discourse/docs/SECURITY.md at main · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/main/docs/SECURITY.md) で確認できます。執筆時点では、600,000 回のイテレーションで PBKDF2-SHA256 を使用しています。

状況によっては、Discourse からハッシュ化されたパスワードをすべてエクスポートし、別のシステムにインポートしたい場合があります。例えば、Discourse 組み込みの認証からカスタム SSO システムへ移行する場合などが挙げられます。データベースから元のパスワードを抽出することは不可能であるため、移行先のシステムは同じハッシュアルゴリズムを同じパラメータで実行できる必要があります。

パスワードデータは `user_passwords` テーブルに格納されており、`password_hash`、`password_salt`、`password_algorithm` の各カラムを含みます。`password_algorithm` カラムには完全な PHC アルゴリズムプレフィックス（例: `$pbkdf2-sha256$i=600000,l=32$`）が格納されます。イテレーション数が時間経過とともに増加している場合、ユーザーごとにこの値が異なる可能性があります。

[Data Explorer](https://meta.discourse.org/t/32566?silent=true) を使用して、コンピュータが読み取れる形式で情報をエクスポートできます。

```sql
SELECT users.id, users.username, up.password_salt, up.password_hash, up.password_algorithm
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0

```

これにより、Discourse 独自の形式でデータがエクスポートされます。Salt は hex エンコードされ、パスワードハッシュも hex エンコードされます。

一部の外部システムは、パスワードハッシュ関数の出力をアルゴリズムを跨いで表現することを目的とした [PHC ストリング形式](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) をサポートしています。pbkdf2-sha256 の場合、このストリングにはアルゴリズムの種類、イテレーション数、base64 エンコードされた Salt、base64 エンコードされたハッシュが含まれます。幸いにも、Postgres は単一のクエリでこれらすべてを処理できます。

各 Discourse ユーザーに対して PHC ストリングを生成するには、[Data Explorer](https://meta.discourse.org/t/32566?silent=true) で以下のようなクエリを使用できます。

```sql
SELECT users.id, users.username,
  concat(
    up.password_algorithm,
    replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
    '$',
    replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
  ) as phc
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0

```

Auth0 を使用している場合は、代わりに以下のクエリを使用してください。

```sql
SELECT
    user_emails.email,
    users.active as email_verified,
    concat(
        up.password_algorithm,
        replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
        '$',
        replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
    ) as password_hash
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
INNER JOIN user_emails 
ON users.id = user_emails.user_id 
AND user_emails.primary IS TRUE
AND users.id > 0

```

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [2020 年 8 月 5 日午前 9:46 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/2 "2020-08-05T09:46:40Z")

</div>

余計なお世話かもしれませんが、私は（友好的な Auth0 チームの助けを借りて）Auth0 にユーザーパスワードをインポートするための有効な PHC 文字列を生成するように、サンプルクエリを微調整しました。

また、以下の行を変更して、ソルトを base64 でエンコードしました。

```plaintext
salt,

```

を

```plaintext
replace(encode(users.salt::bytea, 'base64'), '=', ''),

```

に変更しました。  
詳細はこちら（Discourse ユーザーとそのパスワードを Auth0 にインポートする手順を含む）をご覧ください。

> **[Bulk User Import Custom Password Hash Issue](https://community.auth0.com/t/bulk-user-import-custom-password-hash-issue/47408)**
>
> I am attempting to import users, including their passwords, from Discourse to Auth0. I’m following these guides: https://auth0.com/docs/users/guides/bulk-user-imports ...

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [2020 年 8 月 5 日午前 10:13 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/3 "2020-08-05T10:13:25Z")

</div>

@angus さん、ありがとうございます。これは興味深いですね。OP に記載されたクエリを使って、ある顧客が Auth0 へのユーザーインポートに成功した事例があるからです。インポートプロセスに変更があったのでしょうか？記憶では、PHC 文字列を Auth0 にインポートできる機能は去年の 11 月にはまだ非常に新しいものだったと思います 🤔

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [2020 年 8 月 5 日午前 10:46 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/4 "2020-08-05T10:46:51Z")

</div>

はい、私もその点について疑問に思い、同じように考えていました。

PHC 仕様の記述も少し曖昧で、塩（salt）が Base64 エンコードされている必要があるのかどうかも明確ではありませんでした。

> 塩は、[a-zA-Z0-9/+.-]（小文字、大文字、数字、/、+、.、-）の文字の並びで構成されます。関数仕様は、有効な塩の値のセットと、このフィールドの最大長を定義しなければなりません。任意のバイナリ塩を扱う関数は、定義された範囲または範囲のセットに収まる長さを持つバイナリ値の Base64 エンコードをそのフィールドとして定義すべきです。

---

<div class="post-metadata">

### Author: ![renato](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/renato/32/383632_2.png) [@renato](https://meta.discourse.org/u/renato)
#### Post date: [2020 年 12 月 1 日午後 2:03 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/5 "2020-12-01T14:03:22Z")

</div>

話題がそれてしまい申し訳ありませんが、Auth0からDiscourseへパスワードハッシュをインポートした方はいますか？この移行を検討しているため、ご助言いただければ幸いです。有料のAuth0顧客ではないため、パスワードハッシュのエクスポートに費用をかける前に、これが可能かどうかを確認したかったのです。

よろしくお願いいたします。

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [2020 年 12 月 1 日午後 2:20 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/6 "2020-12-01T14:20:10Z")

</div>

Discourse コアではパスワードのインポートはサポートされていませんが、このサードパーティ製プラグインの適応版を使用することで実現できる可能性があります。

> [@Migrated password hashes support](https://meta.discourse.org/t/migrated-password-hashes-support/19512?u=david):
>
> Here is the password migration support plugin: The original thread follows. We do regular forum conversions (yes, we’ll open source the converter once it’s stable enough) and one of the big quirks when migrating to Discourse is the fact that all users have to set a new password, because the password in the original forum is encrypted. So we thought of the following mechanism. when creating users in the conversion step, we store the original password hash in a custom field when a user log…

---

<div class="post-metadata">

### Author: ![renato](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/renato/32/383632_2.png) [@renato](https://meta.discourse.org/u/renato)
#### Post date: [2020 年 12 月 1 日午後 2:22 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/7 "2020-12-01T14:22:36Z")

</div>

ありがとうございます！GitHub ではリポジトリを見つけましたが、こちらのメタではトピックが見つかりませんでした。

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [2021 年 1 月 4 日午後 10:30 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/9 "2021-01-04T22:30:21Z")

</div>

@angus さん、こちらで整理を進めています。

元のコードブロックは以下のようになっているべきでしょうか？

```sql
SELECT id, username,
  concat(
    '$pbkdf2-sha256$i=64000,l=32$',
    replace(encode(users.salt::bytea, 'base64'), '=', ''),
    '$',
    replace(encode(decode(password_hash, 'hex'), 'base64'), '=', '')
  ) as phc
FROM users

```

また、以下のような内容を含めるべきでしょうか？

Discourse のパスワードを Auth0 にインポートする方法の詳細については、[Bulk User Import Custom Password Hash Issue - Auth0 Community](https://community.auth0.com/t/bulk-user-import-custom-password-hash-issue/47408) をご覧ください。

Auth0 から Discourse へデータを移行する場合は、こちらが役立つかもしれません：[https://meta.discourse.org/t/migrated-password-hashes-support/19512。](https://meta.discourse.org/t/migrated-password-hashes-support/19512%E3%80%82)

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [2021 年 1 月 7 日午前 8:33 UTC](https://meta.discourse.org/t/export-password-hashes-in-the-phc-format/133805/10 "2021-01-07T08:33:26Z")

</div>

はい、その通りです。

各インポートには特定の注意が必要であることを追加することをお勧めします。扱うユーザーデータはユースケースによって異なるため、これらのクエリをそのままコピー＆ペーストするだけではいけません。

また、PHC からのパスワードのエクスポートは必ずしも Auth0 専用というわけではないので、単に「例」として言及する方が良いかもしれません。

私がエクスポートに使用した完全なクエリは以下の通りです。

```sql
SELECT
    user_emails.email,
    users.active as email_verified,
    concat(
        '$pbkdf2-sha256$i=64000,l=32$',
        replace(encode(users.salt::bytea, 'base64'), '=', ''),
        '$',
        replace(encode(decode(users.password_hash, 'hex'), 'base64'), '=', '')
    ) as password_hash
FROM users
INNER JOIN user_emails 
ON users.id = user_emails.user_id 
AND user_emails.primary IS TRUE
AND users.id > 0

```
