Using signed URLs to secure your CDN content
Content Delivery Networks (CDNs) are essential for efficient content delivery across the globe, but they can expose your content to unauthorized access if proper security measures are not in place. This DevTip explains how signed URLs can enhance your CDN security by ensuring that only authorized users can obtain access to your resources. A signed URL is a bearer credential: anyone who receives it can use it until it expires. Your application must authorize the user before issuing it.
Understanding CDN security and signed URLs
CDNs boost content delivery speed and improve user experience by caching content at edge locations. However, without robust access controls, your content may be vulnerable to misuse or piracy. Implementing signed URLs adds a layer of token-based authentication that grants temporary, secure access to protected resources.
Benefits of using signed URLs:
- Restrict access to premium or sensitive content
- Prevent unauthorized hotlinking and reduce bandwidth theft
- Support access restrictions required by your licensing agreements and security policies
- Limit access duration; revoking an already-issued URL generally requires changing its signing keys or the distribution's access configuration
- Enhance content security without sacrificing performance
CDN provider comparison for signed URLs
Different CDN providers implement signed URL functionality with varying levels of complexity:
| CDN Provider | Signed URL Support | Token Auth | Implementation Complexity |
|---|---|---|---|
| AWS CloudFront | Yes | Yes | Medium |
| Azure CDN | Yes | Yes | Medium |
| Google Cloud CDN | Yes | Yes | Medium |
| Fastly | Yes | Yes | Complex |
| Cloudflare | Yes | Yes | Simple |
Prerequisites for implementation
Before implementing signed URLs, ensure you have completed the following:
- Access to your CDN's management console with administrative privileges.
- Appropriate permissions (for example, necessary IAM roles in AWS CloudFront) to generate and manage key pairs.
- The required API credentials or SDK configurations along with your key pair details.
- HTTPS enabled on your domain with a valid SSL/TLS certificate.
- An origin server configured for CDN integration, including proper cache-control headers.
- A synchronized system clock to avoid issues with URL expiration.
Implementing signed URLs with AWS CloudFront
Run this example on your server using Node.js 22 or later and install
@aws-sdk/cloudfront-signer. Save it as signed-url.mjs. It accepts an expiration in seconds,
defaulting to 3600 seconds (1 hour).
Before using the signer, configure the CloudFront cache behavior to require signed URLs using a
trusted key group, add your public key to that group, and protect the origin from direct access.
CLOUDFRONT_KEY_PAIR_ID is that public key's ID, not an IAM access key. Supply the matching PEM
private key through server-side secret configuration; never include it in client code.
See AWS's signed URL setup.
import { getSignedUrl } from '@aws-sdk/cloudfront-signer'
async function generateSignedUrl(
resourceUrl,
privateKeyString,
keyPairId,
expirationSeconds = 3600,
) {
try {
const signedUrl = getSignedUrl({
url: resourceUrl,
keyPairId: keyPairId,
privateKey: privateKeyString,
dateLessThan: new Date(Date.now() + expirationSeconds * 1000).toISOString(),
})
return signedUrl
} catch (error) {
console.error('Error generating signed URL:', error)
throw error
}
}
// Usage example
const resourceUrl = 'https://your-distribution.cloudfront.net/path/to/content'
try {
const signedUrl = await generateSignedUrl(
resourceUrl,
process.env.CLOUDFRONT_PRIVATE_KEY,
process.env.CLOUDFRONT_KEY_PAIR_ID,
)
console.log('Signed URL:', signedUrl)
} catch (error) {
console.error('Failed to generate URL:', error)
}
Developers using other CDN providers (such as Azure CDN, Google Cloud CDN, Fastly, or Cloudflare) should refer to their respective documentation for similar signed URL implementations.
Security best practices
Elevate your CDN security with these measures:
-
Key Management:
- Rotate signing keys regularly (ideally every 90 days or as defined by your security policy).
- Store private keys securely using a dedicated key management service or secrets manager.
- Implement key versioning to ensure smooth transitions without service interruption.
-
Access Controls:
- Configure strict expiration times based on the sensitivity of your content.
- Apply IP-based restrictions when feasible to limit access to known addresses.
- Use token-based authentication for granular access control.
-
Monitoring and Logging:
- Enable detailed logging on your CDN endpoints to track access and monitor anomalies.
- Regularly review access logs to identify and respond to unusual activity.
- Set up alerts for suspicious traffic patterns or potential security breaches.
-
HTTPS Enforcement:
- Mandate HTTPS-only access to your CDN resources.
- Use current TLS versions (TLS 1.2 or higher) for secure connections.
- Manage SSL/TLS certificates diligently to prevent vulnerabilities.
Troubleshooting common issues
Implementing signed URLs can sometimes lead to challenges. Consider these troubleshooting tips:
-
Signature Validation Errors:
- Ensure your server's clock is synchronized.
- Confirm that the key pair ID and private key match correctly.
- Verify that URL encoding follows the expected format.
-
Cache-related Problems:
- Set appropriate cache-control headers on your origin server.
- Double-check your CDN cache settings to ensure they align with your content policies.
- Inspect origin server response headers for consistency.
-
CORS Issues:
- Configure proper CORS headers on your server.
- Specify allowed origins clearly in your CDN settings.
- Correctly handle preflight requests to support secure cross-origin access.
-
Common Error Codes:
- 403: Indicates an invalid signature or an expired URL.
- 400: Suggests a malformed URL or missing parameters.
- 504: Points to an origin timeout, which may require server-side adjustments.
Testing and validation
Thorough testing ensures your signed URL implementation works as expected. Here are two scenarios:
-
Basic Functionality:
const testSignedUrl = async () => { const url = await generateSignedUrl( resourceUrl, process.env.CLOUDFRONT_PRIVATE_KEY, process.env.CLOUDFRONT_KEY_PAIR_ID, ) const response = await fetch(url) if (!response.ok) { throw new Error(`Failed to access content: ${response.status}`) } return response } -
Expiration Testing:
const testExpiration = async () => { // Generate a URL that expires in 1 second const shortLivedUrl = await generateSignedUrl( resourceUrl, process.env.CLOUDFRONT_PRIVATE_KEY, process.env.CLOUDFRONT_KEY_PAIR_ID, 1, ) // Wait for 2 seconds to ensure expiration await new Promise((resolve) => setTimeout(resolve, 2000)) const response = await fetch(shortLivedUrl) if (response.status !== 403) { throw new Error('URL did not expire as expected') } }
Conclusion
Implementing signed URLs is a powerful strategy for safeguarding your CDN content by restricting access to authorized users only. By following the updated implementation steps, adhering to security best practices, and thoroughly testing your setup, you can significantly boost your content security while maintaining optimal delivery performance.
While securing your CDN content, consider how Transloadit can enhance your file processing workflow.
