TL;DR
Yes, a Javascript WebGL proof of work (PoW) system can help prevent website spam, but it’s not a perfect solution. It adds computational cost to submitting forms, making automated spam bots much slower and less effective. It won’t stop determined attackers, but significantly raises the bar for simple bot attacks.
How it Works
The idea is to require users to solve a computationally intensive problem using their browser’s WebGL capabilities before submitting forms (e.g., comments, registrations). This uses the user’s GPU power, which bots typically don’t have easy access to or are limited in.
Step-by-Step Implementation
- Choose a PoW Algorithm: Select an algorithm suitable for WebGL. Simple options include rendering a complex fractal (Mandelbrot set) or performing numerous matrix multiplications. The complexity determines the difficulty.
- Rendering Fractals: This is visually verifiable and relatively easy to implement in WebGL.
- Matrix Multiplication: More computationally intensive, but less visually interesting for debugging.
- Implement the WebGL Shader: Write a GLSL shader that performs the chosen algorithm.
// Example GLSL fragment shader (simplified Mandelbrot) void main() { vec2 uv = gl_FragCoord.xy / vec2(512.0, 512.0); float c = -0.7 + imag(uv.y * 0.8); // Example constant int i = 0; vec3 z = vec3(0.0); while (dot(z, z) < 4.0 && i < 100) { z = vec3(z.x * z.x - z.y * z.y + c, 2.0 * z.x * z.y, 1.0); i++; } gl_FragColor = vec4(float(i) / 100.0, float(i) / 100.0, float(i) / 100.0, 1.0); } - Create the Javascript Canvas and WebGL Context: Set up a canvas element in your HTML and initialize the WebGL context.
const canvas = document.getElementById('myCanvas'); const gl = canvas.getContext('webgl'); - Load and Compile Shaders: Load the GLSL shader code, compile it, and link it to create a WebGL program.
This involves using functions like
gl.createShader(),gl.shaderSource(),gl.compileShader(),gl.createProgram(), andgl.linkProgram(). - Implement the Proof of Work Function: This function will render a certain number of frames using the WebGL program.
function performProofOfWork(iterations) { const startTime = performance.now(); for (let i = 0; i < iterations; i++) { gl.drawArrays(gl.TRIANGLES, 0, 3); } const endTime = performance.now(); return endTime - startTime; } - Generate a Challenge: Create a random challenge value (e.g., a seed for the fractal rendering) on the server-side.
This prevents users from pre-computing solutions.
- Verify the Solution: When the form is submitted, send the challenge and the time taken to complete the PoW to the server. The server should re-run the same PoW algorithm with the challenge and verify that the provided time is reasonable.
- Time Threshold: Set a minimum acceptable time (e.g., 2 seconds).
- Server-Side Validation: Crucially, perform the PoW calculation on your server to confirm the result isn’t fabricated.
- Integrate with Form Submission: Before submitting the form, trigger the
performProofOfWork()function and send the results to the server.
Important Considerations
- Difficulty Adjustment: Adjust the number of iterations based on average GPU performance to maintain a consistent difficulty level.
- User Experience: PoW can be resource-intensive. Provide clear feedback to the user about progress and estimated completion time. Consider offering a simpler CAPTCHA as an alternative for users with older hardware.
- Browser Compatibility: Ensure WebGL is supported by the target browsers.
- Security: This is not foolproof. Determined attackers can still bypass it (e.g., using multiple GPUs or cloud-based rendering services). It’s best used in conjunction with other anti-spam measures like CAPTCHAs, honeypots, and rate limiting.
- Server Load: Server-side validation adds load. Optimize the PoW algorithm for speed on your server.

