阿里云主机折上折
  • 微信号
Current Site:Index > Secure coding standards

Secure coding standards

Author:Chuan Chen 阅读数:49235人阅读 分类: 前端安全

Secure coding standards are the cornerstone of front-end application security. Adhering to these standards can effectively reduce vulnerability risks and improve code quality. From input validation to output encoding, from dependency management to sensitive data handling, each step requires stringent security measures.

Input Validation and Filtering

All user input should be treated as untrusted data. Form inputs, URL parameters, Cookie values, and even local storage data must be validated:

// Dangerous example: Directly using unvalidated DOM input
const userInput = document.getElementById('search').value;
document.body.innerHTML += userInput;

// Secure practice: Using text nodes instead of innerHTML
const sanitizedInput = DOMPurify.sanitize(userInput);
document.body.appendChild(document.createTextNode(sanitizedInput));

Regular expression validation example:

// Validate email format
function isValidEmail(email) {
  const re = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  return re.test(String(email).toLowerCase());
}

// Validate number range
function isValidNumber(num, min, max) {
  return !isNaN(num) && num >= min && num <= max;
}

Output Encoding and XSS Protection

Different contexts require different encoding methods:

  1. HTML context:
// Dangerous example
element.innerHTML = userData;

// Secure practice
element.textContent = userData;
// Or use library functions
element.innerHTML = DOMPurify.sanitize(userData);
  1. URL context:
// Encode parameters when constructing URLs
const safeParam = encodeURIComponent(userInput);
const url = `/search?q=${safeParam}`;
  1. CSS context:
// Dangerous example
element.style.backgroundImage = `url(${userUrl})`;

// Secure practice
const safeUrl = CSS.escape(userUrl);
element.style.backgroundImage = `url(${safeUrl})`;

Content Security Policy (CSP) Implementation

CSP HTTP header example:

Content-Security-Policy: 
  default-src 'self';
  script-src 'self' 'unsafe-inline' cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
  connect-src 'self' api.example.com;
  frame-ancestors 'none';
  form-action 'self';

Special configuration for frameworks like React:

<meta http-equiv="Content-Security-Policy" 
      content="script-src 'self' 'unsafe-eval'">

Authentication and Session Management

Common security practices:

  1. Token storage:
// Insecure practice
localStorage.setItem('token', sensitiveToken);

// Recommended practice
document.cookie = `token=${sensitiveToken}; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600`;
  1. Password strength validation:
function validatePassword(password) {
  const minLength = 12;
  const hasUpper = /[A-Z]/.test(password);
  const hasLower = /[a-z]/.test(password);
  const hasNumber = /\d/.test(password);
  const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password);
  
  return password.length >= minLength && 
         hasUpper && 
         hasLower && 
         hasNumber && 
         hasSpecial;
}

Dependency Management Security

  1. Regular dependency audits:
npm audit
npx snyk test
  1. Lock file example (package.json snippet):
{
  "dependencies": {
    "react": "18.2.0",
    "lodash": "^4.17.21"
  },
  "overrides": {
    "lodash": "4.17.21"
  }
}
  1. Auto-update tool configuration:
# .renovaterc.json
{
  "extends": ["config:recommended"],
  "vulnerabilityAlerts": {
    "enabled": true
  }
}

Front-End Sensitive Data Handling

  1. Clearing sensitive data in memory:
function handleSensitiveData(data) {
  try {
    // Process data...
  } finally {
    // Clear memory
    for (let i = 0; i < data.length; i++) {
      data[i] = 0;
    }
    data.length = 0;
  }
}
  1. Avoiding log leaks:
// Bad example
console.log(`User token: ${userToken}`);

// Correct practice
console.log('User authenticated', { userId: 123 });

Cross-Origin Resource Sharing (CORS) Configuration

Correct configuration example:

// Express example
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://trusted.example.com');
  res.header('Access-Control-Allow-Methods', 'GET,POST');
  res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
  res.header('Access-Control-Allow-Credentials', 'true');
  res.header('Access-Control-Max-Age', '86400');
  next();
});

Dangerous configuration warnings:

// Dangerous configuration - Allow any origin
res.header('Access-Control-Allow-Origin', '*');
// Dangerous configuration - Allow any method
res.header('Access-Control-Allow-Methods', '*');

Front-End Encryption Practices

  1. Web Crypto API example:
async function hashPassword(password) {
  const encoder = new TextEncoder();
  const data = encoder.encode(password);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
  1. Encrypted storage example:
async function encryptData(data, secretKey) {
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const encoded = new TextEncoder().encode(data);
  
  const keyMaterial = await crypto.subtle.importKey(
    'raw',
    new TextEncoder().encode(secretKey),
    { name: 'PBKDF2' },
    false,
    ['deriveKey']
  );
  
  const key = await crypto.subtle.deriveKey(
    {
      name: 'PBKDF2',
      salt: iv,
      iterations: 100000,
      hash: 'SHA-256'
    },
    keyMaterial,
    { name: 'AES-GCM', length: 256 },
    false,
    ['encrypt']
  );
  
  const encrypted = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv },
    key,
    encoded
  );
  
  return {
    iv: Array.from(iv).join(','),
    data: Array.from(new Uint8Array(encrypted)).join(',')
  };
}

