在 WordPress 上使用 Hitch 作为 TLS 代理和 Varnish 访问 HTTPS 网站时出现混合内容错误?

问题描述 投票:0回答:1

我网站的 https 版本出现混合内容错误。

我有以下设置

端口 443 上的流量正在运行 Hitch TLS 代理,该代理被转发到 Varnish,并最终在 Apache Web Server 中结束。

我的想法是我网站上的第一个请求通过 HTTPS 加载,但所有后续请求都由 Varnish 在 HTTP 中直接处理。

我需要帮助弄清楚如何在客户端通过 TLS 加载所有网址。

这是我的 Hitch TLS 代理配置文件

# Upstream server address.
backend = "[127.0.0.1]:8443"

pem-file = {
        cert = "/etc/letsencrypt/live/staging1.sainikbiswas.com/fullchain.pem"
        private-key = "/etc/letsencrypt/live/staging1.sainikbiswas.com/privkey.pem"
}

ocsp-dir = "/var/lib/hitch-ocsp"

ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"

# List of allowed TLS ciphers.

ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHAA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RRSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"   
                            
# Enforce server cipher list order
#
# type: boolean
prefer-server-ciphers = off

tls-protos = TLSv1.2 TLSv1.3
alpn-protos = "h2, http/1.1"

workers = 4

backlog = 100
keepalive = 3600

chroot = ""
user = "hitch"
group = "hitch"

syslog = on
syslog-facility = "daemon"
daemon = on

write-ip = off
write-proxy-v1 = off
write-proxy-v2 = on
proxy-proxy = off
sni-nomatch-abort = off

Apache 2 配置文件

<VirtualHost *:8080>
        ServerName staging1.sainikbiswas.com
        ServerAdmin [email protected]

        DocumentRoot "/home/sainikbiswas/domains/sainikbiswas-com/public"

        <Directory /home/sainikbiswas/domains/sainikbiswas-com/public>
            #Disable .htaccess file
            AllowOverride None

            #WordPress Rewrite Rules
            <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
                RewriteBase /
                RewriteRule ^index\.php$ - [L]
                RewriteCond %{REQUEST_FILENAME} !-f
                RewriteCond %{REQUEST_FILENAME} !-d
                RewriteRule . /index.php [L]
            </IfModule>

            #Disable File Index
            Options -Indexes -FollowSymLinks +SymLinksIfOwnerMatch

            #Enable Access to the Document Root
            Require all granted
        </Directory>

</VirtualHost>

清漆配置文件

vcl 4.1;

import proxy;
import std;

# Default backend definition. Set this to point to your content server.
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

# Add hostnames, IP addresses and subnets that are allowed to purge content
acl purge {
    "localhost";
    "127.0.0.1";
    "::1";
}


sub vcl_recv {
        if ((req.http.X-Forwarded-Proto && req.http.X-Forwarded-Proto != "https") ||
            (req.http.Scheme && req.http.Scheme != "https")) {
                return (synth(750));
        } elseif (!req.http.X-Forwarded-Proto &&
                  !req.http.Scheme && !proxy.is_ssl()) {
                return (synth(750));
   }

# WordPress Varnish Configuration
# Remove empty query string parameters
    # e.g.: www.example.com/index.html?
    if (req.url ~ "\?$") {
        set req.url = regsub(req.url, "\?$", "");
    }

    # Remove port number from host header
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # Sorts query string parameters alphabetically for cache normalization purposes
    set req.url = std.querysort(req.url);

    # Remove the proxy header to mitigate the httpoxy vulnerability
    # See https://httpoxy.org/
    unset req.http.proxy;

# Add X-Forwarded-Proto header when using https

        if(!req.http.X-Forwarded-Proto) {
        if (proxy.is_ssl()) {
            set req.http.X-Forwarded-Proto = "https";
        } else {
            set req.http.X-Forwarded-Proto = "http";
        }
    }

    # Purge logic to remove objects from the cache.
    # Tailored to the Proxy Cache Purge WordPress plugin
    # See https://wordpress.org/plugins/varnish-http-purge/
    if(req.method == "PURGE") {
        if(!client.ip ~ purge) {
            return(synth(405,"PURGE not allowed for this IP address"));
        }
        if (req.http.X-Purge-Method == "regex") {
            ban("obj.http.x-url ~ " + req.url + " && obj.http.x-host == " + req.http.host);
            return(synth(200, "Purged"));
        }
        ban("obj.http.x-url == " + req.url + " && obj.http.x-host == " + req.http.host);
        return(synth(200, "Purged"));
    }


 # Only handle relevant HTTP request methods
    if (
        req.method != "GET" &&
        req.method != "HEAD" &&
        req.method != "PUT" &&
        req.method != "POST" &&
        req.method != "PATCH" &&
        req.method != "TRACE" &&
        req.method != "OPTIONS" &&
        req.method != "DELETE"
    ) {
        return (pipe);
    }

    # Remove tracking query string parameters used by analytics tools
    if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteur
l)=") {
        set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gcli
