Puncte:0

apache behind varnish; htaccess deny rules ignored

drapel de

So, I have a wordpress website running behind nginx -> varnish -> httpd

The htaccess rule for wp-login.php is set as:

<Files wp-login.php>
allow from client ip
deny from all
</Files>

This used to work fine without using varnish, but when I put varnish in the middle between nginx and httpd, this caching issue or IP forwarding issue started happening.

Since I can easily change the webserver config, I can disable/enable varnish for a site easily. So, as a test, I changed the htaccess rule to:

<Files wp-login.php>
allow from Server Public IP
deny from all
</Files>

This made wp-login accessible to everyone. Then I disabled varnish and kept the Server public IP in htaccess, and now nobody can access the page (which is what is supposed to happen).

So, the culprit is varnish.

I have mod_cloudflare setup on apache. I've also tested by switching it to mod_remoteip to no avail.

Here's my nginx:443, varnish:82 and apache:8181 vhost templates (This IP 108.148.54.124 is an example for the server public IP):

server {
    listen 108.148.54.124:443 ssl http2;
    server_name %domain_idn% %alias_idn%;
    
    access_log /usr/local/apache/domlogs/%domain%.bytes bytes;
    access_log /usr/local/apache/domlogs/%domain%.log full;
    error_log /usr/local/apache/domlogs/%domain%.error.log error;

    ssl_certificate      %ssl_cert_path%/%domain%.bundle;
    ssl_certificate_key  %ssl_key_path%/%domain%.key;
    ssl_protocols TLSv1.3;
    ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA!RC4:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
    ssl_prefer_server_ciphers   on;

    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 60m;

    location / {
        location ~.*\.(3gp|gif|jpg|jpeg|png|ico|wmv|avi|asf|asx|mpg|mpeg|mp4|pls|mp3|mid|wav|swf|flv|html|htm|txt|js|css|exe|zip|tar|rar|gz|tgz|bz2|uha|7z|doc|docx|xls|xlsx|pdf|iso|woff|ttf|svg|eot|sh|webp)$ {
            root %docroot%;
            expires max;
            try_files $uri $uri/ @backend;
        }
        
        error_page 405 = @backend;
        error_page 500 = @custom;
        add_header X-Cache "HIT from Backend";
        add_header Strict-Transport-Security "max-age=31536000";
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        proxy_pass %proxy_protocol%://108.148.54.124:82;
        include proxy.inc;
    }

    location @backend {
        internal;
        proxy_pass %proxy_protocol%://108.148.54.124:82;
        include proxy.inc;
    }

    location @custom {
        internal;
        proxy_pass %proxy_protocol%://108.148.54.124:82;
        include proxy.inc;
    }

    location ~ .*\.(php|jsp|cgi|pl|py)?$ {
        proxy_pass %proxy_protocol%://108.148.54.124:82;
        include proxy.inc;
    }

    location ~ /\.ht    {deny all;}
    location ~ /\.svn/  {deny all;}
    location ~ /\.git/  {deny all;}
    location ~ /\.hg/   {deny all;}
    location ~ /\.bzr/  {deny all;}
    location ~\.(ini|log|conf)$ {deny all;error_page 403 =404 / ;}

    disable_symlinks if_not_owner from=%docroot%;

    location /.well-known/acme-challenge {
        default_type "text/plain";
        alias /usr/local/apache/autossl_tmp/.well-known/acme-challenge;
    }

    location /.well-known/pki-validation {
        default_type "text/plain";
        alias /usr/local/apache/autossl_tmp/.well-known/acme-challenge;
    }
}
.....
backend %backend_domain% {
    .host = "108.148.54.124";
    .port = "8181";
}

