Deny Fetch API requests on server side (PHP or Apache) from Opera address bar

3k Views Asked by At

As new Opera 65 came few days ago with address bar redesign, I have noticed an issues on my web page. While typing or copying an address into the bar, Opera sends requests to server, however, I am not able to capture the requests in PHP, as it seems, Fetch API is used under the hood.

Is there any way to deny or block the Fetch API requests in PHP 7 or Apache 2.4? In other words, block the requests on server side produced by Opera while typing / copying (PHP preferred)?

Particularly, I need to exclude GET requests providing an action with hash key in a query (test in the sample bellow). When the address is copied (from mail for e.g.) to the address bar, Opera sends the request "in the background", the request is executed, however after submitting the address by Enter, second request returns error, because of forbidden operation (hash key is not valid anymore).

From Apache log:

127.0.0.1 - - [29/Nov/2019:01:56:08 +0100] "GET /? HTTP/1.1" 200 179736
127.0.0.1 - - [29/Nov/2019:01:56:08 +0100] "GET /?t HTTP/1.1" 200 179813
127.0.0.1 - - [29/Nov/2019:01:56:08 +0100] "GET /?te HTTP/1.1" 200 179808
127.0.0.1 - - [29/Nov/2019:01:56:08 +0100] "GET /?tes HTTP/1.1" 200 179819
127.0.0.1 - - [29/Nov/2019:01:56:08 +0100] "GET /?test HTTP/1.1" 200 179823

From Wireshark (one of the requests):

/?test HTTP/1.1
Host: sk.localhost
Connection: keep-alive
Sec-Fetch-Site: none
Sec-Fetch-Mode: no-cors
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36 OPR/65.0.3467.48
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

Used technologies: PHP 7.3.7, Apache/2.4.39

1

There are 1 best solutions below

0
Dom On

The requests can be denied (response sent) by Apache rewrite conditions or PHP response based on parsed headers.

Opera sends two Fetch API headers while typing:

Sec-Fetch-Site: none
Sec-Fetch-Mode: no-cors

List of all headers can be found at https://w3c.github.io/webappsec-fetch-metadata/.

To not sent a full response (not engage PHP) for requests with this headers, you can use Apache 2.4 mod rewrite module:

RewriteCond %{HTTP:Sec-Fetch-Site} ^none$ [NC]
RewriteCond %{HTTP:Sec-Fetch-Mode} ^no-cors$ [NC]
RewriteRule ^ - [R=204,L]

or send response via PHP (sample using Kohana/Koseven FW):

    $header_sec_fetch_site = $this->request->headers('Sec-Fetch-Site');
    $header_sec_fetch_mode = $this->request->headers('Sec-Fetch-Mode');
    if (isset($header_sec_fetch_site, $header_sec_fetch_mode)
            && $header_sec_fetch_site == 'none'
            && $header_sec_fetch_mode == 'no-cors')
    {
        $message = 'Header ' . $header_sec_fetch_mode . ' received. No content for this request.';
        Log::instance()->add(Log::NOTICE, $message);
        throw HTTP_Exception::factory(204, $message, array(
                ':uri' => Request::current()->uri(),
            ));
    }

The headers should be available in global variables:

$_SERVER['HTTP_SEC_FETCH_DEST']
$_SERVER['HTTP_SEC_FETCH_SITE']
$_SERVER['HTTP_SEC_FETCH_USER']
$_SERVER['HTTP_SEC_FETCH_MODE']