JavaSASLの概要

Javaトップ

Spring5とSpringBoot2の基礎に焦点を当てた新しいLearnSpringコースを発表しました。

>>コースをチェックしてください

1。概要

このチュートリアルでは、Simple Authentication and Security Layer(SASL)の基本について説明します。Javaが通信を保護するためのSASLの採用をどのようにサポートしているかを理解します。

このプロセスでは、単純なクライアントとサーバーの通信を使用して、SASLで保護します。

2. SASLとは何ですか?

SASLは、インターネットプロトコルの認証とデータセキュリティのためのフレームワークです。これは、インターネットプロトコルを特定の認証メカニズムから切り離すことを目的としています。進むにつれて、この定義の一部をよりよく理解できるようになります。

通信におけるセキュリティの必要性は暗黙のうちにあります。クライアントとサーバーの通信のコンテキストでこれ理解してみましょう。通常、クライアントとサーバーはネットワークを介してデータを交換します。両者がお互いを信頼し、安全にデータを送信できることが不可欠です。

2.1。SASLはどこに適合しますか?

アプリケーションでは、SMTPを使用して電子メールを送信し、LDAPを使用してディレクトリサービスにアクセスする場合があります。ただし、これらの各プロトコルは、Digest-MD5やKerberosなどの別の認証メカニズムをサポートしている場合があります。

プロトコルが認証メカニズムをより宣言的に交換する方法があった場合はどうなりますか?これがまさにSASLの出番です。SASLをサポートするプロトコルは、常にSASLメカニズムのいずれかをサポートできます。

したがって、アプリケーションは適切なメカニズムネゴシエートし、認証と安全な通信のためにそれを採用できます。

2.2。SASLはどのように機能しますか?

SASLがセキュリティの全体的なスキームのどこに適合するかを見てきたので、それがどのように機能するかを理解しましょう。

SASLはチャレンジ/レスポンスフレームワークです。ここで、サーバーはクライアントにチャレンジを発行し、クライアントはチャレンジに基づいて応答を送信します。チャレンジとレスポンスは任意の長さのバイト配列であるため、メカニズム固有のデータを運ぶことができます。

この交換は複数の反復で継続でき、サーバーがそれ以上のチャレンジを発行しなくなったときに最終的に終了します。

さらに、クライアントとサーバーは、認証後にセキュリティレイヤーをネゴシエートできます。その後のすべての通信では、このセキュリティレイヤーを活用できます。ただし、一部のメカニズムは認証のみをサポートする場合があることに注意してください。

ここで重要なのは、 SASLはチャレンジデータとレスポンスデータを交換するためのフレームワークのみを提供するということです。データ自体やデータの交換方法については何も言及されていません。これらの詳細は、SASLの使用を採用するアプリケーションに残されています。

3.JavaでのSASLサポート

Javaには、SASLを使用したクライアント側とサーバー側の両方のアプリケーションの開発サポートするAPIがあります。APIは、実際のメカニズム自体には依存しません。Java SASL APIを使用するアプリケーションは、必要なセキュリティ機能に基づいてメカニズムを選択できます。

3.1。Java SASL API

パッケージ「javax.security.sasl」の一部として注目すべき主要なインターフェースは、SaslServerSaslClientです

SaslServerは、SASLのサーバー側メカニズムを表します。

SaslServerをインスタンス化する方法を見てみましょう。

SaslServer ss = Sasl.createSaslServer( mechanism, protocol, serverName, props, callbackHandler);

SaslServerをインスタンス化するためにファクトリクラスSaslを使用していますcreateSaslServerメソッドは、いくつかのパラメーターを受け入れます。

  • メカニズム–SASLでサポートされているメカニズムのIANA登録名
  • プロトコル–認証が行われているプロトコルの名前
  • serverName –サーバーの完全修飾ホスト名
  • 小道具–認証交換を構成するために使用される一連のプロパティ
  • callbackHandler –選択したメカニズムが詳細情報を取得するために使用するコールバックハンドラー

上記のうち、最初の2つのみが必須であり、残りはnull許容です。

SaslClientは、SASLのクライアント側メカニズムを表します。SaslClientをインスタンス化する方法を見てみましょう。

SaslClient sc = Sasl.createSaslClient( mechanisms, authorizationId, protocol, serverName, props, callbackHandler);

ここでも、ファクトリクラスSaslを使用してSaslClientをインスタンス化しています。createSaslClientが受け入れるパラメーターのリストは、以前とほとんど同じです。

