csrf-protection

安装量: 129
排名: #6684

安装

npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill csrf-protection

CSRF Protection Overview

Implement comprehensive Cross-Site Request Forgery protection using synchronizer tokens, double-submit cookies, SameSite cookie attributes, and custom headers.

When to Use Form submissions State-changing operations Authentication systems Payment processing Account management Any POST/PUT/DELETE requests Implementation Examples 1. Node.js/Express CSRF Protection // csrf-protection.js const crypto = require('crypto'); const csrf = require('csurf');

class CSRFProtection { constructor() { this.tokens = new Map(); this.tokenExpiry = 3600000; // 1 hour }

/* * Generate CSRF token / generateToken() { return crypto.randomBytes(32).toString('hex'); }

/* * Create token for session / createToken(sessionId) { const token = this.generateToken(); const expiry = Date.now() + this.tokenExpiry;

this.tokens.set(sessionId, {
  token,
  expiry
});

return token;

}

/* * Validate CSRF token / validateToken(sessionId, token) { const stored = this.tokens.get(sessionId);

if (!stored) {
  return false;
}

if (Date.now() > stored.expiry) {
  this.tokens.delete(sessionId);
  return false;
}

return crypto.timingSafeEqual(
  Buffer.from(stored.token),
  Buffer.from(token)
);

}

/* * Express middleware / middleware() { return (req, res, next) => { // Skip GET, HEAD, OPTIONS if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) { return next(); }

  const token = req.headers['x-csrf-token'] || req.body._csrf;
  const sessionId = req.session?.id;

  if (!token) {
    return res.status(403).json({
      error: 'csrf_token_missing',
      message: 'CSRF token is required'
    });
  }

  if (!this.validateToken(sessionId, token)) {
    return res.status(403).json({
      error: 'csrf_token_invalid',
      message: 'Invalid or expired CSRF token'
    });
  }

  next();
};

} }

// Express setup with csurf package const express = require('express'); const session = require('express-session'); const cookieParser = require('cookie-parser');

const app = express();

// Session configuration app.use(cookieParser()); app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600000 } }));

// CSRF protection middleware const csrfProtection = csrf({ cookie: { httpOnly: true, secure: true, sameSite: 'strict' } });

app.use(csrfProtection);

// Provide token to templates app.use((req, res, next) => { res.locals.csrfToken = req.csrfToken(); next(); });

// API endpoint to get CSRF token app.get('/api/csrf-token', (req, res) => { res.json({ csrfToken: req.csrfToken() }); });

// Protected route app.post('/api/transfer', csrfProtection, (req, res) => { const { amount, toAccount } = req.body;

// Process transfer res.json({ message: 'Transfer successful', amount, toAccount }); });

// Error handler for CSRF errors app.use((err, req, res, next) => { if (err.code === 'EBADCSRFTOKEN') { return res.status(403).json({ error: 'csrf_error', message: 'Invalid CSRF token' }); }

next(err); });

module.exports = { CSRFProtection, csrfProtection };

  1. Double Submit Cookie Pattern // double-submit-csrf.js const crypto = require('crypto');

class DoubleSubmitCSRF { /* * Generate CSRF token and set cookie / static generateAndSetToken(res) { const token = crypto.randomBytes(32).toString('hex');

// Set CSRF cookie
res.cookie('XSRF-TOKEN', token, {
  httpOnly: false, // Allow JS to read for double submit
  secure: true,
  sameSite: 'strict',
  maxAge: 3600000
});

return token;

}

/* * Middleware to validate double submit / static middleware() { return (req, res, next) => { // Skip GET, HEAD, OPTIONS if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) { return next(); }

  const cookieToken = req.cookies['XSRF-TOKEN'];
  const headerToken = req.headers['x-xsrf-token'];

  if (!cookieToken || !headerToken) {
    return res.status(403).json({
      error: 'csrf_token_missing'
    });
  }

  // Compare tokens (timing-safe)
  if (!crypto.timingSafeEqual(
    Buffer.from(cookieToken),
    Buffer.from(headerToken)
  )) {
    return res.status(403).json({
      error: 'csrf_token_mismatch'
    });
  }

  next();
};

} }

// Express setup const app = express(); const cookieParser = require('cookie-parser');

app.use(cookieParser()); app.use(express.json());

// Generate token on login app.post('/api/login', async (req, res) => { // Authenticate user const token = DoubleSubmitCSRF.generateAndSetToken(res);

res.json({ message: 'Login successful', csrfToken: token }); });

// Protected routes app.use('/api/*', DoubleSubmitCSRF.middleware());

app.post('/api/update-profile', (req, res) => { // Update profile res.json({ message: 'Profile updated' }); });

  1. Python Flask CSRF Protection

csrf_protection.py

from flask import Flask, session, request, jsonify from flask_wtf.csrf import CSRFProtect, generate_csrf, validate_csrf from functools import wraps import secrets

app = Flask(name) app.config['SECRET_KEY'] = 'your-secret-key' app.config['WTF_CSRF_TIME_LIMIT'] = 3600 # 1 hour app.config['WTF_CSRF_SSL_STRICT'] = True

csrf = CSRFProtect(app)

Cookie configuration

app.config.update( SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE='Strict' )

@app.before_request def csrf_protect(): """Validate CSRF token for state-changing methods""" if request.method in ['POST', 'PUT', 'DELETE', 'PATCH']: token = request.headers.get('X-CSRF-Token') or request.form.get('csrf_token')

    if not token:
        return jsonify({'error': 'CSRF token missing'}), 403

    try:
        validate_csrf(token)
    except:
        return jsonify({'error': 'Invalid CSRF token'}), 403

@app.route('/api/csrf-token', methods=['GET']) def get_csrf_token(): """Provide CSRF token to clients""" token = generate_csrf() return jsonify({'csrfToken': token})

@app.route('/api/transfer', methods=['POST']) def transfer_funds(): """Protected endpoint""" data = request.get_json()

return jsonify({
    'message': 'Transfer successful',
    'amount': data.get('amount')
})

Custom CSRF decorator

def require_csrf(f): @wraps(f) def decorated_function(args, *kwargs): if request.method in ['POST', 'PUT', 'DELETE']: token = request.headers.get('X-CSRF-Token')

        if not token:
            return jsonify({'error': 'CSRF token required'}), 403

        try:
            validate_csrf(token)
        except:
            return jsonify({'error': 'Invalid CSRF token'}), 403

    return f(*args, **kwargs)

return decorated_function

@app.route('/api/sensitive-action', methods=['POST']) @require_csrf def sensitive_action(): return jsonify({'message': 'Action completed'})

if name == 'main': app.run(ssl_context='adhoc')

  1. Frontend CSRF Implementation // csrf-client.js class CSRFClient { constructor() { this.token = null; this.tokenExpiry = null; }

/* * Fetch CSRF token from server / async fetchToken() { const response = await fetch('/api/csrf-token', { credentials: 'include' });

const data = await response.json();
this.token = data.csrfToken;
this.tokenExpiry = Date.now() + 3600000; // 1 hour

return this.token;

}

/* * Get valid token (fetch if needed) / async getToken() { if (!this.token || Date.now() > this.tokenExpiry) { await this.fetchToken(); }

return this.token;

}

/* * Make protected request / async request(url, options = {}) { const token = await this.getToken();

const headers = {
  'Content-Type': 'application/json',
  'X-CSRF-Token': token,
  ...options.headers
};

return fetch(url, {
  ...options,
  headers,
  credentials: 'include'
});

}

/* * POST request with CSRF token / async post(url, data) { return this.request(url, { method: 'POST', body: JSON.stringify(data) }); }

/* * PUT request with CSRF token / async put(url, data) { return this.request(url, { method: 'PUT', body: JSON.stringify(data) }); }

/* * DELETE request with CSRF token / async delete(url) { return this.request(url, { method: 'DELETE' }); } }

// Usage const client = new CSRFClient();

async function transferFunds() { try { const response = await client.post('/api/transfer', { amount: 1000, toAccount: '123456' });

const result = await response.json();
console.log('Transfer successful:', result);

} catch (error) { console.error('Transfer failed:', error); } }

// React hook for CSRF function useCSRF() { const [token, setToken] = React.useState(null);

React.useEffect(() => { async function fetchToken() { const response = await fetch('/api/csrf-token'); const data = await response.json(); setToken(data.csrfToken); }

fetchToken();

}, []);

return token; }

// Usage in React form function TransferForm() { const csrfToken = useCSRF();

const handleSubmit = async (e) => { e.preventDefault();

await fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({
    amount: 1000,
    toAccount: '123456'
  })
});

};

return (

{/ form fields /}
); }

  1. Origin and Referer Validation // origin-validation.js function validateOrigin(req, res, next) { const allowedOrigins = [ 'https://example.com', 'https://app.example.com' ];

const origin = req.headers.origin; const referer = req.headers.referer;

// Check Origin header if (origin && !allowedOrigins.includes(origin)) { return res.status(403).json({ error: 'invalid_origin' }); }

// Check Referer header as fallback if (!origin && referer) { const refererUrl = new URL(referer); if (!allowedOrigins.includes(refererUrl.origin)) { return res.status(403).json({ error: 'invalid_referer' }); } }

next(); }

// Apply to state-changing routes app.use('/api/*', validateOrigin);

Best Practices ✅ DO Use CSRF tokens for all state-changing operations Set SameSite=Strict on cookies Validate Origin/Referer headers Use secure, random tokens Implement token expiration Use HTTPS only Include tokens in AJAX requests Test CSRF protection ❌ DON'T Skip CSRF for authenticated requests Use GET for state changes Trust Origin header alone Reuse tokens Store tokens in localStorage Allow credentials in CORS without validation CSRF Protection Methods Synchronizer Token: Server-generated tokens Double Submit Cookie: Cookie and header match SameSite Cookies: Browser-level protection Custom Headers: X-Requested-With Origin Validation: Check request origin Defense Layers CSRF tokens implemented SameSite cookies configured Origin/Referer validation Custom request headers Token expiration Secure cookie flags HTTPS enforced Resources OWASP CSRF Prevention SameSite Cookie Spec Double Submit Cookies

返回排行榜