-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Work around gRPC-Gateway bug in
X-Forwarded-For
handling (#2152)
This PR primarily aims to work around an issue with `X-Forwarded-For` handling in the gRPC-Gateway (grpc-ecosystem/grpc-gateway#4320). Given a remote IP of 4.4.4.4 sending incoming headers of ``` X-Forwarded-For: 1.1.1.1, 2.2.2.2 X-Forwarded-For: 3.3.3.3 ``` the resulting headers forwarded by the gRPC-gateway are ``` X-Forwarded-For: 1.1.1.1, 2.2.2.2 X-Forwarded-For: 3.3.3.3 X-Forwarded-For: 1.1.1.1, 2.2.2.2, 4.4.4.4 ``` The workaround I have added means that the resulting headers are ``` X-Forwarded-For: 1.1.1.1, 2.2.2.2 X-Forwarded-For: 3.3.3.3 X-Forwarded-For: 4.4.4.4 ``` We now join the values with `", "` rather than `"|"` to preserve the [de-facto standard syntax](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#syntax). This PR also prevents spoofing the remote address in the audit logs by setting the `x-cerbos-http-remote-addr` header; currently we take that header into account even for requests not originating from the gRPC-Gateway where it should be set. Even in the case of requests from the gRPC-Gateway, our header is appended to the request headers, so we need to make sure to use the last value for the header, not the first. Signed-off-by: Andrew Haines <haines@cerbos.dev>
- Loading branch information
Showing
3 changed files
with
134 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright 2021-2024 Zenauth Ltd. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package server | ||
|
||
import ( | ||
"context" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/cerbos/cerbos/internal/audit" | ||
gateway "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"google.golang.org/grpc/metadata" | ||
"google.golang.org/grpc/peer" | ||
) | ||
|
||
func TestPeerFromContext(t *testing.T) { | ||
t.Run("gRPC", func(t *testing.T) { | ||
ctx := peer.NewContext( | ||
metadata.NewIncomingContext(context.Background(), metadata.Pairs( | ||
audit.HTTPRemoteAddrKey, "attempted spoof", | ||
audit.SetByGRPCGatewayKey, "attempted spoof", | ||
"User-Agent", "peer-from-context", | ||
"X-Forwarded-For", "1.1.1.1, 2.2.2.2", | ||
"X-Forwarded-For", "3.3.3.3", | ||
)), | ||
&peer.Peer{Addr: peerAddr("4.4.4.4:12345")}, | ||
) | ||
|
||
p := audit.PeerFromContext(ctx) | ||
assert.Equal(t, "4.4.4.4:12345", p.Address) | ||
assert.Equal(t, "1.1.1.1, 2.2.2.2, 3.3.3.3", p.ForwardedFor) | ||
assert.Equal(t, "peer-from-context", p.UserAgent) | ||
}) | ||
|
||
t.Run("HTTP", func(t *testing.T) { | ||
req := httptest.NewRequest("GET", "/", nil) | ||
req.Header.Set(audit.HTTPRemoteAddrKey, "attempted spoof") | ||
req.Header.Set(audit.SetByGRPCGatewayKey, "attempted spoof") | ||
req.Header.Set("User-Agent", "peer-from-context") | ||
req.Header.Add("X-Forwarded-For", "1.1.1.1, 2.2.2.2") | ||
req.Header.Add("X-Forwarded-For", "3.3.3.3") | ||
req.RemoteAddr = "4.4.4.4:12345" | ||
|
||
ctx, err := gateway.AnnotateIncomingContext(context.Background(), mkGatewayMux(nil), req, "example.Service/Method") | ||
require.NoError(t, err) | ||
|
||
peer := audit.PeerFromContext(ctx) | ||
assert.Equal(t, "4.4.4.4:12345", peer.Address) | ||
assert.Equal(t, "1.1.1.1, 2.2.2.2, 3.3.3.3, 4.4.4.4", peer.ForwardedFor) | ||
assert.Equal(t, "peer-from-context", peer.UserAgent) | ||
}) | ||
} | ||
|
||
type peerAddr string | ||
|
||
func (peerAddr) Network() string { | ||
return "tcp" | ||
} | ||
|
||
func (a peerAddr) String() string { | ||
return string(a) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters