如何在 create-react-app 中隐藏 API 密钥?

IT技术 reactjs api github create-react-app api-key
2021-04-22 01:15:58

我在 create-react-app 中做了一个天气应用。如何隐藏 API 密钥以便我可以提交到 GitHub?

现在关键是在 App.js: const API_KEY = "123456";

6个回答

不幸的是,即使您使用的是 gitignore 和.env文件,在您的 React 客户端中保留任何密钥也是不安全的。正如@ClaudiuCreanga 指出的那样,React 环境变量嵌入在构建中并且可以公开访问。

您真的应该只在后端(例如 Node / Express)中保存 API 密钥或机密。您可以让您的客户端向您的后端 API 发送请求,然后后端 API 可以使用 API 密钥进行实际的 API 调用,并将数据发送回您的客户端。

这是正确答案。在浏览器上运行的客户端应用程序无法安全地存储机密。
2021-05-23 01:15:58
这应该是公认的答案。我想知道有多少人正在部署不安全的应用程序,因为没有阅读本文并依赖其他人的回答。
2021-05-27 01:15:58
@techi 理想情况下,在 React 前端应用程序中,用户是提供凭据(用户名/密码)来访问后端(带有身份验证服务的 Node/Express)的人,后端向后端发送生成的令牌供前端存储内存(未嵌入在 HTML/JS 等中)。所以现在,前端可以告诉后端访问第三方 API 等。这样我们就可以缓解前端暴露的攻击面,并将第三方 API 令牌隐藏在后端。
2021-06-13 01:15:58
@devuxer 确实如此,如果 API 密钥被设计为在前端公开/使用,就像您使用 Google Maps Javascript API 的示例一样,那么可以在那里使用它。
2021-06-16 01:15:58
这比其他答案要好,但即使在运行时请求它,他们仍然可以查看网络流量并查看 api 密钥是什么,对吗?我的意思是,你可以尝试以某种方式混淆它,但它仍然是同样的问题。据我所知,没有办法在前端应用程序上真正保密 api 密钥。我错了吗?
2021-06-18 01:15:58

免责声明

警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!

环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。

以下答案提供了在环境变量中存储非机密数据的正确方法。请记住,可以通过开发人员工具访问机密数据,因此将其存储为环境变量是不安全的。如果你想存储一些秘密数据,那么存储在后端是更好的选择,如果客户端想要访问秘密数据,可以通过向服务器发出请求来访问它。(有关存储秘密数据的更多详细信息,请参阅@Antonia 的回答。)

事实证明,create-react-app 有一些内置功能可以帮助您解决这个问题。感谢George Karametas的洞察力。要访问该功能,您需要:

1..env在项目目录的根目录中创建一个文件

- your_project_folder
  - node_modules
  - public
  - src
  - .env         <-- create it here
  - .gitignore
  - package-lock.json
  - package.json

2. 在.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

3. 将.env文件添加到您的.gitignore文件中。

添加以下行后,保存.gitignore文件并执行 agit status以确保您的.env文件不会在 git 中显示为新文件。

// .gitignore

# api keys
.env       <-- add this line

# dependencies
/node_modules
...

4. 通过process.env对象访问 API 密钥

