Proteger Astro de ataques a la cadena de… | LaunchFast
LaunchFast Logo LaunchFast
Blog
2867 palabras 15 min de lectura

Proteger Astro de ataques a la cadena de suministro: Parte 2 - Medidas de seguridad a largo plazo

Implemente medidas de seguridad integrales para su proyecto Astro. Aprenda a asegurar su pipeline de CI/CD, automatizar el escaneo de dependencias y prevenir futuros ataques a la cadena de suministro de npm.

Rishi Raj Jain
Rishi Raj Jain Autor
Proteger Astro de ataques a la cadena de suministro Parte 2

Esta es la Parte 2 de una serie de 2 artículos sobre cómo proteger sitios Astro de ataques a la cadena de suministro de npm. La Parte 1 cubrió la comprensión de la amenaza y la respuesta inmediata. Este artículo se centra en medidas de seguridad a largo plazo, monitorización y buenas prácticas.

Sponsored

Kits de inicio de alta calidad con flujo de autenticación integrada (Auth.js), carga de objetos (AWS, Clouflare R2, Firebase Storage, Supabase Storage), pagos integrados (Stripe, LemonSqueezy), flujo de verificación de correo electrónico (Resend, Postmark, Sendgrid) y mucho más . Compatible con cualquier base de datos (Redis, Postgres, MongoDB, SQLite, Firestore).

Get all 3 kits Bundle ↗

One-time license · Lifetime updates

En la Parte 1, cubrimos la respuesta inmediata al ataque Shai-Hulud 2.0. Ahora es el momento de implementar medidas de seguridad integrales que protejan su proyecto Astro de futuros ataques a la cadena de suministro. No son parches temporales: son prácticas esenciales que deberían formar parte de su flujo de trabajo de desarrollo.

Requisitos previos

Necesitará lo siguiente:

  • Haber completado la Parte 1 de esta serie

1. Implementar bloqueo y verificación de paquetes

La primera línea de defensa contra ataques a la cadena de suministro es asegurarse de que siempre instala exactamente las versiones de los paquetes que ha probado y verificado.

1.1 Usar números de versión exactos

Nunca use rangos de versión en su package.json para dependencias de producción:

// ❌ Malo: permite actualizaciones automáticas
{
"dependencies": {
"astro": "^4.16.1", // Puede instalar 4.16.x o 4.x.x
"sharp": "~0.33.1" // Puede instalar 0.33.x
}
}
// ✅ Bueno: solo versiones exactas
{
"dependencies": {
"astro": "4.16.1",
"sharp": "0.33.1"
}
}

1.2 Configurar npm/pnpm para seguridad

Cree un archivo .npmrc en la raíz de su proyecto con configuraciones de seguridad estrictas:

.npmrc
# Always use exact versions when saving packages
save-exact=true
# Ensure package-lock.json is always created and used
package-lock=true
# Run audit on every install
audit=true
# Set minimum audit level (low, moderate, high, critical)
audit-level=moderate
# Fail install if vulnerabilities are found
audit-report=true

Para usuarios de pnpm (recomendado), configure funciones de seguridad adicionales:

Terminal window
# File: .npmrc (for pnpm)
# Require exact versions
save-exact=true
# Strict peer dependencies
strict-peer-dependencies=true
# Verify package integrity using checksums
package-import-method=copy
# Run security audit on install
audit=true
# Only allow packages from verified registries
registry=https://registry.npmjs.org/
# Verify SSL certificates
strict-ssl=true

1.3 Confirmar siempre los archivos de bloqueo

Su archivo de bloqueo (package-lock.json o pnpm-lock.yaml) es fundamental para builds reproducibles:

Terminal window
# Ensure lock file is tracked in git
git add pnpm-lock.yaml
git commit -m "chore: commit lock file for security"

Actualice su .gitignore para asegurarse de que los archivos de bloqueo nunca se ignoren:

.gitignore
# Make sure these are NOT in .gitignore:
# pnpm-lock.yaml
# package-lock.json
# yarn.lock
# But DO ignore
node_modules/

2. Usar herramientas de escaneo de dependencias

