我在 create-react-app 中做了一个天气应用。如何隐藏 API 密钥以便我可以提交到 GitHub?
现在关键是在 App.js: const API_KEY = "123456";
我在 create-react-app 中做了一个天气应用。如何隐藏 API 密钥以便我可以提交到 GitHub?
现在关键是在 App.js: const API_KEY = "123456";
不幸的是,即使您使用的是 gitignore 和.env
文件,在您的 React 客户端中保留任何密钥也是不安全的。正如@ClaudiuCreanga 指出的那样,React 环境变量嵌入在构建中并且可以公开访问。
您真的应该只在后端(例如 Node / Express)中保存 API 密钥或机密。您可以让您的客户端向您的后端 API 发送请求,然后后端 API 可以使用 API 密钥进行实际的 API 调用,并将数据发送回您的客户端。
免责声明
警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!
环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。
以下答案提供了在环境变量中存储非机密数据的正确方法。请记住,可以通过开发人员工具访问机密数据,因此将其存储为环境变量是不安全的。如果你想存储一些秘密数据,那么存储在后端是更好的选择,如果客户端想要访问秘密数据,可以通过向服务器发出请求来访问它。(有关存储秘密数据的更多详细信息,请参阅@Antonia 的回答。)
事实证明,create-react-app 有一些内置功能可以帮助您解决这个问题。感谢George Karametas的洞察力。要访问该功能,您需要:
.env
在项目目录的根目录中创建一个文件。- your_project_folder
- node_modules
- public
- src
- .env <-- create it here
- .gitignore
- package-lock.json
- package.json
.env
文件内,REACT_APP_
在您选择的 API 密钥名称之前添加并分配它。该create-react-app
工具用于REACT_APP_
识别这些变量。如果您的 API 密钥名称不以它开头,create-react-app
则不会看到它。
// .env
REACT_APP_API_KEY=your_api_key <-- yes
API_KEY=your_api_key <-- no
// Example (from 이준형's response):
REACT_APP_WEATHER_API_KEY=123456
.env
文件添加到您的.gitignore
文件中。添加以下行后,保存.gitignore
文件并执行 agit status
以确保您的.env
文件不会在 git 中显示为新文件。
// .gitignore
# api keys
.env <-- add this line
# dependencies
/node_modules
...
process.env
对象访问 API 密钥。要检查您是否可以访问 API 密钥,请转到您的App.js
文件并console.log
在require
语句下方的顶部添加一个。保存文件并重新加载页面后,如果控制台日志未显示您的 API 密钥,请尝试重新启动react服务器。在提交代码之前,请务必删除控制台日志行。
// src/App.js
import React, { Component } from 'react';
import './App.css';
console.log(process.env.REACT_APP_WEATHER_API_KEY)
class App extends Component {
...
警告
除非您正在制作教程应用程序,否则不要在客户端源代码(例如 React 应用程序)中放置诸如 API 密钥之类的秘密。来自 Create React App 的文档:
警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!
环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。
首先,在项目的根目录中创建一个 .env 文件,即您将在 src 文件夹之外运行react-scripts start
(或yarn start
)的位置。
然后加
REACT_APP_WEATHER_API_KEY=123456
在提交之前,您应该排除这个 .env 文件,以便找到 .gitignore 文件并添加 .env。
变量的名称需要以它开头,REACT_APP_
以防止您在构建中意外包含机密。
不要忘记在 .gitignore 文件中添加 .env 。
要在代码中使用 env 变量:
const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;
为了在将 env 变量添加到 后读取它们.env
,请重新启动服务器。
来自react文档:
警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!
环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。
虽然@Antonia Blair 已经回答了这个问题,但我想更详细地了解一些基本规则。
1:大多数答案都建议使用 .env 文件。我想一次性说清楚。env 不是在这里添加任何安全层。.env 顾名思义,仅用于在构建时设置环境。例如,通过使用环境变量,您可以在构建时设置一些全局值,并可以在运行时在应用程序中访问这些值。
2:Reactjs 只是一个在客户端浏览器中运行你的 javascript 代码的框架。因此客户端可以完全访问 javascript (Reactjs) 代码。客户端没有什么是安全的。因此,永远不要想通过将所有代码保留在客户端来使某些内容安全或对客户端隐藏。每当您需要对客户端隐藏某些内容时,您都需要合并服务器端的某些内容。只有服务器端代码对客户端是安全的。
3:所以你要做的是,你将把你的安全密钥保存在服务器端。
假设您的安全密钥的目的是为您的客户制作一个 cookie。所以客户端需要cookie而不是安全密钥,对吗?因此客户端向服务器请求cookie,服务器使用安全密钥制作cookie并将cookie返回给客户端。毕竟客户只是来吃饼干而不知道我们如何制作饼干对吗?
4:所以经验法则是,无论您在何处拥有一些机密数据,都将其保存在服务器上。服务器将使用这些机密数据并将结果数据返回给客户端。
编辑 Sep_06_2021
一位用户要求提供一个编码示例,因此我将展示我使用上述技术处理的实时场景。这是我的用例
我有一个 Reactjs 应用程序,它向非公共 API 提交公共表单。
非公共 API 是由https://www.greenhouse.io/托管的 Harvest API
这个 API 需要一个 Authentication Header 来使用它发出请求。我已经订阅了 API 所有者并从他们那里收到了一个秘密令牌,我可以将其用于我的请求以访问他们的 API
当然,我想保持我的令牌个人化,不要将其暴露给公共用户
我已经使用 axios 客户端与 API 通信
我有两种方法来执行上述场景
不正确的方法
我直接从我的 Reactjs 应用程序向 API 发出请求
让我们说下面是我想要点击的 API 端点
apiURL=https://boardsapi.greenhouse.io/v1/boards/xyz/jobs/"+jobId+""
上述 API 端点需要一个授权头,我将在其中提供我的秘密令牌。
const config = {
headers: {
"Authorization": "Basic ####MySecretCode#####",
} };
假设我想用这个请求发布一些表单数据
let formData=MyFormData
我现在可以使用 axios 客户端发送我的请求,如下所示
let result=await axios.post(apiURL, formData,config);
使用上述技术,我可以成功地将我的表单数据发布到 Harvest API。
但是就像我说的那样,与此 API 进行通信是一种不正确的方式。因为我已经在客户端暴露了我的秘密令牌。
正确的方法
我在 Nodejs 上构建了一个 API 并公开托管它。
假设我想将一些表单数据发布到 Harvest API
let formData=MyFormData
我不会直接从我的客户端应用程序访问 Harvest API。相反,我在我的中间件 API 中公开了端点来处理这个问题。让我们说下面是我想要点击的中间件 API 的端点 URL
apiURL=https://proxy-server/apply
上述 API 端点不需要授权标头。所以我可以使用 axios 客户端发送一个 post 请求,如下所示
let result=await axios.post(apiURL, formData);
区别很明显。这次我没有在我的请求中提供秘密令牌。因为这不是对 Harvest API 的直接请求,而是对由我开发和托管的中间件 API 的请求。
我在我的中间件 API 中收到此请求,添加我的秘密令牌并将其转发到 Harvest API。来自 Harvest API 的响应返回到我们的 middle_ware API,因此转发回我们的 Reactjs 客户端应用程序。
秘密令牌现在驻留在我的服务器端 API 上并且不受外部用户的影响。