Error Handling and Logging

Secure error handling patterns:

// Insecure error handling
try {
  sensitiveOperation();
} catch (err) {
  showError(err.stack);
}

// Secure error handling
try {
  sensitiveOperation();
} catch (err) {
  logError(err);
  showGenericError();
}

function logError(err) {
  const safeInfo = {
    message: err.message,
    code: err.code,
    timestamp: Date.now(),
    path: window.location.pathname
  };
  sendToServer('/error-log', safeInfo);
}

Modern Framework Security Practices

React-specific security measures:

// Dangerous usage
<div dangerouslySetInnerHTML={{ __html: userContent }} />

// Secure alternative
<div>{userContent}</div>

// Or use sanitization library
import sanitizeHtml from 'sanitize-html';

function SafeHTML({ html }) {
  const clean = sanitizeHtml(html, {
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: {
      a: ['href', 'target']
    }
  });
  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

Vue security practices:

<template>
  <!-- Dangerous usage -->
  <div v-html="userContent"></div>
  
  <!-- Secure usage -->
  <div>{{ userContent }}</div>
</template>

<script>
import DOMPurify from 'dompurify';

export default {
  methods: {
    sanitize(html) {
      return DOMPurify.sanitize(html);
    }
  }
}
</script>

Browser Security Headers

Key security header configuration example:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Feature-Policy: geolocation 'none'; microphone 'none'; camera 'none'

Nginx configuration example:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Content-Security-Policy "default-src 'self'";

Automated Security Testing

Integration testing example:

// Using Jest for XSS testing
describe('XSS Protection', () => {
  test('should sanitize script tags', () => {
    const maliciousInput = '<script>alert(1)</script>';
    render(<Component userInput={maliciousInput} />);
    expect(document.scripts.length).toBe(0);
  });
});

// Using Cypress for CSRF testing
describe('CSRF Protection', () => {
  it('should reject requests without CSRF token', () => {
    cy.request({
      url: '/api/sensitive',
      method: 'POST',
      failOnStatusCode: false
    }).then((response) => {
      expect(response.status).to.eq(403);
    });
  });
});

Balancing Performance and Security

Cache security example:

// Insecure caching
app.use(express.static('public', { 
  maxAge: '1y' 
}));

// Secure caching
app.use(express.static('public', {
  maxAge: '1y',
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      res.setHeader('Cache-Control', 'no-cache');
    }
  }
}));

Service Worker security practices:

// Security policy example
self.addEventListener('fetch', event => {
  const url = new URL(event.request.url);
  
  // Limit cache scope
  if (url.origin !== self.location.origin) {
    return;
  }
  
  // Don't cache sensitive requests
  if (event.request.url.includes('/api/')) {
    event.respondWith(fetch(event.request));
    return;
  }
  
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

Mobile-Specific Security Considerations

WebView security configuration example (Android):

// Android WebView security settings
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(false);
webView.getSettings().setAllowContentAccess(false);
webView.getSettings().setAllowFileAccessFromFileURLs(false);
webView.getSettings().setAllowUniversalAccessFromFileURLs(false);
webView.setWebContentsDebuggingEnabled(false);

iOS WKWebView configuration:

// iOS WKWebView security configuration
let config = WKWebViewConfiguration()
config.websiteDataStore = WKWebsiteDataStore.nonPersistent()
config.preferences.javaScriptCanOpenWindowsAutomatically = false
let webView = WKWebView(frame: .zero, configuration: config)
webView.configuration.mediaTypesRequiringUserActionForPlayback = .all

Third-Party Service Integration Security

Google Analytics secure integration:

<!-- Secure configuration example -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  
  // Configure cookies domain
  gtag('config', 'GA_MEASUREMENT_ID', {
    cookie_domain: 'yourdomain.com',
    cookie_flags: 'SameSite=Strict; Secure',
    anonymize_ip: true
  });
</script>

Payment integration security example:

// Insecure practice - Directly handling payment data
function processPayment(cardData) {
  // Send card data directly to backend
}

// Secure practice - Using payment processor tokens
function initPayment() {
  loadPaymentSDK().then(sdk => {
    sdk.tokenize({
      cardNumber: '4111111111111111',
      expiry: '12/25',
      cvv: '123'
    }).then(token => {
      // Only send token to backend
      submitPayment(token);
    });
  });
}

Continuous Monitoring and Response

Front-end monitoring example:

// Security event monitoring
window.addEventListener('securitypolicyviolation', (e) => {
  sendToAnalytics({
    type: 'CSP_VIOLATION',
    data: {
      violatedDirective: e.violatedDirective,
      blockedURI: e.blockedURI,
      documentURI: e.documentURI,
      referrer: e.referrer
    }
  });
});

// Exception monitoring
window.onerror = function(message, source, lineno, colno, error) {
  const safeData = {
    message: String(message).substring(0, 100),
    source: source ? new URL(source).pathname : null,
    line: lineno,
    column: colno
  };
  logError(safeData);
  return true; // Prevent default error display
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.