質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.80%

利用ユーザしか復号化できない暗号化処理

解決済

回答 5

投稿

  • 評価
  • クリップ 2
  • VIEW 2,532

kensii

score 180

前提・実現したいこと

PHP(CakePHP2.x)でログインを必要とするWebアプリケーションを作成しています。
MySqlにデータを保存する際、暗号化して保存→取り出す時は文字列を複合化して表示させるようにしたのですが、
これだと、最悪の場合システム管理者(復号化キーを知る者)が悪意を持ってしまったら、DB
からデータを抜き取って複合化出来てしまうと思いました。

DBを抜き取られてもアプリケーションの管理側すら復号化できない様にすることなどは可能なのでしょうか。

恥ずかしながら方法論がなかなか見つけ出せません。
ご存知の方いらっしゃいますでしょうか。

試したこと

・crypt系の関数を使い、復号化キーを持たせて、DBに保存してある暗号化文字列を復号化
・復号化キーはアプリケーション全体で一つを定数化している

// 復号化のために必要なキー
define('CRYPT_KEY' ,'hogehoge'); 

$text = '保存したい情報';

// 暗号化(DBへの保存時)
$encrypted_string_for_db_save = openssl_encrypt($text,'aes-256-ecb',CRYPT_KEY);

// 復号化(DBからデータを取り出したとき)
$decrypted_string = openssl_decrypt($encrypted_string_for_db_save ,'aes-256-ecb',CRYPT_KEY);

補足情報(言語/FW/ツール等のバージョンなど)

結局DBに情報が保存されてしまうので実現できてないのですが、各ユーザのハッシュ化されたログインパスワードを復号化キーにすべきかとも考えました。

PHP5.6.10

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+6

Passpackというパスワード管理サービスが利用ユーザーしか復号化できない仕組みを取っています。

仕組み的には次のような形であると(自称)しています。

  1. サービスにログインします。(これは通常の方法です。他サービスとのシングルサインオンにも対応しています)
  2. パッキングキー(packing key)を入力します。このキーはブラウザ上にのみ保存されており、サーバーには送られません。正しいかどうかは、サーバー側に正しいキーのみ複合化できる暗号化されたデータがあり、それをブラウザに送って、ブラウザ上で復号化していて確認しているようです。また、実際はパッキングキーそのものでは無く、パッキングキーをハッシュ化したものを秘密鍵として使います。
  3. パスワードを登録します。パスワードはJavaScriptを用いてブラウザ上で2.で保存された秘密鍵で暗号化します。暗号化済みのデータをサーバーに送ります。
  4. 登録したパスワードを複合化する場合は、サーバー側から暗号化されたデータを送って貰い、ブラウザ上で2.で保存された秘密鍵を使って復号化します。

パッキングキーを忘れた場合、サービス管理者でも復号化は不可能になります(実際は、変更前のパッキングキーで暗号化したデータを一回分のみサーバー側で保存しているため、変更直後のみ変更前のキーで復号化ができるようです)。クライアントサーバー間の通信には暗号化済みのデータしか送られず、サーバーには暗号化済みのデータしか保存されません。そのため、たとえSSL/TLSの未知の脆弱性を使って盗み見られても、サーバーをハッキングされてデータを全て盗まれても、暗号化の仕組みそのもの自体に脆弱性がなければ、生のデータを取ることは(現実的ではない時間を掛けない限り)不可能です。

このようにブラウザ上で暗号化・復号化を完結させる必要があります。PHPだけでは不可能であり、むしろ、PHP側では暗号化・復号化の処理を行ってはいけません。キーを毎回クライアントからサーバーへ送るという安易な方法が思いついたかもしれませんが、PHPを少し改造して、その送られてくるキーをログに出すようにするだけで、キーは入手し放題なるため、意味がありません。

具体的なJavaScriptについては私も知らないので何もアドバイスできないのですが、JavaScriptを用いた暗号化・復号化について、調べるといいかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/28 14:42

    なるほど。
    ブラウザ側での実装をしないとだめみたいですね。
    そうなるとこのPasspackのようにそれだけでサービスが出来上がってしまいそうですね汗
    私にはハードルが高そうですがJSでの実装も調べてみます。
    大変勉強になります。ありがとうございました。

    キャンセル

