MySQLのユーザー名とパスワードを逆コンパイルから保護するにはどうすればよいですか?


87

Java.classファイルはかなり簡単に逆コンパイルできます。コードでログインデータを使用する必要がある場合、データベースを保護するにはどうすればよいですか?


私があなたの質問を再タグ付けしたことを気にしないでください。「ユーザー名」と「パスワード」を削除し、「リバースエンジニアリング」と「逆コンパイル」を追加しました。オリジナルよりもわかりやすいと思います。ちなみに、ファンダメンタルズについての素晴らしい質問です!
ウィリアムブレンデル

6
ここでは、Javaを使用しているという事実は実際には関係がないことに注意してください。どの言語でもパスワードをハードコーディングすると、ほとんど同じように問題が発生します( "strings thebinary"は、Cプログラムの文字列定数も示します)。
ヨアヒムザウアー

@saua:本当ですが、おそらく誰かがJavaでユーザー名とパスワードを分離する方法に関するサンプルコードを投稿するでしょう。時間があれば自分でもやるかもしれません。
ウィリアムブレンデル

1
多くの回答が、アプリを実行しているユーザーが問題ない間、権限のないユーザーからユーザー名/パスワードを隠そうとしていると考えていることに気づきました。私はあなたからパスワードを非表示にすると信じていEVERYONE。質問でこれを明確にしてください。
pek 2009年

1
たとえば、資格情報を使用して、アプリケーション以外の誰もログインできないサーバーに接続するとします。
pek 2009年

回答:


123

パスワードをコードにハードコーディングしないでください。これは最近、プログラミングの最も危険な間違いトップ25で取り上げられました。

秘密のアカウントとパスワードをソフトウェアにハードコーディングすると、熟練したリバースエンジニアにとって非常に便利です。パスワードがすべてのソフトウェアで同じである場合、そのパスワードが必然的に知られるようになると、すべての顧客が脆弱になります。また、ハードコーディングされているため、修正するのは非常に面倒です。

パスワードを含む構成情報は、アプリケーションの起動時に読み取る別のファイルに保存する必要があります。これが、逆コンパイルの結果としてパスワードがリークするのを防ぐ唯一の実際の方法です(最初からバイナリにコンパイルしないでください)。

このよくある間違いの詳細については、CWE-259の記事を参照してください。この記事には、より完全な定義、例、および問題に関するその他の多くの情報が含まれています。

Javaでは、これを行う最も簡単な方法の1つは、Preferencesクラスを使用することです。あらゆる種類のプログラム設定を保存するように設計されており、その一部にはユーザー名とパスワードが含まれている可能性があります。

import java.util.prefs.Preferences;

public class DemoApplication {
  Preferences preferences = 
      Preferences.userNodeForPackage(DemoApplication.class);

  public void setCredentials(String username, String password) {
    preferences.put("db_username", username);
    preferences.put("db_password", password);
  }

  public String getUsername() {
    return preferences.get("db_username", null);
  }

  public String getPassword() {
    return preferences.get("db_password", null);
  }

  // your code here
}

上記のコードでsetCredentialsは、ユーザー名とパスワードを尋ねるダイアログを表示した後、メソッドを呼び出すことができます。データベースに接続する必要がある場合は、getUsernameandgetPasswordメソッドを使用して保存された値を取得できます。ログイン資格情報はバイナリにハードコードされないため、逆コンパイルによってセキュリティリスクが発生することはありません。

重要な注意:設定ファイルはプレーンテキストのXMLファイルです。許可されていないユーザーがrawファイル(UNIXのアクセス許可、Windowsのアクセス許可など)を表示しないように、適切な手順を実行してください。Linuxでは、少なくともこれは問題ではありません。呼び出すPreferences.userNodeForPackageと、現在のユーザーのホームディレクトリにXMLファイルが作成され、他のユーザーはそれを読み取ることができないためです。Windowsでは、状況が異なる場合があります。