Las herramientas de escaneo automatizado pueden detectar vulnerabilidades antes de que lleguen a producción. Configuremos un flujo de trabajo de escaneo integral.

2.1 Escaneo de seguridad con Snyk y GitHub Actions

Snyk es una plataforma de seguridad para desarrolladores líder, especializada en escanear sus dependencias en busca de vulnerabilidades.

Cree un flujo de trabajo de GitHub Actions para el escaneo con Snyk:

.github/workflows/snyk-security-scan.yml
name: Snyk Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
snyk-scan:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Install dependencies (safely)
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Run npm audit
run: pnpm audit --audit-level=moderate
continue-on-error: true
id: npm-audit
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high --all-projects
continue-on-error: true
id: snyk-scan
- name: Generate Security Report
if: always()
run: |
echo "# Snyk Security Scan Report" > security-report.md
echo "Generated: $(date)" >> security-report.md
echo "" >> security-report.md
echo "## Scan Results" >> security-report.md
echo "- npm audit: ${{ steps.npm-audit.outcome }}" >> security-report.md
echo "- Snyk scan: ${{ steps.snyk-scan.outcome }}" >> security-report.md
- name: Upload Security Report
uses: actions/upload-artifact@v4
if: always()
with:
name: snyk-security-report-${{ github.run_number }}
path: security-report.md
retention-days: 90

Snyk ofrece monitorización continua de sus dependencias, rastreando nuevas vulnerabilidades incluso después de que su código se haya fusionado. Proporciona sugerencias de corrección que identifican exactamente qué actualizaciones resolverán problemas conocidos. Con una sólida integración en IDE y CI/CD, Snyk le ayuda a detectar problemas de seguridad antes de que sus dependencias lleguen a producción. Además, Snyk ofrece un generoso plan gratuito para repositorios públicos y de código abierto, lo que lo hace accesible para la comunidad de desarrolladores en general.

2.2 Escáner de vulnerabilidades Trivy con GitHub Actions

Trivy es un escáner de vulnerabilidades de código abierto que ofrece un escaneo más amplio, incluyendo seguridad de infraestructura y contenedores.

Configure Trivy con GitHub Actions:

.github/workflows/trivy-scan.yml
name: Trivy Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
trivy-scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Install dependencies (safely)
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Trivy vulnerability scan (code & dependencies)
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'

Trivy es un escáner de seguridad de código abierto que ofrece una cobertura amplia de vulnerabilidades en todo su proyecto: no solo en node_modules, sino también en contenedores, paquetes del sistema operativo, archivos de configuración e infraestructura como código. Sus resultados pueden exportarse en formato SARIF, lo que permite una integración fluida con las funciones de seguridad de GitHub. Trivy es gratuito, sencillo de automatizar y está bien adaptado tanto para flujos de trabajo locales como de CI/CD.

2.3 Configurar escaneo de seguridad local

No espere a que CI/CD detecte los problemas. Escanee localmente antes de hacer push:

Terminal window
# Install Snyk CLI globally
npm install -g snyk
# Authenticate with Snyk
snyk auth
# Scan your project
snyk test
# Monitor your project (sends snapshot to Snyk for continuous monitoring)
snyk monitor

Añada un hook de git pre-push:

Terminal window
# Install husky if you haven't already
pnpm add -D husky
# Initialize husky
npx husky init
# Create pre-push hook
cat > .husky/pre-push << 'EOF'
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "🔍 Running security scan before push..."
pnpm audit --audit-level=moderate
EOF
chmod +x .husky/pre-push

3. Asegurar su pipeline de CI/CD

El ataque Shai-Hulud 2.0 apuntó específicamente a entornos de CI/CD donde los secretos están fácilmente disponibles. Así es como puede reforzar su pipeline.

3.1 Usar permisos mínimos

Configure sus GitHub Actions con el principio de mínimo privilegio:

.github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
# Set minimal default permissions
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
# Override only for specific needs
permissions:
contents: read
deployments: write
id-token: write # For OIDC authentication
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
# Critical: Disable install scripts in CI
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Build
env:
# Use environment-specific secrets
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
API_KEY: ${{ secrets.PROD_API_KEY }}
run: pnpm run build
- name: Deploy
run: pnpm run deploy

