¿Odias los anuncios? Ir Sin publicidad Hoy

Archivos .env — 6 Errores que Dejan tus Claves en GitHub

Actualizado en

La mayoría de las fugas de .env no provienen de hackers: surgen de desarrolladores que subieron archivos antes de configurar .gitignore, entregaron .env.example con valores en producción o permitieron que un framework empaquete secretos de servidor en JavaScript del cliente. Aquí están los 6 errores que realmente ocurren.

Archivos .env — 6 errores que ponen tus secretos en GitHub 1
ANUNCIO · ¿ELIMINAR?

El informe de GitGuardian sobre el estado de la expansión de secretos de 2023 encontró más de 12 millones de secretos comprometidos en repositorios públicos de GitHub. La mayoría no fueron robados — fueron subidos por desarrolladores que realmente creían que los habían manejado correctamente. Estas son las patrones responsables.

1. Añadir .gitignore después del primer commit

.gitignore Después de eso, el archivo permanece en el disco pero Git lo ignora a partir de ahora. Reglas de negación: re-incluir archivos archivos de no estar en el estado de preparación. Una vez que un archivo es seguido — incluso brevemente — está en la historia de git. Si creaste .env, ejecutaste git add . && git commit, luego añadiste .env a .gitignore después, el archivo sigue en cada commit que precedió a ese cambio.

Verifique si ya está en la historia:

git log --all -- .env

Si eso devuelve commits, los secretos están en la historia. Rotar las credenciales primero. Luego elimina el archivo de la historia usando git-filter-repo (la sustitución recomendada para git filter-branch):

pip install git-filter-repo
git filter-repo --path .env --invert-paths

Realizar un force-push a todos los remotos y notificar a los compañeros para que reclonen. Los commits existen en cada clon que se creó antes de la eliminación — incluyendo cualquier sistema de CI que se haya realizado el repositorio.

2. Copiar .env a .env.example sin eliminar los valores

El flujo estándar: crear .env con valores reales, luego copiarlo a .env.example para mostrar a los compañeros qué claves necesita el proyecto. El copiado es donde ocurre el error.

cp .env .env.example copia todo — claves y valores. Y .env.example se supone que se debe commitear. Ese es el propósito completo. Valores reales en .env.example entran intencionalmente al repositorio.

❌ Lo que termina en git:

DATABASE_URL=postgres://admin:supersecretpassword@prod-db.example.com/appdb
STRIPE_SECRET_KEY=sk_live_51AbcDefGhiJklMnopQrstUvwx...
JWT_SECRET=my-actual-production-jwt-secret

✅ Lo que .env.example debería parecer:

DATABASE_URL=postgres://user:password@localhost:5432/appdb
STRIPE_SECRET_KEY=sk_live_YOUR_KEY_HERE
JWT_SECRET=generate-a-random-secret-min-32-chars

Crear .env.example con valores de lugar primero, comitearlo, luego copiarlo a .env y rellenar con credenciales reales — no al revés.

3. Registrar process.env en manejadores de errores

Este comienza como una “verificación rápida” durante un incidente y nunca se elimina. O se encuentra en un middleware genérico que parece inofensivo.

// Classic debug line that makes it to production
console.log('Starting with config:', process.env);

// Generic error handler that dumps everything
app.use((err, req, res, next) => {
  logger.error({ config: process.env, error: err.message });
  res.status(500).json({ error: 'Internal server error' });
});

process.env en tiempo de ejecución contiene todas las variables cargadas por dotenv, más variables del sistema. Pasar el objeto completo a un registro significa que llega a tu agregador de logs, a tu servicio de seguimiento de errores (Sentry, Datadog, Rollbar) y posiblemente a correos de notificación o webhooks de errores. Muchos de esos servicios envían a almacenamiento de terceros con sus propios controles de acceso.

Registra solo los valores específicos que necesitas para el diagnóstico:

logger.error({
  nodeEnv: process.env.NODE_ENV,
  appVersion: process.env.APP_VERSION,
  error: err.message,
  stack: err.stack
});

