Variáveis de ambiente e arquivo .env: como proteger tokens e senhas

Variáveis de ambiente e arquivo .env: como proteger tokens e senhas

Um dos erros mais caros que um desenvolvedor pode cometer é publicar uma senha ou um token de API no GitHub. Robôs varrem repositórios públicos o tempo todo atrás de chaves de nuvem, tokens de pagamento e credenciais de APIs, e um segredo exposto pode ser explorado em minutos. A defesa mais básica — e mais eficaz — contra isso são as variáveis de ambiente e o arquivo .env.

Neste tutorial você vai entender o que são variáveis de ambiente, como usar o arquivo .env em Node.js e PHP, como garantir que ele nunca vá para o Git, como validar a configuração na inicialização da aplicação e como levar tudo isso para Docker e produção. Todos os prints mostram execuções reais.

O que são variáveis de ambiente

Variáveis de ambiente são pares de nome e valor que o sistema operacional disponibiliza para os programas em execução. Você já usa várias sem perceber: PATH diz onde procurar executáveis, HOME aponta para a sua pasta de usuário e LANG define o idioma.

A ideia central é simples: o código é o mesmo em todos os lugares; a configuração muda conforme o ambiente. A API que roda no seu notebook e a que roda no servidor de produção são o mesmo código, mas usam bancos, URLs e tokens diferentes. Em vez de editar o código para cada ambiente, você muda as variáveis.

Veja como definir e ler uma variável no terminal e acessá-la no Node.js e no PHP:

Terminal definindo e lendo variáveis de ambiente no shell, no Node.js e no PHP
A mesma variável lida pelo shell, pelo Node.js e pelo PHP

Repare no último comando: definir a variável na mesma linha do comando vale só para aquela execução. É um truque útil para testar a aplicação com outra configuração sem mexer em nada.

O que deve ser uma variável de ambiente

  • Segredos: tokens de API, senhas de banco, chaves de criptografia, credenciais de e-mail.
  • Configurações que mudam por ambiente: URL do banco, porta, nível de log, URLs de outros serviços, modo debug.
  • Chaves de funcionalidades: ligar ou desligar recursos sem novo deploy.

O que não deve ser: regras de negócio, textos da interface e constantes que nunca mudam. Isso fica no código.

O arquivo .env

Definir dezenas de variáveis no terminal toda vez seria inviável. Por isso surgiu a convenção do arquivo .env: um arquivo de texto na raiz do projeto, com uma variável por linha no formato NOME=valor, carregado automaticamente quando a aplicação inicia.

Arquivo .env com variáveis de ambiente de uma aplicação que usa a APIBrasil
Um .env típico: ambiente, porta e os tokens da APIBrasil

Regras de sintaxe que evitam dor de cabeça:

  • Nomes em MAIÚSCULAS, com palavras separadas por _.
  • Sem espaços ao redor do =.
  • Valores com espaços ou caracteres especiais vão entre aspas: APP_NAME="Minha Loja".
  • Linhas começando com # são comentários.
  • Tudo é lido como texto. PORT=3000 chega ao código como a string "3000", e DEBUG=false como a string "false" — que, em JavaScript, é truthy. Converta os tipos no código.

A regra de ouro: .env nunca vai para o Git

O .env contém segredos, portanto nunca deve ser commitado. Adicione-o ao .gitignore antes do primeiro commit:

node_modules/
vendor/
.env

Mas então como um colega sabe quais variáveis o projeto precisa? Com o .env.example: uma cópia do .env sem os valores sensíveis, que vai para o repositório e serve de documentação:

APP_ENV=local
PORT=3000
APIBRASIL_BEARER_TOKEN=
APIBRASIL_DEVICE_TOKEN=

Quem clonar o projeto roda cp .env.example .env e preenche os próprios valores. Frameworks como Laravel já seguem exatamente esse padrão. Se você é novo no Git, veja Git e GitHub para iniciantes.

Usando .env no Node.js

Opção 1: suporte nativo (Node.js 20.6+)

As versões recentes do Node.js leem o .env sem nenhuma biblioteca, com a flag --env-file:

node --env-file=.env config.js

No package.json, fica assim:

"scripts": {
  "dev": "node --watch --env-file=.env index.js"
}

Validando as variáveis na inicialização

Uma prática que economiza horas de depuração: falhar rápido. Se uma variável obrigatória estiver faltando, a aplicação deve se recusar a iniciar com uma mensagem clara, em vez de quebrar lá na frente com um erro confuso como “401 Unauthorized”. Crie um config.js:

Código config.js validando variáveis de ambiente obrigatórias e mascarando o token
Valida as variáveis obrigatórias e nunca imprime o token inteiro

Duas boas práticas nesse código: a validação de variáveis obrigatórias e a função mascarar, que exibe só o começo do token nos logs. Nunca imprima segredos completos, nem em logs de depuração.

Terminal com node --env-file carregando o .env, erro sem o .env e uso do dotenv
Com o .env a configuração carrega; sem ele, a aplicação para com uma mensagem clara

Opção 2: biblioteca dotenv

Em versões mais antigas do Node.js, ou se preferir, use o pacote dotenv:

npm install dotenv
require('dotenv').config();

console.log(process.env.APP_ENV);

A linha require('dotenv').config() deve estar no topo do arquivo de entrada, antes de qualquer código que use as variáveis.

Usando .env no PHP

No PHP, a biblioteca mais usada é a vlucas/phpdotenv, a mesma que o Laravel usa por baixo:

composer require vlucas/phpdotenv
<?php

require __DIR__ . '/vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// Falha na inicialização se faltar alguma variável obrigatória
$dotenv->required(['APIBRASIL_BEARER_TOKEN', 'APIBRASIL_DEVICE_TOKEN'])->notEmpty();

echo $_ENV['APP_ENV'];

Para entender o que a biblioteca faz, veja uma versão mínima escrita à mão: ela lê o arquivo linha a linha, ignora comentários e registra cada par com putenv() e $_ENV:

