security-patterns.mdc•13.6 kB
---
description: SFCC security best practices and validation patterns
alwaysApply: true
---
# SFCC Security Best Practices
Use this rule when implementing security-sensitive features or validating user input.
## Mandatory MCP Tools Sequence
**BEFORE implementing ANY security-sensitive code:**
1. `mcp_sfcc-dev_search_best_practices` with query: "security"
2. `mcp_sfcc-dev_get_best_practice_guide` with guideName: "security"
3. `mcp_sfcc-dev_search_best_practices` with query: "validation"
4. `mcp_sfcc-dev_search_sfcc_classes` with query: relevant security domains
## MCP-Guided Security Development Process
### Step 1: Get Security Best Practices
```
Use: mcp_sfcc-dev_search_best_practices with query: "security"
Use: mcp_sfcc-dev_get_best_practice_guide with guideName: "security"
Purpose: Get comprehensive security guidelines, validation patterns, and threat mitigation strategies
```
### Step 2: Input Validation Patterns
```
Use: mcp_sfcc-dev_search_best_practices with query: "validation"
Purpose: Get input validation, sanitization, and XSS prevention patterns
```
### Step 3: SFCC Security API Research
```
Use: mcp_sfcc-dev_search_sfcc_classes with query: [security domain]
Use: mcp_sfcc-dev_get_sfcc_class_info with className: [security-related classes]
Purpose: Understand available SFCC security APIs and encryption methods
```
## MCP-Enhanced Input Validation Template
```javascript
'use strict';
/**
 * Input Validation Utilities
 * Implementation based on:
 * - mcp_sfcc-dev_search_best_practices with query: "security"
 * - mcp_sfcc-dev_get_best_practice_guide with guideName: "security"
 */
var StringUtils = require('dw/util/StringUtils');
var Logger = require('dw/system/Logger').getLogger('security', 'InputValidation');
/**
 * Validate and sanitize user input
 * Security patterns from MCP security best practices
 * @param {string} input - User provided input
 * @param {string} type - Expected input type (email, phone, text, etc.)
 * @param {Object} options - Validation options
 * @returns {Object} Validation result
 */
function validateInput(input, type, options) {
    options = options || {};
    try {
        // Basic type validation (from MCP security guide)
        if (!input || typeof input !== 'string') {
            return { valid: false, error: 'Invalid input type', code: 'INVALID_TYPE' };
        }
        // Length validation (security pattern from MCP)
        var maxLength = options.maxLength || 1000;
        if (input.length > maxLength) {
            Logger.warn('Input length exceeded limit: {0} > {1}', input.length, maxLength);
            return { valid: false, error: 'Input too long', code: 'LENGTH_EXCEEDED' };
        }
        // Empty input handling (from MCP validation patterns)
        if (input.trim().length === 0) {
            return { valid: false, error: 'Input cannot be empty', code: 'EMPTY_INPUT' };
        }
        // Sanitize for XSS (critical security pattern from MCP)
        var sanitized = StringUtils.stringToHtml(input);
        // Type-specific validation (patterns from MCP security guide)
        switch (type) {
            case 'email':
                var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
                if (!emailRegex.test(input)) {
                    return { valid: false, error: 'Invalid email format', code: 'INVALID_EMAIL' };
                }
                break;
            case 'phone':
                var phoneRegex = /^\+?[\d\s\-\(\)]+$/;
                if (!phoneRegex.test(input)) {
                    return { valid: false, error: 'Invalid phone format', code: 'INVALID_PHONE' };
                }
                break;
            case 'alphanumeric':
                var alphaNumRegex = /^[a-zA-Z0-9]+$/;
                if (!alphaNumRegex.test(input)) {
                    return { valid: false, error: 'Only alphanumeric characters allowed', code: 'INVALID_ALPHANUMERIC' };
                }
                break;
            case 'customerNo':
                // Customer number validation (SFCC-specific pattern from MCP)
                var customerNoRegex = /^[a-zA-Z0-9\-_]+$/;
                if (!customerNoRegex.test(input) || input.length > 50) {
                    return { valid: false, error: 'Invalid customer number format', code: 'INVALID_CUSTOMER_NO' };
                }
                break;
            case 'productId':
                // Product ID validation (SFCC-specific pattern from MCP)
                var productIdRegex = /^[a-zA-Z0-9\-_\.]+$/;
                if (!productIdRegex.test(input) || input.length > 100) {
                    return { valid: false, error: 'Invalid product ID format', code: 'INVALID_PRODUCT_ID' };
                }
                break;
        }
        // Additional security checks (from MCP security patterns)
        if (containsSuspiciousPatterns(input)) {
            Logger.warn('Suspicious input pattern detected: {0}', input.substring(0, 50) + '...');
            return { valid: false, error: 'Input contains invalid patterns', code: 'SUSPICIOUS_INPUT' };
        }
        return { valid: true, sanitized: sanitized, original: input };
    } catch (e) {
        Logger.error('Error during input validation: {0}', e.message);
        return { valid: false, error: 'Validation error', code: 'VALIDATION_ERROR' };
    }
}
/**
 * Check for suspicious patterns that could indicate attacks
 * Security patterns from MCP security guide
 */
function containsSuspiciousPatterns(input) {
    var suspiciousPatterns = [
        /<script/i,           // XSS attempt
        /javascript:/i,       // JavaScript protocol
        /on\w+\s*=/i,        // Event handlers
        /eval\s*\(/i,        // Code execution
        /expression\s*\(/i,   // CSS expression
        /'.*OR.*'/i,         // SQL injection
        /UNION.*SELECT/i,     // SQL injection
        /DROP.*TABLE/i,       // SQL injection
        /--/,                // SQL comment
        /\/\*/,              // Multi-line comment
        /\.\.\//,            // Path traversal
        /%2e%2e%2f/i,        // Encoded path traversal
        /\x00/,              // Null byte
    ];
    return suspiciousPatterns.some(function(pattern) {
        return pattern.test(input);
    });
}
module.exports.validateInput = validateInput;
module.exports.containsSuspiciousPatterns = containsSuspiciousPatterns;
```
## MCP-Enhanced Authentication Patterns
```javascript
'use strict';
/**
 * Authentication and Authorization Utilities
 * Implementation based on MCP security best practices
 */
var Logger = require('dw/system/Logger').getLogger('security', 'Authentication');
/**
 * Check customer authentication with comprehensive logging
 * Security pattern from MCP security guide
 */
function validateCustomerAuthentication(req, res, options) {
    options = options || {};
    try {
        var customer = req.currentCustomer;
        // Basic authentication check (from MCP security patterns)
        if (!customer || !customer.authenticated) {
            Logger.warn('Unauthenticated access attempt to protected resource: {0}', req.httpURL);
            if (options.returnJson) {
                res.setStatusCode(401);
                res.json({
                    error: 'AUTHENTICATION_REQUIRED',
                    message: 'Authentication required'
                });
            } else {
                res.setStatusCode(401);
                res.render('error/unauthorized');
            }
            return false;
        }
        // Additional security checks (from MCP security guide)
        if (options.requireActiveCustomer && !customer.profile) {
            Logger.warn('Customer authenticated but no profile found: {0}', customer.ID);
            if (options.returnJson) {
                res.setStatusCode(403);
                res.json({
                    error: 'INVALID_CUSTOMER_STATE',
                    message: 'Customer profile required'
                });
            } else {
                res.setStatusCode(403);
                res.render('error/forbidden');
            }
            return false;
        }
        // Log successful authentication (for security auditing)
        Logger.debug('Customer authentication validated: {0}', customer.profile ? customer.profile.customerNo : customer.ID);
        return true;
    } catch (e) {
        Logger.error('Error during authentication validation: {0}', e.message);
        if (options.returnJson) {
            res.setStatusCode(500);
            res.json({
                error: 'AUTHENTICATION_ERROR',
                message: 'Authentication validation failed'
            });
        } else {
            res.setStatusCode(500);
            res.render('error/servererror');
        }
        return false;
    }
}
/**
 * Check specific permissions for authenticated customers
 * Authorization pattern from MCP security guide
 */
function checkCustomerPermissions(customer, requiredPermissions) {
    if (!customer || !customer.authenticated || !customer.profile) {
        return { authorized: false, error: 'Customer not authenticated' };
    }
    // Implement permission checking logic based on your business requirements
    // This is a template - customize based on your permission system
    if (requiredPermissions && requiredPermissions.length > 0) {
        // Check customer groups, custom attributes, or other permission mechanisms
        var hasPermissions = requiredPermissions.every(function(permission) {
            return checkSinglePermission(customer, permission);
        });
        if (!hasPermissions) {
            Logger.warn('Customer {0} lacks required permissions: {1}',
                customer.profile.customerNo, requiredPermissions.join(', '));
            return { authorized: false, error: 'Insufficient permissions' };
        }
    }
    return { authorized: true };
}
function checkSinglePermission(customer, permission) {
    // Implement your specific permission logic here
    // Examples: customer groups, custom attributes, etc.
    return true; // Placeholder implementation
}
module.exports.validateCustomerAuthentication = validateCustomerAuthentication;
module.exports.checkCustomerPermissions = checkCustomerPermissions;
```
## Security Checklist (MCP-Verified)
Before implementing security features, verify with MCP:
- [ ] `mcp_sfcc-dev_search_best_practices` with query: "security" - Get security patterns
- [ ] `mcp_sfcc-dev_get_best_practice_guide` with guideName: "security" - Comprehensive guide
- [ ] `mcp_sfcc-dev_search_best_practices` with query: "validation" - Input validation patterns
Implementation verification:
- [ ] Validate all user inputs with type-specific validation
- [ ] Sanitize data before rendering in templates
- [ ] Use CSRF protection for forms
- [ ] Implement proper authentication checks
- [ ] Avoid exposing sensitive data in errors
- [ ] Use HTTPS for all sensitive operations
- [ ] Validate file uploads and restrict types
- [ ] Implement rate limiting for APIs
- [ ] Use secure session management
- [ ] Log security events appropriately
## Common Security Anti-Patterns (from MCP Security Guide)
```javascript
// DON'T: Direct parameter access without validation (security vulnerability)
var userInput = request.httpParameterMap.parameter.value;
response.getWriter().print(userInput); // XSS vulnerability
// DO: Validate and sanitize (pattern from MCP security guide)
var userInput = request.httpParameterMap.parameter.value;
var validation = validateInput(userInput, 'text');
if (validation.valid) {
    response.getWriter().print(validation.sanitized);
} else {
    Logger.warn('Invalid input rejected: {0}', validation.error);
    response.getWriter().print('Invalid input provided');
}
// DON'T: Expose system errors to users (information disclosure)
try {
    // Operation
} catch (e) {
    response.getWriter().print('Database error: ' + e.message); // Exposes system info
}
// DO: Log errors securely and return generic messages (MCP security pattern)
try {
    // Operation
} catch (e) {
    Logger.error('Database operation failed: {0}', e.message);
    response.getWriter().print('An error occurred. Please try again later.');
}
```
## CSRF Protection Pattern (from MCP Security Guide)
```javascript
// Controller implementation with CSRF protection
var csrfProtection = require('*/cartridge/scripts/middleware/csrf');
// Route to display the form with CSRF token
server.get('ShowForm', csrfProtection.generateToken, function (req, res, next) {
    res.render('myFormTemplate', {
        csrf: res.getViewData().csrf // Pass token to template
    });
    next();
});
// Route to handle the submission with CSRF validation
server.post('SubmitForm', csrfProtection.validateRequest, function (req, res, next) {
    // If execution reaches here, the token was valid
    var formData = req.form;
    var validation = validateInput(formData.userInput, 'text');
    if (!validation.valid) {
        res.json({
            success: false,
            error: validation.error
        });
        return next();
    }
    // Process validated data
    res.json({ success: true });
    next();
});
```
## NEVER Implement Security Without MCP
- ❌ Don't implement validation without patterns - use `mcp_sfcc-dev_search_best_practices`
- ❌ Don't skip input sanitization - use MCP XSS prevention patterns
- ❌ Don't expose system errors - follow MCP error handling guide
- ❌ Don't implement authentication without consulting MCP security guide
- ❌ Don't assume security APIs - use `mcp_sfcc-dev_search_sfcc_classes`