fix(http): decode proxy Basic auth with standard base64 (#1596)
The HTTP proxy server's dispatch method decodes the Proxy-Authorization Basic credential using base64.URLEncoding, but RFC 7617 specifies that Basic authentication uses standard Base64 encoding (base64.StdEncoding). The two encodings differ in their use of +/ vs -_ characters, so any credential containing 0xff or other bytes that encode to / or + in standard Base64 will fail to decode with URLEncoding, causing valid authentication attempts to always be rejected with 407. Additionally, the "Basic " scheme prefix check was case-sensitive, but RFC 7235 section 2.1 specifies that auth-scheme is case-insensitive. Fix both issues by switching to base64.StdEncoding and using strings.ToLower for the scheme comparison.
This commit is contained in:
parent
829d125ea2
commit
8e78342c2b
2 changed files with 29 additions and 2 deletions
|
|
@ -59,8 +59,8 @@ func (s *Server) dispatch(conn net.Conn) {
|
|||
authOK := false
|
||||
// Check the Proxy-Authorization header
|
||||
pAuth := req.Header.Get("Proxy-Authorization")
|
||||
if strings.HasPrefix(pAuth, "Basic ") {
|
||||
userPass, err := base64.URLEncoding.DecodeString(pAuth[6:])
|
||||
if strings.HasPrefix(strings.ToLower(pAuth), "basic ") {
|
||||
userPass, err := base64.StdEncoding.DecodeString(pAuth[6:])
|
||||
if err == nil {
|
||||
userPassParts := strings.SplitN(string(userPass), ":", 2)
|
||||
if len(userPassParts) == 2 {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
|
|
@ -57,3 +59,28 @@ func TestServer(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, "OK", strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
func TestServerBasicAuthUsesStandardBase64(t *testing.T) {
|
||||
authCalled := false
|
||||
s := &Server{
|
||||
HyClient: &mockHyClient{},
|
||||
AuthFunc: func(username, password string) bool {
|
||||
authCalled = true
|
||||
return username == string([]byte{0xff}) && password == ""
|
||||
},
|
||||
}
|
||||
clientConn, serverConn := net.Pipe()
|
||||
defer clientConn.Close()
|
||||
_ = clientConn.SetDeadline(time.Now().Add(time.Second))
|
||||
go s.dispatch(serverConn)
|
||||
|
||||
// "/zo=" is standard Base64 for []byte{0xff, ':'}. It is valid Basic Auth,
|
||||
// but it is not valid URL-safe Base64.
|
||||
_, err := clientConn.Write([]byte("CONNECT 127.0.0.1:1 HTTP/1.1\r\nHost: 127.0.0.1:1\r\nProxy-Authorization: Basic /zo=\r\n\r\n"))
|
||||
assert.NoError(t, err)
|
||||
resp, err := http.ReadResponse(bufio.NewReader(clientConn), nil)
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
assert.True(t, authCalled)
|
||||
assert.NotEqual(t, http.StatusProxyAuthRequired, resp.StatusCode)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue