4.2. Security Practices

4.2. Security Practices

PHP

1. Input Validation and Sanitization

  • Best Practices:

    • Validate input data to ensure it meets expected formats (e.g., email, date, integer).
    • Sanitize input to remove or escape harmful characters.
  • Techniques:

    • Use filter_var() for individual inputs:
      $email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
    • Use filter_input():
      $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
    • Use filter_input_array() for multiple inputs:
      $inputs = filter_input_array(INPUT_POST, [
          'email' => FILTER_VALIDATE_EMAIL,
          'age' => FILTER_VALIDATE_INT
      ]);

2. SQL Injection Protection

  • Best Practices:

    • Always use prepared statements and parameterized queries.
  • Examples:

    • Using PDO:
      $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
      $stmt->execute(['email' => $email]);
      $user = $stmt->fetch();
    • Using MySQLi:
      $stmt = $mysqli->prepare("SELECT * FROM users WHERE email = ?");
      $stmt->bind_param('s', $email);
      $stmt->execute();
      $result = $stmt->get_result();
      $user = $result->fetch_assoc();

3. Cross-Site Scripting (XSS) Prevention

  • Best Practices:

    • Sanitize output by escaping HTML characters.
    • Use CSP headers to control the sources of scripts and other content.
  • Examples:

    echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
    • Setting CSP headers:
      header("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self';");

4. Cross-Site Request Forgery (CSRF) Protection

  • Best Practices:

    • Use CSRF tokens in forms and validate them on the server side.
  • Examples:

    • Generating a CSRF token:
      session_start();
      $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    • Including the token in a form:
      <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
    • Validating the token:
      if (hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
          // Process form
      } else {
          // Invalid CSRF token
      }

5. Session Management

  • Best Practices:

    • Configure session settings for security.
  • Examples:

    ini_set('session.use_strict_mode', 1);
    ini_set('session.cookie_httponly', 1);
    ini_set('session.cookie_secure', 1);
    session_start();
    session_regenerate_id(true);

6. Error Handling and Logging

  • Best Practices:

    • Disable error display in production and log errors securely.
  • Examples:

    ini_set('display_errors', 0);
    ini_set('log_errors', 1);
    ini_set('error_log', '/path/to/error.log');

7. File Upload Security

  • Best Practices:

    • Validate and sanitize file names.
    • Check MIME types and file extensions.
    • Store uploaded files outside the web root.
  • Examples:

    $allowed_types = ['image/jpeg', 'image/png', 'application/pdf'];
    $file_type = mime_content_type($_FILES['file']['tmp_name']);
    if (in_array($file_type, $allowed_types)) {
        // Process file
    } else {
        // Invalid file type
    }

8. Password Management

  • Best Practices:

    • Use strong password hashing algorithms.
    • Implement multi-factor authentication (MFA).
  • Examples:

    $hashed_password = password_hash($password, PASSWORD_DEFAULT);
    if (password_verify($password, $hashed_password)) {
        // Password is correct
    }

9. Configuration and Deployment

  • Best Practices:

    • Disable unnecessary PHP functions.
    • Keep PHP up-to-date.
    • Use HTTPS for all communications.
  • Examples:

    • Disabling functions:
      disable_functions = exec,passthru,shell_exec,system
    • Forcing HTTPS:
      if ($_SERVER['HTTPS'] !== 'on') {
          header("Location: https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
          exit();
      }

Node.js

1. Input Validation and Sanitization

  • Best Practices:

    • Validate all user inputs to ensure they meet expected formats.
    • Sanitize inputs to remove harmful characters.
  • Techniques:

    • Use libraries like validator for input validation:
      const validator = require('validator');
      if (validator.isEmail(req.body.email)) {
          // Proceed with email
      }

2. Avoiding NoSQL Injection

  • Best Practices:

    • Use ORM/ODM libraries that provide query parameterization (e.g., Mongoose for MongoDB).
  • Examples:

    // Using Mongoose
    const user = await User.findOne({ email: req.body.email });

3. Preventing SQL Injection

  • Best Practices:

    • Use parameterized queries or ORM libraries.
  • Examples:

    • Using mysql module with parameterized queries:
      const mysql = require('mysql');
      const connection = mysql.createConnection({ /* config */ });
      connection.query('SELECT * FROM users WHERE email = ?', [req.body.email], (error, results) => {
          if (error) throw error;
          // Process results
      });

4. Cross-Site Scripting (XSS) Prevention

  • Best Practices:

    • Escape HTML characters in output.
    • Use CSP headers to control content sources.
  • Examples:

    const escape = require('escape-html');
    res.send(escape(userInput));
    • Setting CSP headers:
      app.use((req, res, next) => {
          res.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'; style-src 'self';");
          next();
      });

5. Cross-Site Request Forgery (CSRF) Protection

  • Best Practices:

    • Use CSRF tokens in forms and validate them on the server side.
    • Use libraries like csurf.
  • Examples:

    const csurf = require('csurf');
    const csrfProtection = csurf({ cookie: true });
    app.use(csrfProtection);
    
    app.get('/form', (req, res) => {
        res.render('send', { csrfToken: req.csrfToken() });
    });
    
    app.post('/process', (req, res) => {
        // Process form
    });

6. Session Management

  • Best Practices:

    • Use secure session configurations.
    • Use libraries like express-session with secure settings.
  • Examples:

    const session = require('express-session');
    app.use(session({
        secret: 'yourSecret',
        resave: false,
        saveUninitialized: true,
        cookie: { secure: true, httpOnly: true }
    }));

7. Error Handling and Logging

  • Best Practices:

    • Handle errors gracefully without exposing sensitive information.
    • Use centralized logging solutions.
  • Examples:

    app.use((err, req, res, next) => {
        console.error(err.stack);
        res.status(500).send('Something broke!');
    });

8. Secure Configuration and Deployment

  • Best Practices:

    • Disable X-Powered-By header.
    • Use environment variables for configuration.
    • Keep dependencies up-to-date.
  • Examples:

    • Disabling X-Powered-By header:
      app.disable('x-powered-by');
    • Using environment variables:
      const config = {
          db: process.env.DB_CONNECTION_STRING,
          port: process.env.PORT || 3000
      };

9. Dependency Management

  • Best Practices:

    • Regularly update dependencies.
    • Use tools like npm audit to find and fix vulnerabilities.
    • Avoid using deprecated or unmaintained packages.
  • Examples:

    npm audit

10. Secure File Uploads

  • Best Practices:

    • Validate file types and sizes.
    • Store files securely outside the web root.
  • Examples:

    • Using multer for file uploads:
      const multer = require('multer');
      const upload = multer({
          dest: 'uploads/',
          fileFilter: (req, file, cb) => {
              if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
                  cb(null, true);
              } else {
                  cb(new Error('Invalid file type'), false);
              }
          }
      });
      app.post('/upload', upload.single('avatar'), (req, res) => {
          res.send('File uploaded!');
      });

11. Using HTTPS

  • Best Practices:

    • Always use HTTPS for communication.
    • Redirect HTTP to HTTPS.
  • Examples:

    const fs = require('fs');
    const https = require('https');
    const express = require('express');
    const app = express();
    
    https.createServer({
        key: fs.readFileSync('server.key'),
        cert: fs.readFileSync('server.cert')
    }, app).listen(443, () => {
        console.log('HTTPS server running on port 443');
    });
    
    app.use((req, res, next) => {
        if (req.headers['x-forwarded-proto'] !== 'https') {
            return res.redirect('https://' + req.headers.host + req.url);
        }
        next();
    });