web-dev-qa-db-ja.com

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

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

81
Jakob Cosoroaba

コードにパスワードをハードコーディングしないでください。これは最近 Top Dangerous Programming Mistakesのトップ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メソッドを呼び出すことができます。データベースに接続する必要がある場合は、getUsernameメソッドとgetPasswordメソッドを使用して、保存されている値を取得できます。ログイン資格情報はバイナリにハードコードされないため、逆コンパイルしてもセキュリティ上のリスクはありません。

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

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

最初のケース:ユーザーは、データベースのログイン資格情報を知る権限があります

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

2番目のケース:ユーザーからログイン資格情報を非表示にしようとしています

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

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

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

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

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

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

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

115
William Brendel

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

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

15
Keltia

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

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

3
Tim Howland

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

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

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

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

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

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

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

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

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

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

2
Caner

この質問は、暗号化されたファイルにパスワードやその他のデータを保存する方法を示しています。 Java 256ビットAESパスワードベースの暗号化

1
Aaron Digulla

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

0
renegadeMind