Lock Me In, But Not the Hackers
— A Workshop on Web Security
npm audit
-
When using
npm
, runnpm audit
to check for vulnerabilities in your dependencies. -
Run it with
--fix
to automatically fix issues when possible.
SRI: Sub-Resource Integrity
When loading a 3rd party-script like this:
<script defer
src="https://unpkg.com/smoothscroll-polyfill@0.4.4/dist/smoothscroll.min.js">
</script>
What happens if unpkg.com gets hacked and the script is replaced with a malicious one?
To prevent this, we can use the integrity
attribute:
<script defer
src="https://unpkg.com/smoothscroll-polyfill@0.4.4/dist/smoothscroll.min.js"
integrity="sha384-R1+zrYTQk6y5F9GQMXZ..."
crossorigin="anonymous">
</script>
How SRI Works
-
The
integrity
attribute contains a cryptographic hash of the file. -
The browser will check the file against this hash, and if it doesn't match, the file won't be loaded.
-
In this case, just add the
?meta
query parameter to the URL to get a JSON object containing the hash:
https://unpkg.com/smoothscroll-polyfill@0.4.4/?meta
Security Headers
What are Security Headers?
Security headers are HTTP response headers that help protect your website from common attacks by controlling browser behavior.
Strict-Transport-Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Forces browsers to use HTTPS, protecting against protocol downgrade attacks and cookie hijacking.
If missing: Attackers can intercept traffic over HTTP, making users vulnerable to man-in-the-middle attacks.
HSTS Preloading: Submit your domain to hstspreload.org to be built into browsers.
X-Frame-Options
Prevents your site from being embedded in iframes, protecting against clickjacking.
X-Frame-Options: DENY
If missing: Attackers can trick users into clicking hidden buttons or links on your site.
X-Content-Type-Options
Stops browsers from MIME-sniffing a response away from the declared content-type.
X-Content-Type-Options: nosniff
If missing: Browsers may interpret files as executable scripts, increasing risk of attacks.
Referrer-Policy
Controls how much referrer information is sent with requests, protecting user privacy.
Referrer-Policy: no-referrer
If missing: Sensitive URLs may be leaked to third-party sites.
rel="noopener noreferrer"
Explicitly controls link security behavior (though modern browsers default to safe behavior).
<a href="https://external-site.com" target="_blank"
rel="noopener noreferrer">External Link</a>
Permissions-Policy
Restricts access to browser features like camera, microphone, geolocation, etc.
Permissions-Policy: geolocation=(), camera=()
If missing: Malicious sites may abuse browser features without user consent.
Permissions-Policy (FULL LIST)
accelerometer=(), ambient-light-sensor=(),
autoplay=(), battery=(), camera=(), cross-origin-isolated=(),
display-capture=(), document-domain=(), encrypted-media=(),
execution-while-not-rendered=(), execution-while-out-of-viewport=(),
fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(),
magnetometer=(), microphone=(), midi=(), navigation-override=(),
payment=(), picture-in-picture=(), publickey-credentials-get=(),
screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(),
xr-spatial-tracking=()
Content-Security-Policy (CSP)
Content-Security-Policy (CSP) is a powerful security header that helps prevent cross-site scripting (XSS), data injection, and other attacks by specifying which sources the browser can load resources from.
Why use CSP?
- Limits the impact of XSS and code injection vulnerabilities
- Controls where scripts, styles, images, fonts, and other resources can be loaded from
CSP: default-src
Fallback for other resource types if not specified.
Content-Security-Policy: default-src 'self'
CSP: script-src
Controls allowed sources for JavaScript.
Content-Security-Policy: script-src 'self' https://apis.example.com
CSP: style-src
Controls allowed sources for CSS.
Content-Security-Policy: style-src 'self' https://fonts.googleapis.com
CSP: img-src
Controls allowed sources for images.
Content-Security-Policy: img-src 'self' data: https://images.example.com
CSP: img-src — data:URL's
Base64-encoded images embedded directly in HTML/CSS using the data:
scheme.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==" alt="1x1 pixel">
Common use cases:
- Small icons and SVGs
- Loading spinners and placeholders
- Inlined assets from build processes
- Images that need immediate availability
CSP: connect-src
Controls allowed endpoints for XHR, WebSockets, and fetch.
Content-Security-Policy: connect-src 'self' https://api.example.com
CSP: Additional Directives
Content-Security-Policy:
font-src 'self' https://fonts.gstatic.com;
media-src 'self';
object-src 'none';
frame-src 'self' https://trusted-frames.example.com
CSP Best Practices
If missing: Attackers can inject malicious scripts, styles, or other resources, leading to data theft, site defacement, or malware distribution.
Tips:
- Start with a strict policy and relax only as needed
- Use browser developer tools to test and refine
- Consider using report-only mode initially
- Use nonces or hashes for inline scripts/styles
CSP in CMS Environments
Configurable CSP with secure defaults, allowing editors controlled exceptions per page.
Approach:
- Base policy: Secure defaults for all pages
- Editor controls: Whitelist specific domains per page/section
- Validation: Prevent wildcard (*) entries from editors
- Audit trail: Log when policies are modified
# Default strict policy
Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self' data:
# Page-specific relaxation (editor configurable)
Content-Security-Policy: default-src 'self'; script-src 'self' https://widgets.example.com; img-src 'self' data: https://cdn.images.com
WAF
WEB APPLICATION FIREWALL
- Filters malicious traffic before it reaches your application
— first line of defense. - Sits between users and your servers, analyzing HTTP requests in real-time.
- Blocks known attack patterns, bad bots, and scrapers while allowing legitimate traffic through.
WAF
Cloudflare
- Enable via Security → WAF → Custom rules
- Pre-built rulesets for OWASP Top 10, bot protection
- Rate limiting and geographic blocking
WAF
Vercel
- Built-in DDoS protection and edge caching
- Configure via vercel.json or dashboard
- Custom rules for API rate limiting
WAF
Umbraco Cloud
- Managed WAF with automatic updates
- OWASP Core Rule Set enabled by default
- Configure via Cloud portal
Backend Security Topics
API & Server Developers
While many security principles apply to both frontend and backend, backend developers should pay special attention to the following areas:
API Security Fundamentals
- Use strong authentication and authorization (OAuth2, JWT, API keys)
- Implement rate limiting and throttling to prevent abuse
- Validate and sanitize all input to prevent injection attacks
- Avoid leaking sensitive information in error messages
Rate Limiting & Throttling
Rate limiting restricts how many requests a user or client can make to your API in a given time period.
Why is rate limiting important?
- Prevents abuse, denial-of-service (DoS), and brute-force attacks
- Protects backend resources and ensures fair usage
Best Practices:
- Set reasonable limits per user, IP, or API key (e.g., 100 requests per minute)
- Return HTTP 429 Too Many Requests when limits are exceeded
- Use libraries or middleware (e.g., express-rate-limit for Node.js)
Brute-force Protection
Brute-force attacks occur when an attacker tries many username/password combinations in rapid succession to gain unauthorized access.
Best Practices:
- Enforce account lockout or temporary blocking after several failed login attempts
- Use exponential backoff or increasing delays for repeated failures
- Integrate CAPTCHA or other human verification for critical endpoints
- Monitor and alert on suspicious activity
Example: Lock an account for 15 minutes after 5 failed login attempts.
Data Protection
- Encrypt sensitive data at rest and in transit (TLS/SSL)
- Store credentials and secrets securely (environment variables, vaults)
Logging and Monitoring
- Log security events centrally and monitor in real time
- Protect logs from tampering and ensure proper retention
CORS (Cross-Origin Resource Sharing)
CORS controls how web applications interact with resources from different origins (domains).
Best Practices:
- Set
Access-Control-Allow-Origin
to specific domains, not*
- Restrict allowed HTTP methods and headers
- Use credentials only when necessary, never with wildcard origin
- Always validate the origin server-side
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Additional Backend Security
Session Management:
- Use secure cookie settings (HttpOnly, Secure, SameSite)
- Expire and invalidate sessions appropriately
File Upload Security:
- Validate file types and sizes
- Scan uploads for malware
- Store files outside the web root
Security Testing:
- Use automated security testing tools (SAST, DAST)
- Perform regular penetration testing
Ongoing Maintenance
Keeping your web application secure is an ongoing process. Here are some do's and don'ts to help maintain a strong security posture:
Do's:
- Regularly update dependencies and frameworks to patch known vulnerabilities
- Schedule frequent security audits and code reviews
- Use automated tools to scan for vulnerabilities (e.g., Snyk, OWASP Dependency-Check, GitHub Dependabot)
- Monitor security advisories for your tech stack
- Enforce strong authentication and access controls
Ongoing Maintenance
Don'ts:
- Don't ignore security warnings from your package manager or build tools
- Don't rely solely on default configurations—review and harden them
- Don't expose sensitive information in error messages or logs
- Don't postpone applying critical security updates
Security Tools & Resources
Recommended Tools:
- Snyk: Scans for vulnerabilities in code, dependencies, containers, and IaC
- SonarQube: Continuous inspection of code quality and security
- npm audit: Checks for vulnerabilities in npm packages
We might consider:
- Detectify: External attack surface scanning and penetration testing
- OWASP ZAP: runtime security testing
DEMO LINKS
We need a security-guild
a group of developers that can inspect our current solutions and new sites
- Set up tools like Snyk and SonarQube including CI/CD, Slack and Jira-integration
- Test and verify Security Headers
- Setup and configuring a WAF
- If a WAF is not possible, maintain a dynamically generated robots.txt
We need a security-guild
do you want to be a part of it?
Let me know and join
den-security-guild
thank you!
Lock Me In, But Not the Hackers — A Workshop on Web Security
By Mads Stoumann
Lock Me In, But Not the Hackers — A Workshop on Web Security
- 36