Git Credential Manager 凭据存储(Credential Stores)完全指南:八大存储后端的选择、配置与底层实现
2026/9/16 18:44:16 网站建设 项目流程

Git Credential Manager 凭据存储(Credential Stores)完全指南:八大存储后端的选择、配置与底层实现

【免费下载链接】git-credential-managerSecure, cross-platform Git credential storage with authentication to GitHub, Azure Repos, and other popular Git hosting services.项目地址: https://gitcode.com/GitHub_Trending/gi/git-credential-manager

Git Credential Manager(GCM)为 Windows、macOS 与 Linux 提供了多种凭据存储后端(Credential Store),用于安全保存访问 GitHub、Azure Repos、GitLab、Bitbucket 等远程仓库所需的用户名与令牌。本文以 docs/credstores.md 为主干,逐一讲解八大存储后端的适用平台、配置命令、默认路径、限制条件,并结合本仓库源码(如 CredentialStore.cs、PlaintextCredentialStore.cs、GpgPassCredentialStore.cs 等)剖析其底层实现原理。读完本文,你将能够根据操作系统与安全需求,正确选择并配置 GCM 的凭据存储方案,并理解无头(headless)环境下 GPG/Secret Service 等后端的排障要点。

一、凭据存储后端总览

GCM 共支持八种凭据存储选项:

后端标识名称可用平台是否默认
wincredmanWindows Credential ManagerWindowsWindows 默认
dpapiDPAPI 保护文件Windows
keychainmacOS KeychainmacOSmacOS 默认
secretservicefreedesktop.org Secret Service APILinux
gpgGPG /pass兼容文件macOS、Linux
cacheGit 内置 credential cachemacOS、Linux
plaintext明文文件Windows、macOS、Linux
none透传/空操作(不存储)Windows、macOS、Linux

默认值规则:macOS 与 Windows 的默认存储分别是 macOS Keychain 与 Windows Credential Manager;而GCM 在 Linux 发行版上没有默认存储后端——这意味着在 Linux 上你必须显式配置GCM_CREDENTIAL_STOREcredential.credentialStore,否则 GCM 无法持久化凭据。

这一默认逻辑在源码中有清晰体现:CredentialStore.cs 的GetDefaultStore()方法:

