パスワードをコードにハードコーディングしないでください。これは最近、 Top 25 Most Dangerous ProgrammingMistakes<で取り上げられました。 / a> :
秘密のアカウントとパスワードをソフトウェアにハードコーディングすることは、熟練したリバースエンジニアにとって非常に便利です。パスワードがすべてのソフトウェアで同じである場合、そのパスワードが必然的に知られるようになると、すべての顧客が脆弱になります。また、ハードコーディングされているため、修正するのは非常に困難です。
パスワードなどの構成情報は、アプリケーションの起動時に読み取る別のファイルに保存する必要があります。これが、逆コンパイルの結果としてパスワードが漏洩するのを防ぐ唯一の実際の方法です(最初からパスワードをバイナリにコンパイルしないでください)。
このよくある間違いの詳細については、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ファイルです。許可されていないユーザーがrawファイル(UNIXのアクセス許可、Windowsのアクセス許可など)を表示できないように、適切な手順を実行してください。 Linuxでは、少なくとも、これは問題ではありません。Preferences.userNodeForPackage
を呼び出すからです。 現在のユーザーのホームディレクトリにXMLファイルを作成しますが、他のユーザーはこのファイルを読み取ることができません。 Windowsでは、状況が異なる場合があります。
その他の重要な注意事項: この回答や他の人のコメントでは、この状況に適したアーキテクチャについて多くの議論がありました。元の質問では、アプリケーションが使用されているコンテキストについては実際には言及されていないため、考えられる2つの状況について説明します。 1つ目は、プログラムを使用している人がデータベースの資格情報をすでに知っている(そして知ることを許可されている)場合です。 2つ目は、開発者であるあなたが、プログラムを使用している人からデータベースのクレデンシャルを秘密にしようとしている場合です。
最初のケース:ユーザーはデータベースのログイン資格情報を知ることを許可されています
この場合、上記の解決策が機能します。 JavaのPreference
クラスはユーザー名とパスワードをプレーンテキストで保存しますが、設定ファイルは許可されたユーザーのみが読み取ることができます。ユーザーは設定XMLファイルを開いてログイン資格情報を読み取るだけで済みますが、ユーザーは最初から資格情報を知っているため、セキュリティ上のリスクはありません。
2番目のケース:ユーザーからログイン資格情報を隠そうとしている
これはより複雑なケースです。ユーザーはログイン資格情報を知らないはずですが、それでもデータベースにアクセスする必要があります。この場合、アプリケーションを実行しているユーザーはデータベースに直接アクセスできます。つまり、プログラムは事前にログイン資格情報を知っている必要があります。上記の解決策は、この場合には適切ではありません。データベースのログイン資格情報は設定ファイルに保存できますが、所有者になるため、ユーザーはそのファイルを読み取ることができます。実際、このケースを安全な方法で使用する良い方法は実際にはありません。
正しいケース:多層アーキテクチャを使用する
これを行う正しい方法は、データベースサーバーとクライアントアプリケーションの間に、個々のユーザーを認証し、限られた一連の操作を実行できるようにする中間層を設けることです。各ユーザーは独自のログイン資格情報を持っていますが、データベースサーバー用ではありません。クレデンシャルは、中間層(ビジネスロジック層)へのアクセスを許可し、ユーザーごとに異なります。
すべてのユーザーは独自のユーザー名とパスワードを持っており、セキュリティ上のリスクなしに設定ファイルにローカルに保存できます。これは、3層アーキテクチャ と呼ばれます。 (階層は、データベースサーバー、ビジネスロジックサーバー、およびクライアントアプリケーションです)。より複雑ですが、この種のことを行うための最も安全な方法です。
操作の基本的な順序は次のとおりです。
- クライアントは、ユーザーの個人ユーザー名/パスワードを使用してビジネスロジック層で認証します。ユーザー名とパスワードはユーザーに認識されており、データベースのログイン資格情報とはまったく関係ありません。
- 認証が成功すると、クライアントはビジネスロジック層にデータベースからの情報を要求します。たとえば、製品の在庫。クライアントの要求はSQLクエリではないことに注意してください。これは、
getInventoryList
などのリモートプロシージャコールです。 。 - ビジネスロジック層はデータベースに接続し、要求された情報を取得します。ビジネスロジック層は、ユーザーの要求に基づいて安全なSQLクエリを作成する役割を果たします。 SQLインジェクション攻撃を防ぐために、SQLクエリのパラメータはすべてサニタイズする必要があります。
- ビジネスロジック層は、インベントリリストをクライアントアプリケーションに送り返します。
- クライアントはインベントリリストをユーザーに表示します。
プロセス全体で、クライアントアプリケーションがデータベースに直接接続することはありませんことに注意してください。 。ビジネスロジック層は、認証されたユーザーから要求を受け取り、インベントリリストに対するクライアントの要求を処理してから、SQLクエリを実行します。