解决WordPress网站反向代理后文章无法核对密码的问题

笔者借助宝塔面板,通过反向代理,使得 http://www.bbb.com/ 单独对应博客页 http://www.aaa.com/ccc/

💬相关

详情可以查看前一篇博客《不同域名对应WordPress网站不同页面》

https://blog.csdn.net/weixin_42077074/article/details/123134062

但随后笔者发现,WordPress 网站需要密码的文章无法核对密码了,输入密码提交后直接白屏

折腾了半天,终于发现了两个问题

  • 页面跳转——涉及 PHP 获取请求 URL 和 WordPress 跳转函数
  • 密码核对——涉及 cookie 作用域机制

在服务器上找到 WordPress 站点目录,如笔者的是 /www/wwwroot/[站点文件名]

输入密码并提交后,WordPress 会到目录下 wp-login.php 中通过 case 'postpass':底下的代码进行后续处理,本文将从此处入手

页面跳转——涉及 PHP 获取请求 URL 和 WordPress 跳转函数

输入文章密码并提交后,WordPress 会跳转到 wp-login.php 进行后续处理,并通过PHP 中 $_SERVER['HTTP_REFERER'] 获取请求 URL(跳转前的 URL)

然而,经反向代理后,$_SERVER['HTTP_REFERER'] 只能获取到 http://www.bbb.com,没法获取到 http://www.bbb.com/[页面名及其他参数],笔者也不太懂是什么原因

那就需要添加代码获取完整的请求 URL,因而我们需要对文章填写密码的表单相关代码进行简单的修改

其对应于 wp-includes/post-template.php 中的 get_the_password_form() 函数,我们将整段函数替换成下面的代码

function get_the_password_form( $post = 0 ) {
    
    $_request_uri=substr($_SERVER['REQUEST_URI'],strpos($_SERVER['REQUEST_URI'],'/',1)+1);
    
	$post   = get_post( $post );
	$label  = 'pwbox-' . ( empty( $post->ID ) ? rand() : $post->ID );
	$output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass' . '&requri=' . $_request_uri, 'login_post' ) ) . '" class="post-password-form" method="post">
	<p>' . __( 'This content is password protected. To view it please enter your password below:' ) . '</p>
	<p><label for="' . $label . '">' . __( 'Password:' ) . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr_x( 'Enter', 'post password form' ) . '" /></p></form>
	';

	/**
	 * Filters the HTML output for the protected post password form.
	 *
	 * If modifying the password field, please note that the core database schema
	 * limits the password field to 20 characters regardless of the value of the
	 * size attribute in the form input.
	 *
	 * @since 2.7.0
	 * @since 5.8.0 Added the `$post` parameter.
	 *
	 * @param string  $output The password form HTML output.
	 * @param WP_Post $post   Post object.
	 */
	return apply_filters( 'the_password_form', $output, $post );
}

笔者做出的修改是,$_request_uri 获取 [页面名及其他参数],随后作为参数将其附加在表单跳转到 wp-login.php 的 URL 中

image-20220227214120718

随后找到 wp-login.php,在 case 'postpass': 底下,找到 $referer = wp_get_referer(); 代码并删掉,再在 case 'postpass': 底下开头添加下面的代码

	   $pos1=strpos($_SERVER['HTTP_REFERER'],'/')+2;
	   $pos2=strpos($_SERVER['HTTP_REFERER'],'.');
	   $pos3=strpos($_SERVER['HTTP_REFERER'],'/',$pos1);
	   
	   $refer_domain=substr($_SERVER['HTTP_REFERER'],$pos1,$pos3-$pos1);//获取请求域名
	   $refer_page_name=substr($refer_domain,0,$pos2-$pos1);//获取请求域名中最低级的域名作为页面名
	   
       $request_uri=$_REQUEST['requri'];

        if($refer_page_name =='blog') $isDomainAllowed=true;//此处blog可以换成任意你域名中最低级的域名作为页面名
        else $isDomainAllowed=false;

这意为从通过 $_REQUEST[] 获取此前附加在 URL 里的参数 [页面名及其他参数],并将原先的 $referer 经过处理,变成完整的请求 URL

随后你还能在 case 'postpass': 底下找到两处 wp_safe_redirect($referer);

wp_safe_redirect() 是 WordPress 的跳转函数,它跳转时会判断 URL 是否在同一域名下,因而我们需要将两处它都替换成以下代码

if($isDomainAllowed) wp_redirect($referer);
else wp_safe_redirect( $referer);