private static string GetDefaultStore() { if (PlatformUtils.IsWindows()) return StoreNames.WindowsCredentialManager; if (PlatformUtils.IsMacOS()) return StoreNames.MacOSKeychain; // Other platforms have no default store return null; }

存储后端的合法标识在 Constants.cs 的CredentialStoreNames中集中定义:wincredmandpapikeychaingpgsecretserviceplaintextcachenone

如何选择存储后端

通过设置环境变量GCM_CREDENTIAL_STOREGit 配置项credential.credentialStore即可选择后端,两者二选一即可(环境变量优先于 Git 配置,见 Settings.cs 中CredentialBackingStore属性对TryGetSetting的调用顺序)。例如:

git config --global credential.credentialStore gpg

后端分发与平台校验的底层实现

所有后端统一实现ICredentialStore接口(Get/GetAccounts/AddOrUpdate/Remove),由门面类 CredentialStore.cs 的EnsureBackingStore()根据所选名称懒加载对应实现,并对平台适配性做前置校验:

  • wincredman:仅限 Windows,且要求当前登录会话允许持久化(WindowsCredentialManager.CanPersist(),见下文)。
  • dpapi:仅限 Windows;默认存储根目录为%USERPROFILE%\.gcm\dpapi_store,可用GCM_DPAPI_STORE_PATH环境变量或credential.dpapiStorePathGit 配置覆盖。
  • keychain:仅限 macOS。
  • secretservice:仅限 Linux,且要求当前为图形会话(IsDesktopSession)。
  • gpg:仅限 POSIX(macOS/Linux);headless 环境下要求设置GPG_TTYSSH_TTY,否则直接报错。
  • cache不可用于 Windows(Git for Windows 缺乏 UNIX socket 支持),并读取GCM_CREDENTIAL_CACHE_OPTIONS/credential.cacheOptions作为附加参数。
  • plaintext:全平台可用,无平台限制。
  • none:全平台可用,直接返回NullCredentialStore空操作实现。

若配置了未知的后端名称,GCM 会抛出异常,并在错误信息中列出当前平台所有可用的后端清单(见AppendAvailableStoreList)。

二、Windows Credential Manager(wincredman

可用平台:Windows默认状态:Windows 上的默认存储后端。⚠️ 限制:在通过网络/SSH 会话连接到 Windows 机器时无法工作

SET GCM_CREDENTIAL_STORE="wincredman"

git config --global credential.credentialStore wincredman

实现原理

该后端使用 Windows 凭据 API(wincred.h)将数据安全地存入 Windows Credential Manager(早期 Windows 版本中也称为 Windows Credential Vault)。对应实现为 WindowsCredentialManager.cs,它通过 P/Invoke 调用Advapi32中的CredReadCredWriteCredEnumerateCredDelete等原生 API 完成凭据增删改查。

你可以通过控制面板的"凭据管理器",或使用cmdkey命令行工具访问和管理其中的数据。

为什么网络/SSH 会话下不可用

当通过 SSH 等网络会话连接 Windows 机器时,GCM 无法将凭据持久化到 Windows Credential Manager,这是 Windows 系统本身的限制;通过远程桌面(Remote Desktop)连接则不受此限制。源码层面,CredentialStore.cs 在加载该后端前会调用WindowsCredentialManager.CanPersist(),其实现(WindowsCredentialManager.cs)通过CredGetSessionTypes查询当前会话允许的持久化级别:

public static bool CanPersist() { uint count = Advapi32.CRED_TYPE_MAXIMUM; var arr = new CredentialPersist[count]; int result = Win32Error.GetLastError(Advapi32.CredGetSessionTypes(count, arr)); CredentialPersist persist = CredentialPersist.None; if (result == Win32Error.Success) { persist = arr[(int)CredentialType.Generic]; } // If the maximum allowed is anything less than "local machine" then cannot persist credentials. return persist >= CredentialPersist.LocalMachine; }

即当会话类型不支持持久化到"本机"级别时,GCM 会判定无法使用该后端并抛出错误。这类场景下,可改用下一节的 DPAPI 文件存储。

三、DPAPI 保护文件(dpapi

可用平台:Windows

SET GCM_CREDENTIAL_STORE="dpapi"

git config --global credential.credentialStore dpapi

文件结构与加密方式

该后端使用 Windows DPAPI 加密凭据,并将其以文件形式保存在文件系统中。文件结构与后面的明文文件后端一致,唯一区别是第一行(即秘密值)受 DPAPI 保护:写入时先用ProtectedData.Protect(plainBytes, null, DataProtectionScope.CurrentUser)加密再 Base64 编码,读取时反向用ProtectedData.Unprotect解密(见 DpapiCredentialStore.cs)。

一个典型文件内容如下(第一行为 Base64 密文,后续行为元数据):

<base64-encoded-DPAPI-ciphertext> service=https://github.com account=octocat

DataProtectionScope.CurrentUser意味着密文只能由加密它的同一个 Windows 用户解密,其他用户即使拿到文件也无法还原明文。

存储路径与目录自动创建

默认文件存放在%USERPROFILE%\.gcm\dpapi_store,可通过环境变量GCM_DPAPI_STORE_PATH(或 Git 配置credential.dpapiStorePath)修改。若目录不存在,GCM 会自动创建(CredentialStore.cs 的ValidateDpapi负责解析路径,目录创建由文件系统操作完成)。相比 wincredman,DPAPI 文件后端不依赖会话持久化能力,可作为网络会话场景的替代方案。

四、macOS Keychain(keychain

可用平台:macOS默认状态:macOS 上的默认存储后端。

export GCM_CREDENTIAL_STORE=keychain # 或 git config --global credential.credentialStore keychain

实现原理

该后端使用 macOS 默认钥匙串(Keychain),通常是login钥匙串。实现位于 MacOSKeychain.cs,通过 P/Invoke 调用 Security Framework(SecurityFramework.cs)中的SecItemAddSecItemCopyMatchingSecItemUpdateSecItemDelete等 API 操作钥匙串条目。

你可以使用"钥匙串访问"(Keychain Access)应用管理其中存储的数据。若在 macOS 上遇到钥匙串权限弹窗,允许 GCM 访问login钥匙串即可正常工作。

五、freedesktop.org Secret Service API(secretservice

可用平台:Linux⚠️ 限制:需要图形用户界面(GUI)会话

export GCM_CREDENTIAL_STORE=secretservice # 或 git config --global credential.credentialStore secretservice

实现原理

该后端通过libsecret库与系统的 Secret Service 守护进程交互(实现见 SecretServiceCollection.cs 及其 P/Invoke 绑定 Libsecret.cs、Glib.cs、Gobject.cs),将凭据安全地存储在 Secret Service 的"集合"(collections)中。在 GNOME 桌面(gnome-keyring)与 KDE(KWallet)等环境中均有 Secret Service 实现,用户可以使用secret-toolseahorse等工具查看这些凭据。

GCM 使用的 schema 名为com.microsoft.GitCredentialManager,通过serviceaccount两个字符串属性索引凭据;写入时调用secret_service_store_sync,查询时调用secret_service_search_sync,删除时调用secret_service_clear_sync(并处理 collection 被锁定时的自动解锁流程)。

为什么需要图形会话

当 Secret Service 集合处于锁定状态时,需要弹出图形化的安全提示框请求用户解锁集合。因此若当前是纯 TTY/无桌面会话,GCM 会在加载该后端时直接拒绝——CredentialStore.cs 的ValidateSecretService会检查_context.SessionManager.IsDesktopSession,非桌面会话即抛出 "Cannot use the 'secretservice' credential backing store without a graphical interface present."。这正是 headless 场景下应改用gpg后端的原因。

六、GPG /pass兼容文件(gpg

可用平台:macOS、Linux⚠️ 前置条件:需要gpgpass以及一对有效的 GPG 密钥。

export GCM_CREDENTIAL_STORE=gpg # 或 git config --global credential.credentialStore gpg

初始化pass存储

该后端使用 GPG 加密包含凭据的文件,文件结构兼容流行的pass工具。使用前必须先用pass工具初始化存储,而初始化又需要有效的 GPG 密钥对:

pass init <gpg-id>

其中<gpg-id>是系统上某对 GPG 密钥的用户 ID。若还没有密钥对,先执行:

gpg --gen-key

按提示完成创建后再执行pass init

实现原理与文件布局

实现位于 GpgPassCredentialStore.cs,它继承明文文件后端的目录结构逻辑,但:

  • 文件扩展名为.gpg(而非.credential),内容整体经 GPG 加密;
  • 加密前,先把密码放在第一行,后续行写入service=account=元数据,再整体交给 Gpg.cs 执行gpg --encrypt --batch --recipient "<gpg-id>" --output "<path>";读取时执行gpg --batch --decrypt "<path>"还原明文再解析;
  • 通过沿目录层级向上查找最近的.gpg-id文件来确定加密所用的收件人(recipient),这与 GNU Pass 的行为一致(GpgPassCredentialStore.cs)。若在存储根目录也找不到.gpg-id,会抛出提示 "runpass init <gpg-id>to initialize the store"。

默认文件存放在~/.password-store,可通过pass的环境变量PASSWORD_STORE_DIR(或 Git 配置credential.gpgPassStorePath)修改。注意 GCM 会优先使用gpg2(若 PATH 中存在),否则回退到gpg;也可以用GCM_GPG_PATH环境变量显式指定 GPG 可执行文件路径(CredentialStore.cs)。

上述行为均有测试覆盖,例如 GnuPassCredentialStoreTests.cs 验证了凭据文件路径形如namespace/https/example.com/<uuid>/<username>.gpg.gpg-id向上逐级查找、以及不同子目录各自持有独立.gpg-id时按最近者加密的行为。

Headless / 纯 TTY 会话

在无图形界面的 headless/TTY 环境中使用gpg后端,必须为 GPG Agent(gpg-agent)配置合适的终端 pin-entry 程序,例如pinentry-ttypinentry-curses

  • 若通过 SSH 连接系统,SSH_TTY变量通常会被自动设置。GCM 会把SSH_TTY的值作为 TTY 设备传给 GPG/GPG Agent 用于输入口令(见 Gpg.cs 的PrepareEnvironment:headless 会话下若未显式设置GPG_TTY而存在SSH_TTY,则用SSH_TTY填充子进程的GPG_TTY)。
  • 若并非通过 SSH 连接,或未设置SSH_TTY,则必须在运行 GCM 之前设置GPG_TTY环境变量。最简单的方法是在 profile(~/.bashrc~/.profile等)中加入:
export GPG_TTY=$(tty)

注意:这里不能使用/dev/tty,必须使用tty命令返回的真实 TTY 设备路径。另外,若在 headless 会话下GPG_TTYSSH_TTY均未设置,GCM 会在加载该后端时直接报错(提示添加export GPG_TTY=$(tty)到 profile),见 CredentialStore.cs。

七、Git 内置的凭据缓存(cache

可用平台:macOS、Linux(不可用于 Windows

export GCM_CREDENTIAL_STORE=cache # 或 git config --global credential.credentialStore cache

适用场景

该后端使用 Git 自带的易失性内存凭据缓存(git credential-cache)。它可以帮助你减少重复认证的次数,但不要求把凭据写入持久化存储,非常适合 Azure Cloud Shell 或 AWS CloudShell 这类场景——既不想在磁盘上留下凭据,又不希望在每次 Git 操作时重新认证。

缓存时长与自定义选项

默认情况下git credential-cache会将凭据缓存900 秒(15 分钟)。该时长以及其他 git-credential-cache 支持的全部选项,可以通过环境变量GCM_CREDENTIAL_CACHE_OPTIONS或 Git 配置credential.cacheOptions修改(例如--timeout;文档同时提示--socket选项虽未经测试与官方支持,但理论上没有不工作的理由):

export GCM_CREDENTIAL_CACHE_OPTIONS="--timeout 300" # 或 git config --global credential.cacheOptions "--timeout 300"

实现原理

实现位于 CredentialCacheStore.cs,它本质上是把操作转发给 Git 自身:通过git.InvokeHelperAsync依次调用git credential-cache storegit credential-cache getgit credential-cache erase,并把配置好的_options追加到命令尾部。由于依赖 Git for Windows 的 UNIX socket 支持,该后端在 Windows 上不可用(CredentialStore.cs)。此外,缓存后端不支持枚举账号列表,GetAccounts只能尽力返回首个凭据的用户名或空列表。

八、明文文件(plaintext

可用平台:Windows、macOS、Linux⚠️ 警告:这不是一种安全的凭据存储方式!

export GCM_CREDENTIAL_STORE=plaintext # 或 git config --global credential.credentialStore plaintext

文件格式与默认路径

该后端将凭据以明文文件形式保存在文件系统中。默认存放于~/.gcm/store(macOS/Linux)或%USERPROFILE%\.gcm\store(Windows),可通过环境变量GCM_PLAINTEXT_STORE_PATH(或 Git 配置credential.plaintextStorePath)修改。目录不存在时会自动创建。

文件采用"密码首行 + 元数据行"的格式,一个账户对应一个以.credential结尾的文件(见 PlaintextCredentialStore.cs 的SerializeCredential):

my-secret-password service=https://github.com account=octocat

服务名会被转换为目录层级(形如https/github.com/<路径>),账户名作为文件名;同名同值写入会被跳过,避免无谓的磁盘 I/O。

POSIX 权限处理

在 POSIX 平台上,新建的存储目录会被设置为仅属主可读写执行(700drwx------),已有目录的权限则不会被修改(PlaintextCredentialStore.cs 的EnsureStoreRoot,通过chmod设置S_IRUSR | S_IWUSR | S_IXUSR)。

与 git-credential-store 的区别

GCM 的明文存储与 Git 自带的 git-credential-store 是两个不同的实现,尽管文件格式相似,默认路径也不同(GCM 用~/.gcm/store,git-credential-store 默认用~/.git-credentials)。

⚠️ 严重安全警告

此存储机制不安全!秘密与凭据以明文文件保存,不带任何安全保护!

强烈建议始终使用上述其他存储后端之一。该选项仅用于兼容性,以及在没有其他安全方案可用的环境中。

如果确实要使用该后端,强烈建议:把目录权限设置为禁止其他用户或应用访问;如果可能,将路径放在随身携带的外部卷上,并使用全盘加密。

九、Passthrough / 空操作(none

可用平台:Windows、macOS、Linux

SET GCM_CREDENTIAL_STORE="none"

git config --global credential.credentialStore none

用途与注意事项

该选项禁用 GCM 内部凭据存储:所有存储或检索凭据的操作都不做任何事并直接返回成功(对应实现为 NullCredentialStore.cs)。典型用途是:你希望使用另一个凭据存储,通过 Git 配置按顺序链式组合多个 credential helper,而不想让 GCM 自己存凭据。

注意:使用该选项时,务必确保另一个 credential helper 在 Git 配置credential.helper中排在 GCM之前,否则每次与远程仓库交互时你都会被提示输入凭据(因为 GCM 既不存储也不返回凭据,前面的 helper 又拿不到结果时,Git 只能回退到交互式提示)。

十、相关文档与源码指引

  • 配置项参考:configuration.md(含credential.credentialStore等 Git 配置键说明)
  • 环境变量参考:environment.md(含GCM_CREDENTIAL_STOREGCM_DPAPI_STORE_PATHGCM_PLAINTEXT_STORE_PATHGCM_CREDENTIAL_CACHE_OPTIONSGCM_GPG_PATH等)
  • 后端分发与默认值:src/shared/Core/CredentialStore.cs
  • 存储名与环境变量常量:src/shared/Core/Constants.cs
  • 明文文件实现:src/shared/Core/PlaintextCredentialStore.cs
  • DPAPI 实现:src/shared/Core/Interop/Windows/DpapiCredentialStore.cs
  • Secret Service 实现:src/shared/Core/Interop/Linux/SecretServiceCollection.cs
  • GPG/pass 实现:src/shared/Core/Interop/Posix/GpgPassCredentialStore.cs、src/shared/Core/Gpg.cs
  • 缓存实现:src/shared/Core/CredentialCacheStore.cs
  • 相关测试:GnuPassCredentialStoreTests.cs、DpapiCredentialStoreTests.cs

选择建议速查:日常桌面环境 Windows 用默认的wincredman、macOS 用默认的keychain、Linux 桌面用secretservice;SSH 远程会话连 Windows 用dpapi;无图形界面的 Linux/macOS 服务器用gpg(记得配好GPG_TTY);云 Shell 等临时环境用cache;除非万不得已,永远不要用plaintext

【免费下载链接】git-credential-managerSecure, cross-platform Git credential storage with authentication to GitHub, Azure Repos, and other popular Git hosting services.项目地址: https://gitcode.com/GitHub_Trending/gi/git-credential-manager

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询