3.2 Desactivar scripts de instalación

Los scripts de instalación son el vector de ataque principal. Desactívelos siempre en CI/CD:

# Always use --ignore-scripts in CI
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts

Para paquetes que legítimamente necesitan scripts de instalación (como sharp o esbuild), reconstrúyalos explícitamente:

scripts/secure-install.ts
import { execSync } from 'child_process'
console.log('🔒 Running secure installation...\n')
try {
// Install without running any scripts
console.log('📦 Installing packages without scripts...')
execSync('pnpm install --frozen-lockfile --ignore-scripts', {
stdio: 'inherit',
})
console.log('\n✅ Dependencies installed safely')
// Explicitly rebuild trusted packages that need native bindings
const TRUSTED_PACKAGES = [
'sharp', // Image processing
'esbuild', // Bundler
'@parcel/watcher', // File watcher
// Add other trusted packages here
]
console.log('\n📦 Rebuilding trusted native packages...')
for (const pkg of TRUSTED_PACKAGES) {
try {
console.log(` - Rebuilding ${pkg}...`)
execSync(`pnpm rebuild ${pkg}`, { stdio: 'inherit' })
console.log(` ✅ ${pkg} rebuilt successfully`)
} catch (error) {
console.error(` ❌ Failed to rebuild ${pkg}`)
// Don't fail the whole process - package might not be installed
}
}
console.log('\n✅ Secure installation complete!')
} catch (error) {
console.error('\n❌ Installation failed:', error.message)
process.exit(1)
}

Actualice su package.json:

{
"scripts": {
"install:safe": "tsx scripts/secure-install.ts",
"build": "astro build",
"dev": "astro dev"
}
}

3.3 Usar aislamiento de entornos

Use secretos y credenciales diferentes para cada entorno (dev, staging, producción) para contener posibles brechas y evitar que las filtraciones se propaguen entre entornos.

.github/workflows/deploy-staging.yml
name: Deploy to Staging
on:
push:
branches: [develop]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # GitHub environment
steps:
- uses: actions/checkout@v4
- name: Build and Deploy
env:
# Staging-specific secrets
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
API_KEY: ${{ secrets.STAGING_API_KEY }}
run: |
pnpm install --frozen-lockfile --ignore-scripts
pnpm run build
pnpm run deploy:staging

.github/workflows/deploy-production.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: production # Different environment
steps:
- uses: actions/checkout@v4
- name: Build and Deploy
env:
# Production-specific secrets
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
API_KEY: ${{ secrets.PROD_API_KEY }}
run: |
pnpm install --frozen-lockfile --ignore-scripts
pnpm run build
pnpm run deploy:production

3.4 Usar OIDC en lugar de tokens de larga duración

Para despliegues en la nube, use OpenID Connect (OIDC) en lugar de almacenar credenciales de larga duración:

.github/workflows/deploy-aws.yml
name: Deploy to AWS
on:
push:
branches: [main]
permissions:
id-token: write # Required for OIDC
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Use OIDC to get temporary credentials
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
aws-region: us-east-1
# Now you have temporary AWS credentials
- name: Deploy to S3
run: |
pnpm run build
aws s3 sync dist/ s3://my-bucket/

Al adoptar OIDC, elimina la necesidad de almacenar credenciales de nube de larga duración en GitHub, reduciendo significativamente el riesgo si su entorno de CI alguna vez se ve comprometido. En su lugar, GitHub Actions puede solicitar credenciales temporales que expiran automáticamente para cada ejecución del flujo de trabajo. Cada evento de autenticación se registra y es auditable en AWS CloudTrail, garantizando trazabilidad completa y transparencia de seguridad.

4. Configurar la automatización de npm audit

Convierta las auditorías de seguridad en una parte habitual de su flujo de trabajo de desarrollo.

4.1 Configurar hooks pre-commit

