Skip to content

Commit

Permalink
API for Unified Header Validators (envoyproxy#21172)
Browse files Browse the repository at this point in the history
API for Unified Header Validators

Signed-off-by: Yan Avlasov <[email protected]>
  • Loading branch information
yanavlasov authored May 25, 2022
1 parent dc07116 commit e569ce0
Show file tree
Hide file tree
Showing 23 changed files with 692 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp
/*/extensions/filters/http/ip_tagging @rgs1 @alyssawilk
# cors
/*/extensions/filters/http/cors @wbpcode @daixiang0
# Header Validators
/*/extensions/http/header_validators/envoy_default @yanavlasov @alyssawilk

# Intentionally exempt (treated as core code)
/*/extensions/filters/common @UNOWNED @UNOWNED
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ proto_library(
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/http/header_formatters/preserve_case/v3:pkg",
"//envoy/extensions/http/header_validators/envoy_default/v3:pkg",
"//envoy/extensions/http/original_ip_detection/custom_header/v3:pkg",
"//envoy/extensions/http/original_ip_detection/xff/v3:pkg",
"//envoy/extensions/http/stateful_session/cookie/v3:pkg",
Expand Down
3 changes: 3 additions & 0 deletions api/envoy/config/core/v3/protocol.proto
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ message Http1ProtocolOptions {
// .. attention::
// Enabling this option might lead to request smuggling vulnerability, especially if traffic
// is proxied via multiple layers of proxies.
// [#comment:TODO: This field is ignored when the
// :ref:`header validation configuration <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.typed_header_validation_config>`
// is present.]
bool allow_chunked_length = 6;

// Allows invalid HTTP messaging. When this option is false, then Envoy will terminate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// HTTP connection manager :ref:`configuration overview <config_http_conn_man>`.
// [#extension: envoy.filters.network.http_connection_manager]

// [#next-free-field: 50]
// [#next-free-field: 51]
message HttpConnectionManager {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager";
Expand Down Expand Up @@ -403,6 +403,10 @@ message HttpConnectionManager {
[(udpa.annotations.security).configure_for_untrusted_downstream = true];

// Additional HTTP/1 settings that are passed to the HTTP/1 codec.
// [#comment:TODO: The following fields are ignored when the
// :ref:`header validation configuration <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.typed_header_validation_config>`
// is present:
// 1. :ref:`allow_chunked_length <envoy_v3_api_field_config.core.v3.Http1ProtocolOptions.allow_chunked_length>`]
config.core.v3.Http1ProtocolOptions http_protocol_options = 8;

// Additional HTTP/2 settings that are passed directly to the HTTP/2 codec.
Expand Down Expand Up @@ -660,20 +664,29 @@ message HttpConnectionManager {
// for details of normalization.
// Note that Envoy does not perform
// `case normalization <https://tools.ietf.org/html/rfc3986#section-6.2.2.1>`_
// [#comment:TODO: This field is ignored when the
// :ref:`header validation configuration <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.typed_header_validation_config>`
// is present.]
google.protobuf.BoolValue normalize_path = 30;

// Determines if adjacent slashes in the path are merged into one before any processing of
// requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without
// setting this option, incoming requests with path `//dir///file` will not match against route
// with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of
// `HTTP spec <https://tools.ietf.org/html/rfc3986>`_ and is provided for convenience.
// [#comment:TODO: This field is ignored when the
// :ref:`header validation configuration <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.typed_header_validation_config>`
// is present.]
bool merge_slashes = 33;

// Action to take when request URL path contains escaped slash sequences (%2F, %2f, %5C and %5c).
// The default value can be overridden by the :ref:`http_connection_manager.path_with_escaped_slashes_action<config_http_conn_man_runtime_path_with_escaped_slashes_action>`
// runtime variable.
// The :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling<config_http_conn_man_runtime_path_with_escaped_slashes_action_enabled>` runtime
// variable can be used to apply the action to a portion of all requests.
// [#comment:TODO: This field is ignored when the
// :ref:`header validation configuration <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.typed_header_validation_config>`
// is present.]
PathWithEscapedSlashesAction path_with_escaped_slashes_action = 45;

// The configuration of the request ID extension. This includes operations such as
Expand Down Expand Up @@ -765,6 +778,30 @@ message HttpConnectionManager {
// If this config is set, the Proxy-Status HTTP response header field is
// populated. By default, it is not.
ProxyStatusConfig proxy_status_config = 49;

// Configuration options for Header Validation (UHV).
// UHV is an extensible mechanism for checking validity of HTTP requests as well as providing
// normalization for request attributes, such as URI path.
// If the typed_header_validation_config is present it overrides the following options:
// ``normalize_path``, ``merge_slashes``, ``path_with_escaped_slashes_action``
// ``http_protocol_options.allow_chunked_length``.
//
// The default UHV checks the following:
//
// #. HTTP/1 header map validity according to `RFC 7230 section 3.2<https://datatracker.ietf.org/doc/html/rfc7230#section-3.2>`_
// #. Syntax of HTTP/1 request target URI and response status
// #. HTTP/2 header map validity according to `RFC 7540 section 8.1.2<https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2`_
// #. Syntax of HTTP/2 pseudo headers
// #. HTTP/3 header map validity according to `draft standard <https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34>`_
// #. Syntax of HTTP/3 pseudo headers
// #. Syntax of ``Content-Length`` and ``Transfer-Encoding``
// #. Validation of HTTP/1 requests with both ``Content-Length`` and ``Transfer-Encoding`` headers
// #. Normalization of the URI path according to `Normalization and Comparison <https://datatracker.ietf.org/doc/html/rfc3986#section-6>`_
// without `case normalization <https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1>`_
//
// [#not-implemented-hide:]
// [#extension-category: envoy.http.header_validators]
config.core.v3.TypedExtensionConfig typed_header_validation_config = 50;
}

// The configuration to customize local reply returned by Envoy.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
syntax = "proto3";

package envoy.extensions.http.header_validators.envoy_default.v3;

import "google/protobuf/wrappers.proto";

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.http.header_validators.envoy_default.v3";
option java_outer_classname = "HeaderValidatorProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/http/header_validators/envoy_default/v3;envoy_defaultv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Envoy's default Header Validator config]

// This extension validates that HTTP request and response headers are well formed according to respective RFCs.
//
// #. HTTP/1 header map validity according to `RFC 7230 section 3.2 <https://datatracker.ietf.org/doc/html/rfc7230#section-3.2>`_
// #. Syntax of HTTP/1 request target URI and response status
// #. HTTP/2 header map validity according to `RFC 7540 section 8.1.2 <https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2>`_
// #. Syntax of HTTP/2 pseudo headers
// #. HTTP/3 header map validity according to `draft standard <https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34>`_
// #. Syntax of HTTP/3 pseudo headers
// #. Syntax of Content-Length and Transfer-Encoding
// #. Validation of HTTP/1 requests with both ``Content-Length`` and ``Transfer-Encoding`` headers
// #. Normalization of the URI path according to `Normalization and Comparison <https://datatracker.ietf.org/doc/html/rfc3986#section-6>`_
// without `case normalization <https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1>`_
//
message HeaderValidatorConfig {
message UriPathNormalizationOptions {
// Determines the action for requests that contain ``%2F``, ``%2f``, ``%5C`` or ``%5c`` sequences in the URI path.
// This operation occurs before URL normalization and the merge slashes transformations if they were enabled.
enum PathWithEscapedSlashesAction {
// Default behavior specific to implementation (i.e. Envoy) of this configuration option.
// Envoy, by default, takes the ``KEEP_UNCHANGED`` action.
// NOTE: the implementation may change the default behavior at-will.
IMPLEMENTATION_SPECIFIC_DEFAULT = 0;

// Keep escaped slashes.
KEEP_UNCHANGED = 1;

// Reject client request with the 400 status. gRPC requests will be rejected with the ``INTERNAL`` (13) error code.
// The ``http#.downstream_rq_failed_path_normalization`` counter is incremented for each rejected request.
REJECT_REQUEST = 2;

// Unescape ``%2F`` and ``%5C`` sequences and redirect the request to the new path if these sequences were present.
// The redirect occurs after path normalization and merge slashes transformations if they were configured.
// NOTE: gRPC requests will be rejected with the ``INTERNAL`` (13) error code.
// This option minimizes possibility of path confusion exploits by forcing request with unescaped slashes to
// traverse all parties: downstream client, intermediate proxies, Envoy and upstream server.
// The ``http#.downstream_rq_redirected_with_normalized_path`` counter is incremented for each
// redirected request.
UNESCAPE_AND_REDIRECT = 3;

// Unescape ``%2F`` and ``%5C`` sequences.
// Note: this option should not be enabled if intermediaries perform path based access control as
// it may lead to path confusion vulnerabilities.
UNESCAPE_AND_FORWARD = 4;
}

// Should paths be normalized according to RFC 3986?
// This operation overwrites the original request URI path and the new path is used for processing of
// the request by HTTP filters and proxied to the upstream service.
// Envoy will respond with 400 to requests with malformed paths that fail path normalization.
// The default behavior is to normalize the path.
// This value may be overridden by the runtime variable
// :ref:`http_connection_manager.normalize_path<config_http_conn_man_runtime_normalize_path>`.
// See `Normalization and Comparison <https://datatracker.ietf.org/doc/html/rfc3986#section-6>`_
// for details of normalization.
// Note that Envoy does not perform
// `case normalization <https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1>`_
// URI path normalization can be applied to a portion of requests by setting the
// ``envoy_default_header_validator.path_normalization`` runtime value.
bool skip_path_normalization = 1;

// Determines if adjacent slashes in the path are merged into one.
// This operation overwrites the original request URI path and the new path is used for processing of
// the request by HTTP filters and proxied to the upstream service.
// Setting this option to true will cause incoming requests with path ``//dir///file`` to not match against
// route with ``prefix`` match set to ``/dir``. Defaults to ``false``. Note that slash merging is not part of
// `HTTP spec <https://datatracker.ietf.org/doc/html/rfc3986>`_ and is provided for convenience.
// Merging of slashes in URI path can be applied to a portion of requests by setting the
// ``envoy_default_header_validator.merge_slashes`` runtime value.
bool skip_merging_slashes = 2;

// The action to take when request URL path contains escaped slash sequences (``%2F``, ``%2f``, ``%5C`` and ``%5c``).
// This operation may overwrite the original request URI path and the new path is used for processing of
// the request by HTTP filters and proxied to the upstream service.
PathWithEscapedSlashesAction path_with_escaped_slashes_action = 3;
}

message Http1ProtocolOptions {
// Allows Envoy to process HTTP/1 requests/responses with both ``Content-Length`` and ``Transfer-Encoding``
// headers set. By default such messages are rejected, but if option is enabled - Envoy will
// remove the ``Content-Length`` header and process the message.
// See `RFC7230, sec. 3.3.3 <https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3>`_ for details.
//
// .. attention::
// Enabling this option might lead to request smuggling vulnerabilities, especially if traffic
// is proxied via multiple layers of proxies.
bool allow_chunked_length = 1;
}

Http1ProtocolOptions http1_protocol_options = 1;

// The URI path normalization options.
// By default Envoy normalizes URI path using the default values of the :ref:`UriPathNormalizationOptions
// <envoy_v3_api_msg_extensions.http.header_validators.envoy_default.v3.HeaderValidatorConfig.UriPathNormalizationOptions>`.
// URI path transformations specified by the ``uri_path_normalization_options`` configuration can be applied to a portion
// of requests by setting the ``envoy_default_header_validator.uri_path_transformations`` runtime value.
// Caution: disabling path normalization may lead to path confusion vulnerabilities in access control or incorrect service
// selection.
UriPathNormalizationOptions uri_path_normalization_options = 2;

// Restrict HTTP methods to these defined in the `RFC 7231 section 4.1 <https://datatracker.ietf.org/doc/html/rfc7231#section-4.1>`_
// Envoy will respond with 400 to requests with disallowed methods.
// By default methods with arbitrary names are accepted.
bool restrict_http_methods = 3;
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ proto_library(
"//envoy/extensions/formatter/req_without_query/v3:pkg",
"//envoy/extensions/health_checkers/redis/v3:pkg",
"//envoy/extensions/http/header_formatters/preserve_case/v3:pkg",
"//envoy/extensions/http/header_validators/envoy_default/v3:pkg",
"//envoy/extensions/http/original_ip_detection/custom_header/v3:pkg",
"//envoy/extensions/http/original_ip_detection/xff/v3:pkg",
"//envoy/extensions/http/stateful_session/cookie/v3:pkg",
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v3/config/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Extensions
http/header_formatters
http/original_ip_detection
http/stateful_session
http/header_validators
stat_sinks/stat_sinks
quic/quic_extensions
formatter/formatter
Expand Down
8 changes: 8 additions & 0 deletions docs/root/api-v3/config/http/header_validators.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Header Validators
=================

.. toctree::
:glob:
:maxdepth: 2

../../extensions/http/header_validators/*/v3/*
11 changes: 11 additions & 0 deletions envoy/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,14 @@ envoy_cc_library(
name = "persistent_quic_info_interface",
hdrs = ["persistent_quic_info.h"],
)

envoy_cc_library(
name = "header_validator_interface",
hdrs = ["header_validator.h"],
deps = [
"//envoy/config:typed_config_interface",
"//envoy/http:header_map_interface",
"//envoy/server:factory_context_interface",
"//envoy/stream_info:stream_info_interface",
],
)
13 changes: 3 additions & 10 deletions envoy/http/header_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,6 @@ using InlineHeaderVector = absl::InlinedVector<char, 128>;
*/
using VariantHeader = absl::variant<absl::string_view, InlineHeaderVector>;

// Forward declare test classes that have access to HeaderString::setCopyUnvalidatedForTestOnly()
namespace Http2 {
class Http2CodecImplTest;
}

/**
* This is a string implementation for use in header processing. It is heavily optimized for
* performance. It supports 2 different types of storage and can switch between them:
Expand Down Expand Up @@ -229,18 +224,16 @@ class HeaderString {
}
bool operator!=(absl::string_view rhs) const { return getStringView() != rhs; }

// Test only method that does not have validation and allows setting arbitrary values.
void setCopyUnvalidatedForTestOnly(absl::string_view view);

private:
enum class Type { Reference, Inline };

VariantHeader buffer_;

bool valid() const;

// Test only method that does not have validation and allows setting arbitrary values.
// Test code that needs access to it is declared below.
friend class Http2::Http2CodecImplTest;
void setCopyUnvalidatedForTestOnly(absl::string_view view);

/**
* @return the type of backing storage for the string.
*/
Expand Down
Loading

0 comments on commit e569ce0

Please sign in to comment.