ただし、いくつかの微妙な違いがあります。

  • メカニズム–ここでは、これは試してみるメカニズムのリストです
  • authenticationId –これは承認に使用されるプロトコル依存のIDです

残りのパラメーターは、意味とオプション性が似ています。

3.2。JavaSASLセキュリティプロバイダー

Java SASL APIの下には、セキュリティ機能を提供する実際のメカニズムがあります。これらのメカニズム実装は、Java Cryptography Architecture(JCA)に登録されているセキュリティプロバイダーによって提供されます

JCAに登録されているセキュリティプロバイダーは複数存在する可能性があります。これらそれぞれ、1つ以上のSASLメカニズムをサポートする場合があります。

Javaには、セキュリティプロバイダーとしてSunSASLが付属しており、デフォルトでJCAプロバイダーとして登録されます。ただし、これは削除されるか、他の利用可能なプロバイダーに再注文される場合があります。

さらに、カスタムセキュリティプロバイダーを提供することは常に可能です。これには、インターフェースSaslClientSaslServerを実装する必要があります。そうすることで、カスタムセキュリティメカニズムも実装する可能性があります。

4.例によるSASL

SaslServerSaslClientの作成方法を確認したので、次はそれらの使用方法を理解します。クライアントとサーバーのコンポーネントを開発します。これらは、認証を達成するためにチャレンジとレスポンスを繰り返し交換します。ここでは、簡単な例でDIGEST-MD5メカニズムを利用します。

4.1。クライアントとサーバーのCallbackHandler

前に見たように、CallbackHandlerの実装をSaslServerSaslClientに提供する必要があります。現在、CallbackHandlerは、単一のメソッド(handle)を定義する単純なインターフェースです。このメソッドは、コールバックの配列を受け入れます。

ここで、コールバックは、セキュリティメカニズムが呼び出し元のアプリケーションから認証データを収集する方法を示します。たとえば、セキュリティメカニズムでは、ユーザー名とパスワードが必要になる場合があります。NameCallbackPasswordCallbackなどの使用可能なコールバック実装がかなりあります。

Let's see how we can define a CallbackHandler for the server, to begin with:

public class ServerCallbackHandler implements CallbackHandler { @Override public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException { for (Callback cb : cbs) { if (cb instanceof AuthorizeCallback) { AuthorizeCallback ac = (AuthorizeCallback) cb; //Perform application-specific authorization action ac.setAuthorized(true); } else if (cb instanceof NameCallback) { NameCallback nc = (NameCallback) cb; //Collect username in application-specific manner nc.setName("username"); } else if (cb instanceof PasswordCallback) { PasswordCallback pc = (PasswordCallback) cb; //Collect password in application-specific manner pc.setPassword("password".toCharArray()); } else if (cb instanceof RealmCallback) { RealmCallback rc = (RealmCallback) cb; //Collect realm data in application-specific manner rc.setText("myServer"); } } } }

Now, let's see our client-side of the Callbackhandler:

public class ClientCallbackHandler implements CallbackHandler { @Override public void handle(Callback[] cbs) throws IOException, UnsupportedCallbackException { for (Callback cb : cbs) { if (cb instanceof NameCallback) { NameCallback nc = (NameCallback) cb; //Collect username in application-specific manner nc.setName("username"); } else if (cb instanceof PasswordCallback) { PasswordCallback pc = (PasswordCallback) cb; //Collect password in application-specific manner pc.setPassword("password".toCharArray()); } else if (cb instanceof RealmCallback) { RealmCallback rc = (RealmCallback) cb; //Collect realm data in application-specific manner rc.setText("myServer"); } } } }

To clarify, we're looping through the Callback array and handling only specific ones. The ones that we have to handle is specific to the mechanism in use, which is DIGEST-MD5 here.

4.2. SASL Authentication

So, we've written our client and server CallbackHandler. We've also instantiated SaslClient and SaslServer for DIGEST-MD5 mechanism.

Now is the time to see them in action:

@Test public void givenHandlers_whenStarted_thenAutenticationWorks() throws SaslException { byte[] challenge; byte[] response; challenge = saslServer.evaluateResponse(new byte[0]); response = saslClient.evaluateChallenge(challenge); challenge = saslServer.evaluateResponse(response); response = saslClient.evaluateChallenge(challenge); assertTrue(saslServer.isComplete()); assertTrue(saslClient.isComplete()); }

Let's try to understand what is happening here:

