R0CKing666 opened a new issue, #11178:
URL: https://github.com/apache/rocketmq/issues/11178
### Runtime platform environment
- OS: Linux (reproduced in a Docker container)
- RocketMQ: branch `develop`, version `5.5.1`, commit `80e1ae557` (also
still present in the latest upstream `develop`)
### JDK Version
- Compiler: JDK 1.8
### Describe the Bug
In the Remoting (TCP) authorization path, the authorization subject is taken
directly from the client-supplied `AccessKey` in the request extFields, without
any signature verification:
```java
// DefaultAuthorizationContextBuilder#build(ChannelHandlerContext,
RemotingCommand)
Subject subject = null;
if (fields.containsKey(SessionCredentials.ACCESS_KEY)) {
subject = User.of(fields.get(SessionCredentials.ACCESS_KEY)); //
client-controlled, unverified
}
```
`authorizationEnabled` and `authenticationEnabled` are independent switches
with no cross-validation. With `authorizationEnabled=true` and
`authenticationEnabled=false`, the `AuthenticationPipeline` returns early and
does nothing, while the `AuthorizationPipeline` still derives the caller
identity from the raw `AccessKey`. An attacker who knows any user's AccessKey
(e.g. the SUPER user) can impersonate them — publish, consume, delete topics,
etc. — without providing a SecretKey/signature.
The gRPC path is not affected: it clears the client-supplied
`AUTHORIZATION_AK` and only re-injects the verified identity after successful
authentication.
### Steps to Reproduce
1. Start a broker with `authorizationEnabled=true` and
`authenticationEnabled=false`, and a SUPER user with a known AccessKey (e.g.
`rocketmq2`) present in the auth metadata.
2. Send a `SEND_MESSAGE` Remoting request whose extFields contain
`AccessKey=rocketmq2` but no `Signature`.
3. Observe that the request is authorized and processed.
A minimal JUnit reproduction that exercises the exact broker authorization
path (`DefaultAuthorizationContextBuilder` + `AuthorizationEvaluator` +
`UserAuthorizationHandler`) is included in the accompanying PR. Its three tests
confirm: the forged identity is authorized, an unknown AccessKey is denied, and
enabling authentication rejects the unsigned request.
### What Did You Expect to See?
With authorization enabled but authentication disabled, the broker should
either refuse to start (fail-closed), or treat the caller as unauthenticated
and deny the request.
### What Did You See Instead?
The forged `AccessKey` is accepted as an authenticated SUPER identity and
the request passes authorization.
### Additional Context
Suggested fix (fail-closed): refuse to start when
`authorizationEnabled=true` and `authenticationEnabled=false`, mirroring the
existing fail-closed guards in `ProxyAdminAuthInterceptor` for the gRPC admin
surface. The accompanying PR adds this startup validation plus a unit test.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]