Apache Camel の KeycloakSecurityPolicy は、JWT トークンの iss (issuer) クレームを設定されたレルムに対して検証しません。つまり、ある Keycloak レルムから発行されたトークンが、まったく別のレルム用に設定されたポリシーによって暗黙に受け入れられ、テナントの分離が壊れます。
影響を受けるバージョン: 4.15.0, 4.16.0, 4.17.0
追跡先: https://issues.apache.org/jira/browse/CAMEL-22854
KeycloakSecurityHelper.parseAccessToken() では、公開鍵が明示的に提供されていない場合 (デフォルト設定)、トークンは Base64 からデコードされるだけで、検証されることはありません:
public static AccessToken parseAccessToken(String tokenString, PublicKey publicKey)
throws VerificationException {
if (publicKey != null) {
return TokenVerifier.create(tokenString, AccessToken.class)
.publicKey(publicKey)
.verify()
.getToken();
} else {
// no signature verification, no issuer check
return TokenVerifier.create(tokenString, AccessToken.class).getToken();
}
}
デフォルトのコードパスは else 分岐に入るため、次の 3 つの項目がチェックされません:
iss クレームが期待される {serverUrl}/realms/{realm} と比較されないロールチェックはトークンペイロード内のロール名のみを参照するため、依然として通過します。ロール名 (tenant-user) がレルム間で一致する場合 (マルチテナント構成ではよくあることです)、リクエストはそのまま通ってしまいます。
各テナントが個別の Keycloak レルムに対応するマルチテナントアプリケーションでは、テナント A のユーザーがテナント B 用に保護されたルートにアクセスできます。具体的には次のとおりです:
このプロジェクトは、Apache Camel 4.17.0 とローカルの Keycloak インスタンスを使用して、この脆弱性を実証します。
jbang app install camel@apache/camel)camel infra が内部的に使用)ローカルの Keycloak を起動します:
camel infra run keycloak
これにより、管理資格情報 admin/admin を使用して Keycloak が localhost:8080 で起動します。
mvn verify
統合テスト (CrossRealmTokenBypassIT) は次のことを行います:
acme と globex の 2 つのレルムを作成しますtenant-user レルムロールを作成しますacme レルムにユーザー alice (パスワード alice123) を作成し、彼女に tenant-user ロールを割り当てますglobex レルムにバインドされた KeycloakSecurityPolicy によって保護された Camel ルート (direct:globex-protected) を設定しますacme レルムから alice の JWT トークンを取得します (発行者: http://localhost:8080/realms/acme)リクエストは成功します。acme トークンは、エラーなしで globex ポリシーを通過します。
| テスト | 結果 | 意味 |
|---|---|---|
testAcmeTokenIsObtainable | PASS | 健全性チェック -- トークン取得が機能する |
パッチ適用済みバージョン (4.18.0+) では、2 番目のテストは失敗し、3 番目のテストは成功します。
camel infra stop keycloak
テストは @AfterAll で acme および globex レルムも削除します。
KeycloakSecurityPolicy は、iss クレームが {serverUrl}/realms/{realm} と一致しないトークンを拒否する必要があります。修正は CAMEL-22854 で追跡されており、Camel 4.18.0 (次の LTS リリース) で提供されます。
testCrossRealmTokenAccepted | PASS | 脆弱性が存在することを確認する |
testCrossRealmTokenShouldBeRejected | FAIL | 正しい動作を示す -- 4.17.0 では例外がスローされない |