💬相关

详细 wp_safe_redirect() 介绍可查看博客《wordpress安全重定向跳转函数wp_safe_redirect()》

http://www.thefox.cn/wordpress-security-redirection-jump-fu.shtml

密码核对——涉及 cookie 作用域机制

假如一篇文章需要密码,那当你输入文章密码并提交后,WordPress 会将其记录在 cookie 中,随后读取 cookie 记录进行判断,以便让你在一段时间 expire 内不需要重复输入密码

具体则是在 wp-login.phpcase 'postpass': 底下的这段代码

setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );

cookie 中有一项 domain,规定了 cookie 的作用域,默认是当前域,且只能设置为当前域或当前域的上级域

举个例子,一个在 yyy.xxx.com 的页面,可以设置 cookie 的 domainyyy.xxx.comxxx.comdomainyyy.xxx.com 的 cookie 只能被访问于 yyy.xxx.com,若 domainxxx.com 的 cookie,则可以在 xxx.com 的任意下级域被访问

💬相关

详细 cookie 作用域机制可以查看博客《php怎么设置cookie作用域?》

https://www.php.cn/php-ask-456517.html

假如反向代理使用 http://ddd.aaa.com/ 单独对应博客页 http://www.aaa.com/ccc/,但实际上还是相当于 www.aaa.com 在访问页面,在 PHP 中使用 setcookie() 函数设置 cookie 时无法将 cookie 的 domain 设置为 ddd.aaa.comdomain 还是 www.aaa.com

image-20220227162915228

WordPress 密码核对涉及在 wp-includes/post-template.php 中的post_password_required()函数,其中有相关访问cookie的代码,经查阅代码发现ddd.aaa.com根本访问不到domainwww.aaa.com的cookie

那应该怎么改?那就只能在最开始设置cookie时,不默认设置为当前域www.aaa.com,而设置为上级域 aaa.com,那 ddd.aaa.com 也就可以访问到该 cookie 了

那我们需要将 setcookie() 替换成下述代码

        if($isDomainAllowed) $cookie_domain=substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],'.')+1);//获取当前域的上级域
        else $cookie_domain=COOKIE_DOMAIN;
        
		setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, $cookie_domain, $secure );

随后,折腾许久,终于解决反向代理后,WordPress 网站需要密码的文章无法核对密码的问题了,大!功!告!成!

最后,附上经本文修改后,wp-login.phpcase 'postpass':case 'logout': 这一段完整代码

	case 'postpass':
	   
	   $pos1=strpos($_SERVER['HTTP_REFERER'],'/')+2;
	   $pos2=strpos($_SERVER['HTTP_REFERER'],'.');
	   $pos3=strpos($_SERVER['HTTP_REFERER'],'/',$pos1);
	   
	   $refer_domain=substr($_SERVER['HTTP_REFERER'],$pos1,$pos3-$pos1);//获取请求域名
	   $refer_page_name=substr($refer_domain,0,$pos2-$pos1);//获取请求域名中最低级的域名作为页面名

       $request_uri=$_REQUEST['requri'];
       
        if($refer_page_name =='blog') $isDomainAllowed=true;
        else $isDomainAllowed=false;

	   if($isDomainAllowed) $referer = $_SERVER['HTTP_REFERER'] . $request_uri;
	   else $referer = wp_get_referer();

		if ( ! array_key_exists( 'post_password', $_POST ) ) {
		    
    		if($isDomainAllowed) wp_redirect( $referer);
            else wp_safe_redirect( $referer);

			exit;
		}
        
		require_once ABSPATH . WPINC . '/class-phpass.php';
		$hasher = new PasswordHash( 8, true );

		/**
		 * Filters the life span of the post password cookie.
		 *
		 * By default, the cookie expires 10 days from creation. To turn this
		 * into a session cookie, return 0.
		 *
		 * @since 3.7.0
		 *
		 * @param int $expires The expiry time, as passed to setcookie().
		 */
		$expire  = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
		

		if ( $referer ) {
			$secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
		} else {
			$secure = false;
		}
		
        if($isDomainAllowed) $cookie_domain=substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],'.')+1);//获取当前域的上级域
        else $cookie_domain=COOKIE_DOMAIN;
        
		setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, $cookie_domain, $secure );
		

		if($isDomainAllowed) wp_redirect( $referer);
        else wp_safe_redirect( $referer);
		exit;

	case 'logout':
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值