記事ディレクトリ
0. 序文
背景: 同社のプロジェクトは、Spring-Kafka でワイルドカード パターン マッチングを使用してセキュリティ バイパスの脆弱性 CVE-2023-20873 をスキャンしました。
抜け穴
中程度のリスク | 2023 年 8 月 23 日 | CVE-2023-34040
Apache Kafka 3.0.9 以前および 2.9.10 以前の Spring では、非シリアル化攻撃ベクトルの可能性がありましたが、これは一般的ではない構成が適用された場合に限られていました。攻撃者は、逆シリアル化例外レコード ヘッダー内に悪意のあるシリアル化オブジェクトを構築する必要があります。
春のカフカ入門
Spring Kafka は Spring フレームワークによって提供されるライブラリであり、Apache Kafka を使用する便利な方法を提供します。Apache Kafka は、オープン ソースのストリーム処理プラットフォームであり、主にリアルタイム データ ストリーム パイプラインとアプリケーションの構築に使用されます。Spring Kafka は、抽象化とカプセル化のアプローチを提供することにより、開発者が Spring フレームワークで Apache Kafka を簡単に使用できるようにします。これにより、Spring フレームワークで Apache Kafka を使用する複雑さが大幅に簡素化され、開発者はビジネス ロジックの開発にさらに集中できるようになります。
簡素化された Kafka プロデューサーとコンシューマー構成: Spring Kafka は、Kafka プロデューサーとコンシューマーを構成する簡単な方法を提供します。Spring Boot との統合が提供され、構成が容易になります。
例外処理: Spring Kafka は、メッセージの送信失敗やメッセージ形式エラーなどの例外を含め、使用中にプロデューサーとコンシューマーが遭遇する例外を処理するための一連のメカニズムを提供します。
メッセージ変換: Spring Kafka は、お気に入りのデータ形式 (JSON、Avro など) を使用して Kafka メッセージを送受信できるように、Kafka メッセージを変換する一連のメカニズムを提供します。
トランザクションのサポート: Spring Kafka は Kafka トランザクションのサポートを提供し、1 つのトランザクションで複数の Kafka メッセージを送信できるようにします。
コールバックを使用したメッセージ送信: Spring Kafka は、さらなる処理のためにメッセージが送信された後に送信結果のコールバックを取得するメソッドを提供します。
1. 参考資料
CVE公式サイトhttps://www.cve.org/CVERecord?id=CVE-2023-34040
Spring公式サイトhttps://spring.io/security/cve-2023-34040
2. 基本的な紹介
CVE-2023-34040: 不適切に構成された場合の Spring-Kafka の Java 逆シリアル化の脆弱性 中リスク
| 2023 年 8 月 23 日 | CVE-2023-34040 は、Apache Kafka 3.0.9 以前および 2.9.10 以前の Spring で
説明されています。
デシリアライゼーション攻撃ベクトルの可能性がありますが、これは珍しい構成が適用された場合に限ります。攻撃者は、逆シリアル化例外レコード ヘッダー内に悪意のあるシリアル化オブジェクトを構築する必要があります。
具体的には、次の条件がすべて満たされると、アプリケーションは脆弱になります。
ユーザーは、レコードのキーおよび/または値に対して ErrorHandlingDeserializer を構成しませんでした
。 ユーザーは、コンテナー プロパティ checkDeserExWhenKeyNull および/または checkDeserExWhenValueNull を true に明示的に設定しました。
ユーザーは、信頼できないソースによる Kafka トピックへのパブリッシュを許可します。
デフォルトでは、これらのプロパティは false であり、コンテナーは、ErrorHandlingDeserializer が構成されている場合にのみこれらのヘッダーを逆シリアル化しようとします。ErrorHandlingDeserializer は、レコードを処理する前にそのような悪意のあるヘッダーをすべて削除することで、この脆弱性の発生を防ぎます。
影響を受ける Spring 製品とバージョン
Spring for Apache Kafka
2.8.1 ~ 2.9.10
3.0.0 ~ 3.0.9
3. 解決策
3.1. バージョンアップ
- 2.8.x および 2.9.x のユーザーは 2.9.11 にアップグレードする必要があります。
- 3.0.x ユーザーは 3.0.10 にアップグレードする必要があります。
- この問題を修正したバージョンには次のものがあります。
Spring for Apache Kafka
3.0.10
2.9.11 Spring boot 3.0.10 (またはそれ以降) の依存関係管理では、Spring for Apache Kafka 3.0.10 (またはそれ以降) が自動的に使用されます。Spring Boot 2.7.x ユーザーは、Boot の Spring for Apache Kafka 2.8.x 依存関係管理バージョンを 2.9.11 (またはそれ以降) にオーバーライドする必要があります。
3.2. 代替案
ErrorHandlingDeserializers を使用しない場合は、コンテナー プロパティ checkDeserExWhenKeyNull または checkDeserExWhenValueNull を設定しないか、ErrorHandlingDeserializers を使用してください。
4. Spring Kafka の使用チュートリアルのコード例
pom.xml
Spring Kafka の依存関係をファイルに追加します。
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
application.properties ファイルで Kafka 構成を設定します。
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup
spring.kafka.template.default-topic=myTopic
メッセージプロデューサーを作成します。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
@Service
public class KafkaProducer {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String message) {
kafkaTemplate.sendDefault(message);
}
}
メッセージ コンシューマを作成します。
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;
@Service
public class KafkaConsumer {
@KafkaListener(topics = "myTopic", groupId = "myGroup")
public void listen(String message) {
System.out.println("Received message: " + message);
}
}
メッセージの送受信は、単純な REST API を作成することでテストできます。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/kafka")
public class KafkaController {
@Autowired
private KafkaProducer producer;
@PostMapping(value = "/publish")
public void sendMessageToKafka(@RequestBody String message) {
this.producer.sendMessage(message);
}
}
この API は POST リクエストを受け取り、リクエスト本文のメッセージを Kafka に送信します。