Configurar hooks pre-commit añade un punto de control automatizado en su flujo de trabajo para evitar que confirme código inseguro. Cada vez que intente hacer un commit, Husky activará la auditoría de seguridad (usando pnpm audit --audit-level=moderate). Si se detectan vulnerabilidades por encima del umbral, el commit se bloquea hasta que se resuelvan los problemas o se omitan intencionalmente. Esto ayuda a garantizar que solo se confirme código seguro en el repositorio, manteniendo la integridad de su proyecto desde el principio.

.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "🔍 Running pre-commit security checks...\n"
# Run audit
echo "📦 Checking for vulnerabilities..."
pnpm audit --audit-level=moderate
if [ $? -ne 0 ]; then
echo "\n❌ Security vulnerabilities found!"
echo "Run 'pnpm audit fix' to resolve issues."
echo "Or use --no-verify to skip (not recommended)."
exit 1
fi
echo "✅ Security checks passed!\n"

Además, actualice los scripts en package.json para ejecutar las auditorías a través del gestor de paquetes correspondiente.

{
"scripts": {
"audit": "pnpm audit --audit-level=moderate",
"audit:fix": "pnpm audit fix",
"audit:production": "pnpm audit --production --audit-level=high",
"precommit": "pnpm run audit",
"prepush": "pnpm run audit:production"
}
}

4.2 Crear informes de seguridad automatizados

Esta sección muestra cómo crear informes de seguridad automatizados para su proyecto.

scripts/generate-security-report.ts
import { execSync } from 'child_process'
import { writeFileSync } from 'fs'
const generateSecurityReport = () => {
console.log('📊 Generating security report...\n')
const report = {
timestamp: new Date().toISOString(),
auditResults: null as any,
outdatedPackages: null as any,
recommendations: [] as string[],
}
try {
// Run npm audit
const auditOutput = execSync('pnpm audit --json', {
encoding: 'utf-8',
})
report.auditResults = JSON.parse(auditOutput)
} catch (error: any) {
// Audit exits with non-zero if vulnerabilities found
if (error.stdout) {
report.auditResults = JSON.parse(error.stdout)
}
}
// Generate recommendations
const vulnerabilities = report.auditResults?.metadata?.vulnerabilities
if (vulnerabilities) {
const { critical, high, moderate } = vulnerabilities
if (critical > 0) {
report.recommendations.push(
`🚨 CRITICAL: ${critical} critical vulnerabilities require immediate attention`
)
}
if (high > 0) {
report.recommendations.push(
`⚠️ HIGH: ${high} high-severity vulnerabilities should be addressed soon`
)
}
if (moderate > 0) {
report.recommendations.push(
`ℹ️ MODERATE: ${moderate} moderate vulnerabilities should be reviewed`
)
}
}
// Write report
const reportPath = `security-report-${Date.now()}.json`
writeFileSync(reportPath, JSON.stringify(report, null, 2))
console.log(`✅ Security report generated: ${reportPath}\n`)
// Print summary
console.log('📊 Summary:')
report.recommendations.forEach(rec => console.log(rec))
return report
}
generateSecurityReport()
  • Ejecute un comando pnpm audit para escanear sus dependencias en busca de vulnerabilidades y capturar los resultados en JSON.
  • Recopile la marca de tiempo del descubrimiento, los resultados de la auditoría y las recomendaciones de remediación.
  • Resuma las vulnerabilidades por gravedad (critical, high, moderate) y proporcione recomendaciones accionables si hay problemas.
  • Escriba el informe de seguridad resultante en un archivo que pueda revisar o compartir con su equipo.

Al integrar este script en su flujo de trabajo, garantiza una visibilidad clara y regular del estado de seguridad de su proyecto. Esto facilita el seguimiento y la corrección efectiva de vulnerabilidades, y respalda una política de monitorización continua de la seguridad.

Conclusión

Los pasos que hemos cubierto aquí establecen una defensa fiable: use siempre versiones exactas y archivos de bloqueo, automatice las comprobaciones de seguridad en su pipeline de CI/CD, desactive los scripts de instalación durante los builds de producción, use OIDC en lugar de credenciales estáticas y convierta las revisiones de seguridad en una parte estándar de su proceso con git.

Si tiene preguntas o comentarios, no dude en contactarme en Twitter.

Sigue leyendo