[
https://issues.apache.org/jira/browse/CASSANDRA-21755?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Brad Schoening updated CASSANDRA-21755:
---------------------------------------
Description:
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]
was:
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
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]
> 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: 3.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]