Javaセキュリティの基本

  • Java

  • link:/category/security-2/ [セキュリティ]

1. 概要

このチュートリアルでは、Javaプラットフォームのセキュリティの基本について説明します。 また、安全なアプリケーションを作成するために利用できるものにも焦点を当てます。
セキュリティは、*多くの分野*を含む広大なトピックです。 これらの一部は、アクセス修飾子やクラスローダーなど、言語自体の一部です。 さらに、データ暗号化、安全な通信、認証、承認など、いくつかのサービスも利用できます。
したがって、このチュートリアルでこれらすべてについて有意義な洞察を得るのは実用的ではありません。 ただし、少なくとも意味のある語彙を獲得しようとします。

2. 言語機能

とりわけ、* Javaのセキュリティは、言語機能のレベルで始まります*。 これにより、セキュリティで保護されたコードを記述できるだけでなく、多くの暗黙的なセキュリティ機能を利用できます。
  • 静的データ型付け:Javaは静的に型付けされた言語であり、
    型関連エラーの実行時検出の可能性を減らします

  • アクセス修飾子:Javaでは、異なるアクセス修飾子を使用できます
    フィールド、メソッド、クラスへのアクセスを制御するパブリックおよびプライベートなど

  • 自動メモリ管理:Javaには*ガベージコレクションベースのメモリがあります
    管理*。これにより、開発者はこれを手動で管理できなくなります。

  • バイトコード検証:Javaはコンパイルされた言語であり、つまり
    コードをプラットフォームに依存しないバイトコードに変換し、ランタイムは、実行のためにロードするすべてのバイトコードを検証します

    これはJavaが提供するセキュリティ機能の完全なリストではありませんが、ある程度の保証を与えるのに十分です!

3. Javaのセキュリティアーキテクチャ

特定の領域の調査を開始する前に、Javaのセキュリティのコアアーキテクチャを理解する時間をとりましょう。
Javaのセキュリティの中核となる原則は、*相互運用可能で拡張可能な_Provider_実装*によって推進されています。 _Provider_の特定の実装では、セキュリティサービスの一部またはすべてを実装できます。
たとえば、_Provider_が実装する典型的なサービスの一部は次のとおりです。
  • 暗号化アルゴリズム(DSA、RSA、SHA-256など)

  • 鍵の生成、変換、および管理機能(たとえば
    アルゴリズム固有のキー)

    Javaには*多くの組み込みプロバイダー*が付属しています。 また、アプリケーションで複数のプロバイダーを優先順位で構成することもできます。
    link:/uploads/Java-Providers.jpg []
     
    そのため、* Javaのプロバイダーフレームワークは、すべてのプロバイダーに設定された優先順位*の順序でサービスの特定の実装を検索します。
    さらに、このアーキテクチャでは、プラグ可能なセキュリティ機能を備えたカスタムプロバイダーをいつでも実装できます。

4. 暗号化

暗号化は、一般的なセキュリティ機能とJavaのセキュリティ機能の基礎です。 これは、*攻撃者の存在下での安全な通信のためのツールとテクニック*を指します。

4.1. Java暗号化

https://docs.oracle.com/javase/9​​/security/java-cryptography-architecture-jca-reference-guide.htm[Java Cryptographic Architecture(JCA)]は、Javaの暗号化機能にアクセスして実装するためのフレームワークを提供します。以下を含む:
  • デジタル署名

  • link:/java-password-hashing [メッセージダイジェスト]

  • link:/java-cipher-class [対称および非対称
    暗号]

  • メッセージ認証コード

  • キージェネレーターとキーファクトリー

    最も重要なことは、Javaはhttps://docs.oracle.com/javase/9​​/security/howtoimplaprovider.htm[_Provider_-based implementation]を暗号化機能に利用することです。
    さらに、Javaには、RSA、DSA、AESなどの一般的に使用される暗号化アルゴリズムの組み込みプロバイダーが含まれています。 これらのアルゴリズムを使用して、安静時、使用中、または移動中のデータにセキュリティを追加できます*。

4.2. 暗号化の実践

アプリケーションの非常に一般的な使用例は、ユーザーのパスワードを保存することです。 これは後の認証に使用します。 これで、プレーンテキストパスワードを保存するとセキュリティが低下することは明らかです。
そのため、1つの解決策は、プロセスが繰り返し可能で、しかも一方向のみであるようにパスワードをスクランブルすることです。 このプロセスは暗号化ハッシュ関数と呼ばれ、SHA1はそのような一般的なアルゴリズムの1つです。
それでは、Javaでこれを行う方法を見てみましょう。
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] hashedPassword = md.digest("password".getBytes());
ここで、_MessageDigest_は、興味のある暗号化サービスです。 * _getInstance_()メソッドを使用して、利用可能なセキュリティプロバイダーからこのサービスをリクエストしています*。

