AWS ALB / CloudFront
Unfortunately, as of 2025, neither AWS ALB nor CloudFront has a native JA4 extraction feature.
There is also no mechanism for putting a template variable into a custom header (the equivalent of GCP's {client_ja4_fingerprint}).
A workaround is needed.
Workaround A: Put Cloudflare in front
Place Cloudflare in front of the AWS ALB and let Cloudflare do the JA4 extraction. The simplest and most
production-ready option. See the Cloudflare tab for details.
Workaround B: Compute it with Lambda@Edge
Bind a Lambda@Edge function to CloudFront to parse the TLS handshake at the viewer request stage โ
compute the JA4 โ inject the header. Implement it per the ja4 spec. Parsing uses the aws-sdk
family plus your own implementation.
// Lambda@Edge (Node.js) sketch โ viewer request event
exports.handler = async (event) => {
const req = event.Records[0].cf.request;
// CloudFront provides req.clientIp and some TLS info, but
// the full ClientHello bytes do not arrive, so a complete JA4 implementation is hard.
// Instead, a pragmatic implementation that builds a proxy
// signature by combining a ja3 hash, clientTLSVersion, etc. is the realistic answer.
req.headers['x-client-ja4'] = [{ key: 'X-Client-JA4', value: 'placeholder' }];
return req;
};
Practical guidance: AWS load balancers do not expose the client JA4 today, so on AWS a JA4-less setup โ forward-auth mode with the UA filter, rate limit and honeypot โ is the realistic choice. unmask works without JA4; detection of stealth bots drops, but the other signals still catch most bots.
Workaround C: Bypass the ALB and terminate TLS directly on EC2
Bind an Elastic IP + ACM certificate directly to the EC2 instance and terminate TLS with nginx. nginx
can then see the client TLS handshake directly via the unmask native module โ it can obtain the complete JA4.
However, you lose ALB features (sticky sessions, WAF integration).