diff mbox series

http: redact all cookies, teach GIT_TRACE_REDACT=0

Message ID 20200605212136.227468-1-jonathantanmy@google.com (mailing list archive)
State New, archived
Headers show
Series http: redact all cookies, teach GIT_TRACE_REDACT=0 | expand

Commit Message

Jonathan Tan June 5, 2020, 9:21 p.m. UTC
In trace output (when GIT_TRACE_CURL is true), redact the values of all
HTTP cookies by default. Now that auth headers (since the implementation
of GIT_TRACE_CURL in 74c682d3c6 ("http.c: implement the GIT_TRACE_CURL
environment variable", 2016-05-24)) and cookie values (since this
commit) are redacted by default in these traces, also allow the user to
inhibit these redactions through an environment variable.

Since values of all cookies are now redacted by default,
GIT_REDACT_COOKIES (which previously allowed users to select individual
cookies to redact) now has no effect.

Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
---
This is on jt/curl-verbose-on-trace-curl.

Thanks, Junio, for the reminder in What's Cooking.

This is a followup from this email thread:
https://lore.kernel.org/git/cover.1589218693.git.jonathantanmy@google.com/

I took a look at transport_anonymize_url() as requested in [1], which
indeed appears in user-visible output (and could conceivably be used in
debugging). It can be done (just be careful about the different uses -
send-pack uses it to make a push cert, so that can't be changed, but we
can change it when it is used to print a message for the user). But it
doesn't seem useful to me (for HTTP(S), we would be better off looking
at the Authorization header, I think, and for SSH, the password is
either wrong or correct, so I don't think that there is much Git-related
stuff to debug), and I can't think of a good name to give the
environment variable that controls all these. (Right now we have
GIT_TRACE_REDACT, which makes sense because we are redacting a trace.
GIT_HTTP_REDACT would work too, because everything we're redacting is
HTTP-related. But the URL is neither HTTP-specific nor trace-specific.)

Having said that, if we want one single environment variable to redact
everything, it's probably best to do it now. It would be unexpected if
an environment variable suddenly also controls redaction of the URL.

[1] https://lore.kernel.org/git/xmqqlflvtysu.fsf@gitster.c.googlers.com/
---
 Documentation/git.txt       |  9 ++++-----
 http.c                      | 35 +++++++++++-----------------------
 t/t5551-http-fetch-smart.sh | 38 +++++++++++++++++++++++--------------
 3 files changed, 39 insertions(+), 43 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 427ea70701..d451f465dc 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -775,11 +775,10 @@  for full details.
 	See `GIT_TRACE2` for available trace output options and
 	link:technical/api-trace2.html[Trace2 documentation] for full details.
 
-`GIT_REDACT_COOKIES`::
-	This can be set to a comma-separated list of strings. When a curl trace
-	is enabled (see `GIT_TRACE_CURL` above), whenever a "Cookies:" header
-	sent by the client is dumped, values of cookies whose key is in that
-	list (case-sensitive) are redacted.
+`GIT_TRACE_REDACT`::
+	By default, when tracing is activated, Git redacts the values of
+	cookies, the "Authorization:" header, and the "Proxy-Authorization:"
+	header. Set this variable to `0` to prevent this redaction.
 
 `GIT_LITERAL_PATHSPECS`::
 	Setting this variable to `1` will cause Git to treat all
diff --git a/http.c b/http.c
index 4882c9f5b2..0eb1931a15 100644
--- a/http.c
+++ b/http.c
@@ -18,7 +18,7 @@ 
 
 static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
 static int trace_curl_data = 1;
-static struct string_list cookies_to_redact = STRING_LIST_INIT_DUP;
+static int trace_curl_redact = 1;
 #if LIBCURL_VERSION_NUM >= 0x070a08
 long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
 #else