5. 公開鍵インフラ

公開キーインフラストラクチャ(PKI)とは、公開キー暗号化を使用してネットワーク上で安全に情報を交換できるようにするセットアップのことです*。 このセットアップは、通信に関係する当事者間に構築された信頼に依存しています。 この信頼は、認証局(CA)として知られる中立で信頼できる機関によって発行されたデジタル証明書に基づいています。

5.1. JavaでのPKIサポート

Javaプラットフォームには、https://docs.oracle.com/javase/9​​/security/java-pki-programmers-guide.htm [デジタル証明書の作成、保存、および検証を促進する]へのAPIがあります。
  • KeyStore:Javaは、
    暗号化キーと信頼できる証明書の永続的なストレージのための_KeyStore_クラス。 ここで、* _ KeyStore_は、キーストアファイルとトラストストアファイルの両方を表すことができます*。 これらのファイルの内容は似ていますが、使用方法が異なります。

  • CertStore:さらに、Javaには_CertStore_クラスがあり、これは
    信頼できない可能性のある証明書と失効リストの公開リポジトリを表します。 証明書と失効リストを取得する必要があります*他の用途の中で証明書パスを構築するため*

    Javaには、「cacerts」と呼ばれる*組み込みの信頼ストアがあります。これには、既知のCAの証明書が含まれています。

5.2. PKIのJavaツール

Javaには、信頼できる通信を促進するための非常に便利なツールがいくつかあります。
  • 作成および管理するための「keytool」と呼ばれる組み込みツールがあります
    キーストアとトラストストア

  • また、署名と署名に使用できる別のツール「jarsigner」もあります。
    JARファイルを検証する

5.3. Javaでの証明書の使用

Javaで証明書を操作して、SSLを使用して安全な接続を確立する方法を見てみましょう。 相互認証されたSSL接続では、2つのことを行う必要があります。
  • 証明書の提示-有効な証明書を提示する必要があります
    コミュニケーションの別の当事者。 そのためには、公開鍵が必要なキーストアファイルをロードする必要があります。

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] keyStorePassword = "changeit".toCharArray();
try(InputStream keyStoreData = new FileInputStream("keystore.jks")){
    keyStore.load(keyStoreData, keyStorePassword);
}
  • 証明書を確認する–提示された証明書も確認する必要があります
    コミュニケーションの別の当事者によって。 そのためには、トラストストアをロードする必要があります。ここでは、他の関係者から以前に信頼された証明書が必要です。

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// Load the trust-store from filesystem as before
プログラムでこれを行う必要はほとんどなく、通常は実行時にシステムパラメータをJavaに渡します。
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.keyStore=keystore.jks

6. 認証

認証とは、パスワード、トークン、または現在利用可能なその他のさまざまな資格情報などの追加データに基づいて、ユーザーまたはマシンの提示されたIDを検証するプロセスです。

6.1. Javaでの認証

Java APIはhttps://docs.oracle.com/javase/9​​/security/java-authentication-and-authorization-service-jaas-loginmodule-developers-guide1.htm [プラグイン可能なログインモジュール]を使用して、さまざまなアプリケーションに対する複数の認証メカニズム。 _LoginContext_は、この抽象化を提供します。この抽象化は、構成を参照し、適切な_LoginModule_をロードします。
複数のプロバイダーがログインモジュールを利用できるようにしていますが、* Javaにはいくつかのデフォルトモジュールがあります*使用可能です:
  • Krb5LoginModule、Kerberosベースの認証用

  • JndiLoginModule、ユーザー名およびパスワードベースの認証用
    LDAPストアに支えられている

  • KeyStoreLoginModule、暗号化キーベース認証用

6.2. 例によるログイン

認証の最も一般的なメカニズムの1つは、ユーザー名とパスワードです。 _JndiLoginModule_を使用してこれを実現する方法を見てみましょう。
このモジュールは、ユーザーからユーザー名とパスワードを取得し、JNDIで設定されたディレクトリサービスに対して検証します。
LoginContext loginContext = new LoginContext("Sample", new SampleCallbackHandler());
loginContext.login();
ここでは、* LoginContext_のインスタンスを使用してログインを実行しています*。 _LoginContext_は、ログイン構成のエントリの名前を取ります。この場合は、「Sample」です。 また、ユーザー名やパスワードなどの詳細についてユーザーと対話する_LoginModule_を使用して、_CallbackHandler_のインスタンスを提供する必要があります。
ログイン構成を見てみましょう。
Sample {
  com.sun.security.auth.module.JndiLoginModule required;
};
簡単なことですが、必須の_LoginModule_として_JndiLoginModule_を使用していることを示唆しています。

