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
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
} 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?
2. Which function escapes HTML in Magento templates?
3. What does the X-XSS-Protection header do?
4. How should you safely pass PHP data to JavaScript?
Flashcards
Question
Magento CSRF token?
Click to reveal answer
Answer
form_key embedded in forms, validated server-side
Question
Escape HTML in templates?
Click to reveal answer
Answer
$block->escapeHtml($untrustedString)
Question
XSS prevention?
Click to reveal answer
Answer
Output escaping, CSP headers, input validation
Question
X-Frame-Options: DENY
Click to reveal answer
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