Skip to content

Commit 326d62f

Browse files
Ensure loggableDSN scrubs passwords in different ways
The previous implementation of the function was only scrubbing those passwords that were part of a basic http authentication method, which means it expected passwords to be provided as part of the URL. However, the password may also be specified as a parameter, or when using key-values, it may be specified as a password=value string. This commit ensures those passwords will also not be retained, but removed. Signed-off-by: Feike Steenbergen <[email protected]>
1 parent 1b492a6 commit 326d62f

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

Diff for: cmd/postgres_exporter/util.go

+15
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"fmt"
1818
"math"
1919
"net/url"
20+
"regexp"
2021
"strconv"
2122
"strings"
2223
"time"
@@ -212,10 +213,24 @@ func loggableDSN(dsn string) string {
212213
if err != nil {
213214
return "could not parse DATA_SOURCE_NAME"
214215
}
216+
217+
// If the DSN is not a URL it is expected to be in the `key1=value1 key2=value2` format
218+
if pDSN.Scheme == "" {
219+
re := regexp.MustCompile(`(\s?password=([^"\s]+|"[^"]+"))`)
220+
stripped := re.ReplaceAllString(dsn, " password=PASSWORD_REMOVED")
221+
return strings.TrimSpace(stripped)
222+
}
223+
215224
// Blank user info if not nil
216225
if pDSN.User != nil {
217226
pDSN.User = url.UserPassword(pDSN.User.Username(), "PASSWORD_REMOVED")
218227
}
219228

229+
// If the password is contained in a URL parameter, we should remove it there
230+
if q, err := url.ParseQuery(pDSN.RawQuery); err == nil && q.Has("password") {
231+
q.Set("password", "PASSWORD_REMOVED")
232+
pDSN.RawQuery = q.Encode()
233+
}
234+
220235
return pDSN.String()
221236
}

Diff for: cmd/postgres_exporter/util_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2021 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package main
15+
16+
import (
17+
. "gopkg.in/check.v1"
18+
)
19+
20+
func (s *FunctionalSuite) TestLoggableDSN(c *C) {
21+
type TestCase struct {
22+
input string
23+
expected string
24+
}
25+
26+
cases := []TestCase{
27+
{
28+
input: "host=host.example.com user=postgres port=5432 password=s3cr3t",
29+
expected: "host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
30+
},
31+
32+
{
33+
input: "host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
34+
expected: "host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
35+
},
36+
37+
{
38+
input: "password=abcde host=host.example.com user=postgres port=5432",
39+
expected: "password=PASSWORD_REMOVED host=host.example.com user=postgres port=5432",
40+
},
41+
42+
{
43+
input: "password=abcde host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
44+
expected: "password=PASSWORD_REMOVED host=host.example.com user=postgres port=5432 password=PASSWORD_REMOVED",
45+
},
46+
47+
{
48+
input: "postgresql://host.example.com:5432/tsdb?user=postgres",
49+
expected: "postgresql://host.example.com:5432/tsdb?user=postgres",
50+
},
51+
52+
{
53+
input: "postgresql://user:[email protected]:5432/tsdb?user=postgres",
54+
expected: "postgresql://user:[email protected]:5432/tsdb?user=postgres",
55+
},
56+
57+
{
58+
input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t",
59+
expected: "postgresql://host.example.com:5432/tsdb?password=PASSWORD_REMOVED&user=postgres",
60+
},
61+
62+
{
63+
input: "host=host.example.com user=postgres port=5432",
64+
expected: "host=host.example.com user=postgres port=5432",
65+
},
66+
}
67+
68+
for _, cs := range cases {
69+
loggable := loggableDSN(cs.input)
70+
c.Assert(loggable, Equals, cs.expected)
71+
}
72+
73+
}

0 commit comments

Comments
 (0)