d|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gcl
id|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        set req.url = regsub(req.url, "\?$", "");
    }

    # Only cache GET and HEAD requests
    if (req.method != "GET" && req.method != "HEAD") {
        set req.http.X-Cacheable = "NO:REQUEST-METHOD";
        return(pass);

 # Mark static files with the X-Static-File header, and remove any cookies
    # X-Static-File is also used in vcl_backend_response to identify static files
    if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js
|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|t
ar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
        set req.http.X-Static-File = "true";
        unset req.http.Cookie;
        return(hash);
    }

    # No caching of special URLs, logged in users and some plugins
    if (
        req.http.Cookie ~ "wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0
-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordp
ress_logged_in_|comment_author|PHPSESSID" ||
        req.http.Authorization ||
        req.url ~ "add_to_cart" ||
        req.url ~ "edd_action" ||
        req.url ~ "nocache" ||
        req.url ~ "^/addons" ||
        req.url ~ "^/bb-admin" ||
        req.url ~ "^/bb-login.php" ||
        req.url ~ "^/bb-reset-password.php" ||
        req.url ~ "^/cart" ||
        req.url ~ "^/checkout" ||
        req.url ~ "^/control.php" ||
        req.url ~ "^/login" ||
        req.url ~ "^/logout" ||
        req.url ~ "^/lost-password" ||
        req.url ~ "^/my-account" ||
        req.url ~ "^/product" ||
        req.url ~ "^/register" ||
        
req.url ~ "^/register.php" ||
        req.url ~ "^/server-status" ||
        req.url ~ "^/signin" ||
        req.url ~ "^/signup" ||
        req.url ~ "^/stats" ||
        req.url ~ "^/wc-api" ||
        req.url ~ "^/wp-admin" ||
        req.url ~ "^/wp-comments-post.php" ||
        req.url ~ "^/wp-cron.php" ||
        req.url ~ "^/wp-login.php" ||
        req.url ~ "^/wp-activate.php" ||
        req.url ~ "^/wp-mail.php" ||
        req.url ~ "^/wp-login.php" ||
        req.url ~ "^\?add-to-cart=" ||
        req.url ~ "^\?wc-api=" ||
        req.url ~ "^/preview=" ||
        req.url ~ "^/\.well-known/acme-challenge/"
    ) {
             set req.http.X-Cacheable = "NO:Logged in/Got Sessions";
             if(req.http.X-Requested-With == "XMLHttpRequest") {
                     set req.http.X-Cacheable = "NO:Ajax";
             }
        return(pass);
    }

    # Remove any cookies left
    unset req.http.Cookie;
    return(hash);
}


sub vcl_synth {
        if (resp.status == 750) {
                set resp.status = 301;
                set resp.http.location = "https://" + req.http.Host + req.url;
                set resp.reason = "Moved";
                return (deliver);
        }
}

sub vcl_hash {
#WordPress Varnish Configuration

    if(req.http.X-Forwarded-Proto) {
        # Create cache variations depending on the request protocol
        hash_data(req.http.X-Forwarded-Proto);
    }
}

