# 安全地存储机密

了解软件开发中的机密以及如何安全地管理机密。

## 什么是机密？

在软件开发中，机密是一段敏感信息，用于对系统、服务、数据和 API 的访问权限进行身份验证或授权。 示例包括：

* API 密钥和访问令牌，使你能够与外部服务（例如 GitHub 的 REST API）进行交互\*\*\*\*\*\*\*\*。 访问令牌还允许像 GitHub Actions 这样的服务执行需要身份验证的任务，正如我们稍后将进行的实验所示。
* 数据库凭据，授予对本地数据库和外部数据库和存储的访问权限\*\*\*\*。
* 私钥（例如专用 SSH 和 PGP 密钥），可用于访问其他服务器并加密数据\*\*\*\*。

由于机密提供如此多的访问权限，包括对关键系统的访问权限，因此我们完全理解确保机密安全的重要性\*\*\*\*。

### 当机密被公开时，会发生什么情况？

* 攻击者可以未经授权地访问机密所允许访问的所有内容。
* 黑客可能会窃取数据，包括敏感的用户数据\*\*\*\*。 这可能会带来隐私和法律后果，并损害你和你的应用程序的信任。
* 如果黑客在你的云提供商帐户上运行未经授权的工作负载，公开的机密可能造成经济损失\*\*\*\*。
* 黑客还可能会利用公开的机密删除、修改和干扰服务器，可能导致停机和数据丢失\*\*\*\*。

请务必全面评估机密所授予的所有访问权限和能力，并警惕黑客可能借此实施的恶意行为。 例如，如果你的 personal access token 帐户的 GitHub 已被公开，黑客就能以你的身份在 GitHub 上发布内容和进行修改。

## 管理机密的最佳做法

要避免此类问题，请遵循最佳做法，以防止泄露，并降低泄密后的损失影响。

### 遵循**最小特权原则 (PoLP)**

应尽可能限制机密的权限范围，仅授予必要的操作权限和访问范围。 例如：

* 如果机密仅用于读取数据而不对数据进行更改，请选择将其设置为只读\*\*\*\*。
* 如果使用的 API 允许将机密限制为仅特定范围或权限，请仅选择你需要的范围或权限。\*\*\*\* 例如，如果只需要创建使用 GitHub 机密的议题，则机密没有理由访问仓库内容或其他任何内容。
* 如果机密将授予攻击者对拥有该机密的用户帐户的完全访问权限，请考虑创建服务帐户，以便拥有该机密的所有权\*\*\*\*。

### 保护应用程序中的机密

* **从不硬编码机密**。 始终使用环境变量或平台的机密管理工具（如 GitHub 的仓库机密）\*\*\*\*。
* 如果必须与他人共享机密，请使用专用工具，例如密码管理器\*\*\*\*。 请勿通过电子邮件或即时消息发送机密。
* 如果可能，请设置过期日期，并定期轮换机密；这降低了旧机密被利用的风险\*\*\*\*\*\*\*\*。
* 如果应用程序生成日志，请确保在记录之前对机密信息进行遮蔽。 否则，活动机密可能会保存到纯文本文件中。

### 如果公开机密，应尽量降低损失

* 即使机密只公开了一秒钟，也应视为已泄露，并立即撤销该机密\*\*\*\*。 然后，生成一个新的机密并确保存储安全。
* 请检查任何可能显示已泄露机密被用于可疑操作的活动日志\*\*\*\*。
* 分析机密被泄露的原因，并优化相关流程，避免类似问题再次出现。

## GitHub 如何帮助保护你的机密安全

你可以采取许多措施来保护你的机密安全，而 GitHub 也提供了多种功能，帮助你守护这些机密。 人人都会犯错，而我们提供的功能可以帮助你捕捉那些不小心泄露的机密：

* ```
            **推送保护**（我们稍后会进行试验），可阻止将机密推送到 GitHub 上的存储库。
  ```
* **机密扫描**扫描仓库，并在发现机密时创建警报。 对于某些机密，我们还会通知提供商，以便他们可以采取措施，例如自动撤销这些机密。

## 练习安全地存储机密

在本练习中，我们将创建 personal access token 并将其存储在安全位置，以便可以将其与 GitHub Actions 一起使用。 我们将创建的操作是一个简单的工作流，响应问题。

### 1.创建练习仓库

我们将从创建一个代码仓库开始。
`new2code` 帐户有一个模板仓库，可用于快速入门。

