Skip to content
intermediate Phase 71 · Security Fundamentals

CSRF and XSS Protection

45m
2 problems
Topic Progress 0%

CSRF Protection with Form Keys

Form Key Implementation

Magento uses form_key for CSRF protection on all admin forms.

// Adding form key to custom form
use Magento\Framework\View\Element\Template;

class CustomForm extends Template
{
    public function getFormKey()
    {
        return $this->formKey->getFormKey();
    }
}

Template Form Key

<!-- app/code/Vendor/Module/view/adminhtml/templates/form.phtml -->
<form action="<?= $block->getFormAction() ?>" method="post">
    <?= $block->getBlockHtml('formkey') ?>
    <input type="text" name="field" />
    <button type="submit">Submit</button>
</form>

CSRF Validation in Controller

namespace Vendor\Module\Controller\Adminhtml;

use Magento\Backend\App\Action;
use Magento\Framework\Controller\Result\RedirectFactory;

class Save extends Action
{
    public function execute()
    {
        $formKey = $this->getRequest()->getParam('form_key');
        
        if (!$formKey || !$this->_formKeyValidator->validate($this->getRequest())) {
            $this->messageManager->addErrorMessage(__('Invalid form key.'));
            return $this->resultRedirectFactory->create()->setPath('*/*/');
        }

        // Process form data
    }
}

Key Points

  • form_key is generated per session and embedded in forms
  • Validation occurs server-side on every POST request
  • Tokens expire with session lifetime
  • Custom forms must include form_key manually

Output Escaping in Templates

PHP Output Escaping

// Escape HTML entities
$escaped = $block->escapeHtml($untrustedString);

// Escape with allowed tags
$escaped = $block->escapeHtml($html, ['b', 'i', 'em', 'strong']);

// Escape URL
$url = $block->escapeUrl($untrustedUrl);

// Escape CSS
$css = $block->escapeCss($untrustedCss);

// Escape JavaScript
$js = $block->escapeJs($untrustedJs);

// Escape HTML attributes
$attr = $block->escapeHtmlAttr($untrustedAttr);

Template Escaping Examples

<!-- app/code/Vendor/Module/view/frontend/templates/product.phtml -->
<div>
    <!-- Safe: escaped output -->
    <h1><?= $block->escapeHtml($_product->getName()) ?></h1>
    
    <!-- Safe: escaped URL -->
    <a href="<?= $block->escapeUrl($_product->getProductUrl()) ?>">
        <?= $block->escapeHtml($_product->getName()) ?>
    </a>
    
    <!-- Safe: attribute escaping -->
    <img src="<?= $block->escapeUrl($imageUrl) ?>"
         alt="<?= $block->escapeHtmlAttr($_product->getName()) ?>" />
</div>

Key Points

  • Always escape user-generated content before display
  • Use appropriate escaping method for context
  • Magento 2.4+ enforces escaping by default
  • Never use raw output without verification

XSS Prevention Techniques

Content Security Policy (CSP)

// Enable CSP headers
use Magento\Framework\HTTP\Response\HeaderResolver;

class CspHeaders
{
    public function addCspHeaders($response)
    {
        $csp = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";
        $response->setHeader('Content-Security-Policy', $csp);
        return $response;
    }
}

JavaScript XSS Prevention

// Use Magento's template literal escaping
define([], function() {
    'use strict';
    
    return function(data) {
        // Sanitize before DOM insertion
        var element = document.createElement('div');
        element.textContent = data.userInput;
        document.body.appendChild(element);
    };
});

JSON Encoding for JavaScript

// Safely pass data to JavaScript
$jsonData = $block->escapeJs(json_encode($data));

// In template
<script>
    var config = <?= $jsonData ?>;
</script>

Key Points

  • Never use innerHTML with untrusted content
  • Use textContent instead of innerHTML
  • Implement CSP headers to restrict script sources
  • Validate and sanitize all user inputs server-side

Security Headers Configuration

Essential Security Headers

use Magento\Framework\App\Response\HeaderProviderInterface;

class SecurityHeaders implements HeaderProviderInterface
{
    public function getHeaders()
    {
        return [
            'X-Content-Type-Options' => 'nosniff',
            'X-Frame-Options' => 'DENY',
            'X-XSS-Protection' => '1; mode=block',
            'Referrer-Policy' => 'strict-origin-when-cross-origin',
            'Permissions-Policy' => 'camera=(), microphone=(), geolocation=()',
        ];
    }
}

HSTS Configuration

// Force HTTPS and prevent protocol downgrade
$StrictTransportSecurity = 'max-age=31536000; includeSubDomains; preload';

// Cache control for sensitive pages
$CacheControl = 'no-store, no-cache, must-revalidate, max-age=0';

Key Points

  • Headers should be configured at web server level when possible
  • CSP requires careful planning to avoid breaking functionality
  • Test headers with online scanners like securityheaders.com
  • HSTS should only be enabled after confirming HTTPS works everywhere

Practice Problems

0 / 2 solved
CSRF-Protected Form

Create a custom form with proper CSRF protection that validates the form_key on submission.

Solution
// Template:
<form action="<?= $block->getFormAction() ?>" method="post">
    <?= $block->getBlockHtml('formkey') ?>
    <input type="text" name="data" />
    <button type="submit">Submit</button>
</form>

// Controller:
public function execute() {
    if (!$this->_formKeyValidator->validate($this->getRequest())) {
        throw new \Exception('Invalid form key');
    }
    // Process data
}
XSS-Safe Template

Convert an unsafe template to use proper output escaping for all dynamic content.

Solution
// Safe template:
<div>
    <h1><?= $block->escapeHtml($_product->getName()) ?></h1>
    <a href="<?= $block->escapeUrl($_product->getProductUrl()) ?>"><?= $block->escapeHtml($_product->getDescription()) ?></a>
    <img src="<?= $block->escapeUrl($_product->getImageUrl()) ?>" alt="<?= $block->escapeHtmlAttr($_product->getName()) ?>" />
</div>

Quiz

1. What is Magento's primary CSRF protection mechanism?

Question 1 options

2. Which function escapes HTML in Magento templates?

Question 2 options

3. What does the X-XSS-Protection header do?

Question 3 options

4. How should you safely pass PHP data to JavaScript?

Question 4 options

Flashcards

Question

Magento CSRF token?

Answer

form_key embedded in forms, validated server-side

Question

Escape HTML in templates?

Answer

$block->escapeHtml($untrustedString)

Question

XSS prevention?

Answer

Output escaping, CSP headers, input validation

Question

X-Frame-Options: DENY

Answer

Prevents clickjacking by blocking iframe embedding

Revision Notes

Key Takeaways

  • 1. form_key is Magento's CSRF token for all forms
  • 2. Always use escapeHtml() for user content in templates
  • 3. Security headers provide defense in depth
  • 4. CSP headers restrict script sources to prevent XSS

Interview Tips

  • Explain how form_key prevents CSRF attacks
  • Discuss different escaping methods and when to use each
  • Know how CSP protects against XSS

Cheat Sheet

CSRF/XSS

  • CSRF: form_key token in forms
  • XSS: escapeHtml(), escapeUrl(), escapeJs()
  • Headers: X-Frame-Options, CSP, HSTS
  • Never trust user input, always escape output