Skip to content

Commit

Permalink
Merge #30932
Browse files Browse the repository at this point in the history
30932: security: use same error message for user DNE and bad password r=mjibson a=mjibson

This prevents attacks to determine which users exist.

Fixes #30879

Release note (bug fix): "user does not exist" and "invalid password"
errors now produce the same error message during password login.

Co-authored-by: Matt Jibson <matt.jibson@gmail.com>
  • Loading branch information
craig[bot] and maddyblue committed Oct 3, 2018
2 parents 3ce4145 + ac7b080 commit 2d123a8
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 10 deletions.
2 changes: 1 addition & 1 deletion pkg/cli/interactive_tests/test_secure.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ eexpect $prompt
send "$argv sql --certs-dir=$certs_dir --user=eisen\r"
eexpect "Enter password:"
send "*****\r"
eexpect "Error: pq: invalid password"
eexpect "Error: pq: password authentication failed for user eisen"
eexpect "Failed running \"sql\""
# Check that history is scrubbed.
send "$argv sql --certs-dir=$certs_dir\r"
Expand Down
7 changes: 6 additions & 1 deletion pkg/security/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,14 @@ func UserAuthPasswordHook(insecureMode bool, password string, hashedPassword []b

// If the requested user has an empty password, disallow authentication.
if len(password) == 0 || CompareHashAndPassword(hashedPassword, password) != nil {
return errors.New("invalid password")
return errors.Errorf(ErrPasswordUserAuthFailed, requestedUser)
}

return nil
}
}

// ErrPasswordUserAuthFailed is the error template for failed password auth
// of a user. It should be used when the password is incorrect or the user
// does not exist.
const ErrPasswordUserAuthFailed = "password authentication failed for user %s"
4 changes: 2 additions & 2 deletions pkg/security/certs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func TestUseSplitCACerts(t *testing.T) {
expectedError string
}{
// Success, but "node" is not a sql user.
{"node", security.EmbeddedCACert, "client.node", "pq: user node does not exist"},
{"node", security.EmbeddedCACert, "client.node", "pq: password authentication failed for user node"},
// Success!
{"root", security.EmbeddedCACert, "client.root", ""},
// Bad server CA: can't verify server certificate.
Expand Down Expand Up @@ -541,7 +541,7 @@ func TestUseWrongSplitCACerts(t *testing.T) {
// Certificate signed by wrong client CA.
{"root", security.EmbeddedCACert, "client.root", "tls: bad certificate"},
// Success! The node certificate still contains "CN=node" and is signed by ca.crt.
{"node", security.EmbeddedCACert, "node", "pq: user node does not exist"},
{"node", security.EmbeddedCACert, "node", "pq: password authentication failed for user node"},
}

for i, tc := range testCases {
Expand Down
3 changes: 1 addition & 2 deletions pkg/sql/pgwire/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,6 @@ func (r *pgwireReader) ReadByte() (byte, error) {
// point the sql.Session does not exist yet! If need exists to access the
// database to look up authentication data, use the internal executor.
func (c *conn) handleAuthentication(ctx context.Context, insecure bool) error {

sendError := func(err error) error {
_ /* err */ = writeErr(err, &c.msgBuilder, c.conn)
return err
Expand All @@ -1236,7 +1235,7 @@ func (c *conn) handleAuthentication(ctx context.Context, insecure bool) error {
return sendError(err)
}
if !exists {
return sendError(errors.Errorf("user %s does not exist", c.sessionArgs.User))
return sendError(errors.Errorf(security.ErrPasswordUserAuthFailed, c.sessionArgs.User))
}

if tlsConn, ok := c.conn.(*tls.Conn); ok {
Expand Down
8 changes: 4 additions & 4 deletions pkg/sql/pgwire/pgwire_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func TestPGWire(t *testing.T) {
if optUser == server.TestUser {
// The user TestUser has not been created so authentication
// will fail with a valid certificate.
if !testutils.IsError(err, fmt.Sprintf("pq: user %s does not exist", server.TestUser)) {
if !testutils.IsError(err, fmt.Sprintf("pq: password authentication failed for user %s", server.TestUser)) {
t.Errorf("unexpected error: %v", err)
}
} else {
Expand Down Expand Up @@ -199,7 +199,7 @@ func TestPGWireNonexistentUser(t *testing.T) {
}

err := trivialQuery(pgURL)
if !testutils.IsError(err, fmt.Sprintf("pq: user %s does not exist", server.TestUser)) {
if !testutils.IsError(err, fmt.Sprintf("pq: password authentication failed for user %s", server.TestUser)) {
t.Errorf("unexpected error: %v", err)
}
})
Expand Down Expand Up @@ -1849,7 +1849,7 @@ func TestPGWireAuth(t *testing.T) {
Host: net.JoinHostPort(host, port),
RawQuery: "sslmode=require",
}
if err := trivialQuery(unicodeUserPgURL); !testutils.IsError(err, "pq: invalid password") {
if err := trivialQuery(unicodeUserPgURL); !testutils.IsError(err, "pq: password authentication failed for user") {
t.Fatalf("unexpected error: %v", err)
}

Expand Down Expand Up @@ -1883,7 +1883,7 @@ func TestPGWireAuth(t *testing.T) {
// Even though the correct password is supplied (empty string), this
// should fail because we do not support password authentication for
// users with empty passwords.
if err := trivialQuery(testUserPgURL); !testutils.IsError(err, "pq: invalid password") {
if err := trivialQuery(testUserPgURL); !testutils.IsError(err, "pq: password authentication failed for user") {
t.Fatalf("unexpected error: %v", err)
}
})
Expand Down

0 comments on commit 2d123a8

Please sign in to comment.