7. 安全な通信

ネットワークを介した通信は、多くの攻撃ベクトルに対して脆弱です。 たとえば、誰かがネットワークを利用して、転送中にデータパケットを読み取る可能性があります。 長年にわたり、業界はこの通信を保護するために多くのプロトコルを確立してきました。

7.1. 安全な通信のためのJavaサポート

Javaは、https://docs.oracle.com/javase/9​​/security/java-secure-socket-extension-jsse-reference-guide.htm [ネットワーク通信を保護するためのAPI]に*暗号化、メッセージ整合性、および両方のクライアントを提供しますおよびサーバー認証*:
  • SSL / TLS:SSLおよびその後継であるTLSは、信頼されていないセキュリティを提供します
    データ暗号化と公開鍵インフラストラクチャによるネットワーク通信。 Javaは、パッケージ「java.security.ssl」で定義されている_SSLSocket_を介してSSL / TLSのサポートを提供します。

  • SASL:Simple Authentication and Security Layer(SASL)は標準です
    クライアントとサーバー間の認証用。 Javaは、パッケージ「java.security.sasl」の一部としてSASLをサポートしています。

  • GGS-API / Kerberos:Generic Security Service API(GSS-API)が提供する
    Kerberos v5などのさまざまなセキュリティメカニズムを介したセキュリティサービスへの均一なアクセス。 Javaは、パッケージ「java.security.jgss」の一部としてGSS-APIをサポートしています。

7.2. 動作中のSSL通信

link:/java-ssl[_SSLSocket_を使用したJava]で他の関係者との安全な接続を開く方法を見てみましょう。
SocketFactory factory = SSLSocketFactory.getDefault();
try (Socket connection = factory.createSocket(host, port)) {
    BufferedReader input = new BufferedReader(
      new InputStreamReader(connection.getInputStream()));
    return input.readLine();
}
ここでは、_SSLSocketFactory_を使用して_SSLSocket_を作成しています。 その一環として、暗号スイートや使用するプロトコルなどのオプションのパラメーターを設定できます。
これが適切に機能するためには、先ほど見たように、キーストアとトラストストアを作成して設定する必要があります。

8. アクセス制御

アクセス制御とは、ファイルシステムやコードベースなどの機密リソースを不当なアクセスから保護することです。 これは通常、そのようなリソースへのアクセスを制限することで実現されます。

8.1. Javaでのアクセス制御

https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html#Authorization[Javaでアクセス制御を実現] * _SecurityManager_クラスを介して仲介されるクラス_Policy_および_Permission_を使用* 。 _SecurityManager_は“_java.lang_âパッケージの一部であり、Javaでアクセス制御チェックを実施する責任があります。
クラスローダーは、ランタイムでクラスをロードするときに、_Permission_オブジェクトにカプセル化されたクラスにデフォルトのアクセス許可を自動的に付与します。 これらの既定のアクセス許可を超えて、セキュリティポリシーを通じてクラスにより多くのレバレッジを付与できます。 これらはクラス_Policy_で表されます。
コード実行のシーケンス中に、ランタイムが保護されたリソースの要求を検出すると、* _ SecurityManager_は、コールスタックを介して、インストールされた_Policy_ *に対して要求された_Permission_を検証します。 その結果、許可を与えるか、_SecurityException_をスローします。

8.2. ポリシー用のJavaツール

Javaには、プロパティファイルから認証データを読み取る_Policy_のデフォルト実装があります。 ただし、これらのポリシーファイルのポリシーエントリは特定の形式である必要があります。
Javaには、ポリシーファイルを作成するためのグラフィカルユーティリティ「policytool」が付属しています。

8.3. 例によるアクセス制御

Javaのファイルのようなリソースへのアクセスを制限する方法を見てみましょう。
SecurityManager securityManager = System.getSecurityManager();
if (securityManager != null) {
    securityManager.checkPermission(
      new FilePermission("/var/logs", "read"));
}
ここでは、_FilePermission_にラップされたファイルの読み取り要求を検証するために_SecurityManager_を使用しています。
ただし、_SecurityManager_はこの要求を_AccessController_に委任します。 _AccessController_は内部で、インストールされた_Policy_を使用して決定に到達します。
ポリシーファイルの例を見てみましょう。
grant {
  permission
    java.security.FilePermission
      <<ALL FILES>>, "read";
};
基本的に、すべてのファイルの読み取り許可を全員に付与しています。 ただし、*セキュリティポリシーにより、よりきめ細かな制御を提供できます*。
Javaでは、_SecurityManager_がデフォルトでインストールされない可能性があることに注意してください。 常にパラメーターを使用してJavaを起動することにより、これを保証できます。
-Djava.security.manager -Djava.security.policy=/path/to/sample.policy

