ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

Git Credential Manager 凭据存储(Credential Stores)完全指南:八大存储后端的选择、配置与底层实现 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-managerGit Credential ManagerGCM为 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_STORE或credential.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中集中定义wincredman、dpapi、keychain、gpg、secretservice、plaintext、cache、none。如何选择存储后端通过设置环境变量GCM_CREDENTIAL_STORE或Git 配置项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仅限 POSIXmacOS/Linuxheadless 环境下要求设置GPG_TTY或SSH_TTY否则直接报错。cache不可用于 WindowsGit for Windows 缺乏 UNIX socket 支持并读取GCM_CREDENTIAL_CACHE_OPTIONS/credential.cacheOptions作为附加参数。plaintext全平台可用无平台限制。none全平台可用直接返回NullCredentialStore空操作实现。若配置了未知的后端名称GCM 会抛出异常并在错误信息中列出当前平台所有可用的后端清单见AppendAvailableStoreList。二、Windows Credential Managerwincredman可用平台Windows默认状态Windows 上的默认存储后端。⚠️ 限制在通过网络/SSH 会话连接到 Windows 机器时无法工作。SET GCM_CREDENTIAL_STOREwincredman或git config --global credential.credentialStore wincredman实现原理该后端使用 Windows 凭据 APIwincred.h将数据安全地存入 Windows Credential Manager早期 Windows 版本中也称为 Windows Credential Vault。对应实现为 WindowsCredentialManager.cs它通过 P/Invoke 调用Advapi32中的CredRead、CredWrite、CredEnumerate、CredDelete等原生 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可用平台WindowsSET GCM_CREDENTIAL_STOREdpapi或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 servicehttps://github.com accountoctocatDataProtectionScope.CurrentUser意味着密文只能由加密它的同一个 Windows 用户解密其他用户即使拿到文件也无法还原明文。存储路径与目录自动创建默认文件存放在%USERPROFILE%\.gcm\dpapi_store可通过环境变量GCM_DPAPI_STORE_PATH或 Git 配置credential.dpapiStorePath修改。若目录不存在GCM 会自动创建CredentialStore.cs 的ValidateDpapi负责解析路径目录创建由文件系统操作完成。相比 wincredmanDPAPI 文件后端不依赖会话持久化能力可作为网络会话场景的替代方案。四、macOS Keychainkeychain可用平台macOS默认状态macOS 上的默认存储后端。export GCM_CREDENTIAL_STOREkeychain # 或 git config --global credential.credentialStore keychain实现原理该后端使用 macOS 默认钥匙串Keychain通常是login钥匙串。实现位于 MacOSKeychain.cs通过 P/Invoke 调用 Security FrameworkSecurityFramework.cs中的SecItemAdd、SecItemCopyMatching、SecItemUpdate、SecItemDelete等 API 操作钥匙串条目。你可以使用钥匙串访问Keychain Access应用管理其中存储的数据。若在 macOS 上遇到钥匙串权限弹窗允许 GCM 访问login钥匙串即可正常工作。五、freedesktop.org Secret Service APIsecretservice可用平台Linux⚠️ 限制需要图形用户界面GUI会话。export GCM_CREDENTIAL_STOREsecretservice # 或 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与 KDEKWallet等环境中均有 Secret Service 实现用户可以使用secret-tool、seahorse等工具查看这些凭据。GCM 使用的 schema 名为com.microsoft.GitCredentialManager通过service与account两个字符串属性索引凭据写入时调用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⚠️ 前置条件需要gpg、pass以及一对有效的 GPG 密钥。export GCM_CREDENTIAL_STOREgpg # 或 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-idto 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 Agentgpg-agent配置合适的终端 pin-entry 程序例如pinentry-tty或pinentry-curses。若通过 SSH 连接系统SSH_TTY变量通常会被自动设置。GCM 会把SSH_TTY的值作为 TTY 设备传给 GPG/GPG Agent 用于输入口令见 Gpg.cs 的PrepareEnvironmentheadless 会话下若未显式设置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_TTY与SSH_TTY均未设置GCM 会在加载该后端时直接报错提示添加export GPG_TTY$(tty)到 profile见 CredentialStore.cs。七、Git 内置的凭据缓存cache可用平台macOS、Linux不可用于 Windowsexport GCM_CREDENTIAL_STOREcache # 或 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 store、git credential-cache get、git credential-cache erase并把配置好的_options追加到命令尾部。由于依赖 Git for Windows 的 UNIX socket 支持该后端在 Windows 上不可用CredentialStore.cs。此外缓存后端不支持枚举账号列表GetAccounts只能尽力返回首个凭据的用户名或空列表。八、明文文件plaintext可用平台Windows、macOS、Linux⚠️ 警告这不是一种安全的凭据存储方式export GCM_CREDENTIAL_STOREplaintext # 或 git config --global credential.credentialStore plaintext文件格式与默认路径该后端将凭据以明文文件形式保存在文件系统中。默认存放于~/.gcm/storemacOS/Linux或%USERPROFILE%\.gcm\storeWindows可通过环境变量GCM_PLAINTEXT_STORE_PATH或 Git 配置credential.plaintextStorePath修改。目录不存在时会自动创建。文件采用密码首行 元数据行的格式一个账户对应一个以.credential结尾的文件见 PlaintextCredentialStore.cs 的SerializeCredentialmy-secret-password servicehttps://github.com accountoctocat服务名会被转换为目录层级形如https/github.com/路径账户名作为文件名同名同值写入会被跳过避免无谓的磁盘 I/O。POSIX 权限处理在 POSIX 平台上新建的存储目录会被设置为仅属主可读写执行700或drwx------已有目录的权限则不会被修改PlaintextCredentialStore.cs 的EnsureStoreRoot通过chmod设置S_IRUSR | S_IWUSR | S_IXUSR。与 git-credential-store 的区别GCM 的明文存储与 Git 自带的 git-credential-store 是两个不同的实现尽管文件格式相似默认路径也不同GCM 用~/.gcm/storegit-credential-store 默认用~/.git-credentials。⚠️ 严重安全警告此存储机制不安全秘密与凭据以明文文件保存不带任何安全保护强烈建议始终使用上述其他存储后端之一。该选项仅用于兼容性以及在没有其他安全方案可用的环境中。如果确实要使用该后端强烈建议把目录权限设置为禁止其他用户或应用访问如果可能将路径放在随身携带的外部卷上并使用全盘加密。九、Passthrough / 空操作none可用平台Windows、macOS、LinuxSET GCM_CREDENTIAL_STOREnone或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_STORE、GCM_DPAPI_STORE_PATH、GCM_PLAINTEXT_STORE_PATH、GCM_CREDENTIAL_CACHE_OPTIONS、GCM_GPG_PATH等后端分发与默认值src/shared/Core/CredentialStore.cs存储名与环境变量常量src/shared/Core/Constants.cs明文文件实现src/shared/Core/PlaintextCredentialStore.csDPAPI 实现src/shared/Core/Interop/Windows/DpapiCredentialStore.csSecret Service 实现src/shared/Core/Interop/Linux/SecretServiceCollection.csGPG/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 桌面用secretserviceSSH 远程会话连 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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进