より重要な注意事項:この回答や他の人のコメントでは、この状況に適したアーキテクチャについて多くの議論がありました。元の質問では、アプリケーションが使用されているコンテキストについては実際には言及されていないため、考えられる2つの状況について説明します。1つ目は、プログラムを使用している人がデータベースの資格情報をすでに知っている(そして知ることを許可されている)場合です。2つ目は、開発者であるあなたが、プログラムを使用している人からデータベースの資格情報を秘密にしようとしている場合です。

最初のケース:ユーザーはデータベースのログイン資格情報を知ることを許可されています

この場合、上記の解決策が機能します。JavaPreferenceクラスはユーザー名とパスワードをプレーンテキストで保存しますが、設定ファイルは許可されたユーザーのみが読み取ることができます。ユーザーは、設定XMLファイルを開いてログイン資格情報を読み取るだけで済みますが、ユーザーは最初から資格情報を知っているため、セキュリティ上のリスクはありません。

2番目のケース:ユーザーからログイン資格情報を隠そうとしている

これはより複雑なケースです。ユーザーはログイン資格情報を知らないはずですが、それでもデータベースにアクセスする必要があります。この場合、アプリケーションを実行しているユーザーはデータベースに直接アクセスできます。つまり、プログラムは事前にログイン資格情報を知っている必要があります。上記の解決策は、この場合には適切ではありません。データベースのログイン資格情報は設定ファイルに保存できますが、所有者になるため、ユーザーはそのファイルを読み取ることができます。実際、このケースを安全な方法で使用する良い方法は実際にはありません。

正しいケース:多層アーキテクチャを使用する

これを行う正しい方法は、データベースサーバーとクライアントアプリケーションの間に、個々のユーザーを認証し、限られた一連の操作を実行できるようにする中間層を設けることです。各ユーザーは独自のログイン資格情報を持っていますが、データベースサーバー用ではありません。資格情報は、中間層(ビジネスロジック層)へのアクセスを許可し、ユーザーごとに異なります。

すべてのユーザーは独自のユーザー名とパスワードを持っており、セキュリティ上のリスクなしに設定ファイルにローカルに保存できます。これは、3層アーキテクチャ(データベースサーバー、ビジネスロジックサーバー、およびクライアントアプリケーションである)と呼ばれます。それはもっと複雑ですが、それは本当にこの種のことをするための最も安全な方法です。

操作の基本的な順序は次のとおりです。

  1. クライアントは、ユーザーの個人ユーザー名/パスワードを使用してビジネスロジック層で認証します。ユーザー名とパスワードはユーザーに認識されており、データベースのログイン資格情報とはまったく関係ありません。
  2. 認証が成功すると、クライアントはビジネスロジック層にデータベースからの情報を要求します。たとえば、製品の在庫。クライアントの要求はSQLクエリではないことに注意してください。これは、などのリモートプロシージャコールgetInventoryListです。
  3. ビジネスロジック層はデータベースに接続し、要求された情報を取得します。ビジネスロジック層は、ユーザーの要求に基づいて安全なSQLクエリを作成する役割を果たします。SQLインジェクション攻撃を防ぐために、SQLクエリのパラメータはすべてサニタイズする必要があります。
  4. ビジネスロジック層は、インベントリリストをクライアントアプリケーションに送り返します。
  5. クライアントは、インベントリリストをユーザーに表示します。

プロセス全体で、クライアントアプリケーションがデータベースに直接接続することは決してないことに注意してください。ビジネスロジック層は、認証されたユーザーから要求を受け取り、インベントリリストに対するクライアントの要求を処理してから、SQLクエリを実行します。


4
これにより、誰かがユーザー名/パスワードを取得できなくなるのはどの程度正確ですか?それでは、ファイルからそれを読み取ることはできませんか?
ジョーフィリップス

