none
バスワードの格納方法について RRS feed

  • 質問

  • お世話になります。

    ソフトを起動してから、ユーザーが、パスワードを入れること無くデータベースに接続するソフトを VB2005 で作りたいと思います。
    データベース接続用の、データベース名、ユーザー名、パスワードは、パスワードのみ暗号化して、テキストファイルに保存します。
    ソフトを起動時に上記テキストファイルを読み込み、パスワードを復号化して、データベースに接続します。


    Visual Studio .NET は、逆コンパイル出来るのでして見たら、パスワード復号化用のkeyが、丸見えで、Dotfuscator Community Editionで、難読化してもやはり丸見えで、困っています。
    Dotfuscatorの上級バージョン等、難読化ツールを購入する予定はありません。

     

    セキュリティーについては、決して厳しいものを要求されていません。
    しかし、「誰でも簡単に」は、不可です。
    Visual Studio .NET の、逆コンパイルは、インターネットにも情報が多く、「誰でも簡単に」の範疇に入るのではないかと思います。

     

    VB6で、暗号化部分を作って参照しようとも考えましたが、VB6では、.NETが、使えないので、暗号化の仕方が分かりません。

    良い隠し方はないでしょうか。

     

    2007年10月15日 10:01

回答

  • ログオン認証用のDBと言うより、スキーマを作りまして、関数を作りまして、操作者のユーザー名とパスワードを渡すと、認証できた場合、接続用のパスワードの復号キーを返すように作りかけたのですが、操作者が他のツールで、この関数を実行すると、簡単に復号キーを手に入れられてしまうので、止めました。

     

    んーと、

    私の説明が理解できていないようですね。

     

    どうして復号キーが出てくるのですか?

    ログオン認証用のDBを作るなら、復号ーなど要りません。

     

    ログオン認証用のDBは、復号キーでなく、そのユーザーに対応するDB接続用のユーザー名とパスワード返せばいいだけです。

    操作者がシステムログオン用のユーザー名とパスワードを知っているなら、

    それに対応するDB接続用のユーザー名とパスワードをログオン認証用のDBから取得できるのは問題ないはずです。

    他のツールを使って取得されても、ユーザーが信頼できるので、問題はありません。

     

    せっかくユーザー名とパスワードで認証してるのに、

    認証の情報を復号キーに集約してしまったら、アクセス制御ができなくなってしまい、

    意味がありません。

     

    念のため、復号キーを再度暗号化し秘密の場所に隠して、その復号キー生成ロジックを持たせる方法で考えます。

     

    セキュリティはそれほど重要でないということなので、

    それでもいいのでしょうが。

     

    私も含め、皆が何を言っているのか、

    きちんと理解してから行動したほうがよいと思いますよ。

     

    技術系の掲示板の場合、殆どの回答は一考の価値があります。

    少なくとも、この件の回答には、変なものは一つもありません。

     

    多少内容が理解しづらくても調べて理解したほうが、

    あとで苦労しませんし、技術力がつくのではないかと。

    2007年10月18日 11:41

