GitHub密码认证淘汰后,如何安全使用Personal Access Token与SSH密钥
1. 从“密码登录”到“令牌访问”一次关键的安全升级如果你最近在命令行里执行git push或者用一些老旧的客户端连接 GitHub 时突然弹出一条错误信息“Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.”别慌你不是一个人。这个看似简单的登录失败提示背后是 GitHub 在 2021 年 8 月 13 日实施的一项重大安全策略变更彻底移除了对账户密码的直接认证支持。这意味着过去那种直接把用户名和密码填在 Git 命令行或者第三方工具里的“懒人”方式彻底行不通了。这不仅仅是一个技术细节的调整它标志着开源协作和个人开发安全实践的一次重要升级。简单来说GitHub 不再允许你用账户密码去访问它的 API 或者进行 Git 操作。取而代之的是更安全、更可控的认证方式主要是Personal Access Token和SSH 密钥。对于很多习惯了密码登录的开发者尤其是那些在服务器上配置了自动化脚本、或者在一些集成开发环境里保存了密码的朋友来说这无疑是一个需要立刻处理的“技术债”。理解这次变更的原因、掌握新的认证方法并顺利迁移你手头的所有工具和流程是保证你开发工作流不中断的关键。2. 为什么密码认证被淘汰安全演进的必然要理解为什么 GitHub 要“自找麻烦”地取消一个看似方便的功能我们需要从几个角度来看待密码认证在自动化场景下的固有缺陷。2.1 密码的“静态”与“全权”风险你的 GitHub 账户密码是一个“静态凭证”。它一旦被设置在修改之前都是固定不变的。当你在 Git 命令行中输入git clone https://github.com/username/repo.git并输入密码时这个密码可能会被缓存在系统的凭据管理器里比如 Windows 的凭据管理器、macOS 的钥匙串。问题在于这个密码拥有你账户的“全权”访问能力。任何获取到这个密码的人或程序都可以以你的身份执行任何操作推送代码、删除仓库、修改设置甚至删除整个账户。在自动化场景下比如 CI/CD 流水线、部署脚本、或者第三方集成服务中把密码硬编码在脚本或环境变量里是极其危险的。如果脚本仓库的访问权限泄露或者服务器被入侵攻击者就能直接拿到这个“万能钥匙”。更糟糕的是由于密码是静态的你很难在不影响其他服务的情况下单独撤销某个脚本或服务的访问权限——你只能修改全局密码这会导致所有依赖此密码的服务同时失效。2.2 令牌Token的“动态”与“细粒度”优势Personal Access Token 正是为了解决上述问题而生的。你可以把它理解为一个专门为特定用途生成的、具有特定权限的“一次性密码”或“门禁卡”。细粒度权限控制在创建 Token 时你可以精确勾选它所需要的权限范围比如只允许“读取仓库内容”repo的read权限或者只允许“写入单个仓库”repo的write权限并指定仓库。这样即使这个 Token 泄露其破坏力也被限制在最小范围。独立管理与撤销每个 Token 都是独立的。你可以在 GitHub 设置页面随时查看、为 Token 添加描述以便识别、或者直接将其撤销。撤销一个用于 CI 服务的 Token不会影响你本地 Git 命令行使用的另一个 Token更不会影响你的主账户密码。无状态与可审计Token 本身不包含你的密码信息它是一个由服务器签发的凭证。GitHub 可以更好地追踪每个 Token 的使用情况为安全审计提供便利。从平台安全的角度看强制使用 Token 能大幅降低因密码泄露导致的账户劫持、大规模代码污染或删除等安全事件的风险。这是行业向更安全的认证标准如 OAuth 2.0、基于令牌的认证迈进的标准操作。类似地许多其他云服务和 API 提供商也早已采用了类似的策略。3. 核心解决方案创建与使用 Personal Access Token既然密码行不通了我们首要的任务就是学会如何创建和使用 Personal Access Token。整个过程并不复杂但有几个关键细节需要注意。3.1 创建你的第一个 Personal Access Token登录并进入设置首先用你的浏览器正常登录 GitHub 账户。点击右上角你的头像在下拉菜单中选择“Settings”。找到开发者设置在左侧边栏的最底部找到并点击“Developer settings”。选择个人访问令牌在开发者设置页面继续点击左侧的“Personal access tokens”然后选择“Tokens (classic)”或更新的“Fine-grained tokens”。目前“经典令牌”功能更全面我们以此为例。点击“Generate new token”下拉菜单选择“Generate new token (classic)”。配置令牌信息Note这是最重要的字段务必填写一个清晰、具有描述性的名称例如“My MacBook Pro Git”、“Company CI Server - Production Deploy”。这能帮助你在未来管理几十个令牌时一眼就知道每个是干什么用的。Expiration强烈建议设置一个过期时间。对于个人电脑可以选择“30 days”或“90 days”对于生产环境的服务器可以考虑“No expiration”但需承担更高风险需妥善保管。设置过期时间是一种良好的安全习惯能强制你定期轮换凭证。Select scopes这是权限选择区域。根据你的用途勾选最基本的 Git 操作勾选repo。这将授予对所有公共和私有仓库的完全控制权读、写、删除。如果你希望权限更小可以只勾选public_repo仅公共仓库或在创建“细粒度令牌”时指定具体仓库。其他常见用途如果你需要 Token 来管理 GitHub 其他功能如gist创建、user信息读取等请按需勾选。原则是按需分配最小权限。生成并保存滚动到页面底部点击绿色的“Generate token”按钮。重要生成的 Token 只会在此刻显示一次请立即将其复制并保存到一个安全的地方如密码管理器。一旦你离开这个页面就再也无法查看完整的 Token 了只能看到其前缀。如果你丢失了它唯一的办法就是撤销它并重新生成一个新的。注意Token 是一长串看起来像乱码的字符串例如ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。请像对待密码一样对待它不要将其提交到任何公开的 Git 仓库、日志文件或聊天记录中。3.2 在 Git 命令行中使用 Token拿到 Token 后你需要用它来替换掉之前使用的密码。具体操作取决于你使用的 Git 远程地址协议。对于 HTTPS 远程地址最常见 你的远程地址看起来像https://github.com/username/repo.git。当你下次执行git push、git pull或git clone需要认证时Git 会弹出用户名和密码输入框。用户名填写你的 GitHub 用户名。密码这里不再填你的账户密码而是粘贴你刚刚生成的 Personal Access Token。系统可能会询问你是否将凭据存储到凭据管理器。如果你信任这台电脑可以选择存储这样下次就不需要再输入了。在 Windows 上这通常由“Git Credential Manager”处理在 macOS 上则由“钥匙串访问”管理。一个更直接的方法尤其适用于脚本 你可以直接修改远程仓库的 URL将 Token 嵌入其中。但请注意这会将 Token 明文保存在.git/config文件里安全性较低仅适用于高度受控的环境如临时测试。git remote set-url origin https://YOUR_TOKENgithub.com/USERNAME/REPO_NAME.git例如git remote set-url origin https://ghp_abc123...github.com/yourname/yourrepo.git对于 SSH 远程地址推荐 如果你使用的是 SSH 地址如gitgithub.com:username/repo.git那么认证方式完全不同它不依赖于密码或 Token而是使用 SSH 密钥对。这通常是更安全、更方便的选择。我们会在下一章详细讨论。4. 更优选择配置 SSH 密钥实现免密访问虽然 Personal Access Token 解决了密码认证的问题但对于日常开发配置 SSH 密钥是更优雅、更安全的长期方案。它实现了真正的免密登录无需每次输入 Token并且基于非对称加密安全性更高。4.1 SSH 密钥的工作原理简述SSH 密钥成对出现一个私钥和一个公钥。私钥保存在你的本地电脑上必须绝对保密相当于你的“身份印章”。公钥可以公开分发上传到 GitHub或其他 Git 服务器相当于一把公开的“锁”。当你通过 SSH 连接 GitHub 时本地 Git 客户端会用你的私钥对一个随机挑战码进行签名并发送给服务器。服务器用你事先上传的公钥来验证这个签名。如果验证通过就确认了你的身份允许访问。整个过程无需传输任何密码或 Token。4.2 生成并添加 SSH 密钥到 GitHub检查现有密钥打开终端Linux/macOS或 Git BashWindows输入ls -al ~/.ssh。查看是否有id_rsa、id_ed25519之类的文件对.pub是公钥。如果有且你愿意使用可以跳过生成步骤。生成新的 SSH 密钥以 Ed25519 算法为例更安全更快ssh-keygen -t ed25519 -C your_emailexample.com按回车接受默认的密钥保存路径~/.ssh/id_ed25519。为密钥设置一个安全的密码passphrase。这为私钥增加了一层保护即使私钥文件被盗没有密码也无法使用。如果觉得麻烦可以不设直接回车但安全性会降低。启动 SSH 代理并添加私钥eval $(ssh-agent -s) # 启动代理 ssh-add ~/.ssh/id_ed25519 # 添加私钥会提示输入上一步设置的密码复制公钥cat ~/.ssh/id_ed25519.pub选中并复制终端输出的全部内容从ssh-ed25519开始一直到你的邮箱注释结束。在 GitHub 中添加公钥登录 GitHub点击头像 -“Settings”。左侧边栏选择“SSH and GPG keys”。点击“New SSH key”。Title给你的密钥起个名字如 “Personal Laptop - Ed25519”。Key type保持默认 “Authentication Key”。Key将刚才复制的公钥内容粘贴进去。点击“Add SSH key”。4.3 测试并切换远程协议测试连接ssh -T gitgithub.com如果看到类似 “Hi username! Youve successfully authenticated...” 的欢迎信息说明配置成功。将现有仓库的远程地址从 HTTPS 切换到 SSHgit remote -v # 查看当前远程地址 git remote set-url origin gitgithub.com:username/repo.git # 替换为你的 SSH 地址之后再进行git pull或git push就不会再要求输入密码或 Token 了。使用 SSH 密钥后你本地所有与 GitHub 的 Git 操作都将畅通无阻体验远胜于每次需要 Token 的 HTTPS 方式。对于 CI/CD 服务器虽然也可以配置 SSH 密钥部署但通常更推荐使用具有限定权限的Fine-grained Personal Access Token或GitHub Actions的内置GITHUB_TOKEN以实现更好的权限隔离和审计。5. 排查与解决常见的 Token 与 SSH 问题迁移到新认证方式的过程中你可能会遇到一些“拦路虎”。下面是一些常见问题及其排查思路。5.1 Token 相关错误错误信息remote: Invalid username or password.或remote: Invalid username or token.原因最可能的原因是你在密码框输入的是账户密码而非 Token。请确认你输入的是正确的 Token。排查检查 Token 是否已过期。去 GitHub 设置 - Developer settings - Personal access tokens 页面查看。检查 Token 的权限scopes是否足够。例如如果你尝试向一个私有仓库推送代码但 Token 只拥有public_repo权限就会失败。如果你将 Token 嵌入了 URL 或环境变量检查是否有拼写错误或多余的空格。解决重新生成一个具有足够权限且未过期的 Token并确保正确使用它。错误信息fatal: Authentication failed for https://github.com/...原因本地系统缓存的旧凭据你的密码在作祟。Git 的凭据管理器仍然尝试使用旧的、已失效的密码进行认证。排查与解决需要清除旧的凭据缓存。Windows (Git Credential Manager)打开“控制面板” - “用户账户” - “凭据管理器” - “Windows 凭据”。在“普通凭据”或“Windows 凭据”下找到与git:https://github.com相关的条目将其删除。macOS (钥匙串访问)打开“钥匙串访问”应用搜索 “github.com”。找到相关的“互联网密码”条目将其删除。Linux可以使用命令git config --global --unset credential.helper暂时取消帮助器或者查找并清除对应帮助器如libsecret,gnome-keyring存储的凭据。 清除缓存后再次执行 Git 操作系统就会提示你输入新的用户名和 Token 了。5.2 SSH 相关错误错误信息gitgithub.com: Permission denied (publickey).原因SSH 连接失败服务器拒绝了你的公钥。排查密钥未添加运行ssh-add -l查看 SSH 代理中是否已加载了你的私钥。如果列表为空需要用ssh-add ~/.ssh/你的私钥文件添加。公钥未正确上传仔细检查你粘贴到 GitHub 的公钥内容确保没有遗漏开头或结尾的字符也没有换行。最好用cat命令复制而不是用编辑器打开可能引入格式问题。使用了错误的私钥如果你有多个密钥SSH 可能会尝试默认的id_rsa。你可以通过创建或修改~/.ssh/config文件来指定Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519 # 指定你的私钥路径 IdentitiesOnly yesSSH 代理未运行确保已执行eval $(ssh-agent -s)启动了代理。解决按照上述排查步骤确保私钥已加载、公钥已正确上传、SSH 配置正确。错误信息连接超时或ssh: connect to host github.com port 22: Connection refused原因某些网络环境如公司防火墙、学校网络可能会屏蔽标准的 SSH 端口22。解决GitHub 也支持通过 HTTPS 端口443进行 SSH 连接。编辑~/.ssh/config文件为 GitHub 添加如下配置Host github.com HostName ssh.github.com User git Port 443 IdentityFile ~/.ssh/id_ed25519这样 SSH 连接会尝试通过 443 端口建立通常能绕过防火墙限制。6. 进阶场景自动化脚本与 CI/CD 中的凭证管理在服务器、自动化脚本或 CI/CD 流水线如 Jenkins, GitLab CI, GitHub Actions中使用 GitHub凭证管理需要格外小心。6.1 使用 Token 的最佳实践使用 Fine-grained Personal Access Tokens对于新项目优先使用 GitHub 推出的“细粒度令牌”。它可以精确控制到单个仓库的读写权限甚至能限制可以访问的内容如仅代码、仅议题安全性远超经典令牌。将 Token 存储在安全的地方绝对不要将 Token 硬编码在源代码中。绝对不要将 Token 提交到版本控制系统即使是私有仓库。正确做法是使用环境变量或秘密管理服务。在本地脚本中可以通过export GH_TOKENghp_abc123...设置环境变量然后在脚本中用$GH_TOKEN引用。在 CI/CD 系统中如 GitHub Actions使用平台提供的Secrets功能。将 Token 以加密形式存储在项目或组织的 Secrets 中在 workflow 文件里通过${{ secrets.MY_DEPLOY_TOKEN }}的方式引用。为不同用途创建不同的 Token不要一个 Token 走天下。为生产环境部署、CI 测试、第三方服务集成分别创建独立的 Token。这样如果某个 Token 泄露或需要撤销不会影响其他服务。6.2 在 GitHub Actions 中安全地使用凭证GitHub Actions 提供了最原生、最安全的使用方式。GITHUB_TOKEN这是 GitHub 为每个 workflow 运行自动生成的临时令牌。它默认拥有当前仓库的读写权限对于 Pull Request 来自 fork 的情况权限受限。你无需任何配置直接在 workflow 中通过${{ secrets.GITHUB_TOKEN }}或${{ github.token }}即可使用。这是首选方案因为它生命周期短、权限受控、自动管理。- name: Checkout code uses: actions/checkoutv4 with: token: ${{ secrets.GITHUB_TOKEN }}自定义 Personal Access Token当你的 workflow 需要跨仓库访问、或需要GITHUB_TOKEN不具备的权限如管理组织、访问其他仓库时才需要创建自定义 PAT。在 GitHub 上生成一个具有所需权限的 Token。在仓库或组织的“Settings” - “Secrets and variables” - “Actions”页面添加一个新的 Secret例如命名为MY_CUSTOM_TOKEN并将 Token 值粘贴进去。在 workflow 文件中引用${{ secrets.MY_CUSTOM_TOKEN }}。6.3 服务器上的 SSH 密钥部署在云服务器或自有服务器上配置自动化部署使用 SSH 密钥也是常见做法但需注意使用部署密钥GitHub 支持为单个仓库配置“部署密钥”Deploy Keys。这是一个只绑定到该仓库的 SSH 公钥通常只授予只读或读写权限。这比使用个人账户的 SSH 密钥更安全因为权限被限制在单个仓库内。妥善保管服务器私钥服务器的私钥文件是最高机密。确保其文件权限为600仅所有者可读写。考虑使用类似 HashiCorp Vault 的秘密管理工具来动态提供密钥而不是将其静态存放在服务器磁盘上。使用 SSH Agent Forwarding 需谨慎有时为了方便会使用 SSH 代理转发-A参数将本地私钥的签名能力转发到跳板机或中间服务器。这存在风险因为目标服务器上的 root 用户可能能够滥用转发的连接。在生产环境中应尽量避免而是在目标服务器上单独配置部署密钥。从密码认证到令牌和密钥的转变是开发者安全素养提升的一个缩影。它要求我们更清晰地思考权限的边界更谨慎地管理凭证。刚开始可能会觉得多了一步配置有些麻烦但一旦习惯你会发现整个工作流变得更加清晰、健壮和安全。下次当你再看到那个“password authentication was removed”的提示时希望你能从容地打开设置页面生成一个合适的 Token或者优雅地配置好 SSH 密钥然后继续你的代码之旅。