[
https://issues.apache.org/jira/browse/CASSANDRA-21755?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18134215#comment-18134215
]
Brad Schoening commented on CASSANDRA-21755:
--------------------------------------------
Being able to set limits via system properties is useful, but it only protects
operators who already know about the issue. Since this input arrives before
authentication, I think the default should be bounded.
The [native protocol
spec|https://cassandra.apache.org/doc/6.0-alpha2/cassandra/reference/native-protocol.html#s4.1.1]
defines five STARTUP options:
* {{{}CQL_VERSION{}}}: the CQL version, currently “3.0.0”
* {{{}COMPRESSION{}}}: the frame compression algorithm, “lz4” or “snappy”
* {{{}DRIVER_NAME{}}}: a free-form label for the driver, shown in {{nodetool
clientstats}}
* {{{}DRIVER_VERSION{}}}: a free-form label for the driver version, shown in
{{nodetool clientstats}}
* {{{}THROW_ON_OVERLOAD{}}}: a one-character flag
All of these are short by nature. Shouldn't Cassandra apply limits by default
for unauthenticated input?
The defaults can be generous. They just need to be finite. Values like 64 keys
/ 256-byte keys / 1 KiB values are orders of magnitude above anything a real
driver sends, still allow the extra keys drivers, and reduce the pre-auth
exposure from 16 MiB to roughly 64 KiB per connection.
> NTR STARTUP options are retained and exposed (system_views.clients, nodetool
> clientstats, JMX) before authentication, with no sanitization or size limits
> ---------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CASSANDRA-21755
> URL: https://issues.apache.org/jira/browse/CASSANDRA-21755
> Project: Apache Cassandra
> Issue Type: Bug
> Components: Observability/JMX
> Reporter: Brad Schoening
> Assignee: Rishabh Saraswat
> Priority: Normal
> Time Spent: 4.5h
> Remaining Estimate: 0h
>
> The native protocol STARTUP message carries a {{[string map]}} of options.
> The server
> accepts and retains the entire map up to {{native_transport_max_frame_size}}
> (16 MB by default)— including keys it does not recognize — and exposes it to
> operators via {{system_views.clients}} ({{{}client_options{}}}), {{{}nodetool
> clientstats{}}}, and
> the JMX client metrics.
> This happens {*}before authentication{*}. The connection is registered in the
> connection tracker when STARTUP is processed (via the {{Connection}}
> constructor →
> {{{}ConnectionTracker.addConnection{}}}), and {{StartupMessage.execute()}}
> calls
> {{ClientState.setClientOptions(options)}} before the authentication challenge
> is issued. As a result, an unauthenticated client controls data that appears
> in operator-facing views for as long as it keeps the socket open, whether or
> not it ever presents valid credentials.
> The retained values are also neither sanitized nor bounded:
> * Strings are decoded as UTF-8 but are otherwise unconstrained — control
> characters,
> newlines, and terminal escape sequences are all accepted.
> * {{ConnectedClient.asMap()}} (which feeds {{nodetool clientstats}} and JMX)
> joins the entries as {{k=v, k=v}} with no escaping, so a value containing
> {{", foo=bar"}} is
> indistinguishable from a separate option in that output.
> * There is no limit on key/value length, on the number of entries, or on
> duplicate keys,
> beyond the overall {{native_transport_max_frame_size}} (16 MB by default).
> h3. Steps to reproduce
> # Open a native protocol connection and send a STARTUP message with a
> populated options map
> (optionally including a non-printable character or a {{", k=v"}} fragment in
> a value).
> # Do *not* complete authentication — leave the connection open at the
> authenticating stage.
> # Observe the connection in operator views.
> {noformat}
> % nodetool clientstats --all
> Address SSL Cipher Protocol Version User Keyspace
> Requests Driver-Name Driver-Version
> /127.0.0.1:51690 false undefined undefined 3 anonymous 1
> undefined undefined
> {noformat}
> The same connection appears in {{system_views.clients}} with its
> {{client_options}}
> populated and {{connection_stage}} = {{{}authenticating{}}}.
> h3. Expected behaviour
> Client-supplied STARTUP options should be constrained before being
> retained/displayed, and skip display of un-authenticed clients or,
> alternatively, option paths should not be able to carry control characters or
> forge delimiter structure.
> h3. Proposed hardening
> Aggressively sanitize and limit size of options since these are sent before
> authentication.
> Deferring {{setClientOptions()}} (and option retention generally) until after
> successful
> authentication would additionally remove the unauthenticated-exposure aspect.
> For one approach, see the Postgres
> [pg_clean_ascii()|https://github.com/ryogrid/create_pg_super_document/blob/master/generated_docs/p/pg_clean_ascii.md]
> which sanitizes startup options for display with
> [pg_stat_activity()|https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ACTIVITY-VIEW]
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]