secure-headers-csp-builder

安装量: 50
排名: #14959

安装

npx skills add https://github.com/patricio0312rev/skills --skill secure-headers-csp-builder

Secure Headers & CSP Builder

Add security headers safely without breaking functionality.

Essential Security Headers // middleware/security-headers.ts import { Request, Response, NextFunction } from "express";

export function securityHeaders( req: Request, res: Response, next: NextFunction ) { // Prevent clickjacking res.setHeader("X-Frame-Options", "DENY");

// Prevent MIME sniffing res.setHeader("X-Content-Type-Options", "nosniff");

// XSS Protection (legacy browsers) res.setHeader("X-XSS-Protection", "1; mode=block");

// Referrer Policy res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");

// Permissions Policy (replaces Feature-Policy) res.setHeader( "Permissions-Policy", "camera=(), microphone=(), geolocation=(self), payment=()" );

// HSTS - Force HTTPS (only in production) if (process.env.NODE_ENV === "production") { res.setHeader( "Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload" ); }

next(); }

Content Security Policy (CSP) Phase 1: Report-Only Mode // config/csp-report-only.ts export const cspReportOnly = { "default-src": ["'self'"], "script-src": [ "'self'", "'report-sample'", "https://cdn.jsdelivr.net", "https://www.googletagmanager.com", ], "style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], "img-src": ["'self'", "data:", "https:"], "font-src": ["'self'", "https://fonts.gstatic.com"], "connect-src": ["'self'", "https://api.example.com"], "frame-ancestors": ["'none'"], "base-uri": ["'self'"], "form-action": ["'self'"], "report-uri": ["/api/csp-report"], };

function formatCSP(policy: Record): string { return Object.entries(policy) .map(([key, values]) => ${key} ${values.join(" ")}) .join("; "); }

// Apply report-only header app.use((req, res, next) => { res.setHeader( "Content-Security-Policy-Report-Only", formatCSP(cspReportOnly) ); next(); });

CSP Violation Reporter // routes/csp-report.ts app.post( "/api/csp-report", express.json({ type: "application/csp-report" }), (req, res) => { const violation = req.body["csp-report"];

console.error("CSP Violation:", {
  documentUri: violation["document-uri"],
  violatedDirective: violation["violated-directive"],
  blockedUri: violation["blocked-uri"],
  sourceFile: violation["source-file"],
  lineNumber: violation["line-number"],
});

// Store in monitoring system
trackCSPViolation({
  directive: violation["violated-directive"],
  blockedUri: violation["blocked-uri"],
  userAgent: req.headers["user-agent"],
  timestamp: new Date(),
});

res.status(204).send();

} );

Phase 2: Enforce Mode // config/csp-enforce.ts export const cspEnforce = { "default-src": ["'self'"], "script-src": [ "'self'", // Add nonces for inline scripts "'nonce-{NONCE}'", "https://cdn.jsdelivr.net", "https://www.googletagmanager.com", ], "style-src": [ "'self'", // Replace unsafe-inline with nonces "'nonce-{NONCE}'", "https://fonts.googleapis.com", ], "img-src": ["'self'", "data:", "https:"], "font-src": ["'self'", "https://fonts.gstatic.com"], "connect-src": ["'self'", "https://api.example.com"], "frame-ancestors": ["'none'"], "base-uri": ["'self'"], "form-action": ["'self'"], "upgrade-insecure-requests": [], };

// Generate nonce for each request app.use((req, res, next) => { const nonce = crypto.randomBytes(16).toString("base64"); res.locals.cspNonce = nonce;

const policy = formatCSP(cspEnforce).replace(/{NONCE}/g, nonce);

res.setHeader("Content-Security-Policy", policy); next(); });

Nonce Implementation // views/index.ejs

Secure Page

Helmet.js Integration // Using Helmet for comprehensive security headers import helmet from "helmet";

app.use( helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'nonce-{NONCE}'"], styleSrc: ["'self'", "'nonce-{NONCE}'"], imgSrc: ["'self'", "data:", "https:"], connectSrc: ["'self'", "https://api.example.com"], fontSrc: ["'self'", "https://fonts.gstatic.com"], objectSrc: ["'none'"], mediaSrc: ["'self'"], frameSrc: ["'none'"], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true, }, frameguard: { action: "deny", }, xssFilter: true, noSniff: true, referrerPolicy: { policy: "strict-origin-when-cross-origin", }, }) );

Rollout Plan

CSP Rollout Plan

Week 1: Report-Only Mode

  • [ ] Deploy CSP in report-only mode
  • [ ] Monitor violation reports
  • [ ] Identify problematic resources
  • [ ] Whitelist legitimate sources

Week 2: Analysis

  • [ ] Analyze 1 week of violations
  • [ ] Update CSP policy based on reports
  • [ ] Fix inline scripts/styles
  • [ ] Test on staging

Week 3: Staged Rollout

  • [ ] Enable enforcement for 10% of traffic
  • [ ] Monitor error rates
  • [ ] Check user reports
  • [ ] Adjust policy if needed

Week 4: Full Enforcement

  • [ ] Enable for 50% of traffic
  • [ ] Verify no issues
  • [ ] Enable for 100% of traffic
  • [ ] Keep report-only header for monitoring

Testing CSP // tests/csp.test.ts import { describe, it, expect } from "vitest"; import request from "supertest"; import { app } from "../src/app";

describe("Content Security Policy", () => { it("should set CSP header", async () => { const response = await request(app).get("/");

expect(response.headers["content-security-policy"]).toBeDefined();
expect(response.headers["content-security-policy"]).toContain(
  "default-src 'self'"
);

});

it("should block inline scripts without nonce", async () => { const html = <!DOCTYPE html> <html> <head> <script>alert('blocked')</script> </head> </html>;

// This would be blocked by CSP
// Verify in browser console or automated tests

});

it("should allow scripts with valid nonce", async () => { const response = await request(app).get("/");

// Extract nonce from response
const nonceMatch = response.text.match(/nonce="([^"]+)"/);
expect(nonceMatch).toBeDefined();

}); });

Common CSP Issues & Fixes // Issue 1: Inline event handlers // ❌ Bad

// ✅ Good

// Issue 2: Inline styles // ❌ Bad

Text

// ✅ Good

Text

// Issue 3: eval() usage // ❌ Bad eval('console.log("test")');

// ✅ Good // Don't use eval - refactor code

// Issue 4: Third-party scripts // ❌ Bad - no CSP entry

// ✅ Good - whitelisted in CSP script-src: ['self', 'https://cdn.example.com']

Monitoring & Alerts // monitoring/csp-violations.ts import { CloudWatch } from "@aws-sdk/client-cloudwatch";

const cloudwatch = new CloudWatch();

export async function trackCSPViolation(violation: { directive: string; blockedUri: string; userAgent: string; timestamp: Date; }) { await cloudwatch.putMetricData({ Namespace: "Security/CSP", MetricData: [ { MetricName: "Violations", Value: 1, Unit: "Count", Timestamp: violation.timestamp, Dimensions: [ { Name: "Directive", Value: violation.directive, }, { Name: "BlockedUri", Value: violation.blockedUri, }, ], }, ], });

// Alert if violations spike if (await isViolationSpike()) { await sendAlert({ title: "CSP Violation Spike Detected", message: High number of violations for ${violation.directive}, }); } }

Best Practices Start report-only: Don't break production Gradual rollout: 10% → 50% → 100% Use nonces: Better than unsafe-inline Monitor violations: Track and analyze Test thoroughly: All pages and features Document exceptions: Why resources whitelisted Regular audits: Quarterly CSP review Output Checklist Security headers implemented CSP policy defined (report-only) CSP violation reporter endpoint Nonce generation for inline scripts Helmet.js configured Rollout plan documented Testing strategy implemented Monitoring and alerts configured Team trained on CSP Staged rollout completed

返回排行榜