繁体   English   中英

在 NextJS 中将你的环境变量暴露给浏览器是不安全和不好的做法吗?

[英]Is it insecure and bad practice to expose your environment variables to the browser in NextJS?

我目前正在尝试在我正在使用的 NextJS 应用程序中设置 Firebase v9 身份验证。 我最初尝试将 Next 的服务器端环境变量用于我的 Firebase 配置,但注意到我的所有环境变量一直未定义。 但后来我更新了我的 Firebase 配置以使用NEXT_PUBLIC_然后它工作正常。 所以我想我的问题是:

  1. 将您的 Firebase 配置变量暴露给浏览器是否安全?
  2. 如果不安全。 您如何确保应用程序在服务器端初始化,然后在客户端使用? (链接任何特定的指南或文章将不胜感激)

下面我按顺序提供了我的 firebase 配置文件、AuthContext 提供程序和登录页面。

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET_URL,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth();
import { createContext, useContext, useEffect, useState } from 'react';
import {
  onAuthStateChanged,
  signInWithEmailAndPassword,
  signOut,
} from 'firebase/auth';
import { auth } from '@/lib/firebaseApp';

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export function AuthContextProvider({ children }) {
  const [user, setUser] = useState({ email: null, uid: null });
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        setUser({
          email: user.email,
          uid: user.uid,
        });
      } else {
        setUser({ email: null, uid: null });
      }
    });
    setLoading(false);
    return () => unsubscribe();
  }, []);

  function login(email, password) {
    return signInWithEmailAndPassword(auth, email, password);
  }

  async function logout() {
    setUser({ email: null, uid: null });
    await signOut(auth);
  }

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {loading ? null : children}
    </AuthContext.Provider>
  );
}
import { useState } from 'react';
import { useRouter } from 'next/router';

import { Button } from '@/components';
import { useAuth } from '@/context/AuthContext';

export default function Login() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const { login } = useAuth();
  const router = useRouter();

  async function handleSubmit(event) {
    event.preventDefault();
    try {
      await login(email, password);
      router.push('/dashboard');
    } catch (error) {
      console.log(error.message);
    }
  }

  return (
    <div className="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
      <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
        <div className="mx-auto w-11/12 rounded-2xl border border-zinc-100 p-6 py-8 px-4 dark:border-zinc-700/40 sm:px-10 md:w-full">
          <form className="space-y-6" onSubmit={(event) => handleSubmit(event)}>
            <div>
              <label
                htmlFor="email"
                className="block text-sm font-semibold text-zinc-900 dark:text-zinc-100"
              >
                Email address
              </label>
              <div className="mt-1">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  required
                  className="block w-full appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-2 shadow-sm shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
                  onChange={(e) => setEmail(e.target.value)}
                />
              </div>
            </div>
            <div>
              <label
                htmlFor="password"
                className="block text-sm font-semibold text-zinc-900 dark:text-zinc-100"
              >
                Password
              </label>
              <div className="mt-1">
                <input
                  id="password"
                  name="password"
                  type="password"
                  autoComplete="current-password"
                  required
                  className="block w-full appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-2 shadow-sm shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
                  onChange={(e) => setPassword(e.target.value)}
                />
              </div>
            </div>
            <div className="flex w-full justify-center">
              <Button type="submit" className="w-10/12 px-6 py-4 md:w-5/6">
                Sign In
              </Button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}

为什么你不能访问 your.env 变量

您当前正在客户端访问您的环境变量。 不需要此功能,因此默认情况下不存在,因为客户端上的所有内容对每个人都是可见的。 您可以直接以纯文本形式粘贴 API 密钥。 这是同一件事。

Firebase 管理员与客户端

firebase 有两种选择。您可以使用 API 密钥公开的客户端 SDK,并且可以毫无问题地公开显示。 您在 firestore 控制台中编写自己的规则。 (这就是你似乎正在使用的)

重要如果您发布您的应用程序,您必须将 firestore 规则设置为锁定模式,并且只有在您专门为其编写规则时才允许读/写。

否则你可以使用 firebase admin SDK 应该只在服务器端运行。 然后你通过 Nextjs API 路由与 firebase 通信。 用于初始化此应用程序的 API 密钥是绝对私有的,不会被公开显示。 如果暴露,任何人都可以完全控制您的项目

您可以在此处阅读有关 firebase admin SDK 的更多信息: https://firebase.google.com/docs/admin/setup

结论

您在客户端使用 firebase sdk,因此可以安全地公开您的 API 密钥。 但是不要忘记为谁可以读/写设置规则。 如果您的项目在发布时处于“测试模式”,任何人都可以控制您的应用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM