dokuwiki icon indicating copy to clipboard operation
dokuwiki copied to clipboard

HTTP redirection in midst of a HTTPS context

Open otyugh opened this issue 1 year ago • 6 comments

How to reproduce : set your firefox browser with dom.security.https_only_mode=true

As a result you'll get stopped : 1/after login 2/after editing a page or settings or enabling a mod with the error "NS_ERROR_REDIRECT_LOOP".

If you check that line you can see that, yes. A http request is made - even out of a HTTPS context.

file-R959e46f7706bbe4968f796cd3b217b62

otyugh avatar Jan 01 '24 01:01 otyugh

I cannot reproduce this, neither on one of my own wikis nor https://www.dokuwiki.org/ . Login and editing work with HTTPS only.

xrat avatar Jan 01 '24 09:01 xrat

(note : The problem only occurred on successful logins)

Could it be a combination of my nginx settings & dokuwiki ?

I can give you a "default dokuwiki" that I'd just pasted on my webserver if it can help pinpoint the issue (maybe not, I'm still trying to cope with the fact you couldn't reproduce it :<) https://t2.arzinfo.eu.org/doku.php?id=start

otyugh avatar Jan 01 '24 10:01 otyugh

I can reproduce your error on your https://t2.arzinfo.eu.org/doku.php?id=start I doubt that this is a bug in DW. Also, I'd rather not suspect nginx.

Does your setup involve a proxy? What's your DW baseurl setting? But even then I wonder whether something else is going on since the error is a redirection loop. Also, your server even sends a Strict-Transport-Security: max-age=31536000; includeSubdomains; preload header for each request, so my understanding is that a browser should not even try to access http://….

xrat avatar Jan 01 '24 11:01 xrat

my understanding is that a browser should not even try to access http://…

Yes, at least, that's what I was trying to go for.

Does your setup involve a proxy?

No proxy.

What's your DW baseurl setting?

I defined no baseurl - but I just tried to set it up, and it seem to fix the problem when set.

Now, I still believe it's a bit of an issue in the basurl guessing but as nobody beside me seem to be able to replicate it, it looks very niche.

For "if anyone fall on the same thing and do some connection I don't" here's an extract of my nginx config

add_header Content-Security-Policy "default-src 'none'; base-uri 'self'; script-src 'self'; img-src 'self' data:; style-src 'self'; form-act>
add_header X-XSS-Protection "1; mode=block";
add_header Feature-Policy "geolocation none;midi none;notifications none;push none;sync-xhr none;microphone none;camera none;magnetometer no>

map $sent_http_content_type $expires {
        default                    off;
        text/html                  epoch;
        text/css                   14d;
        application/javascript     off;
        ~image/                    max;
}

server {
        listen 443 ssl http2;
        server_name xxx.xxx;

##SSL
        ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305';
        ssl_ecdh_curve secp384r1;
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_session_timeout 1d;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;
        add_header X-Frame-Options deny;
        add_header X-Content-Type-Options nosniff;
        add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; style-src >
        add_header X-XSS-Protection "1; mode=block";
        add_header Referrer-Policy "no-referrer";
        #add_header Feature-Policy "geolocation none;midi none;notifications none;push none;sync-xhr none;microphone none;camera none;magnetometer n>
        #add_header Permission-Policy "geolocation=(none),midi=(none),notifications=(none),push=(none),sync-xhr=(none),microphone=(none),camera=(non>
        add_header Permissions-Policy "geolocation=(self), microphone=()";
        
##php
        location ~ \.php {
                fastcgi_split_path_info ^(.+?\.php)(/.*)$;
                if (!-f $document_root$fastcgi_script_name) {
                        return 404;
                }
                # A handy function that became available in 0.7.31 that breaks down 
                # The path information based on the provided regex expression
                # This is handy for requests such as file.php/some/paths/here/ 
        
                fastcgi_param  PATH_INFO          $fastcgi_path_info;
                fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;
        
                fastcgi_param  QUERY_STRING       $query_string;
                fastcgi_param  REQUEST_METHOD     $request_method;
                fastcgi_param  CONTENT_TYPE       $content_type;
                fastcgi_param  CONTENT_LENGTH     $content_length;
        
                fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
                fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
                fastcgi_param  REQUEST_URI        $request_uri;
                fastcgi_param  DOCUMENT_URI       $document_uri;
                fastcgi_param  DOCUMENT_ROOT      $document_root;
                fastcgi_param  SERVER_PROTOCOL    $server_protocol;
        
                fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
                fastcgi_param  SERVER_SOFTWARE    nginx;
        
                fastcgi_param  REMOTE_ADDR        $remote_addr;
                fastcgi_param  REMOTE_PORT        $remote_port;
                fastcgi_param  SERVER_ADDR        $server_addr;
                fastcgi_param  SERVER_PORT        $server_port;
                fastcgi_param  SERVER_NAME        $server_name;
        
                fastcgi_pass   unix:/var/run/php/php7.4-fpm.sock;
                fastcgi_index  index.php;
        }
        include snippets/ssl_credentials.conf;
        client_max_body_size 42M;
        root /srv/$subdomain;
        index index.html index.php;
        location / {
                try_files $uri $uri/ =404;
        }
}

otyugh avatar Jan 01 '24 11:01 otyugh

It seems the HTTPS environment variable isn't set. Which is curious. I guess we could also check for the protocol in the REQUEST_URI...

https://github.com/dokuwiki/dokuwiki/blob/5719588d0f688f7f6046619e9d8a8df7aba77ef6/inc/init.php#L535-L547

splitbrain avatar Jan 02 '24 08:01 splitbrain

Oh nice. Looking at understanding the behavior better I tried to add some echo '<pre>'.print_r($_SERVER,true).'</pre>'; to the function.

Apparently the "is_ssl" is called 3 time on each page. The 3 $_SERVER output are exactly the same (I used diff to check).

Also neither -HTTP_X_FORWARDED_PROTO -HTTPS

Are ever set (I'm confused too ! Everything works https without any https flag ?)

Here is also the $SERVER difference between "normal POST request" and the after "pushing the send button while editing a dokuwiki" is this :

-    [REQUEST_METHOD] => POST
+    [REQUEST_METHOD] => GET

-    [REMOTE_PORT] => 40084
+    [REMOTE_PORT] => 10426

-    [CONTENT_LENGTH] => 187
+    [CONTENT_LENGTH] => 

-    [CONTENT_TYPE] => application/x-www-form-urlencoded
+    [CONTENT_TYPE] => 

-    [HTTP_SEC_FETCH_USER] => ?1
-    [HTTP_ORIGIN] => null
-    [HTTP_CONTENT_LENGTH] => 187
-    [HTTP_CONTENT_TYPE] => application/x-www-form-urlencoded

Also because nothing changes for is_ssl check, that condition is the one that triggers every time and return "false"

 if (preg_match('/^(|off|false|disabled)$/i', $_SERVER['HTTPS'] ?? 'off')) { 
         return false; 
  } 

otyugh avatar Jan 02 '24 10:01 otyugh