私の回答で述べたように、ファイルのアクセス許可が適切に設定されている場合、プログラムを実行しているユーザーのみがその設定ファイルへの読み取りアクセス権を持ちます。UNIX環境では、これは自動的に行われます。Windowsには追加の手順が必要な場合があります(Windowsをあまり使用しないため、よくわかりません)。
ウィリアムブレンデル

アプリを実行しているユーザーは、アプリを阻止しようとしているユーザーではないという考えだと思います。その場合は、暗号化する必要があります。
Michael Haren

はい、マイケルは正しいです。基本的には、ユーザー名/パスワードはすでに知っているので、自分から隠す必要はありません。ただし、ファイルのアクセス許可により、他のユーザーには表示されません。
ウィリアムブレンデル

7
DB編集アプリケーションをユーザーにデプロイしていて(例)、データベースのユーザー名とパスワードをユーザーに知られたくない場合は、ソリューションを誤って設計しているため、クライアントソフトウェアはサーバーと通信している必要があります(たとえば、DB関連の処理を行うWebサービス)。
JeeBee 2009年

15

アプリケーションが読み取るファイルにパスワードを入力します。ソースファイルにパスワードを埋め込まないでください。限目。

Rubyには、そのような使用法のためのDBI :: DBRCと呼ばれるあまり知られていないモジュールがあります。Javaに同等のものがあることは間違いありません。とにかく、書くのは難しくありません。


7
これにより、後でパスワードを変更するのが少し簡単になりますが、基本的なセキュリティの問題は解決されません。
Brian Knoblauch

はい、そうです。WilliamBrendelからの回答も参照してください。
ケルティア2009年

1
Keltiaと私が指摘した方法は、この問題に対処するための受け入れられた方法です。ログイン資格情報をコンパイル済みコードから分離することは、最も基本的なソフトウェアセキュリティプラクティスの1つです。ログイン資格情報を別のファイルに入れることは、これを達成するための効果的な方法です。
ウィリアムブレンデル

さらに、構成情報がプレーンテキストファイルにあるという事実は、オペレーティングシステムの制限によってキャンセルする必要があります。たとえば、UNIXでは、プレーンテキストファイルはプログラムを実行しているユーザーが所有し、アクセス許可が0600である必要があるため、所有者のみがファイルを読み取ることができます。
ウィリアムブレンデル

4
OK、ファイルはプログラムを実行しているユーザーだけが読むことができます。すごい。それは何も解決しません。:-)パスワードを秘密にしようとしているユーザーである私は、アプリと同じくらい簡単にパスワードを読むことができます...
Brian Knoblauch

3

Webアプリケーションを作成していますか?その場合は、JNDIを使用してアプリケーションの外部で構成します。概要はこちらから入手できます

JNDIは、アプリケーションがネットワーク経由でリモートサービスを見つけてアクセスするための統一された方法を提供します。リモートサービスは、メッセージングサービスやアプリケーション固有のサービスを含む任意のエンタープライズサービスですが、もちろん、JDBCアプリケーションは主にデータベースサービスに関心があります。DataSourceオブジェクトが作成されてJNDIネーミングサービスに登録されると、アプリケーションはJNDI APIを使用してそのDataSourceオブジェクトにアクセスでき、それを使用して、それが表すデータソースに接続できます。


提供されたリンクが悪い
James Oravec 2016

2

何をしても、機密情報はどこかのファイルに保存されます。あなたの目標は、取得をできるだけ難しくすることです。これをどれだけ達成できるかは、プロジェクト、ニーズ、および会社のウォレットの厚さによって異なります。

最善の方法は、パスワードをどこにも保存しないことです。これは、ハッシュ関数を使用してパスワードハッシュを生成および保存することで実現されます。

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366

