Keywords: CORS error | Private Network Access | webpack-dev-server configuration | HTTPS certificates | preflight requests
Abstract: This article provides an in-depth analysis of CORS errors in Chrome that block access to localhost development servers from remote sites. It explains the security mechanisms of the Private Network Access (formerly CORS-RFC1918) specification, which restricts public network resources from requesting private network resources unless HTTPS and specific CORS headers are in place. The article covers temporary fixes (e.g., disabling Chrome flags) and their limitations, then details a permanent solution: configuring webpack-dev-server with HTTPS via self-signed certificates and adding middleware to handle preflight requests. Step-by-step guidance on certificate generation, server configuration, and browser trust settings is included to help developers securely restore their development environments.
Problem Background and Error Analysis
In development environments, developers often encounter CORS (Cross-Origin Resource Sharing) errors when accessing a local development server (e.g., http://localhost:8080) from a remote site (e.g., http://example.com). A typical error message is:
Access to CSS stylesheet at 'http://localhost:8080/build/app.css' from origin 'http://example.com' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space <code>local</code>.
This error stems from Chrome's implementation of the Private Network Access (formerly CORS-RFC1918) specification. Designed to enhance security, it prevents public network resources (like remote HTTP sites) from requesting private network resources (like localhost) unless the request originates from a secure context (HTTPS) and the target resource provides appropriate CORS headers. This is analogous to security upgrades from HTTP to HTTPS.
Temporary Solutions and Their Limitations
In earlier Chrome versions, a temporary workaround involved disabling the flag chrome://flags/#block-insecure-private-network-requests. However, this approach has significant drawbacks:
- Security Risks: Disabling the flag reopens the security vulnerability that Chrome aims to fix, potentially exposing systems to attacks.
- Compatibility Issues: The flag was removed in subsequent Chrome updates, rendering the workaround ineffective.
- Unstable Development Environment: Relying on browser settings may lead to inconsistencies across devices or versions.
Thus, temporary solutions are only suitable for short-term testing and not recommended for production or ongoing development.
Permanent Solution: Configuring HTTPS and Preflight Request Handling
To permanently resolve this issue, the local development server must be upgraded to HTTPS, and preflight requests must be handled correctly. Below are configuration steps based on webpack-dev-server.
Step 1: Generate Self-Signed Certificates
First, use a tool like mkcert to generate self-signed certificates. Execute the following commands in a terminal:
cd path/to/.ssl
npx mkcert create-cert
This generates three files: cert.key (private key), cert.crt (certificate), and ca.crt (CA certificate), which are used to configure HTTPS.
Step 2: Configure webpack-dev-server
In the webpack configuration file, add HTTPS settings and middleware to handle preflight requests. Example code:
const { readFileSync } = require('fs');
module.exports = {
// Other configurations...
devServer: {
https: {
key: readFileSync("./.ssl/cert.key"),
cert: readFileSync("./.ssl/cert.crt"),
cacert: readFileSync("./.ssl/ca.crt"),
},
allowedHosts: ".example.dev", // Match the remote site domain
setupMiddlewares(middlewares, devServer) {
// Handle OPTIONS preflight requests
devServer.app.options('*', (req, res) => {
// Check if the request origin is allowed
if (/^https:\/\/example\.dev$/.test(req.headers.origin)) {
res.set({
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Private-Network": "true",
"Access-Control-Allow-Origin": req.headers.origin, // Avoid using *
});
res.sendStatus(200);
}
});
return middlewares;
}
}
};
Key points:
- HTTPS Configuration: Enable HTTPS using the generated certificates to ensure requests come from a secure context.
- Preflight Request Handling: Add middleware via
setupMiddlewaresto respond to OPTIONS requests with necessary CORS headers, includingAccess-Control-Allow-Private-Networkto permit private network access. - Domain Matching:
allowedHostsrestricts requests to specific domains, enhancing security.
Step 3: Trust the Certificates
To make browsers trust the self-signed certificates, add the CA certificate to the system's trust store.
- Windows Systems: Right-click the
ca.crtfile, select "Install Certificate," and follow the wizard to import it into "Trusted Root Certification Authorities." - Firefox Browser: Enter
about:configin the address bar, search forsecurity.enterprise_roots.enabled, and set it totrueto enable trust for enterprise root certificates.
Summary and Best Practices
Resolving CORS errors when accessing localhost from remote sites centers on adhering to the Private Network Access specification by implementing HTTPS and preflight request configurations for secure cross-origin communication. While temporary browser flag disabling is convenient, it compromises security; the permanent solution ensures stability and safety through certificates and middleware. Developers should prioritize HTTPS configurations in all projects and regularly update CORS policies to align with browser evolution. This approach is applicable not only to webpack-dev-server but can be extended to other development server tools.