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>
This commit is contained in:
Johannes Schindelin
2025-11-26 18:47:19 +01:00
committed by Git for Windows Build Agent
parent fafbc95752
commit 373fc5b97b
3 changed files with 25 additions and 6 deletions

View File

@@ -231,6 +231,11 @@ http.sslKeyType::
See also libcurl `CURLOPT_SSLKEYTYPE`. Can be overridden by the
`GIT_SSL_KEY_TYPE` environment variable.
http.allowNTLMAuth::
Whether or not to allow NTLM authentication. While very convenient to set
up, and therefore still used in many on-prem scenarios, NTLM is a weak
authentication method and therefore deprecated. Defaults to "false".
http.schannelCheckRevoke::
Used to enforce or disable certificate revocation checks in cURL
when http.sslBackend is set to "schannel". Defaults to `true` if

20
http.c
View File

@@ -131,7 +131,8 @@ enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
static struct credential cert_auth = CREDENTIAL_INIT;
static int ssl_cert_password_required;
static unsigned long http_auth_methods = CURLAUTH_ANY;
static unsigned long http_auth_any = CURLAUTH_ANY & ~CURLAUTH_NTLM;
static unsigned long http_auth_methods;
static int http_auth_methods_restricted;
/* Modes for which empty_auth cannot actually help us. */
static unsigned long empty_auth_useless =
@@ -429,6 +430,15 @@ static int http_options(const char *var, const char *value,
return 0;
}
if (!strcmp("http.allowntlmauth", var)) {
if (git_config_bool(var, value)) {
http_auth_any |= CURLAUTH_NTLM;
} else {
http_auth_any &= ~CURLAUTH_NTLM;
}
return 0;
}
if (!strcmp("http.schannelcheckrevoke", var)) {
http_schannel_check_revoke = git_config_bool(var, value);
return 0;
@@ -709,11 +719,11 @@ static void init_curl_proxy_auth(CURL *result)
if (i == ARRAY_SIZE(proxy_authmethods)) {
warning("unsupported proxy authentication method %s: using anyauth",
http_proxy_authmethod);
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
}
}
else
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
curl_easy_setopt(result, CURLOPT_PROXYAUTH, http_auth_any);
}
static int has_cert_password(void)
@@ -1060,7 +1070,7 @@ static CURL *get_curl_handle(void)
}
curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(result, CURLOPT_HTTPAUTH, http_auth_any);
#ifdef CURLGSSAPI_DELEGATION_FLAG
if (curl_deleg) {
@@ -1448,6 +1458,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
set_long_from_env(&http_max_retries, "GIT_HTTP_MAX_RETRIES");
set_long_from_env(&http_max_retry_time, "GIT_HTTP_MAX_RETRY_TIME");
http_auth_methods = http_auth_any;
curl_default = get_curl_handle();
}

View File

@@ -730,8 +730,10 @@ test_expect_success NTLM 'access using NTLM auth' '
EOF
test_config_global credential.helper test-helper &&
GIT_TRACE_CURL=1 \
git ls-remote "$HTTPD_URL/ntlm_auth/repo.git"
test_must_fail env GIT_TRACE_CURL=1 git \
ls-remote "$HTTPD_URL/ntlm_auth/repo.git" &&
GIT_TRACE_CURL=1 git -c http.$HTTPD_URL.allowNTLMAuth=true \
ls-remote "$HTTPD_URL/ntlm_auth/repo.git"
'
test_done