@@ -642,8 +642,9 @@  static void redact_sensitive_header(struct strbuf *header)
 {
 	const char *sensitive_header;
 
-	if (skip_prefix(header->buf, "Authorization:", &sensitive_header) ||
-	    skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header)) {
+	if (trace_curl_redact &&
+	    (skip_prefix(header->buf, "Authorization:", &sensitive_header) ||
+	     skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header))) {
 		/* The first token is the type, which is OK to log */
 		while (isspace(*sensitive_header))
 			sensitive_header++;
@@ -652,20 +653,15 @@  static void redact_sensitive_header(struct strbuf *header)
 		/* Everything else is opaque and possibly sensitive */
 		strbuf_setlen(header,  sensitive_header - header->buf);
 		strbuf_addstr(header, " <redacted>");
-	} else if (cookies_to_redact.nr &&
+	} else if (trace_curl_redact &&
 		   skip_prefix(header->buf, "Cookie:", &sensitive_header)) {
 		struct strbuf redacted_header = STRBUF_INIT;
-		char *cookie;
+		const char *cookie;
 
 		while (isspace(*sensitive_header))
 			sensitive_header++;
 
-		/*
-		 * The contents of header starting from sensitive_header will
-		 * subsequently be overridden, so it is fine to mutate this
-		 * string (hence the assignment to "char *").
-		 */
-		cookie = (char *) sensitive_header;
+		cookie = sensitive_header;
 
 		while (cookie) {
 			char *equals;
@@ -678,14 +674,8 @@  static void redact_sensitive_header(struct strbuf *header)
 				strbuf_addstr(&redacted_header, cookie);
 				continue;
 			}
-			*equals = 0; /* temporarily set to NUL for lookup */
-			if (string_list_lookup(&cookies_to_redact, cookie)) {
-				strbuf_addstr(&redacted_header, cookie);
-				strbuf_addstr(&redacted_header, "=<redacted>");
-			} else {
-				*equals = '=';
-				strbuf_addstr(&redacted_header, cookie);
-			}
+			strbuf_add(&redacted_header, cookie, equals - cookie);
+			strbuf_addstr(&redacted_header, "=<redacted>");
 			if (semicolon) {
 				/*
 				 * There are more cookies. (Or, for some
@@ -1003,11 +993,8 @@  static CURL *get_curl_handle(void)
 	setup_curl_trace(result);
 	if (getenv("GIT_TRACE_CURL_NO_DATA"))
 		trace_curl_data = 0;
-	if (getenv("GIT_REDACT_COOKIES")) {
-		string_list_split(&cookies_to_redact,
-				  getenv("GIT_REDACT_COOKIES"), ',', -1);
-		string_list_sort(&cookies_to_redact);
-	}
+	if (!git_env_bool("GIT_TRACE_REDACT", 1))
+		trace_curl_redact = 0;
 
 	curl_easy_setopt(result, CURLOPT_USERAGENT,
 		user_agent ? user_agent : git_user_agent());
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index be01cf7bb2..e40e9ed52f 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -209,6 +209,16 @@  test_expect_success 'GIT_CURL_VERBOSE redacts auth details' '
 	grep "Authorization: Basic <redacted>" trace
 '
 
+test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_REDACT=0' '
+	rm -rf redact-auth trace &&
+	set_askpass user@host pass@host &&
+	GIT_TRACE_REDACT=0 GIT_TRACE_CURL="$(pwd)/trace" \
+		git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
+	expect_askpass both user@host &&
+
+	grep "Authorization: Basic [0-9a-zA-Z+/]" trace
+'
+
 test_expect_success 'disable dumb http on server' '
 	git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
 		config http.getanyfile false
@@ -454,37 +464,37 @@  test_expect_success 'fetch by SHA-1 without tag following' '
 		--no-tags origin $(cat bar_hash)
 '
 
-test_expect_success 'GIT_REDACT_COOKIES redacts cookies' '
+test_expect_success 'cookies are redacted by default' '
 	rm -rf clone &&
 	echo "Set-Cookie: Foo=1" >cookies &&
 	echo "Set-Cookie: Bar=2" >>cookies &&
-	GIT_TRACE_CURL=true GIT_REDACT_COOKIES=Bar,Baz \
+	GIT_TRACE_CURL=true \
 		git -c "http.cookieFile=$(pwd)/cookies" clone \
 		$HTTPD_URL/smart/repo.git clone 2>err &&
-	grep "Cookie:.*Foo=1" err &&
+	grep "Cookie:.*Foo=<redacted>" err &&
 	grep "Cookie:.*Bar=<redacted>" err &&
+	! grep "Cookie:.*Foo=1" err &&
 	! grep "Cookie:.*Bar=2" err
 '
 
-test_expect_success 'GIT_REDACT_COOKIES redacts cookies when GIT_CURL_VERBOSE=1' '
+test_expect_success 'empty values of cookies are also redacted' '
 	rm -rf clone &&
-	echo "Set-Cookie: Foo=1" >cookies &&
-	echo "Set-Cookie: Bar=2" >>cookies &&
-	GIT_CURL_VERBOSE=1 GIT_REDACT_COOKIES=Bar,Baz \
+	echo "Set-Cookie: Foo=" >cookies &&
+	GIT_TRACE_CURL=true \
 		git -c "http.cookieFile=$(pwd)/cookies" clone \
 		$HTTPD_URL/smart/repo.git clone 2>err &&
-	grep "Cookie:.*Foo=1" err &&
-	grep "Cookie:.*Bar=<redacted>" err &&
-	! grep "Cookie:.*Bar=2" err
+	grep "Cookie:.*Foo=<redacted>" err
 '
 
-test_expect_success 'GIT_REDACT_COOKIES handles empty values' '
+test_expect_success 'GIT_TRACE_REDACT=0 disables cookie redaction' '
 	rm -rf clone &&
-	echo "Set-Cookie: Foo=" >cookies &&
-	GIT_TRACE_CURL=true GIT_REDACT_COOKIES=Foo \
+	echo "Set-Cookie: Foo=1" >cookies &&
+	echo "Set-Cookie: Bar=2" >>cookies &&
+	GIT_TRACE_REDACT=0 GIT_TRACE_CURL=true \
 		git -c "http.cookieFile=$(pwd)/cookies" clone \
 		$HTTPD_URL/smart/repo.git clone 2>err &&
-	grep "Cookie:.*Foo=<redacted>" err
+	grep "Cookie:.*Foo=1" err &&
+	grep "Cookie:.*Bar=2" err
 '
 
 test_expect_success 'GIT_TRACE_CURL_NO_DATA prevents data from being traced' '