sub vcl_recv {
    if (req.http.host ~ "%domain%") {
        set req.backend_hint = %backend_domain%;

        # Always cache the following file types for all users.
        if (req.url ~ "(?i)\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm)(\?[a-z0-9]+)?$") {
            unset req.http.Cookie;
        }

        # Remove any Google Analytics based cookies
        set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");

        # Do not cache AJAX requests.
        if (req.http.X-Requested-With == "XMLHttpRequest") {
            return(pass);
        }

        # Post requests will not be cached
        if (req.http.Authorization || req.method == "POST") {
            return (pass);
        }
        if (req.method != "GET" && req.method != "HEAD") {
            return (pass);
        }

        # Do not cache Authorized requests.
        if (req.http.Authorization) {
            return(pass);
        }

        # LetsEncrypt Certbot passthrough
        if (req.url ~ "^/\.well-known/acme-challenge/") {
            return (pass);
        }

        if (req.url ~ "^/\.well-known/pki-validation/") {
            return (pass);
        }

        # Forward client's IP to the backend
        if (req.restarts == 0) {
            if (req.http.X-Real-IP) {
                set req.http.X-Forwarded-For = req.http.X-Real-IP;
            } else if (req.http.X-Forwarded-For) {
                set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
            } else {
                set req.http.X-Forwarded-For = client.ip;
            }
        }

        ### Wordpress ###
        if (req.url ~ "(wp-admin|post\.php|edit\.php|wp-login)") {
            return(pass);
        }
        if (req.url ~ "/wp-cron.php" || req.url ~ "preview=true") {
            return (pass);
        }

        # WP-Affiliate
        if ( req.url ~ "\?ref=" ) {
            return (pass);
        }

        set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "PHPSESSID=[^;]+(; )?", "");

        return (hash);
    }
}
<VirtualHost 108.148.54.124:8443>
    ServerName %domain_idn%
    %domain_aliases%
    ServerAdmin webmaster@%domain%
    DocumentRoot %docroot%
    UseCanonicalName Off
    ScriptAlias /cgi-bin/ %docroot%/cgi-bin/

    CustomLog /usr/local/apache/domlogs/%domain%.bytes bytes
    CustomLog /usr/local/apache/domlogs/%domain%.log combined
    ErrorLog /usr/local/apache/domlogs/%domain%.error.log

    ## Custom settings are loaded below this line (if any exist)
    # IncludeOptional "/usr/local/apache/conf/userdata/%user%/%domain%/*.conf"

    SSLEngine on
    SSLCertificateFile %ssl_cert_path%/%domain%.cert
    SSLCertificateKeyFile %ssl_key_path%/%domain%.key
    SSLCertificateChainFile %ssl_cert_path%/%domain%.bundle
    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown

    <IfModule mod_userdir.c>
        UserDir disabled
        UserDir enabled %user%
    </IfModule>

    <IfModule mod_suexec.c>
        SuexecUserGroup %user% %group%
    </IfModule>

    <IfModule mod_suphp.c>
        suPHP_UserGroup %user% %group%
        suPHP_ConfigPath %home%/%user%
    </IfModule>

    <IfModule mod_ruid2.c>
        RMode config
        RUidGid %user% %group%
    </IfModule>

    <IfModule itk.c>
        AssignUserID %user% %group%
    </IfModule>

    <Directory "%docroot%">
        AllowOverride All
        SSLRequireSSL
        Require all granted
    </Directory>

    <IfModule proxy_fcgi_module>
        <FilesMatch \.php$>
            SetHandler "proxy:%backend_fcgi%|fcgi://localhost"
        </FilesMatch>
    </IfModule>

</VirtualHost>

and this is the main nginx conf file:

user nobody;
worker_processes auto;
#worker_rlimit_nofile    65535;
error_log               /var/log/nginx/error.log crit;
pid                     /var/run/nginx.pid;