ハッシュアルゴリズムは一方向性関数です。それらは、任意の量のデータを、元に戻すことができない固定長の「フィンガープリント」に変換します。また、入力が少しでも変化すると、結果のハッシュが完全に異なるという特性もあります(上記の例を参照)。これは、パスワードファイル自体が侵害された場合でもパスワードを保護する形式でパスワードを保存するため、パスワードの保護に最適ですが、同時に、ユーザーのパスワードが正しいことを確認できる必要があります。

無関係な注意:インターネットの昔、「パスワードを忘れた」リンクをクリックすると、Webサイトからプレーンテキストのパスワードが電子メールで送信されていました。彼らはおそらくそれらをどこかのデータベースに保存していたのでしょう。ハッカーがデータベースにアクセスできるようになると、すべてのパスワードにアクセスできるようになります。多くのユーザーが複数のWebサイトで同じパスワードを使用するため、これは大きなセキュリティ問題でした。幸いなことに、今日ではこれは一般的な方法ではありません。

ここで質問があります:パスワードを保存するための最良の方法は何ですか?私はこの(認証およびユーザー管理サービスのストームパスの)ソリューションを非常に理想的なソリューションと見なします

  1. ユーザーが資格情報を入力すると、これがパスワードハッシュに対して検証されます
  2. パスワードハッシュではなく、パスワードハッシュが生成および保存されます
  3. ハッシュは複数回実行されます
  4. ハッシュはランダムに生成されたソルトを使用して生成されます
  5. ハッシュは秘密鍵で暗号化されます
  6. 秘密鍵は、ハッシュとは物理的に異なる場所に保存されます
  7. 秘密鍵は時間ベースで更新されています
  8. 暗号化されたハッシュはチャンクに分割されます
  9. これらのチャンクは、物理的に離れた場所に保存されます

明らかにあなたはグーグルでも銀行でもないので、これはあなたにとってやり過ぎの解決策です。しかし、次に問題が発生します。プロジェクトに必要なセキュリティの量、時間とお金の量はどれくらいですか。

多くのアプリケーションでは、推奨されていませんが、ハードコードされたパスワードをコードに保存することで十分な解決策になる可能性があります。ただし、上記のリストからセキュリティのいくつかの追加手順を簡単に追加することで、アプリケーションをはるかに安全にすることができます。

たとえば、ステップ1がプロジェクトにとって受け入れ可能なソリューションではないと仮定しましょう。ユーザーに毎回パスワードを入力させたくない、またはユーザーにパスワードを知られたくない/必要としない。それでもあなたはどこかに機密情報を持っていて、これを保護したいと思っています。単純なアプリケーションがあり、ファイルを保存するサーバーがないか、これはプロジェクトにとって非常に面倒です。アプリケーションは、ファイルを安全に保存できない環境で実行されます。これは最悪のケースの1つですが、それでもいくつかの追加のセキュリティ対策を講じることで、はるかに安全なソリューションを得ることができます。たとえば、機密情報をファイルに保存したり、ファイルを暗号化したりできます。暗号化秘密鍵をコードにハードコーディングすることができます。コードを難読化できるので、誰かがコードを解読するのが少し難しくなります。このリンク。(これは100%安全ではないことをもう一度警告したいと思います。適切な知識とツールを備えた賢いハッカーはこれをハッキングできます。しかし、要件とニーズに基づいて、これはあなたにとって十分な解決策かもしれません)。



0

MD5はハッシュアルゴリズムであり、暗号化アルゴリズムではありません。つまり、ハッシュされたワットを取り戻すことはできず、比較することしかできません。データベースのユーザー名とパスワードではなく、ユーザー認証情報を保存するときに使用するのが理想的です。db usernameとpwdは暗号化して、最小限のことを行うために構成ファイルに保持する必要があります。


文字列の可能なすべての組み合わせを生成し、対応するMD5ハッシュを格納する人々のことを聞いたことがあります。したがって、誰かのMD5ハッシュを見つけると、保存したハッシュを見つけるだけで、対応する文字列を取得します。
ナビゲーション2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.