mirror of
https://github.com/containous/traefik.git
synced 2026-01-14 12:33:07 +03:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e5d4ba5a1 | ||
|
|
adf47fba31 | ||
|
|
ee265a8509 | ||
|
|
fc67185987 |
@@ -1,3 +1,10 @@
|
||||
## [v2.11.35](https://github.com/traefik/traefik/tree/v2.11.35) (2026-01-14)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.34...v2.11.35)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Add timeout to ACME-TLS/1 challenge handshake ([#12516](https://github.com/traefik/traefik/pull/12516) by [LBF38](https://github.com/LBF38))
|
||||
- **[server]** Make encoded character options opt-in ([#12540](https://github.com/traefik/traefik/pull/12540) by [gndz07](https://github.com/gndz07))
|
||||
|
||||
## [v2.11.34](https://github.com/traefik/traefik/tree/v2.11.34) (2025-12-23)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.33...v2.11.34)
|
||||
|
||||
|
||||
@@ -87,10 +87,10 @@ Complete documentation is available at https://traefik.io`,
|
||||
func runCmd(staticConfiguration *static.Configuration) error {
|
||||
configureLogging(staticConfiguration)
|
||||
|
||||
// Display warning to advertise for new behavior of rejecting encoded characters in the request path.
|
||||
// Deprecated: this has to be removed in the next minor/major version.
|
||||
log.WithoutContext().Warnf("Starting with v2.11.32, Traefik now rejects some encoded characters in the request path by default. " +
|
||||
"Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-in-request-path")
|
||||
log.WithoutContext().Warn("Traefik can reject some encoded characters in the request path." +
|
||||
"When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)," +
|
||||
"it is recommended to set these options to `false` to avoid split-view situation." +
|
||||
"Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-configuration-default-values")
|
||||
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
/* Highlight */
|
||||
(function(hljs) {
|
||||
hljs.initHighlightingOnLoad();
|
||||
})(hljs);
|
||||
})(hljs);
|
||||
|
||||
/* Scarf Analytics - cookieless, anonymous company-level intelligence */
|
||||
(function() {
|
||||
var img = document.createElement('img');
|
||||
img.src = 'https://static.scarf.sh/a.png?x-pxid=1a49232a-b165-4015-8ed2-a1092f1f0d83';
|
||||
img.referrerPolicy = 'no-referrer-when-downgrade';
|
||||
img.loading = 'eager';
|
||||
img.style.cssText = 'visibility:hidden;position:absolute;width:1px;height:1px;';
|
||||
document.body.appendChild(img);
|
||||
})();
|
||||
@@ -57,4 +57,4 @@ You no longer need to create and synchronize configuration files cluttered with
|
||||
Traefik is able to use your cluster API to discover the services and read the attached information.
|
||||
In Traefik, these connectors are called [providers](../providers/overview.md "Link to overview about Traefik providers") because they *provide* the configuration to Traefik.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -94,4 +94,4 @@ All the configuration options are documented in their related section.
|
||||
|
||||
You can browse the available features in the menu, the [providers](../providers/overview.md), or the [routing section](../routing/overview.md) to see them in action.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -252,4 +252,4 @@ In which case, you should make sure your infrastructure is properly set up for a
|
||||
LEGO_DISABLE_CNAME_SUPPORT=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -144,4 +144,4 @@ And run it:
|
||||
|
||||
All the details are available in the [Contributing Guide](../contributing/building-testing.md)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -334,4 +334,4 @@ curl -v http://localhost/
|
||||
- Use [IngressRoute CRD](../providers/kubernetes-crd.md)
|
||||
- Protect [ingresses with TLS](../routing/providers/kubernetes-ingress.md#enabling-tls-via-annotations)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -121,4 +121,4 @@ IP: 172.27.0.4
|
||||
|
||||
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it is time to dive into [the user guides](../../user-guides/docker-compose/basic-example/ "Link to the user guides") and [the documentation](/ "Link to the docs landing page") and let Traefik work for you!
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -797,4 +797,4 @@ If Let's Encrypt is not reachable, the following certificates will apply:
|
||||
!!! important
|
||||
For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -20,4 +20,4 @@ That is to say, how to obtain [TLS certificates](./tls.md#certificates-definitio
|
||||
either through a definition in the dynamic configuration, or through [Let's Encrypt](./acme.md) (ACME).
|
||||
And how to configure [TLS options](./tls.md#tls-options), and [certificates stores](./tls.md#certificates-stores).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -561,4 +561,4 @@ spec:
|
||||
clientAuthType: RequireAndVerifyClientCert
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -404,4 +404,4 @@ http:
|
||||
[http.middlewares.test-auth.basicAuth]
|
||||
removeHeader = true
|
||||
```
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -637,4 +637,4 @@ http:
|
||||
[http.middlewares.test-auth.forwardAuth.tls]
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -480,4 +480,4 @@ Set `isDevelopment` to `true` when developing to mitigate the unwanted effects o
|
||||
Usually testing takes place using HTTP, not HTTPS, and on `localhost`, not your production domain.
|
||||
If you would like your development environment to mimic production with complete Host blocking, SSL redirects, and STS headers, leave this as `false`.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -158,4 +158,4 @@ http:
|
||||
|
||||
Please take a look at the community-contributed plugins in the [plugin catalog](https://plugins.traefik.io/plugins).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -100,4 +100,4 @@ The `replacement` option defines how to modify the URL to have the new target UR
|
||||
|
||||
Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -171,4 +171,4 @@ http:
|
||||
forceSlash = false
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -130,4 +130,4 @@ A list of HTTP middlewares can be found [here](http/overview.md).
|
||||
|
||||
A list of TCP middlewares can be found [here](tcp/overview.md).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -737,3 +737,30 @@ Note: This check is not done against query parameters,
|
||||
but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation for more details.
|
||||
|
||||
## v2.11.35
|
||||
|
||||
### Encoded Characters Configuration Default Values
|
||||
|
||||
Since `v2.11.35`, the options for encoded characters now have a `true` default value.
|
||||
This means that Traefik will not reject requests with a path containing a specific set of encoded characters by default.
|
||||
It is now up to the users to configure the security hardening of encoded characters.
|
||||
|
||||
Here is the list of the encoded characters that can be configured to `false` to disallow them:
|
||||
|
||||
| Encoded Character | Character | Config options | Default value |
|
||||
|-------------------|-------------------------|--------------------------------------------------------------------------------------|---------------|
|
||||
| `%2f` or `%2F` | `/` (slash) | `entryPoints.<name>`<br/>`.http.encodedCharacters`<br/>`.allowEncodedSlash` | `true` |
|
||||
| `%5c` or `%5C` | `\` (backslash) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedBackSlash` | `true` |
|
||||
| `%00` | `NULL` (null character) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedNullCharacter` | `true` |
|
||||
| `%3b` or `%3B` | `;` (semicolon) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedSemicolon` | `true` |
|
||||
| `%25` | `%` (percent) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedPercent` | `true` |
|
||||
| `%3f` or `%3F` | `?` (question mark) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedQuestionMark` | `true` |
|
||||
| `%23` | `#` (hash) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedHash` | `true` |
|
||||
|
||||
Note: This check is not done against query parameters,
|
||||
but only against the request path as defined
|
||||
in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation
|
||||
for more details.
|
||||
|
||||
@@ -281,4 +281,4 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -90,4 +90,4 @@ This allows the logs to be rotated and processed by an external program, such as
|
||||
!!! warning
|
||||
This does not work on Windows due to the lack of USR signals.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -175,4 +175,4 @@ All the following endpoints must be accessed with a `GET` HTTP request.
|
||||
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
|
||||
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -132,4 +132,4 @@ api:
|
||||
--api.dashboard=false
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -31,4 +31,4 @@ The experience of implementing a Traefik plugin is comparable to writing a web b
|
||||
|
||||
To learn more about Traefik plugin creation, please refer to the [developer documentation](https://plugins.traefik.io/create).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -764,4 +764,4 @@ providers:
|
||||
--providers.docker.allowEmptyServices=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -292,4 +292,4 @@ To illustrate, it is possible to easily define multiple routers, services, and T
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -345,4 +345,4 @@ providers:
|
||||
|
||||
For additional information, refer to the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -269,4 +269,4 @@ providers:
|
||||
--providers.kubernetesgateway.throttleDuration=10s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -504,4 +504,4 @@ providers:
|
||||
To learn more about the various aspects of the Ingress specification that Traefik supports,
|
||||
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.11/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -233,4 +233,4 @@ List of providers that support constraints:
|
||||
- [Kubernetes Ingress](./kubernetes-ingress.md#labelselector)
|
||||
- [Kubernetes Gateway](./kubernetes-gateway.md#labelselector)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -36,4 +36,4 @@ Dynamic configuration with Kubernetes Custom Resource
|
||||
--8<-- "content/reference/dynamic-configuration/kubernetes-crd-rbac.yml"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -30,4 +30,4 @@ Dynamic configuration with Kubernetes Gateway provider.
|
||||
--8<-- "content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -124,25 +124,25 @@ Trust only forwarded headers from selected IPs.
|
||||
HTTP configuration.
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedbackslash`:
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedhash`:
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodednullcharacter`:
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedpercent`:
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedquestionmark`:
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedsemicolon`:
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedslash`:
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodequerysemicolons`:
|
||||
Defines whether request query semicolons should be URLEncoded. (Default: ```false```)
|
||||
|
||||
@@ -133,25 +133,25 @@ HTTP/3 configuration. (Default: ```false```)
|
||||
UDP port to advertise, on which HTTP/3 is available. (Default: ```0```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDBACKSLASH`:
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDHASH`:
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDNULLCHARACTER`:
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDPERCENT`:
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDQUESTIONMARK`:
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSEMICOLON`:
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSLASH`:
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEQUERYSEMICOLONS`:
|
||||
Defines whether request query semicolons should be URLEncoded. (Default: ```false```)
|
||||
|
||||
@@ -129,13 +129,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
- "192.168.0.1"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: true
|
||||
allowEncodedBackSlash: true
|
||||
allowEncodedNullCharacter: true
|
||||
allowEncodedSemicolon: true
|
||||
allowEncodedPercent: true
|
||||
allowEncodedQuestionMark: true
|
||||
allowEncodedHash: true
|
||||
allowEncodedSlash: false
|
||||
allowEncodedBackSlash: false
|
||||
allowEncodedNullCharacter: false
|
||||
allowEncodedSemicolon: false
|
||||
allowEncodedPercent: false
|
||||
allowEncodedQuestionMark: false
|
||||
allowEncodedHash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -162,13 +162,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
insecure = true
|
||||
trustedIPs = ["127.0.0.1", "192.168.0.1"]
|
||||
[entryPoints.name.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedBackSlash = true
|
||||
allowEncodedNullCharacter = true
|
||||
allowEncodedSemicolon = true
|
||||
allowEncodedPercent = true
|
||||
allowEncodedQuestionMark = true
|
||||
allowEncodedHash = true
|
||||
allowEncodedSlash = false
|
||||
allowEncodedBackSlash = false
|
||||
allowEncodedNullCharacter = false
|
||||
allowEncodedSemicolon = false
|
||||
allowEncodedPercent = false
|
||||
allowEncodedQuestionMark = false
|
||||
allowEncodedHash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -185,13 +185,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
--entryPoints.name.proxyProtocol.trustedIPs=127.0.0.1,192.168.0.1
|
||||
--entryPoints.name.forwardedHeaders.insecure=true
|
||||
--entryPoints.name.forwardedHeaders.trustedIPs=127.0.0.1,192.168.0.1
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSlash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedPercent=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedHash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSlash=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedPercent=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedHash=false
|
||||
```
|
||||
|
||||
### Address
|
||||
@@ -1021,20 +1021,21 @@ entryPoints:
|
||||
### Encoded Characters
|
||||
|
||||
You can configure Traefik to control the handling of encoded characters in request paths for security purposes.
|
||||
By default, Traefik rejects requests with path containing certain encoded characters that could be used in path traversal or other security attacks.
|
||||
By default, Traefik do not reject requests with path containing certain encoded characters that could be used in path traversal or other security attacks.
|
||||
|
||||
!!! info
|
||||
|
||||
This check is not done against the request query parameters,
|
||||
but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
!!! warning "Security Considerations"
|
||||
!!! info "Security Considerations"
|
||||
|
||||
Allowing certain encoded characters may expose your application to security vulnerabilities.
|
||||
When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path,
|
||||
it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls.
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedSlash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded slash characters (`%2F` or `%2f`) in the path are allowed.
|
||||
|
||||
@@ -1045,7 +1046,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: true
|
||||
allowEncodedSlash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1055,18 +1056,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedSlash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSlash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSlash=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedBackSlash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded back slash characters (`%5C` or `%5c`) in the path are allowed.
|
||||
|
||||
@@ -1077,7 +1078,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedBackSlash: true
|
||||
allowEncodedBackSlash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1087,18 +1088,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedBackSlash = true
|
||||
allowEncodedBackSlash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedNullCharacter`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded null characters (`%00`) in the path are allowed.
|
||||
|
||||
@@ -1109,7 +1110,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedNullCharacter: true
|
||||
allowEncodedNullCharacter: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1119,18 +1120,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedNullCharacter = true
|
||||
allowEncodedNullCharacter = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedSemicolon`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded semicolon characters (`%3B` or `%3b`) in the path are allowed.
|
||||
|
||||
@@ -1141,7 +1142,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSemicolon: true
|
||||
allowEncodedSemicolon: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1151,18 +1152,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSemicolon = true
|
||||
allowEncodedSemicolon = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedPercent`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded percent characters (`%25`) in the path are allowed.
|
||||
|
||||
@@ -1173,7 +1174,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedPercent: true
|
||||
allowEncodedPercent: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1183,18 +1184,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedPercent = true
|
||||
allowEncodedPercent = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedPercent=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedPercent=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedQuestionMark`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded question mark characters (`%3F` or `%3f`) in the path are allowed.
|
||||
|
||||
@@ -1205,7 +1206,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedQuestionMark: true
|
||||
allowEncodedQuestionMark: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1215,18 +1216,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedQuestionMark = true
|
||||
allowEncodedQuestionMark = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedHash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded hash characters (`%23`) in the path are allowed.
|
||||
|
||||
@@ -1237,7 +1238,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedHash: true
|
||||
allowEncodedHash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1247,13 +1248,13 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedHash = true
|
||||
allowEncodedHash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedHash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedHash=false
|
||||
```
|
||||
|
||||
### SanitizePath
|
||||
@@ -1441,4 +1442,4 @@ entryPoints:
|
||||
--entryPoints.foo.udp.timeout=10s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -412,4 +412,4 @@ serversTransport:
|
||||
--serversTransport.forwardingTimeouts.idleConnTimeout=1s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1904,4 +1904,4 @@ If the ServersTransport CRD is defined in another provider the cross-provider fo
|
||||
|
||||
Also see the [full example](../../user-guides/crd-acme/index.md) with Let's Encrypt.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -355,4 +355,4 @@ Kubernetes cluster before creating `TLSRoute` objects.
|
||||
| [11] | `group` | Group is the group of the referent. Only `traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
||||
| [12] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -969,4 +969,4 @@ This will allow users to create a "default router" that will match all unmatched
|
||||
|
||||
To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1349,4 +1349,4 @@ Services are the target for the router.
|
||||
|
||||
!!! important "UDP routers can only target UDP services (and not HTTP or TCP services)."
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1646,4 +1646,4 @@ udp:
|
||||
address = "private-ip-server-2:8080/"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -20,7 +20,7 @@ When Traefik receives an HTTP request, it processes the request path through sev
|
||||
|
||||
Traefik inspects the path for potentially dangerous encoded characters and rejects requests containing them unless explicitly allowed.
|
||||
|
||||
Here is the list of the encoded characters that are rejected by default:
|
||||
Here is the list of the encoded characters that are allowed by default:
|
||||
|
||||
| Encoded Character | Character |
|
||||
|-------------------|-------------------------|
|
||||
@@ -87,7 +87,12 @@ Configure it in the [EntryPoints](../routing/entrypoints.md#encoded-characters)
|
||||
|
||||
This filtering occurs before path sanitization and catches attack attempts that use encoding to bypass other security controls.
|
||||
|
||||
All encoded character filtering is enabled by default (`false` means encoded characters are rejected), providing maximum security:
|
||||
All encoded character filtering is disabled by default (`true` means encoded characters are allowed).
|
||||
|
||||
!!! info "Security Considerations"
|
||||
|
||||
When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path,
|
||||
it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
@@ -95,13 +100,13 @@ entryPoints:
|
||||
address: ":443"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: false # %2F - Default: false (RECOMMENDED)
|
||||
allowEncodedBackSlash: false # %5C - Default: false (RECOMMENDED)
|
||||
allowEncodedNullCharacter: false # %00 - Default: false (RECOMMENDED)
|
||||
allowEncodedSemicolon: false # %3B - Default: false (RECOMMENDED)
|
||||
allowEncodedPercent: false # %25 - Default: false (RECOMMENDED)
|
||||
allowEncodedQuestionMark: false # %3F - Default: false (RECOMMENDED)
|
||||
allowEncodedHash: false # %23 - Default: false (RECOMMENDED)
|
||||
allowEncodedSlash: false # %2F - Default: true
|
||||
allowEncodedBackSlash: false # %5C - Default: true
|
||||
allowEncodedNullCharacter: false # %00 - Default: true
|
||||
allowEncodedSemicolon: false # %3B - Default: true
|
||||
allowEncodedPercent: false # %25 - Default: true
|
||||
allowEncodedQuestionMark: false # %3F - Default: true
|
||||
allowEncodedHash: false # %23 - Default: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
|
||||
@@ -187,4 +187,4 @@ environment:
|
||||
- "OVH_CONSUMER_KEY_FILE=/run/secrets/ovh_consumer_key"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -83,4 +83,4 @@ labels:
|
||||
- "traefik.http.routers.whoami.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -133,4 +133,4 @@ whoami:
|
||||
- "traefik.http.routers.whoami.entrypoints=web"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -39,6 +39,8 @@ plugins:
|
||||
- exclude:
|
||||
glob:
|
||||
- "**/include-*.md"
|
||||
- include-markdown:
|
||||
encoding: utf-8
|
||||
|
||||
# https://squidfunk.github.io/mkdocs-material/extensions/admonition/
|
||||
# https://facelessuser.github.io/pymdown-extensions/
|
||||
@@ -56,9 +58,6 @@ markdown_extensions:
|
||||
- pymdownx.tasklist
|
||||
- pymdownx.snippets:
|
||||
check_paths: true
|
||||
- markdown_include.include:
|
||||
base_path: content/includes/
|
||||
encoding: utf-8
|
||||
- toc:
|
||||
permalink: true
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
markdown-include==0.5.1
|
||||
mkdocs==1.2.4
|
||||
mkdocs==1.4.3
|
||||
mkdocs-include-markdown-plugin==7.2.0
|
||||
mkdocs-exclude==1.0.2
|
||||
mkdocs-traefiklabs>=100.0.7
|
||||
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
[entryPoints]
|
||||
[entryPoints.strict]
|
||||
address = ":8000"
|
||||
# Default: no encoded characters allowed
|
||||
[entryPoints.strict.http.encodedCharacters]
|
||||
allowEncodedSlash = false
|
||||
|
||||
[entryPoints.permissive]
|
||||
address = ":8001"
|
||||
# No config, default values should apply
|
||||
|
||||
[entryPoints.permissive2]
|
||||
address = ":8002"
|
||||
# No config for allowEncodedSlash, default value is effectively true
|
||||
[entryPoints.permissive.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedBackSlash = false
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
@@ -1520,6 +1520,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() {
|
||||
target: "127.0.0.1:8001", // permissive entry point
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Encoded slash should be ALLOWED on permissive2 entry point",
|
||||
request: "GET /path%2Fwith%2Fslash HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8002", // permissive2 entry point
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Regular path should work on strict entry point",
|
||||
request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
@@ -1532,6 +1538,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() {
|
||||
target: "127.0.0.1:8001",
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Regular path should work on permissive2 entry point",
|
||||
request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8002",
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
@@ -43,14 +43,14 @@ type Service struct {
|
||||
|
||||
// Router holds the router configuration.
|
||||
type Router struct {
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
||||
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||
DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||
DeniedEncodedPathCharacters RouterDeniedEncodedPathCharacters `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||
EntryPoints []string `json:"entryPoints,omitempty" toml:"entryPoints,omitempty" yaml:"entryPoints,omitempty" export:"true"`
|
||||
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty" export:"true"`
|
||||
Service string `json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty" export:"true"`
|
||||
Rule string `json:"rule,omitempty" toml:"rule,omitempty" yaml:"rule,omitempty"`
|
||||
Priority int `json:"priority,omitempty" toml:"priority,omitempty,omitzero" yaml:"priority,omitempty" export:"true"`
|
||||
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||
DefaultRule bool `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||
DeniedEncodedPathCharacters *RouterDeniedEncodedPathCharacters `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
@@ -1035,7 +1035,11 @@ func (in *Router) DeepCopyInto(out *Router) {
|
||||
*out = new(RouterTLSConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.DeniedEncodedPathCharacters = in.DeniedEncodedPathCharacters
|
||||
if in.DeniedEncodedPathCharacters != nil {
|
||||
in, out := &in.DeniedEncodedPathCharacters, &out.DeniedEncodedPathCharacters
|
||||
*out = new(RouterDeniedEncodedPathCharacters)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,16 @@ type EncodedCharacters struct {
|
||||
AllowEncodedHash bool `description:"Defines whether requests with encoded hash characters in the path are allowed." json:"allowEncodedHash,omitempty" toml:"allowEncodedHash,omitempty" yaml:"allowEncodedHash,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
func (ec *EncodedCharacters) SetDefaults() {
|
||||
ec.AllowEncodedSlash = true
|
||||
ec.AllowEncodedBackSlash = true
|
||||
ec.AllowEncodedNullCharacter = true
|
||||
ec.AllowEncodedSemicolon = true
|
||||
ec.AllowEncodedPercent = true
|
||||
ec.AllowEncodedQuestionMark = true
|
||||
ec.AllowEncodedHash = true
|
||||
}
|
||||
|
||||
// HTTP2Config is the HTTP2 configuration of an entry point.
|
||||
type HTTP2Config struct {
|
||||
MaxConcurrentStreams int32 `description:"Specifies the number of concurrent streams per connection that each client is allowed to initiate." json:"maxConcurrentStreams,omitempty" toml:"maxConcurrentStreams,omitempty" yaml:"maxConcurrentStreams,omitempty" export:"true"`
|
||||
|
||||
@@ -167,7 +167,7 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||
if m.DeniedEncodedPathCharacters != nil {
|
||||
// As the denied encoded path characters option is not configurable at the router level,
|
||||
// we can simply copy the whole structure to override the router's default config.
|
||||
cp.DeniedEncodedPathCharacters = *m.DeniedEncodedPathCharacters
|
||||
cp.DeniedEncodedPathCharacters = m.DeniedEncodedPathCharacters
|
||||
}
|
||||
|
||||
rtName := name
|
||||
|
||||
@@ -2,29 +2,10 @@ package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/traefik/traefik/v2/pkg/log"
|
||||
)
|
||||
|
||||
// denyFragment rejects the request if the URL path contains a fragment (hash character).
|
||||
// When go receives an HTTP request, it assumes the absence of fragment URL.
|
||||
// However, it is still possible to send a fragment in the request.
|
||||
// In this case, Traefik will encode the '#' character, altering the request's intended meaning.
|
||||
// To avoid this behavior, the following function rejects requests that include a fragment in the URL.
|
||||
func denyFragment(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if strings.Contains(req.URL.RawPath, "#") {
|
||||
log.WithoutContext().Debugf("Rejecting request because it contains a fragment in the URL path: %s", req.URL.RawPath)
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
h.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
||||
// denyEncodedPathCharacters reject the request if the escaped path contains encoded characters in the given list.
|
||||
func denyEncodedPathCharacters(encodedCharacters map[string]struct{}, h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
@@ -8,42 +8,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_denyFragment(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "Rejects fragment character",
|
||||
url: "http://example.com/#",
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "Allows without fragment",
|
||||
url: "http://example.com/",
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := denyFragment(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, test.url, nil)
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(t, test.wantStatus, res.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_denyEncodedPathCharacters(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -223,14 +223,11 @@ func (m *Manager) buildHTTPHandler(ctx context.Context, router *runtime.RouterIn
|
||||
chain = chain.Append(denyrouterrecursion.WrapHandler(routerName))
|
||||
}
|
||||
|
||||
// Here we are adding deny handlers for encoded path characters and fragment.
|
||||
// Deny handler are only added for root routers, child routers are protected by their parent router deny handlers.
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
return denyFragment(next), nil
|
||||
})
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
return denyEncodedPathCharacters(router.DeniedEncodedPathCharacters.Map(), next), nil
|
||||
})
|
||||
if router.DeniedEncodedPathCharacters != nil {
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
return denyEncodedPathCharacters(router.DeniedEncodedPathCharacters.Map(), next), nil
|
||||
})
|
||||
}
|
||||
|
||||
return chain.Extend(*mHandler).Append(tHandler).Then(sHandler)
|
||||
}
|
||||
|
||||
@@ -910,13 +910,16 @@ func TestManager_BuildHandlers_Deny(t *testing.T) {
|
||||
expectedStatusCode int
|
||||
}{
|
||||
{
|
||||
desc: "unallowed request with encoded slash",
|
||||
desc: "disallow request with encoded slash",
|
||||
requestPath: "/foo%2F",
|
||||
routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Service: "service",
|
||||
DeniedEncodedPathCharacters: &dynamic.RouterDeniedEncodedPathCharacters{
|
||||
AllowEncodedSlash: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
services: map[string]*dynamic.Service{
|
||||
@@ -936,9 +939,6 @@ func TestManager_BuildHandlers_Deny(t *testing.T) {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Service: "service",
|
||||
DeniedEncodedPathCharacters: dynamic.RouterDeniedEncodedPathCharacters{
|
||||
AllowEncodedSlash: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
services: map[string]*dynamic.Service{
|
||||
@@ -950,25 +950,6 @@ func TestManager_BuildHandlers_Deny(t *testing.T) {
|
||||
},
|
||||
expectedStatusCode: http.StatusBadGateway,
|
||||
},
|
||||
{
|
||||
desc: "unallowed request with fragment",
|
||||
requestPath: "/foo#",
|
||||
routers: map[string]*dynamic.Router{
|
||||
"parent": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "PathPrefix(`/`)",
|
||||
Service: "service",
|
||||
},
|
||||
},
|
||||
services: map[string]*dynamic.Service{
|
||||
"service": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{{URL: "http://localhost:8080"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
@@ -606,6 +606,8 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
|
||||
|
||||
handler = normalizePath(handler)
|
||||
|
||||
handler = denyFragment(handler)
|
||||
|
||||
serverHTTP := &http.Server{
|
||||
Protocols: &protocols,
|
||||
Handler: handler,
|
||||
@@ -685,6 +687,24 @@ func (t *trackedConnection) Close() error {
|
||||
return t.WriteCloser.Close()
|
||||
}
|
||||
|
||||
// denyFragment rejects the request if the URL path contains a fragment (hash character).
|
||||
// When go receives an HTTP request, it assumes the absence of fragment URL.
|
||||
// However, it is still possible to send a fragment in the request.
|
||||
// In this case, Traefik will encode the '#' character, altering the request's intended meaning.
|
||||
// To avoid this behavior, the following function rejects requests that include a fragment in the URL.
|
||||
func denyFragment(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
if strings.Contains(req.URL.RawPath, "#") {
|
||||
log.WithoutContext().Debugf("Rejecting request because it contains a fragment in the URL path: %s", req.URL.RawPath)
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
h.ServeHTTP(rw, req)
|
||||
})
|
||||
}
|
||||
|
||||
// This function is inspired by http.AllowQuerySemicolons.
|
||||
func encodeQuerySemicolons(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
@@ -388,6 +388,42 @@ func TestKeepAliveH2c(t *testing.T) {
|
||||
require.Contains(t, err.Error(), "use of closed network connection")
|
||||
}
|
||||
|
||||
func Test_denyFragment(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
url string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "Rejects fragment character",
|
||||
url: "http://example.com/#",
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "Allows without fragment",
|
||||
url: "http://example.com/",
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := denyFragment(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, test.url, nil)
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(t, test.wantStatus, res.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
|
||||
@@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
||||
OutputType = "file"
|
||||
FileName = "traefik_changelog.md"
|
||||
|
||||
# example new bugfix v2.11.34
|
||||
# example new bugfix v2.11.35
|
||||
CurrentRef = "v2.11"
|
||||
PreviousRef = "v2.11.33"
|
||||
PreviousRef = "v2.11.34"
|
||||
BaseBranch = "v2.11"
|
||||
FutureCurrentRefName = "v2.11.34"
|
||||
FutureCurrentRefName = "v2.11.35"
|
||||
|
||||
ThresholdPreviousRef = 10000
|
||||
ThresholdCurrentRef = 10000
|
||||
|
||||
Reference in New Issue
Block a user