  • First, our client gets the default challenge from the server
  • The client then evaluates the challenge and prepares a response
  • This challenge-response exchange continues for one more cycle
  • In the process, the client and server make use of callback handlers to collect any additional data as needed by the mechanism
  • This concludes our authentication here, but in reality, it can iterate over multiple cycles

A typical exchange of challenge and response byte arrays happens over the network. But, here for simplicity, we've assumed local communication.

4.3. SASL Secure Communication

As we discussed earlier, SASL is a framework capable of supporting secure communication beyond just authentication. However, this is only possible if the underlying mechanism supports it.

Firstly, let's first check if we have been able to negotiate a secure communication:

String qop = (String) saslClient.getNegotiatedProperty(Sasl.QOP); assertEquals("auth-conf", qop);

Here, QOP stands for the quality of protection. This is something that the client and server negotiate during authentication. A value of “auth-int” indicates authentication and integrity. While, a value of “auth-conf” indicates authentication, integrity, and confidentiality.

Once we have a security layer, we can leverage that to secure our communication.

Let's see how we can secure outgoing communication in the client:

byte[] outgoing = "Baeldung".getBytes(); byte[] secureOutgoing = saslClient.wrap(outgoing, 0, outgoing.length); // Send secureOutgoing to the server over the network

And, similarly, the server can process incoming communication:

// Receive secureIncoming from the client over the network byte[] incoming = saslServer.unwrap(secureIncoming, 0, netIn.length); assertEquals("Baeldung", new String(incoming, StandardCharsets.UTF_8));

5. SASL in the Real World

So, we now have a fair understanding of what SASL is and how to use it in Java. But, typically, that's not what we'll end up using SASL for, at least in our daily routine.

As we saw earlier, SASL is primarily meant for protocols like LDAP and SMTP. Although, more and more applications and coming on board with SASL — for instance, Kafka. So, how do we use SASL to authenticate with such services?

Let's suppose we've configured Kafka Broker for SASL with PLAIN as the mechanism of choice. PLAIN simply means that it authenticates using a combination of username and password in plain text.

Let's now see how can we configure a Java client to use SASL/PLAIN to authenticate against the Kafka Broker.

We begin by providing a simple JAAS configuration, “kafka_jaas.conf”:

KafkaClient { org.apache.kafka.common.security.plain.PlainLoginModule required username="username" password="password"; };

We make use of this JAAS configuration while starting the JVM:

-Djava.security.auth.login.config=kafka_jaas.conf

Finally, we have to add a few properties to pass to our producer and consumer instances:

security.protocol=SASL_SSL sasl.mechanism=PLAIN

That's all there is to it. This is just a small part of Kafka client configurations, though. Apart from PLAIN, Kafka also supports GSSAPI/Kerberos for authentication.

6. SASL in Comparision

Although SASL is quite effective in providing a mechanism-neutral way of authenticating and securing client and server communication. However, SASL is not the only solution available in this regard.

Java itself provides other mechanisms to achieve this objective. We'll briefly discuss them and understand how they fare against SASL:

  • Java Secure Socket Extension (JSSE): JSSE is a set of packages in Java that implements Secure Sockets Layer (SSL) for Java. It provides data encryption, client and server authentication, and message integrity. Unlike SASL, JSSE relies on a Public Key Infrastructure (PKI) to work. Hence, SASL works out to be more flexible and lightweight than JSSE.
  • Java GSS API (JGSS): JGGS is the Java language binding for Generic Security Service Application Programming Interface (GSS-API). GSS-API is an IETF standard for applications to access security services. In Java, under GSS-API, Kerberos is the only mechanism supported. Kerberos again requires a Kerberised infrastructure to work. Compared to SASL, here yet, choices are limited and heavyweight.

全体として、SASLは非常に軽量なフレームワークであり、プラグ可能なメカニズムを通じてさまざまなセキュリティ機能を提供します。SASLを採用するアプリケーションには、必要に応じて、適切なセキュリティ機能のセットを実装するための多くの選択肢があります。

7.結論

要約すると、このチュートリアルでは、認証と安全な通信を提供するSASLフレームワークの基本を理解しました。また、SASLのクライアント側とサーバー側を実装するためにJavaで使用できるAPIについても説明しました。

JCAプロバイダーを介してセキュリティメカニズムを使用する方法を見ました。最後に、さまざまなプロトコルやアプリケーションでの作業におけるSASLの使用法についても説明しました。

いつものように、コードはGitHubにあります。

Javaの底

Spring5とSpringBoot2の基礎に焦点を当てた新しいLearnSpringコースを発表しました。

>>コースをチェックしてください