WebMon analyzes your website's HTTP security headers and assigns a grade based on their presence and configuration. This guide explains each header, why it matters, and how to implement it.
What Are Security Headers?
Security headers are HTTP response headers that instruct browsers how to behave when handling your site's content. They protect against common attacks like cross-site scripting (XSS), clickjacking, and data injection.
Headers We Check
Strict-Transport-Security (HSTS)
Forces browsers to only use HTTPS connections for your site. Once a browser sees this header, it will automatically convert all HTTP requests to HTTPS, even if a user types http:// in the address bar.
Why it matters: Prevents man-in-the-middle attacks and cookie hijacking over insecure connections.
Example value: max-age=31536000; includeSubDomains; preload
Implementation:
- Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" - Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - Laravel: Add to middleware or use spatie/laravel-csp package
Content-Security-Policy (CSP)
Controls which resources (scripts, styles, images, fonts) can be loaded on your page. This is the most powerful header for preventing XSS attacks.
Why it matters: Stops attackers from injecting malicious scripts, even if they find a vulnerability in your site.
Example value: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'
Common directives:
default-src: Fallback for other directivesscript-src: Where JavaScript can be loaded fromstyle-src: Where CSS can be loaded fromimg-src: Where images can be loaded fromconnect-src: Where AJAX/WebSocket connections can goframe-ancestors: Who can embed your site (replaces X-Frame-Options)
Tip: Start with a report-only policy to find issues before enforcing.
X-Frame-Options
Prevents your site from being embedded in iframes on other domains. This protects against clickjacking attacks where attackers overlay invisible frames to trick users into clicking hidden buttons.
Why it matters: Stops attackers from embedding your login page in their site to steal credentials.
Values:
DENY: Never allow framingSAMEORIGIN: Only allow framing by same domainALLOW-FROM uri: Allow specific domain (deprecated, use CSP frame-ancestors instead)
X-Content-Type-Options
Prevents browsers from "sniffing" the content type and executing files as a different type than declared.
Why it matters: Attackers can upload files with malicious content that browsers might execute if they guess the wrong content type.
Value: nosniff (the only valid value)
Referrer-Policy
Controls how much URL information is sent when users navigate away from your site.
Why it matters: Prevents leaking sensitive URL parameters (tokens, IDs) to third-party sites.
Common values:
no-referrer: Never send referrersame-origin: Only send referrer for same-origin requestsstrict-origin-when-cross-origin: Send origin only for cross-origin (recommended)no-referrer-when-downgrade: Don't send when going from HTTPS to HTTP
Permissions-Policy
(formerly Feature-Policy)
Limits which browser features your site can use, like camera, microphone, geolocation, and payment APIs.
Why it matters: Reduces attack surface and prevents embedded third-party content from accessing sensitive APIs.
Example value: camera=(), microphone=(), geolocation=(self), payment=()
Common features to restrict:
camera,microphone: Media devicesgeolocation: User locationpayment: Payment Request APIusb,bluetooth: Hardware access
X-XSS-Protection
Enables the browser's built-in XSS filter. Note: This is a legacy header and modern browsers are removing support in favor of CSP.
Value: 1; mode=block
Note: If you have a strong CSP policy, you may set this to 0 to avoid potential conflicts.
Cross-Origin-Opener-Policy (COOP)
Isolates your browsing context from other origins, preventing other sites from accessing your window object through popups.
Values: same-origin, same-origin-allow-popups, unsafe-none
Cross-Origin-Embedder-Policy (COEP)
Controls whether your page can load cross-origin resources that don't explicitly grant permission.
Values: require-corp, credentialless, unsafe-none
Cross-Origin-Resource-Policy (CORP)
Protects your resources from being loaded by other origins.
Values: same-origin, same-site, cross-origin
Understanding Grades
A+ / A / A- (Excellent)
Your site has most or all critical security headers properly configured. You are well protected against common web vulnerabilities.
B+ / B / B- (Good)
Your site has several important security headers but is missing some recommendations. Consider adding the missing headers for better protection.
C+ / C / C- (Fair)
Your site has basic security headers but is missing important ones. You should prioritize adding the missing headers.
D / F (Needs Improvement)
Your site is missing critical security headers and is vulnerable to common attacks. Immediate action is recommended.
Priority Order for Implementation
- Strict-Transport-Security (HSTS) - If using HTTPS
- X-Content-Type-Options - Easy, no configuration needed
- X-Frame-Options - Simple protection against clickjacking
- Referrer-Policy - Protects URL data leakage
- Content-Security-Policy - Most powerful but requires testing
- Permissions-Policy - Limit unnecessary browser features
- Cross-Origin headers (COOP, COEP, CORP) - For advanced isolation
robots.txt Check
WebMon also checks for your robots.txt file:
- Present: Your site has crawler directives configured
- Blocks All Crawlers: Your robots.txt prevents search engines from indexing (may be intentional for staging sites)
- Not Found: No robots.txt file detected (search engines will crawl everything by default)
How to Run a Security Check
- Go to your monitor's detail page
- Find the "Security Compliance" card
- Click "Check Now" to run an analysis
- Review your grade and missing headers
- Click "Show all headers" to see the complete list
Quick Implementation Guide
For Apache (.htaccess or httpd.conf)
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set X-XSS-Protection "1; mode=block"
</IfModule>
For Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header X-XSS-Protection "1; mode=block" always;
For Laravel (middleware)
return $next($request)
->header('X-Content-Type-Options', 'nosniff')
->header('X-Frame-Options', 'SAMEORIGIN')
->header('Referrer-Policy', 'strict-origin-when-cross-origin');
For Cloudflare
Use Transform Rules to add headers, or configure in the dashboard under Security > Settings.
After making changes, use "Check Now" to verify your new grade.
Testing Your Headers
- Use browser Developer Tools (Network tab) to inspect response headers
- Online tools like
securityheaders.comcan analyze your site - Start CSP in report-only mode to catch issues
Common Mistakes
- Setting CSP too strict initially (breaks functionality)
- Forgetting to include CDN domains in CSP
- Using deprecated header values
- Not testing on all pages (some frameworks override headers)
- Missing the "always" directive in Nginx (headers not sent on errors)