Skip to content

Commit 4d5ffd2

Browse files
committed
http: disallow NTLM authentication by default
NTLM authentication is relatively weak. This is the case even with the default setting of modern Windows versions, where NTLMv1 and LanManager are disabled and only NTLMv2 is enabled: NTLMv2 hashes of even reasonably complex 8-character passwords can be broken in a matter of days, given enough compute resources. Even worse: On Windows, NTLM authentication uses Security Support Provider Interface ("SSPI"), which provides the credentials without requiring the user to type them in. Which means that an attacker could talk an unsuspecting user into cloning from a server that is under the attacker's control and extracts the user's NTLMv2 hash without their knowledge. For that reason, let's disallow NTLM authentication by default. NTLM authentication is quite simple to set up, though, and therefore there are still some on-prem Azure DevOps setups out there whose users and/or automation rely on this type of authentication. To give them an escape hatch, introduce the `http.<url>.allowNTLMAuth` config setting that can be set to `true` to opt back into using NTLM for a specific remote repository. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 50183db commit 4d5ffd2

3 files changed

Lines changed: 25 additions & 6 deletions

File tree

Documentation/config/http.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ http.sslBackend::
216216
This option is ignored if cURL lacks support for choosing the SSL
217217
backend at runtime.
218218

219+
http.allowNTLMAuth::
220+
Whether or not to allow NTLM authentication. While very convenient to set
221+
up, and therefore still used in many on-prem scenarios, NTLM is a weak
222+
authentication method and therefore deprecated. Defaults to "false".
223+
219224
http.schannelCheckRevoke::
220225
Used to enforce or disable certificate revocation checks in cURL
221226
when http.sslBackend is set to "schannel" via "true" and "false",

http.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
128128

129129
static struct credential cert_auth = CREDENTIAL_INIT;
130130
static int ssl_cert_password_required;
131-
static unsigned long http_auth_methods = CURLAUTH_ANY;
131+
static unsigned long http_auth_any = CURLAUTH_ANY & ~CURLAUTH_NTLM;
132+
static unsigned long http_auth_methods;
132133
static int http_auth_methods_restricted;
133134
/* Modes for which empty_auth cannot actually help us. */
134135
static unsigned long empty_auth_useless =
@@ -429,6 +430,15 @@ static int http_options(const char *var, const char *value,
429430
return 0;
430431
}
431432

433+
if (!strcmp("http.allowntlmauth", var)) {
434+
if (git_config_bool(var, value)) {
435+
http_auth_any |= CURLAUTH_NTLM;
436+
} else {
437+
http_auth_any &= ~CURLAUTH_NTLM;
438+
}
439+
return 0;
440+
}
441+
432442
if (!strcmp("http.schannelcheckrevoke", var)) {
433443
if (value && !strcmp(value, "best-effort")) {
434444
http_schannel_check_revoke_mode =
@@ -704,11 +714,11 @@ static void init_curl_proxy_auth(CURL *result)
704714
if (i == ARRAY_SIZE(proxy_authmethods)) {
705715
warning("unsupported proxy authentication method %s: using anyauth",
706716
http_proxy_authmethod);
707-
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
717+
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
708718
}
709719
}
710720
else
711-
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
721+
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
712722
}
713723

714724
static int has_cert_password(void)
@@ -1091,7 +1101,7 @@ static CURL *get_curl_handle(void)
10911101
#endif
10921102

10931103
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1094-
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1104+
curl_easy_setopt(result, CURLOPT_HTTPAUTH, http_auth_any);
10951105

10961106
#ifdef CURLGSSAPI_DELEGATION_FLAG
10971107
if (curl_deleg) {
@@ -1461,6 +1471,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
14611471
ssl_cert_password_required = 1;
14621472
}
14631473

1474+
http_auth_methods = http_auth_any;
1475+
14641476
curl_default = get_curl_handle();
14651477
}
14661478

t/t5563-simple-http-auth.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,8 +686,10 @@ test_expect_success NTLM 'access using NTLM auth' '
686686
EOF
687687
688688
test_config_global credential.helper test-helper &&
689-
GIT_TRACE_CURL=1 \
690-
git ls-remote "$HTTPD_URL/ntlm_auth/repo.git"
689+
test_must_fail env GIT_TRACE_CURL=1 git \
690+
ls-remote "$HTTPD_URL/ntlm_auth/repo.git" &&
691+
GIT_TRACE_CURL=1 git -c http.$HTTPD_URL.allowNTLMAuth=true \
692+
ls-remote "$HTTPD_URL/ntlm_auth/repo.git"
691693
'
692694

693695
test_done

0 commit comments

Comments
 (0)