要检查您是否可以访问 API 密钥,请转到您的App.js文件并console.logrequire语句下方的顶部添加一个保存文件并重新加载页面后,如果控制台日志未显示您的 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 {
...
如果客户端打开开发工具,这不会暴露吗?
2021-06-04 01:15:58
@richardsonae 那么它在生产中是如何工作的?生产就绪代码如何知道从哪里访问密钥?
2021-06-04 01:15:58
这对于机密来说绝对不安全。.env 中的任何内容都可以在开发工具中公开检查。处理此类必须在客户端保密的值的唯一方法是通过将为您处理它的服务器代理请求。请参阅 CludiuCreanga 对已接受答案的评论。
2021-06-10 01:15:58
我得到一个未定义的。我们必须通过 App.js 文件导入还是必须导出 .env?
2021-06-11 01:15:58
@born2gamble 确保将 apiKey 包装在模板文字中,因为它必须是字符串。这是我如何设置的示例:pastebin.com/WQ0CzqQy 然后确保重新启动服务器。
2021-06-20 01:15:58

警告

除非您正在制作教程应用程序,否则不要在客户端源代码(例如 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,请重新启动服务器。

这个被接受的答案如何?facebook.github.io/create-react-app/docs/...:警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。
2021-05-30 01:15:58
您应该重新启动您的应用程序以更新您的秘密。
2021-06-11 01:15:58
@Dickens 你当然可以这样做。该方法并非毫无value,因为您可能有不同的 api 密钥用于开发和生产。env 文件可以干净地分离那些 api 密钥......
2021-06-16 01:15:58
@theprogrammer 是的,类似于处理请求的快速服务器。这是唯一的方法。
2021-06-18 01:15:58
@ClaudiuCreanga 那么解决方案是什么?我们应该在 api 密钥和浏览器请求之间添加一个节点 js 服务器吗?这样,我们的节点服务器是唯一一个持有 api 密钥并使用存储在节点 js 服务器中的秘密 api 密钥代表用户发出第三方请求的服务器。
2021-06-21 01:15:58

来自react文档

警告:不要在你的 React 应用程序中存储任何秘密(例如私有 API 密钥)!

环境变量嵌入到构建中,这意味着任何人都可以通过检查您的应用程序文件来查看它们。

那么我们应该怎么做呢?将其存储在服务器端?在某些时候,前端需要知道 api 密钥......此时任何人都可以查看它。如果有人知道这方面的任何好文章,请分享。
2021-05-26 01:15:58
@TrevorWood 不要将 API 密钥传递给前端,将它保存在后端的秘密位置。将其视为后端执行 API 调用的伙伴关系,但前端可以向后端询问数据。见评论:hashnode.com/post/...
2021-05-30 01:15:58
@AntoniaBlair 不将它们放入应用程序的原因是人们无法读取构建文件来查看 API 密钥。但是人们不能在客户端加载网站后提取 API 密钥吗?一旦前端拥有 API 密钥或前端请求 API 密钥时。
2021-06-11 01:15:58
这个问题的答案如何?
2021-06-11 01:15:58
@TrevorWood 是的,将其存储在服务器端并在那里进行实际的 API 调用。后端应该充当 React 应用程序的代理,存储机密,进行 API 调用,然后发回数据。例如,在 React / Express 应用程序中,您可以创建一个 Express 端点来获取天气。您从 React 调用端点,然后 Express 使用 API 密钥在响应之前获取第 3 方天气数据,以便 React 可以显示数据。rockyourcode.com/secret-keys-in-react
2021-06-17 01:15:58

虽然@Antonia Blair 已经回答了这个问题,但我想更详细地了解一些基本规则。

1:大多数答案都建议使用 .env 文件。我想一次性说清楚。env 不是在这里添加任何安全层.env 顾名思义,仅用于在构建时设置环境。例如,通过使用环境变量,您可以在构建时设置一些全局值,并可以在运行时在应用程序中访问这些值。

2:Reactjs 只是一个在客户端浏览器中运行你的 javascript 代码的框架。因此客户端可以完全访问 javascript (Reactjs) 代码。客户端没有什么是安全的。因此,永远不要想通过将所有代码保留在客户端来使某些内容安全或对客户端隐藏。每当您需要对客户端隐藏某些内容时,您都需要合并服务器端的某些内容。只有服务器端代码对客户端是安全的。

3:所以你要做的是,你将把你的安全密钥保存在服务器端。

假设您的安全密钥的目的是为您的客户制作一个 cookie。所以客户端需要cookie而不是安全密钥,对吗?因此客户端向服务器请求cookie,服务器使用安全密钥制作cookie并将cookie返回给客户端。毕竟客户只是来吃饼干而不知道我们如何制作饼干对吗?

4:所以经验法则是,无论您在何处拥有一些机密数据,都将其保存在服务器上。服务器将使用这些机密数据并将结果数据返回给客户端。

编辑 Sep_06_2021

一位用户要求提供一个编码示例,因此我将展示我使用上述技术处理的实时场景。这是我的用例

  1. 我有一个 Reactjs 应用程序,它向非公共 API 提交公共表单。

  2. 非公共 API 是由https://www.greenhouse.io/托管的 Harvest API

  3. 这个 API 需要一个 Authentication Header 来使用它发出请求。我已经订阅了 API 所有者并从他们那里收到了一个秘密令牌,我可以将其用于我的请求以访问他们的 API

  4. 当然,我想保持我的令牌个人化,不要将其暴露给公共用户

  5. 我已经使用 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 上并且不受外部用户的影响。

完美的答案,易于非技术人员理解。
2021-06-03 01:15:58
根据上面的第 3 条,您知道新开发人员可以用来学习如何执行此操作的任何资源、教程等?
2021-06-04 01:15:58
@us_david 这就是我想要的,任何人都可以点击我的 API,我将从收获 API 获取的结果返回给他们。我的 API 对所有人都是公开的。如果我想将我的 API 设为私有,那么就有了 User Authentication module,只有经过身份验证的用户才能通过它向我的 API 发出请求
2021-06-14 01:15:58
您的方法本身存在安全问题:任何人都可以发布到您的中间件端点,并最终使用您的 API 访问您示例中的收获 API
2021-06-16 01:15:58