4. Incluir secretos en capas de imágenes Docker

Dos patrones que incorporan permanentemente secretos en la historia de imágenes Docker:

# Pattern 1: COPY bakes the entire .env into a layer
COPY .env .

# Pattern 2: ARG/ENV burns values into build metadata
ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL

Aunque elimines el archivo en una capa posterior (RUN rm .env), el valor sigue siendo legible en la historia de la imagen. Cualquiera con acceso de recuperación a la imagen puede ejecutar:

docker history --no-trunc your-image:tag

y recuperar los valores de ARG usados en el momento de la construcción. Los secretos de Docker BuildKit son la herramienta correcta — montan secretos durante la construcción sin escribirlos en ninguna capa:

# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=db_url     DATABASE_URL=$(cat /run/secrets/db_url) ./setup.sh

Para la configuración en tiempo de ejecución, inyecta variables de entorno al inicio del contenedor mediante docker run -e o environment: en Docker Compose que se refieran a variables de entorno del host — nunca valores codificados, nunca COPY‘archivos de secretos.

5. Usar secretos débiles que se envían a producción

JWT_SECRET=secret, SESSION_SECRET=keyboard cat, APP_KEY=changeme, ENCRYPTION_KEY=1234567890abcdef. Estos comienzan como placeholders de desarrollo y a veces nunca se reemplazan. Los atacantes que fuerzan firmas JWT intentan activamente estas cadenas — están en listas de palabras específicamente porque aparecen en búsquedas en GitHub.

Un JWT firmado con HS256 y un secreto débil puede ser crackeado fuera de línea con herramientas como c-jwt-cracker. Un token válido interceptado es suficiente para forzar el secreto y crear tokens arbitrarios.

Los secretos deben ser aleatorios criptográficamente, mínimo 32 bytes. Generarlos antes de que los necesites — la Generador de Secretos de Entorno en IO Tools producirá valores adecuadamente aleatorios para secretos comunes en .env (claves JWT, secretos de sesión, claves API) sin necesidad de configuración. Establecerlos desde el inicio; no usar un placeholder y planificar para “arreglarlo antes de producción”.

6. Convenciones de variables de entorno de marcos que exponen secretos al cliente

Varios marcos populares usan prefijos de nombres de variables para determinar la visibilidad entre cliente y servidor. Hacer esto mal envía secretos en el bundle de JavaScript a cada navegador que cargue tu aplicación — en texto plano.

  • Next.js: aunque NEXT_PUBLIC_-prefijadas variables se incluyen en el lado del cliente. Pero los secretos del servidor se revelan cuando se pasan a través de getServerSideProps props — cualquier valor devuelto en props se serializa en el HTML de la página y es legible en la fuente.
  • Vite: Variables prefijadas VITE_ se incluyen en el JS del cliente. Usar VITE_DATABASE_URL “por comodidad” es un error que realmente cometen los desarrolladores.
  • Create React App: Todo REACT_APP_ las variables terminan en el bundle del cliente, sin excepción. No existe un entorno de ejecución del lado del servidor de CRA — todo lo que se carga va al navegador.

Verifique después de la compilación buscando valores conocidos de secretos en el directorio de salida:

grep -r "sk_live_" ./dist
grep -r "sk_live_" ./.next/static

Si se encuentran coincidencias, esos secretos están en cada pestaña del navegador. Rotarlos inmediatamente y auditar lo demás que fue incluido.

Una costumbre que vale la pena construir desde el inicio

Antes de crear cualquier archivo que contenga secretos, configure .gitignore primero — no como una consideración posterior. El primer commit en cualquier nuevo repositorio debería ser .gitignore y .env.example con valores de lugar. La .gitignore Generador producirá un archivo de ignorar completo, específico del marco, en menos de un minuto.

Los seis errores anteriores son todos prevenibles antes de que se escriba cualquier código. La rotación es la única solución una vez que los secretos se han expuesto — y eso significa rotar en todos los lugares: el proveedor de servicios, cada entorno que tuvo una copia, y cada sistema que podría haber almacenado el valor en logs.

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?