すべての返信

  •  Michael-K さんからの引用

    ユーザーが、パスワードを入れること無く

    だとすると、そのユーザーが正規のユーザであることをどのように確認するのでしょうか。

    結局何らかの正規のユーザしか知らないもので認証しないと「誰でも簡単に」keyが丸見えになると思いますが。

    2007年10月15日 16:39
  •  Michael-K さんからの引用

    セキュリティーについては、決して厳しいものを要求されていません。
    しかし、「誰でも簡単に」は、不可です。
    Visual Studio .NET の、逆コンパイルは、インターネットにも情報が多く、「誰でも簡単に」の範疇に入るのではないかと思います。

     

    「厳しいもの」とか「誰でも簡単に」という単語では、あいまい過ぎてわかりません。

     

    「簡単」という単語の意味の取り方によっては、

    『「ソフトを起動してから、ユーザーが、パスワードを入れること無くデータベースに接続する」のは

    誰でも簡単にできるので誰でも簡単にパスワードがわかるはず。』

    という文章も真になります。

     

    コンパイラが作るコードの逆アセンブルの情報はインターネット上にたくさんあります。

    「誰でも簡単に」できるといえば、できます。

    中でもVB6で作ったexeのコードに関する情報はたくさんあり、

    .Netほどではないですが、かなり戻せます。

    そもそも、文字列定数は.Netでなくても丸見えが普通です。

    ですので、「VB6で、暗号化部分を作って」も意味がありません。

     

    文章からすると、セキュリティに関して理解が少ないように感じられます。

    セキュリティとは何でしょうか?

    もう一度、よく考えたほうがいいと思います。

     

    それはさておき。

     

    つまりは、文字列定数を難読化したいわけですね。

     

    文字列を難読化したい場合、よく符号化が使われます。

    符号化すると文字が直接は見えなくなります。

    Base64符号化が一番有名でしょうか。

    これは.Net Frameworkでもサポートされています。

    情報が失われなければいいので、

    文字列をcharで表して7をかけて65536で割った余りを取る、でもいいですし、

    特定のパターンでXORをとってもいいです。

    複数の符号化を組み合わせるのもアリです。

     

    符号化ですから、どのように符号化したかが分かれば元に戻せます。

    .Netは逆コンパイルしてコードが読めますが、これは他の言語でも同じです。

    CPUが実行できる以上、逆コンパイルしてアルゴリズムを理解することが普通は可能です。

     

    そのアルゴリズムが複雑であればあるほど、

    読むほうのやる気が削がれるので難読化されます。

    つまり、作るほうのやる気と、読む方のやる気の勝負なわけです。

    がんばってやる気の削がれるアルゴリズムを考えてください。

     

    あと、符号化方法によっては、符号化後のデータが特徴のある並びになります。

    それだけでアルゴリズムがばれる場合もありますので、ご注意を。

    2007年10月15日 20:58
  • IIJIMAS 様 れい 様 早速のご回答ありがとうございます。

    ご指摘のセキュリティーについてですが、データベース接続認証とシステムへのログオン認証は別です。
    但し、システムへのログオン認証には、データベースに接続されている必要があります。
    ご指摘のように、難読化した共有キーを外部に持つ方向で、検討します。
    ありがとうございました。

     

    2007年10月16日 5:33
  • ご指摘のセキュリティーについてですが、データベース接続認証とシステムへのログオン認証は別です。
    但し、システムへのログオン認証には、データベースに接続されている必要があります。

     

    システムってOSではないですよね?

     

    別にログオン認証があるならデータベース接続の認証は要らないのでは?

    というか、認証は自分でつくるよりOSとかデータベースの認証を用いるほうが安全だと思います。

     

    ご指摘のように、難読化した共有キーを外部に持つ方向で、検討します。

     

    外部に持ってもいいですが、私は外部に持てとは言ってません。

    難読化しておけばソースコード中に入れてもいいのではないですか?

    2007年10月16日 5:59
  • データベースにシステムログオン用のユーザ名、パスワード、権限を保存したテーブルがあります。
    ソフトは、データベース接続用のユーザ名、パスワードで、データベースに接続した後、ログオンダイアログを出します。
    操作者は、ユーザ名、パスワードを入力し、ソフトは、上記テーブルをクエリし、システムログオンの認証を行います。(ユーザ名でクエリ、パスワードの一致)
    操作者は、パスワードを入力しますので、ハッシュを利用できます。
    ソフトは、システムログオンの認証が出来た場合は、権限に応じたメニュー画面を表示します。
    ソフトは、認証に失敗した場合は、再度、システムログオン用のユーザ名、パスワードを要求します。
    操作者は、データベース接続用のユーザ名、パスワードを知らされません。
    従って、操作者は、ソフト以外のツールでのデータベース接続はできません。
    外部に暗号化した共有キーを持たそうと考えたのは、手順を増やそうと思っただけです。
    納得のいく方法がないので、どこで妥協するか考えています。
    ご指導よろしくお願いいたします。

     

    2007年10月16日 10:35
  • .Netの場合、ソフトのソースは公開されたも同然ですから、

    まともなセキュリティが欲しければ、ソースは周知であるとして組まなければなりません。

     

    ですので、できる限り、自分で実装したログオン方式でなく、

    データベースのロール制御で権限の制限を行うべきです。

    テーブルやクエリ、ストアドプロシージャに適切な制限を課せば、大抵できます。

    そうすれば、ソフトがクラックされたとしても安全です。

    #ソフトのクラック防止には署名という手もありますが。

     

    無限の権限があるユーザー名でDBに接続して、

    ソフトで権限の制約を課したりしてはいけません。

    DB側で、いくつかの権限に分けておくべきです。

    管理者、上級ユーザー、ユーザー、ゲストの4種ぐらいで。

     

    ログオン可否を確認するクエリだけゲストに実行できるようにする、

    という手もよく使われます。

    その際、DBに接続するユーザー名、パスワード等をそのDBから取るようにすれば、

    DBサーバー標準のアクセス制御を柔軟に拡張できます。

     

    他にもテクニックはいろいろありますが、

    一長一短で、一般的方法はありません。

    データベース設計時点で考えなくてはならないことです。

     

    いずれにせよ、クローズドな仕様、専用サーバー、専用クライアントは安全とは呼びません。

    ずいぶん前から、オープンな仕様、オープンなコード、標準的技術が安全な世界になっています。

     

    >納得のいく方法がないので、どこで妥協するか考えています。

     

    どこまでやるかは自分で判断するしかないと思いますが、

    私の意見では、DB側での対処ができないのだったら、何もしないほうがよいと思います。

    悪意を持って逆アセンブルされたら、難読化程度では意味無いですし、

    なら善意の逆アセンブルを禁止する必要も無く。

     

    やっぱり、DBのアクセス制御で対応しなさいということになりますね。

    2007年10月16日 13:33
  •  れい さんからの引用

    ログオン可否を確認するクエリだけゲストに実行できるようにする、

    という手もよく使われます。

    その際、DBに接続するユーザー名、パスワード等をそのDBから取るようにすれば、

    DBサーバー標準のアクセス制御を柔軟に拡張できます。

    参考になります。

    どのように実装すればよいのでしょうか。

    2007年10月17日 7:14
  •  れい さんからの引用

    ずいぶん前から、オープンな仕様、オープンなコード、標準的技術が安全な世界になっています。

    全くその通りで、私の求める物ですので、回答済みを解除させていただきました。

     

    ログオン認証用のDBにクエリをかける。

    認証が、可の場合、

    DBに接続するユーザー名、パスワード等をそのDBから取る。

    不可の場合、

    接続するユーザー名、パスワード等をそのDB読み取れないようにする。

    ここの実装が分かりません。

     

    すごく、正解に近づいてきているような気がします。

    よろしくお願いします。

     

     

     

     

     

     

     

    2007年10月17日 7:44
  • 別の角度から、しかもインストール時に一手間かかる方法になってしまいますが。

     

    http://dotnetfan.org/blogs/dotnetfanblog/articles/604.aspx

    こんな方法でweb.configを暗号化することができます。

    で、この方法はapp.configにたいしても適用することができます。

    DBへの接続にapp.configに記述したコネクションストリングを利用するようにしておけば、上記の方法での暗号化ができることになります。

     

    実際には各マシンにインストールする際にapp.configを一時的にweb.configという名前にします。

    そこでaspnet_regiisを使って暗号化を行います。

    暗号化されたファイルを適切な名前に直します。

    これだけでコネクションストリングを暗号化して利用することができます。

     

    こんな方法もある、ということで。

    2007年10月17日 9:31
  • デバッガ上でデータベースに接続するところにブレイクポイントを設定するとか、データベース接続するライブラリをフックとかすると、そこに至るまでにどれだけ難読化をしようとも、パスワードは丸見えになります。

    いずれにしても、パスワードでデータベースのセキュリティを確保しているのに、パスワードの入力必要なしでそのセキュリティを確保するというのは、原理的に無理です。

    NTLM認証を検討されてはいかがでしょうか?

    2007年10月17日 14:00
  •  Michael-K さんからの引用

    ログオン認証用のDBにクエリをかける。

    認証が、可の場合、

    DBに接続するユーザー名、パスワード等をそのDBから取る。

    不可の場合、接続するユーザー名、パスワード等をそのDB読み取れないようにする。

    ここの実装が分かりません。

     

    んー。難しいことは何も無いのです。そのまま実装すればよいのです。

    前にも書きましたが、独自の認証方式はいろいろあり、一長一短です。

    以下は一例です。

     

    まず、DBへの匿名アクセスを許可します。

    それから、殆ど全てのテーブル、クエリ、ストアドへの匿名アクセスを不許可にします。

    ユーザー認証用クエリ(ストアドの方がいいと思うけど。)だけ、匿名アクセスを許可します。

    認証用のクエリは、ユーザー名とパスワードが送られると

    適切な権限のあるDBアクセス用のユーザー名、パスワードを(場合によっては複数)返すように作ります。

    ユーザー名とパスワードが一致しない場合は何も返さなければよいだけです。

    ソフトのほうは、返されたユーザー名とパスワードでDBへの接続を作り直せばOKです。

    ユーザー名とパスワードが返されない場合は認証エラーにします。

     

    こうすると、実際のユーザー名とパスワードをDBに登録せず、

    DB内のテーブルで管理できます。

     

    もちろん、普通のDBは同じようなことをするための機能が標準でいろいろ用意されてます。

    グループとかロールとか。

    本来はそれを利用したほうがよいです。

     

    あと、発想の仕方ですが、「読み取れないようにする」と考えるのではなく、

    「普通は読み取れない」けど、「許可がある場合のみ読み取れる」という方向で考えるべきです。

     

    別件。

     どっとねっとふぁん さんからの引用

    で、この方法はapp.configにたいしても適用することができます。

     

    おお。言われてみれば、できてもよさそうですね。

    知りませんでした。

     

     Kazuya Ujihara さんからの引用

    NTLM認証を検討されてはいかがでしょうか?

     

    どうしてもユーザーはパスワードとか認証を嫌いますからね。

    Single Sign Onは受けがよいでしょうね。

    管理者としても、権限を一箇所で管理できるの便利ですが。

     

    DB標準のユーザー認証と同じ扱いになるのが普通で、

    独自の認証が必要なケースでは、使えないんですよね。

     

    そもそも、独自の認証が必要にならないように組むべきなんですが、

    これがなかなか難しい。仕様変更とかあるとさらにね…。

    2007年10月17日 15:09
  • アプリケーション認証を使って,

    C/Sシステムを.NETでやれたらなぁ~とか,
    そういうことなんだと思う。

     

     

     

    2007年10月17日 21:25
  • アプリがパスワードを保存して、次回はパスワードそのもの(ハッシュでない)を取り出したいのですね。

    これには、安全な方法はありません。警告文でも表示して、BASE64などで保存するしかないと思います。

    独自のXORとビットシフトの組みあわせも、推薦できませんが、ありかな。

     

    ネットスケープのブラウザーにも、WEBページログインのパスワードを保存する機能がありますが、

    BASE64で、暗号化(?)してテキストファイルに保存していました。IEは、違う方法で暗号化して

    保存していますが、解読するツールも出回っています。

     

    • 暗号化はオープンな方法を使う
    • 勝手に独自の暗号ルーチンを作らない

     

    ネスケは、この基本に基づいて、BASE64で保存したのでしょう。それ以上の方法がなかったのでしょう。

    エンジニアが独自の暗号化を使った場合、パスワードが解読された時に、そのエンジニアが、まず疑われて

    しまします。.NETのようにコード丸見えならば、この心配もないかな。

     

    2007年10月17日 22:35
  • ログオン認証用のDBと言うより、スキーマを作りまして、関数を作りまして、操作者のユーザー名とパスワードを渡すと、認証できた場合、接続用のパスワードの復号キーを返すように作りかけたのですが、操作者が他のツールで、この関数を実行すると、簡単に復号キーを手に入れられてしまうので、止めました。

     

    いろいろ調べましたら、「コード内のデータベース接続文字列やその他の機密設定を保護する -- MSDN Magazine, November 2003」という記事に当たりまして、成程と思いました。

     

    データベース接続文字列等を暗号化して置いておくのは簡単だが、復号キーをどうするかが問題だということのようです。

     

    .NET2.0 より、DpapiProtectedConfigurationProvider クラスが、追加され、Windowsや、ユーザーのデータより復号キーを作るので、問題の復号キーが、不要になると言う物みたいです。
    バージョンを固定しなさいと言うことなので、バージョンを変更したら、生成される復号キーが変わり復号出来なくなるのではないでしょうか。
    また、インストール時に、コンピューター毎に、暗号化をしなければなりません。
    どっとねっとふぁん様のご提案もこの方法で、RAS暗号化しているようです。

    インストール時や、アップデート毎に入力するようにすれば、現場では、CDに書くだろうなと思います。

     

    ソースコード内の復号キーを隠ぺいすることは、非常に良くない事だとしながらも、色々な事情で、方法がない場合は、復号キーではなくキー生成ロジックを持たせたほうが良いようです。
    これは、以前、れい様に頂いたご指摘です。

     

    念のため、復号キーを再度暗号化し秘密の場所に隠して、その復号キー生成ロジックを持たせる方法で考えます。

    がんばってやる気の削がれるアルゴリズムを考えます。
    これも、以前、れい様に頂いたご指摘です。


    いろいろ、ありがとうございました。

     

    2007年10月18日 10:47
  • ログオン認証用のDBと言うより、スキーマを作りまして、関数を作りまして、操作者のユーザー名とパスワードを渡すと、認証できた場合、接続用のパスワードの復号キーを返すように作りかけたのですが、操作者が他のツールで、この関数を実行すると、簡単に復号キーを手に入れられてしまうので、止めました。

     

    んーと、

    私の説明が理解できていないようですね。

     

    どうして復号キーが出てくるのですか?

    ログオン認証用のDBを作るなら、復号ーなど要りません。

     

    ログオン認証用のDBは、復号キーでなく、そのユーザーに対応するDB接続用のユーザー名とパスワード返せばいいだけです。

    操作者がシステムログオン用のユーザー名とパスワードを知っているなら、

    それに対応するDB接続用のユーザー名とパスワードをログオン認証用のDBから取得できるのは問題ないはずです。

    他のツールを使って取得されても、ユーザーが信頼できるので、問題はありません。

     

    せっかくユーザー名とパスワードで認証してるのに、

    認証の情報を復号キーに集約してしまったら、アクセス制御ができなくなってしまい、

    意味がありません。

     

    念のため、復号キーを再度暗号化し秘密の場所に隠して、その復号キー生成ロジックを持たせる方法で考えます。

     

    セキュリティはそれほど重要でないということなので、

    それでもいいのでしょうが。

     

    私も含め、皆が何を言っているのか、

    きちんと理解してから行動したほうがよいと思いますよ。

     

    技術系の掲示板の場合、殆どの回答は一考の価値があります。

    少なくとも、この件の回答には、変なものは一つもありません。

     

    多少内容が理解しづらくても調べて理解したほうが、

    あとで苦労しませんし、技術力がつくのではないかと。

    2007年10月18日 11:41
  • れい 様
    おっしゃっていることは、よく分かっていますよ。
    システムの権限は、作業の権限です。
    例えば、閲覧は、出来るが印刷は出来ない権限の場合、ソフトで制限します。
    顧客マスターのある条件を満たすものは、表示しない場合も、ソフトで制限します。
    作業権限に変更があった場合は、作業権限フラグのビットを書き換えるだけです。
    ロールは、管理者用と操作者用です。
    クローズドの設計です。
    従って、操作者に接続認証は、教えません。
    ソースコード内に安全に隠ぺいすることは、不可能であることを前提になるべく分かりにくく実装します。
    どっとねっとふぁん様のご提案は、ご提案事項として、残ります。

     

    2007年10月19日 5:04
  •  

    Michael-Kさんこんにちは

    私の場合はMD5によって不可逆暗号化したものをデータベースに保存しています。れいさんがおっしゃるようにデータベースの機能でアクセス制限するのが一番ですがその方法が採れませんでした。不可逆のため復号できないので元のパスワードを調べようがありません。開発者ですらお客さんの入れたパスワードがわかりません。

     

    2007年10月22日 5:06