9. XML署名

XML署名は、*データの保護に役立ち、データの整合性を提供します*。 W3Cは、XML署名のガバナンスに関する推奨事項を提供します。 XML署名を使用して、バイナリデータなど、あらゆるタイプのデータを保護できます。

9.1. JavaのXML署名

Java APIは、推奨ガイドラインに従ってhttps://docs.oracle.com/javase/9​​/security/xml-digital-signature1.htm[XML署名の生成と検証]をサポートしています。 Java XMLデジタル署名APIは、パッケージ「_java.xml.crypto_」にカプセル化されています。
署名自体は単なるXMLドキュメントです。 XML署名には次の3つのタイプがあります。
  • 分離:このタイプの署名は、外部のデータに適用されます
    Signature要素

  • エンベロープ:このタイプの署名は、内部のデータに適用されます
    Signature要素へ

  • エンベロープ:このタイプの署名は、
    署名要素自体

    確かに、Javaは上記のすべてのタイプのXML署名の作成と検証をサポートしています。

9.2. XML署名の作成

次に、袖をまくり、データのXML署名を生成します。 たとえば、ネットワーク経由でXMLドキュメントを送信しようとしている場合があります。 したがって、*受信者がその整合性を検証できるようにする必要があります*。
それでは、私たちはJavaでこれを実現する方法を見てみましょう:
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);

Document document = documentBuilderFactory
  .newDocumentBuilder().parse(new FileInputStream("data.xml"));

DOMSignContext domSignContext = new DOMSignContext(
  keyEntry.getPrivateKey(), document.getDocumentElement());

XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
xmlSignature.sign(domSignContext);
明確にするために、ファイル_“ data.xml”にあるデータのXML署名を生成しています。
  • まず、_XMLSignatureFactory_はXMLを生成するためのファクトリクラスです
    署名

  • _XMLSigntaure_が計算する_SignedInfo_オブジェクトが必要です
    署名

  • _XMLSigntaure_には、署名をカプセル化する_KeyInfo_も必要です。
    鍵と証明書

  • 最後に、_XMLSignature_は秘密鍵を使用してドキュメントに署名します
    _DOMSignContext_としてカプセル化

    その結果、* XMLドキュメントにはSignature要素が含まれるようになりました*。これを使用して整合性を検証できます。

10. コアJavaを超えるセキュリティ

これまで見てきたように、Javaプラットフォームは安全なアプリケーションを作成するために必要な多くの機能を提供します。 ただし、これらは非常に低レベルであり、たとえばWeb上の標準のセキュリティメカニズムに直接適用できない場合があります。
たとえば、システムで作業する場合、* OAuth RFCをすべて読んで自分で実装する必要は通常ありません*。 多くの場合、セキュリティを実現するためのより高速で高レベルの方法が必要です。 これが、アプリケーションフレームワークが登場する場所です。これらは、はるかに少ない定型コードで目標を達成するのに役立ちます。
そして、Javaプラットフォームでは、*一般的にはSpring Security *を意味します。 フレームワークはSpringエコシステムの一部ですが、実際には純粋なSpringアプリケーションの外部で使用できます。
簡単に言えば、認証、承認、およびその他のセキュリティ機能をシンプルで宣言的な高レベルの方法で実現するのに役立ちます。
もちろん、Spring Securityは、https://www.baeldung.com/security-spring [一連のチュートリアル]、およびガイド付きのリンク:/ learn-spring-security-course [ Spring Securityコースを学ぶ]。

11. 結論

つまり、このチュートリアルでは、Javaのセキュリティの高レベルアーキテクチャについて説明しました。 また、標準の暗号化サービスのいくつかの実装をJavaが提供する方法を理解しました。
また、認証やアクセス制御などの分野で拡張可能でプラグ可能なセキュリティを実現するために適用できる一般的なパターンもいくつか見ました。
要約すると、これはJavaのセキュリティ機能を簡単に紹介するだけです。 したがって、このチュートリアルで説明する各領域は、さらに調査する価値があります。 しかし、うまくいけば、この方向で始めるのに十分な洞察が必要です!