events {
    worker_connections  1024;
    use                 epoll;
    multi_accept        on;

}
http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    client_header_timeout 3m;
    client_body_timeout 3m;
    client_max_body_size 256m;
    client_header_buffer_size 4k;
    client_body_buffer_size 256k;
    large_client_header_buffers 4 32k;
    send_timeout 3m;
    keepalive_timeout 60 60;
    reset_timedout_connection       on;
    server_names_hash_max_size 1024;
    server_names_hash_bucket_size 1024;
    ignore_invalid_headers on;
    connection_pool_size 256;
    request_pool_size 4k;
    output_buffers 4 32k;
    postpone_output 1460;

    include mime.types;
    default_type application/octet-stream;

    # Compression gzip
    gzip on;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";
    gzip_proxied any;
    gzip_min_length 512;
    gzip_comp_level 6;
    gzip_buffers 8 64k;
    gzip_types text/plain text/xml text/css text/js application/x-javascript application/xml image/png image/x-icon image/gif image/jpeg image/svg+xml application/xml+rss text/javascript application/atom+xml application/javascript application/json application/x-font-ttf font/opentype;

    # Proxy settings
    proxy_redirect      off;
    proxy_set_header    Host            $host;
    proxy_set_header    X-Real-IP       $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass_header   Set-Cookie;
    proxy_connect_timeout   300;
    proxy_send_timeout  300;
    proxy_read_timeout  300;
    proxy_buffers       32 4k;
    proxy_cache_path /var/cache/nginx levels=2 keys_zone=cache:10m inactive=60m max_size=512m;
    proxy_cache_key "$host$request_uri $cookie_user";
    proxy_temp_path  /var/cache/nginx/temp;
    proxy_ignore_headers Expires Cache-Control;
    proxy_cache_use_stale error timeout invalid_header http_502;
    proxy_cache_valid any 1d;

    open_file_cache_valid 120s;
    open_file_cache_min_uses 2;
    open_file_cache_errors off;
    open_file_cache max=5000 inactive=30s;
    open_log_file_cache max=1024 inactive=30s min_uses=2;

    # SSL Settings
    ssl_session_cache   shared:SSL:10m;
    ssl_protocols       TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers        "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA!RC4:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS";

    # Logs
    log_format  main    '$remote_addr - $remote_user [$time_local] $request '
                        '"$status" $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
    log_format  full '[$time_local] $remote_addr $remote_user - "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
    log_format  bytes   '$body_bytes_sent';
    #access_log          /var/log/nginx/access.log main;
    access_log off;

    # Cache bypass
    map $http_cookie $no_cache {
        default 0;
        ~SESS 1;
        ~wordpress_logged_in 1;
    }

    # Include additional configuration
    include /etc/nginx/cloudflare.inc;
    include /etc/nginx/conf.d/*.conf;
}
iraqiboy90 avatar
drapel de
Starea serverului pentru apache arată doar IP-ul serverului ca client, indiferent dacă vernisul este activat sau nu.
Puncte:0
drapel de

Tocmai am găsit o soluție, care este să folosesc asta în schimb

<Files wp-login.php>
SetEnvIf X-Forwarded-For %Client_IP% allow_me
Allow from env=allow_me
deny from all
</Files>

De asemenea, pot pune SetEnvIf în exterior, adică în partea de sus a fișierului htaccess și doar schimb ip-ul pe această linie de fiecare dată când IP-ul meu se schimbă.

SetEnvIf X-Forwarded-For %Client_IP% allow_me
<Fișiere wp-login.php>
Permite de la env=allow_me
nega de la toti
</Fișiere>
Puncte:0
drapel in

The X-Înainte-Pentru antetul ar trebui să conțină adresa IP a clientului. Acest antet va fi setat de Nginx și va fi folosit și de Varnish.

Este posibil ca X-Înainte-Pentru antetul arată astfel:

X-Redirecționat-Pentru: 1.2.3.4, 5.6.7.8

Este o chestiune de a extrage prima valoare și de a o potrivi în ta fișier .htaccess.

Acest articol oferă o modalitate ușoară de a performa permite de la apeluri bazate pe valoarea X-Redirecţionat-Pentru antet: Apache, folosește X-Forwarded-For pentru a permite

Acest lucru s-ar putea traduce în următoarea configurație:

<Files wp-login.php>
    SetEnvIf X-Forwarded-For ^1\.2\.3\.4 proxy_env
    Order allow,deny
    Satisfy Any
    Allow from env=proxy_env
    Deny from all
</Files>

De asemenea, puteți restricționa accesul la wp-login.php în configurația dvs. Nginx sau în VCL-ul dvs. Varnish.

iraqiboy90 avatar
drapel de
Mulțumesc, dar acest lucru aproape repetă același răspuns pe care l-am scris mai sus... Singurul lucru pe care nu l-am menționat în întrebare este de ce încercam să „permit de la SERVER IP” în primul rând. A fost pentru că mod_security bloca unele solicitări făcute de server, așa că am trecut serverul pe lista albă, ceea ce a făcut ca toată lumea să fie trecută pe lista albă din mod_security, ceea ce m-a condus pe calea că includerea pe lista albă în timp ce aveam lac în fața Apache va fi probleme.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.