<?php
function carregarEnv(string $arquivo): void
{
    if (!is_file($arquivo)) {
        throw new RuntimeException("Arquivo $arquivo não encontrado");
    }
    foreach (file($arquivo, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $linha) {
        if (str_starts_with(trim($linha), '#') || !str_contains($linha, '=')) {
            continue;
        }
        [$nome, $valor] = array_map('trim', explode('=', $linha, 2));
        putenv("$nome=$valor");
        $_ENV[$nome] = $valor;
    }
}

carregarEnv(__DIR__ . '/.env');

echo 'Ambiente: ' . getenv('APP_ENV') . PHP_EOL;
echo 'Token definido? ' . (getenv('APIBRASIL_BEARER_TOKEN') ? 'sim' : 'não') . PHP_EOL;

Em projetos reais, prefira a biblioteca, que trata aspas, variáveis aninhadas e casos especiais. No Laravel, o .env já vem configurado: leia os valores via config(), e não com env() espalhado pelo código, porque depois de php artisan config:cache o env() fora dos arquivos de configuração retorna null.

Terminal com PHP lendo o .env e Git confirmando que o arquivo .env está ignorado
O PHP lê as variáveis; o git status não lista o .env e o check-ignore mostra a regra responsável

O comando git check-ignore -v .env é ótimo para confirmar que o arquivo está protegido: ele mostra qual linha de qual .gitignore está ignorando o arquivo.

Tokens de API: o exemplo da APIBrasil

As SDKs oficiais da APIBrasil seguem exatamente esse padrão. Elas leem automaticamente as variáveis APIBRASIL_BEARER_TOKEN, APIBRASIL_DEVICE_TOKEN, APIBRASIL_SECRET_KEY e APIBRASIL_BASE_URL. Com o .env carregado, criar o cliente não exige passar nenhum token no código:

// Node.js
import { ApiBrasil } from 'apigratis-sdk-nodejs';
const api = new ApiBrasil(); // lê os tokens do ambiente
// PHP
$api = new ApiBrasil\ApiBrasil(); // lê os tokens do ambiente

Veja o padrão em ação nos tutoriais Como enviar SMS com PHP e Enviar WhatsApp com Node.js.

Variáveis de ambiente no Docker

Com Docker, você não copia o .env para dentro da imagem (inclua-o no .dockerignore). As variáveis são passadas quando o container inicia:

# Uma a uma
docker run -e APP_ENV=producao -e PORT=3000 minha-api

# A partir de um arquivo
docker run --env-file .env minha-api

No Docker Compose, use env_file ou a chave environment com substituição ${VARIAVEL}, como mostramos em Docker Compose com PHP e MySQL:

services:
  api:
    build: .
    env_file: .env

Variáveis de ambiente em produção

Em produção, o arquivo .env é só uma das opções — e nem sempre a melhor:

  • Painel do provedor: plataformas como Vercel, Render, Railway, Heroku e Laravel Cloud têm uma tela para cadastrar variáveis de ambiente, que ficam criptografadas.
  • CI/CD: GitHub Actions e GitLab CI têm secrets que são injetados como variáveis durante o pipeline.
  • Gerenciadores de segredos: AWS Secrets Manager, Google Secret Manager, Azure Key Vault, HashiCorp Vault e Doppler guardam, versionam e rotacionam segredos com controle de acesso.
  • VPS: se usar .env no servidor, restrinja as permissões (chmod 600 .env) e garanta que o servidor web não sirva o arquivo publicamente.

Boas práticas de segurança

  • Um token por ambiente. Desenvolvimento, homologação e produção devem ter credenciais diferentes. Se a de desenvolvimento vazar, produção continua segura.
  • Privilégio mínimo. Use tokens com o menor acesso necessário e, quando o provedor permitir, restrinja por IP. A APIBrasil, por exemplo, oferece whitelist de IPs na conta.
  • Rotacione periodicamente e sempre que alguém sair da equipe.
  • Nunca coloque segredos no front-end. Tudo o que vai para o navegador pode ser lido por qualquer pessoa. Chamadas com tokens devem passar pelo seu back-end.
  • Nunca logue segredos e cuidado com prints de tela, vídeos e mensagens de suporte.
  • Use ferramentas de detecção, como o secret scanning do GitHub e o gitleaks, para barrar commits com segredos.

Vazou um token. E agora?

  1. Revogue o token imediatamente no painel do provedor e gere um novo. Esse é o passo mais importante.
  2. Atualize o novo valor nos ambientes que o utilizam.
  3. Remover o arquivo em um novo commit não basta, porque ele continua no histórico. Se o repositório era público, considere o segredo comprometido de qualquer forma.
  4. Verifique logs e cobranças do serviço em busca de uso indevido.
  5. Descubra como aconteceu e adicione proteções (.gitignore, secret scanning) para que não se repita.

Perguntas frequentes

O arquivo .env é seguro?

Ele é seguro na medida em que fica fora do repositório e fora do alcance público. O .env em si é texto puro, sem criptografia. Em produção, prefira os recursos de segredos do seu provedor ou um gerenciador de segredos.

Posso ter mais de um arquivo .env?

Sim. É comum ter .env.local, .env.test e .env.production. No Node.js, carregue o arquivo desejado com --env-file=.env.test; frameworks como Laravel e Next.js escolhem automaticamente conforme o ambiente.

Qual a diferença entre process.env e import.meta.env?

process.env é o objeto de variáveis de ambiente do Node.js, no servidor. import.meta.env é usado por ferramentas de build de front-end, como o Vite, e as variáveis expostas ali acabam no código enviado ao navegador — então nunca coloque segredos nelas.

Preciso reiniciar a aplicação depois de alterar o .env?

Sim. O .env é lido quando a aplicação inicia. No Laravel, se a configuração estiver em cache, rode também php artisan config:clear.

Conclusão

Variáveis de ambiente separam o que muda (configuração e segredos) do que não muda (o código). Com o arquivo .env no .gitignore, um .env.example documentando o que é necessário, validação na inicialização e segredos gerenciados de forma adequada em produção, você elimina uma das causas mais comuns de vazamento de credenciais.

Aplique o que aprendeu nos próximos tutoriais da série, que usam tokens da APIBrasil: Consultar CEP com JavaScript e Enviar WhatsApp com Node.js. E, se quiser entender outras camadas de proteção, leia Segurança em APIs: como proteger APIs com PHP.

Loading

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *