Home > Mobile >  Include Header with Redirect
Include Header with Redirect

Time:05-08

Problem: My HTML/JavaScript app receives a CORS error processing a redirect.

Objective: Configure Apache to include an HTTP header only during a specific redirect.

Important note: This HTML runs in a browser from a locally loaded file and not from a page served by a web server.

The Code:

<body>
  <div id="response">Loading page ...</div>

<script type="text/javascript">
  async function get_response() {
      let url = 'https://example.com/endpoint'

      fetch(url, {
        redirect: "follow"
      })
        .then(response => response.text())
        .then(data => {
          document.getElementById('response').innerHTML = data;
        })
        .catch(error => {
          console.log(error);
        });
  }

  get_response();
</script>
</body>

Code Description:

The above code fetches data from a URL and displays it in the browser. However, the website sends a 302 redirect (by design). The redirect causes a CORS error.

CORS Error:

Access to fetch at 'https://example.com/endpoint' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

The Apache configuration that generates the redirect:

RewriteEngine on
RewriteRule ^(/endpoint)$ /system/endpoint.php? [END,NE,R=302]

Possible workarounds that are not acceptable:

  1. Configure Apache to send a CORS header before the RewriteRule:

    Header always set Access-Control-Allow-Origin "*"

This is not a good solution because I do not want to send this header for all URLs only this one redirect. Other pages do set this header and when Chrome receives several Access-Control-Allow-Origin headers with the same value, an error is generated instead of accepting the headers. Note: AFAIK header always set is required to include the header for 3xx responses.

  1. Modify the application to use the redirected URL instead of a URL that redirects.

This will not work as the final URL is configurable and the objective is to not modify the application when the backend routes change.

Other Workarounds:

I realized by writing this question and thinking through the problem, that my RewriteRule is generating a redirect that is not necessary for all situations. For a redirect within the same domain, a URL rewrite is enough. For redirecting to subdomains, which I need to do, rewriting the URL is not enough.

For the same domain URL change, this will work:

RewriteRule ^(/endpoint)$ /system/endpoint.php? [L]

For a true redirect, I need a method to conditionally include the CORS header.

CodePudding user response:

The solution is to combine the Apache <If> directive with the server variable REQUEST_URI:

<If "%{REQUEST_URI} == '/endpoint'">
Header always set Access-Control-Allow-Origin "*"
</If>

RewriteEngine on
RewriteRule ^(/endpoint)$ https://example2.com/system/endpoint? [END,NE,R=302]

The new endpoint must also be configured to respond with the Access-Control-Allow-Origin header.

Apache <If> Directive

Apache Server Variables

[Update]

By responding with Access-Control-Allow-Origin "*", my solution defeats the purpose of CORS which is to prevent unauthorized resource sharing. This solution will trigger a warning or a violation in a security audit. Since I am only wildcarding specific routes in the backend and not all routes, this can be explained/documented.

When I researched this issue on Stack Overflow and on the Internet, each answer/article recommended returning the `Access-Control-Allow-Origin "*" header. That is the wrong solution almost of the time. The purpose of a security control is to enforce it, and not to bypass it.

  • Related