0

I'm trying to retrieve an image from a cross-origin server. I'm using a self-signed certificate on a WAMP stack server, but regardless of which headers I use, fetch() always throws an exception after the pre-flight check. Below is the request/response headers taken from chrome:

General
Request URL: https://starlightproductions.ddnsfree.com/clientgalleries/michael.laver.suncorp.com.au/Snapper/holycrap.jpg
Request Method: OPTIONS
Status Code: 401 Unauthorized
Remote Address: 220.237.95.254:443
Referrer Policy: strict-origin

Response Headers
Connection: Keep-Alive
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1
Date: Wed, 11 Dec 2019 23:28:36 GMT
Keep-Alive: timeout=5, max=100
Server: Apache
WWW-Authenticate: Basic realm="Client Only"
X-Frame-Options: SAMEORIGIN

Request Headers
Date: Wed, 11 Dec 2019 23:28:36 GMT
Keep-Alive: timeout=5, max=100
Server: Apache
WWW-Authenticate: Basic realm="Client Only"
X-Frame-Options: SAMEORIGIN
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: authorization,content-type
Access-Control-Request-Method: GET
Connection: keep-alive
Host: starlightproductions.ddnsfree.com
Origin: http://dev.qwikfoto.com
Referer: http://dev.qwikfoto.com/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36

Here's the javascript code that makes the call to fetch():

let hdr = new Headers();

hdr.append(\'Content-Type\', \'application/octet-stream\');
hdr.append(\'Accept\', \'application/octet-stream\');
hdr.append(\'Authorization\', \'Basic \' + window.btoa(\'' . $xrefrec['ftp_username'] . ':' .
        $xrefrec['ftp_password'] . '\'));
hdr.append(\'Origin\',\'http://dev.qwikfoto.com\');

const myresponse = await fetch(document.getElementById(thm.photo_id).href, {
    mode: \'cors\',
    credentials: \'include\',
    method: \'GET\',
    headers: hdr
});

An here are the headers from .htaccess in the directory where the image resides:

Header set Access-Control-Allow-Methods: "GET, POST, OPTIONS"
Header set Access-Control-Allow-Credentials: true
Header set Cache-Control: no-cache
Header set Access-Control-Expose-Headers: "Content-Length"
Header set Access-Control-Allow-Headers: "*"
# Header set Access-Control-Allow-Headers: "Authorization, Origin, Content-Type, Accept, X-Auth-Token"
Header set WWW-Authenticate: "Basic realm='Client Only'"
Header set Access-Control-Allow-Origin: http://dev.qwikfoto.com
Header set Vary: Origin
Header set Access-Control-Max-Age: 84600

I've been working on this for days. I've even tried forcing a response code of http 200 using a RewriteRule directive in the apache config file. I'd really appreciate some help here.

Thanks,

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Paul
  • 32
  • 5
  • Erm. What is `\'Content-Type\'` supposed to achieve? – Olian04 Dec 12 '19 at 00:06
  • 2
    What's with all the quote escaping? Because in this form, that's definitely not valid JS. – Mike 'Pomax' Kamermans Dec 12 '19 at 00:07
  • The CORS spec requires browsers to omit credentials from preflight OPTIONS requests. So the `https://starlightproductions.ddnsfree.com` server must be configured to allow unauthenticated OPTIONS requests. – sideshowbarker Dec 12 '19 at 00:37
  • The javascript is embedded inside a PHP echo statement, hence, all the escaped quotes. – Paul Dec 12 '19 at 02:15
  • Can 'sidehowbarker' give me an example of how to configure the server? – Paul Dec 12 '19 at 02:19
  • 1
    @Paul see https://stackoverflow.com/a/42558499/441757 and ensure you don’t do `Header set WWW-Authenticate: "Basic realm='Client Only'"` for OPTIONS requests, and ensure you have your Apache configuration set up such that any other authentication it might be requiring for other HTTP methods is not required for OPTIONS requests. – sideshowbarker Dec 12 '19 at 03:08
  • I finally got it to work! Thank you so much! – Paul Dec 12 '19 at 05:56

1 Answers1

0

It seems that the problem is with your self-signed certificate.

When it comes to fetch and SSL, fetch acts somewhat like the browser does when used by a user, which means that it does not allow fetching resources from invalid or self-signed certificates, unless the user takes actions to tell the browser that it is okay to do so.

If you're constructing a user-facing website, my guess is that you will not be able to get your users to take manual steps to allow the browser to do this.

My best advice would be to use something like Let's Encrypt instead of self-signed certificates.

tomahaug
  • 1,446
  • 10
  • 12
  • I get the same error when I run it without the certificate, i.e. using http (port 8080) instead of https. – Paul Dec 12 '19 at 02:39