1. 导航到[新仓库页面](https://github.com/new?template_owner=new2code\&template_name=secret-action)。 遵循此链接将在 `new2code` 帐户上预先选择模板。
2. 在“Owner”下，确保已选择您的用户账户。
3. 在“Repository name”字段中，键入 `secret-action`。
4. 在说明字段下，选择“Public”，设置仓库可见性\*\*\*\*。
5. 单击“创建存储库”。

### 2.提交虚假令牌

人非圣贤，孰能无过。在编码过程中，难免会有不慎提交机密的情况发生。 在本练习中，我们将有意提交一个虚假令牌，以便熟悉并适应触发警报的流程\*\*\*\*。

1. 导航到刚创建的仓库。

2. 单击文件列表中的 `.github/workflows`，导航到 YAML 工作流文件。

3. 单击文件列表中的 `comment.yml`，打开工作流文件。

4. 要编辑工作流文件，请在右上角单击 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-pencil" aria-label="Edit this file" role="img"><path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path></svg>。

5. 在第 13 行 `GH_TOKEN: ""` 上，在引号之间插入此虚假令牌：

   ```text
   secret_scanning_ab85fc6f8d7638cf1c11da812da308d43_abcde
   ```

   最终结果应如下所示：

   ```yaml
   GH_TOKEN: "secret_scanning_ab85fc6f8d7638cf1c11da812da308d43_abcde"
   ```

6. 要尝试提交更改，请在右上角单击“Commit changes...”，然后在对话框中再次单击“Commit changes”\*\*\*\*\*\*\*\*。

7. 现在应会看到推送保护警报，内容为“Secret scanning found a GitHub Secret Scanning secret on line 13”。

   ![尝试提交的文件的第 13 行触发推送保护警报的截图示例。 “Cancel”按钮以橙色轮廓突出显示。](/assets/images/help/security/push-protection-example.png)

   如果我们现在不是在测试一个虚假令牌，那么这个操作就会提醒我们，我们已经离公开令牌只差一步之遥了。 查看可在警报上选择的选项。

8. 要停止提交并避免公开机密，请单击“Cancel”\*\*\*\*。 在右上角，单击**取消更改**，然后放弃未保存的更改（如果出现提示的话）。

### 3.创建真实令牌

接下来，让我们尝试遵循最佳做法。 首先，我们将创建一个 personal access token，它将允许该操作代表你执行任务（它所创建的评论将显示为来自你的用户帐户）。

> \[!NOTE] 请注意，我们在每个配置步骤中都需遵循最低权限原则。 你的令牌将具备最短的有效期、仅限访问所需的仓库，并且只拥有执行操作所必需的最低权限。

1. 导航到[新的 personal access token 页面](https://github.com/settings/personal-access-tokens/new)。
2. 在“Token name”下，为新令牌指定一个名称。 可以使用类似于“Action token”的术语。
3. 在“Expiration”下，选择“7 days”。
4. 在“仓库访问”下，选择“仅选择特定仓库”\*\*\*\*。
5. 在“Select repositories”下拉列表中，只需选择你之前创建的练习仓库\*\*\*\*。
6. 在“Permissions”部分的“Repository permissions”右侧，单击 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-unfold" aria-label="Expand" role="img"><path d="m8.177.677 2.896 2.896a.25.25 0 0 1-.177.427H8.75v1.25a.75.75 0 0 1-1.5 0V4H5.104a.25.25 0 0 1-.177-.427L7.823.677a.25.25 0 0 1 .354 0ZM7.25 10.75a.75.75 0 0 1 1.5 0V12h2.146a.25.25 0 0 1 .177.427l-2.896 2.896a.25.25 0 0 1-.354 0l-2.896-2.896A.25.25 0 0 1 5.104 12H7.25v-1.25Zm-5-2a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM6 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 6 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5ZM12 8a.75.75 0 0 1-.75.75h-.5a.75.75 0 0 1 0-1.5h.5A.75.75 0 0 1 12 8Zm2.25.75a.75.75 0 0 0 0-1.5h-.5a.75.75 0 0 0 0 1.5h.5Z"></path></svg>，查看所有可能的权限。
7. 向下滚动到“Issues”，在右侧的下拉列表中，选择“Read and write”。
8. 在页面底部，单击“Generate token”****。 如果系统提示，请再次单击“Generate token”进行确认****。

从这一刻起，必须确保安全地管理生成的令牌。 由于我们不久将使用该令牌，因此可以暂时将其复制到剪贴板。

### 4.安全地存储令牌

现在可以安全地将新令牌存储在仓库中。

1. 前往您在练习开始时创建的存储库。
2. 在仓库名称下，单击 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-gear" aria-label="gear" role="img"><path d="M8 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM9.5 8a1.5 1.5 0 1 0-3.001.001A1.5 1.5 0 0 0 9.5 8Z"></path></svg>“Settings”\*\*\*\*。 如果看不到“设置”选项卡，请选择“<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-kebab-horizontal" aria-label="kebab horizontal icon" role="img"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg>”下拉菜单，然后单击“设置”。

   ![存储库标头的屏幕截图，其中显示了选项卡。 “设置”选项卡以深橙色边框突出显示。](/assets/images/help/repository/repo-actions-settings.png)
3. 在边栏的“Security”部分中，选择“<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-key-asterisk" aria-label="key-asterisk" role="img"><path d="M0 2.75A2.75 2.75 0 0 1 2.75 0h10.5A2.75 2.75 0 0 1 16 2.75v10.5A2.75 2.75 0 0 1 13.25 16H2.75A2.75 2.75 0 0 1 0 13.25ZM2.75 1.5c-.69 0-1.25.56-1.25 1.25v10.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25V2.75c0-.69-.56-1.25-1.25-1.25Z"></path><path d="M8 4a.75.75 0 0 1 .75.75V6.7l1.69-.975a.75.75 0 0 1 .75 1.3L9.5 8l1.69.976a.75.75 0 0 1-.75 1.298L8.75 9.3v1.951a.75.75 0 0 1-1.5 0V9.299l-1.69.976a.75.75 0 0 1-.75-1.3L6.5 8l-1.69-.975a.75.75 0 0 1 .75-1.3l1.69.976V4.75A.75.75 0 0 1 8 4Z"></path></svg> Secrets and variables”，然后单击“Actions”\*\*\*\*\*\*\*\*。
4. 在“库机密”下，单击**新建库机密**。
5. 在“Name”字段中，键入机密的名称\*\*\*\*。 在本练习中，我们将使用 `MY_TOKEN`。
6. 在“Secret”字段中，粘贴之前生成的 personal access token\*\*\*\*。
7. 单击**添加密钥**。

你的机密现已安全加密，可供使用！

### 5.在操作中引用令牌

现在我们可以更新 YAML 工作流文件，使用该令牌并测试其是否生效。

1. 返回你的代码库。 如果你当前在存储库的设置页面，可以单击存储库名称下方的“<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-code" aria-label="code" role="img"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg> Code”\*\*\*\*。

2. 单击文件列表中的 `.github/workflows`，导航到 YAML 工作流文件。

3. 单击文件列表中的 `comment.yml`，打开工作流文件。

4. 要开始编辑工作流文件，请在右上角单击 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-pencil" aria-label="Edit this file" role="img"><path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path></svg>。

5. 在第 13 行 `GH_TOKEN: ""` 上，将空引号替换为 `${{ secrets.MY_TOKEN }}`。 这将引用我们之前添加的仓库密钥。

   ```yaml
   GH_TOKEN: ${{ secrets.MY_TOKEN }}
   ```

6. 要提交更改，请在右上角单击“Commit changes...”\*\*\*\*

7. 在“Commit changes”对话框中，编辑“Commit message”以反映我们所做的更改。 例如，可以输入“更新工作流程以使用仓库密钥”。

8. 确保已选择“Commit directly to the `main` branch”。

9. 单击“提交更改”。

### 6.测试令牌和工作流

我们现在应该一切已准备就绪！ 接下来让我们来测试一下这个工作流吧。

1. 在仓库名称下，单击 <svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-issue-opened" aria-label="issue-opened" role="img"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg>“Issues”\*\*\*\*。

   ![存储库的主页的屏幕截图。 在水平导航栏中，标记有“问题”的选项卡以深橙色标出。](/assets/images/help/repository/repo-tabs-issues-global-nav-update.png)
2. 单击“新建问题”。
3. 在“Add a title”下，可以键入喜欢的任何标题。
4. 在文本区域中的“Add a description”下，键入 `Hello`。
5. 在文本区域下方，单击“Create”\*\*\*\*。

工作流执行完成后，你应该会看到一条新的评论出现。 由于我们使用的是你的令牌，因此这条评论将由你本人编写，并包含一个回应的问候语。

## 后续步骤

要深入了解机密扫描和推送保护，可以在 GitHub Skills 中完成[机密扫描简介](https://github.com/skills/introduction-to-secret-scanning/tree/main)课程。

代码安全性的另一个重要部分是了解如何识别和修补项目中的代码漏洞。 请参阅“[查找并修复第一个代码漏洞](/zh/get-started/learning-to-code/finding-and-fixing-your-first-code-vulnerability)”。