sub vcl_backend_response {
if(beresp.http.Vary) {
        set beresp.http.Vary = beresp.http.Vary + ", X-Forwarded-Proto";
    } else {
        set beresp.http.Vary = "X-Forwarded-Proto";
    }


# Inject URL & Host header into the object for asynchronous banning purposes
    set beresp.http.x-url = bereq.url;
    set beresp.http.x-host = bereq.http.host;

    # If we dont get a Cache-Control header from the backend
    # we default to 1h cache for all objects
    if (!beresp.http.Cache-Control) {
        set beresp.ttl = 1h;
        set beresp.http.X-Cacheable = "YES:Forced";
    }

    # If the file is marked as static we cache it for 1 day
    if (bereq.http.X-Static-File == "true") {
        unset beresp.http.Set-Cookie;
        set beresp.http.X-Cacheable = "YES:Forced";
        set beresp.ttl = 1d;
    }

        # Remove the Set-Cookie header when a specific Wordfence cookie is set
    if (beresp.http.Set-Cookie ~ "wfvt_|wordfence_verifiedHuman") {
            unset beresp.http.Set-Cookie;
         }

    if (beresp.http.Set-Cookie) {
        set beresp.http.X-Cacheable = "NO:Got Cookies";
    } elseif(beresp.http.Cache-Control ~ "private") {
        set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    }
}


sub vcl_deliver {
    # Debug header
    if(req.http.X-Cacheable) {
        set resp.http.X-Cacheable = req.http.X-Cacheable;
    } elseif(obj.uncacheable) {
        if(!resp.http.X-Cacheable) {
            set resp.http.X-Cacheable = "NO:UNCACHEABLE";
        }
    } elseif(!resp.http.X-Cacheable) {
        set resp.http.X-Cacheable = "YES";
    }

    # Cleanup of headers
    unset resp.http.x-url;
    unset resp.http.x-host;
}

我尝试从 Varnish 教程中实现这一点。我认为这会将所有 HTTP 请求转发到 HTTPS。但很可能只有第一个请求被重定向到 HTTPS,页面上的后续链接通过 HTTP 加载,该链接被浏览器阻止为混合内容错误。

vcl 4.1;

import proxy;

backend default {
    .host = "127.0.0.1";
    .port = 8080;
}

sub vcl_recv {
    if ((req.http.X-Forwarded-Proto && req.http.X-Forwarded-Proto != "https") || 
        (req.http.Scheme && req.http.Scheme != "https")) {
        return (synth(750));
    } elseif (!req.http.X-Forwarded-Proto && !req.http.Scheme && !proxy.is_ssl()) {
        return (synth(750));
    }
}

sub vcl_synth {
    if (resp.status == 750) {
        set resp.status = 301;
        set resp.http.location = "https://" + req.http.Host + req.url;
        set resp.reason = "Moved";
        return (deliver);
    }
}

我尝试在 wp-config.php 文件中设置以下常量,看看强制应用程序中的 URL 是否会进行更改,但这不起作用。

define( 'WP_HOME', 'https://staging1.sainikbiswas.com' );
define( 'WP_SITEURL', 'https://staging1.sainikbiswas.com');
varnish varnish-vcl
1个回答
0
投票

从表面上看,你做的一切都是正确的。使用 TLS 代理时,您需要执行以下几项操作来避免混合内容:

  • 终止 Hitch 中的 TLS
  • 确保您使用PROXY协议来传递原始协议
  • 确保 Varnish 正在侦听具有 PROXY 支持的端口(例如
    -a :8443,PROXY
  • 检查是否一路设置了
    X-Forwarded-Proto
    标题
  • 如果没有
    proxy
    标头,请使用 VCL 中的
    proxy.is_ssl()
    VMOD 调用
    X-Forwarded-Proto
    ,并适当设置标头
  • X-Forwarded-Proto
    标头值添加到哈希中以创建协议感知(例如
    hash_data("X-Forwarded-Proto")
  • 可以选择通过 Varnish 中的重定向强制执行 HTTPS

再一次,看起来你已经做了所有这些事情。

澄清一下:Varnish Cache(开源)本身并不处理 HTTPS,并且当 TLS 在其他地方卸载时,通过 PROXY 协议具有 TLS 感知

这就是为什么

X-Forwarded-Proto
标头如此有用:它宣布初始连接的协议。您可以将以下 PHP 代码添加到您的 WordPress 设置中以强制支持
X-Forwarded-Proto
:

if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
    $_SERVER['HTTPS']='on';
}

如果这没有帮助,请通过

varnishlog
提供一些相关的日志输出供我检查。

假设我们正在监控主页,您将提供以下命令的输出:

sudo varnishlog -g request -q "ReqUrl eq '/'"

运行此命令时请确保您的缓存为空,否则我们不知道后端如何响应您的请求。

© www.soinside.com 2019 - 2024. All rights reserved.