+2

システム管理者(つまりサーバサイド)でもデータを読めないようにするなら、サーバへデータを送信するまえに、利用者のみ知る秘密鍵を使って暗号化して、それをテキスト化(base64等)してDBに保存すればいいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/28 07:54

    横からの質問で恐縮ですが、そのような仕組みを作った場合、秘密鍵はどのように保管(?)するのが一般的なのでしょうか?

    キャンセル

  • 2016/12/28 08:26

    利用者側で管理します。

    キャンセル

  • 2016/12/28 08:34

    あまり意味のない質問でしたね^^;失礼しました。回答ありがとうございます。

    キャンセル

0

暗号化すると情報を隠せると考えられているかもしれませんが、鍵を秘密にしないと暗号化は意味がありません。

利用ユーザしか復号化できない

特定の個人のみ復号化できればよいのであれば、鍵を個人に持たせ、

各ユーザのハッシュ化されたログインパスワードを復号化キーにすべきかとも考えました。

というような方法で秘密にすることは可能です。似た方法はたくさんありますが、個人が鍵を管理するという意味では同じです。一般的には、個人の情報を安全に保管していてもアプリケーションとして動作するときにはそれを外部に持ち出す必要があり、あまりうまくいきません。

これだと、最悪の場合システム管理者(復号化キーを知る者)が悪意を持ってしまったら、DB 
からデータを抜き取って複合化出来てしまうと思いました。

この問題に対しては、複数人の鍵が揃わないと復号化できないという仕組みを備えたものもあります。たとえば、5人に鍵を配布し、そのうち3人の鍵が揃わないとサーバを起動できないというように構成することが可能です。ただし、サーバを起動する毎に5人中3人を集めて鍵を入力してもらう必要があります。

参考:Introduction to Vault

この Vault は鍵の保管庫であり、各サービスはここから鍵を読み出して動作します。このような仕組みを導入するというのも一つの手です。あらゆる管理者パスワード、暗号化鍵を Vault に入れて、サービスの起動時に動的にメモリに呼び出す仕組みであれば、ディスクには鍵が残りません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/28 14:38

    Vaultというものがあるのですね。しりませんでした。有用な情報ありがとうございます。

    キャンセル

0

"元のデータを表示"が必要な時点でほぼ対処不可能。
そもそもpassword_hash()などの一方向関数を用いて元に戻せなくするべき。

なお、余計な実装は不要で、何も考えずにAuthComponentを使っておけば勝手にpassword_hash()されるから、
管理者を含め誰も元パスワードを知ることはできない。

http://book.cakephp.org/2.0/ja/core-libraries/components/authentication.html
http://book.cakephp.org/2.0/ja/tutorials-and-examples/blog-auth-example/auth.html

https://github.com/cakephp/cakephp/blob/df1b9b8aa75ece32dbe5e5343a249f3058ba1f3f/src/Auth/DefaultPasswordHasher.php

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/28 04:51

    復号化が要件なので、それの否定ではなく、「ほぼ対処不可能」の対処できる箇所を回答してあげるべきだと思います。

    キャンセル

-3

そもそも複合化できないようにすればいいかと。

Password Hashing 関数
http://php.net/manual/ja/ref.password.php

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/28 08:12

    表面上の質問はそうですけどねぇ

    キャンセル

  • 2016/12/28 09:31

    文句しか付かないので追記してみます。

    利便性を残して誰にも複合化できないようにするには先に述べた通りの状況ですが、二つ目のパスワード(鍵)を発行する以外で考えると、不可逆パスをDBに保存して、ログイン時の入力を暗号化して時限式で別に持たせるとか、ソースは触れない前提ならいっそクッキーで鍵っとくとか。そんなオープンな環境じゃないなら物理媒体とか秘密鍵認証とか好きにやればいいと思いますが、新しい認証方式を考えるみたいな話でしたら私が場違いでした。

    キャンセル

  • 2016/12/28 09:52 編集

    それで話は戻りますが、どんな無敵の暗号化しても最後に表示させるなら、管理者だったらパスワード抜けますよね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る