Cloudflare Workers on paul-barton.com

Leveling Up Security on paul-barton.com with Cloudflare Workers

As a technology enthusiast and professional, I’m always looking for ways to enhance the security and performance of my online presence. Recently, I implemented a Cloudflare Worker on my website, paul-barton.com, to boost its security profile. In this post, I’ll share my experience and the benefits of this implementation.

What is a Cloudflare Worker?

Cloudflare Workers are serverless functions that run at the edge of Cloudflare’s network. They allow you to execute code closer to your users, resulting in faster response times and the ability to modify requests and responses on the fly.

The Security Enhancements

The Worker I implemented on paul-barton.com focuses on three main areas:

  1. Security Headers: These HTTP headers instruct browsers on how to handle the site’s content, significantly reducing the risk of various attacks.

  2. URL Redirects: Ensures that old URLs are properly redirected to their new locations, maintaining both user experience and SEO value.

  3. Security.txt: Implements a standardized way for security researchers to report vulnerabilities.

Here’s a what the Worker looks like:

const securityHeaders = {
    "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self';",
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
    "X-Xss-Protection": "0",
    "X-Frame-Options": "SAMEORIGIN",
    "X-Content-Type-Options": "nosniff",
    "Referrer-Policy": "strict-origin-when-cross-origin",
    "Permissions-Policy": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
};

const sanitiseHeaders = {
    "Server": ""
};

const removeHeaders = [
    "Public-Key-Pins",
    "X-Powered-By",
    "X-AspNet-Version",
    "X-Pingback"
];

const redirects = {
    '/old-url': '/new-url',
};

async function addHeaders(req) {
    try {
        const response = await fetch(req);
        const newHeaders = new Headers(response.headers);
        const contentType = newHeaders.get("Content-Type");

        if (contentType && !contentType.includes("text/html")) {
            return response; // Return original response for non-HTML content
        }

        Object.entries({...securityHeaders, ...sanitiseHeaders}).forEach(([name, value]) => {
            newHeaders.set(name, value);
        });

        removeHeaders.forEach(name => {
            newHeaders.delete(name);
        });

        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders
        });
    } catch (error) {
        console.error("Error in addHeaders:", error);
        return new Response("Internal Server Error", { status: 500 });
    }
}

async function handleRedirects(request) {
    const url = new URL(request.url);
    const redirectUrl = redirects[url.pathname];
    
    if (redirectUrl) {
        return Response.redirect(new URL(redirectUrl, url.origin).toString(), 301);
    }
    
    return fetch(request);
}

async function handleSecurityTxt(request) {
    const securityTxt = `
Contact: mailto:[email protected]
Expires: 2028-12-31T23:59:00.000Z
Preferred-Languages: en
`;
    return new Response(securityTxt.trim(), {
        headers: { "Content-Type": "text/plain" },
    });
}

addEventListener("fetch", event => {
    event.respondWith((async () => {
        const url = new URL(event.request.url);
        
        try {
            if (url.pathname === '/.well-known/security.txt') {
                return handleSecurityTxt(event.request);
            } else if (redirects[url.pathname]) {
                return handleRedirects(event.request);
            } else {
                return addHeaders(event.request);
            }
        } catch (error) {
            console.error("Unhandled error:", error);
            return new Response("Internal Server Error", { status: 500 });
        }
    })());
});

Why Use Cloudflare Workers for Security?

Implementing these security measures via a Cloudflare Worker, rather than on my web server, offers several advantages:

  1. Separation of Concerns: Security measures remain intact even if the origin server is compromised or misconfigured.
  2. Edge Computing: Faster response times as the security logic runs closer to users.
  3. Consistency: Ensures security measures are applied uniformly across the entire site.

Cloudflare’s Own Security Measures

It’s worth noting that Cloudflare itself implements robust security measures to protect its infrastructure and customer accounts:

  • Strong Multi-Factor Authentication (MFA): Cloudflare supports various MFA methods, including TOTP and hardware security keys.
  • Account Delegation: Allows secure access management for team members without sharing login credentials.
  • API Tokens: Granular access control for programmatic interactions with Cloudflare services.
  • Audit Logs: Detailed logs of account activities for monitoring and compliance.

These measures give me confidence that the platform securing my website is itself well-protected. While this site is already protected by Netlify’s WAF and CDN, it’s the additional functionality, like Workers, that adds real value to the site.

Conclusion

Implementing this Cloudflare Worker has significantly enhanced the security posture of paul-barton.com. It’s a testament to how modern cloud technologies can be leveraged to improve website security with relatively little effort.

While security was my primary focus, it’s worth noting that Cloudflare Workers offer a multitude of other benefits. They can be used for A/B testing, personalized content delivery, load balancing, and even complex computational tasks - all at the edge of the network. This means faster response times, reduced server load, and the ability to create more dynamic and responsive web applications. The possibilities are vast, limited only by your creativity and coding skills.

While no security measure is perfect, using Cloudflare Workers in conjunction with Cloudflare’s robust platform security creates multiple layers of protection. It’s an approach I highly recommend for anyone looking to boost their website’s security and performance.

I use these Workers on all the sites I maintain and also recommend them to clients who don’t have suitable alternative security provisions in place.

Remember, security is an ongoing process. I’ll continue to monitor and update these measures as new best practices emerge.