各位观众老爷们,大家好! 今天咱们来聊聊WordPress里一个看似不起眼,但其实挺重要的函数:wp_get_referer_if_valid()
。 别看名字长,作用可不小,它主要负责验证 HTTP_REFERER
这个“引荐来源网址”的有效性。 嘿,这玩意儿可不是你想随便伪造就能糊弄过去的! WordPress可是有自己的一套验证逻辑的。
啥是 HTTP_REFERER
? 为什么要验证它?
简单来说,HTTP_REFERER
就是你从哪个网页链接跳转过来的。 比如说,你从Google搜索结果点进了一个WordPress博客,那么这个博客收到请求时,HTTP_REFERER
就会包含Google搜索结果页面的网址。
那为啥要验证它呢? 因为 HTTP_REFERER
这玩意儿是可以伪造的! 坏人可以伪造一个假的 HTTP_REFERER
,冒充某个网站,以此来做一些坏事,比如:
- CSRF攻击(跨站请求伪造): 伪造
HTTP_REFERER
诱导用户在不知情的情况下执行一些操作。 - 垃圾评论: 伪造
HTTP_REFERER
绕过某些评论系统的验证机制,发布垃圾评论。 - 统计欺诈: 伪造
HTTP_REFERER
虚增网站的访问量。
所以,验证 HTTP_REFERER
的有效性,可以提高网站的安全性,防止一些恶意行为。
wp_get_referer_if_valid()
源码剖析
咱们直接上代码,边看边聊:
function wp_get_referer_if_valid() {
$ref = wp_get_raw_referer();
if ( $ref && wp_validate_redirect( $ref, false ) ) {
return $ref;
}
return false;
}
这段代码看着挺简洁的,主要做了两件事:
- 获取原始
HTTP_REFERER
: 调用wp_get_raw_referer()
函数获取未经处理的HTTP_REFERER
。 - 验证
HTTP_REFERER
的有效性: 调用wp_validate_redirect()
函数验证HTTP_REFERER
是否是一个有效的重定向目标。
如果 HTTP_REFERER
存在且通过了验证,就返回它;否则,返回 false
。
wp_get_raw_referer()
: 拿到最原始的 HTTP_REFERER
function wp_get_raw_referer() {
$ref = '';
if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
$ref = trim( wp_unslash( $_SERVER['HTTP_REFERER'] ) );
}
return $ref;
}
这个函数非常简单粗暴,就是直接从 $_SERVER['HTTP_REFERER']
里面取出 HTTP_REFERER
的值。
$_SERVER['HTTP_REFERER']
: PHP 超全局变量,包含了客户端发送的HTTP_REFERER
信息。wp_unslash()
: WordPress 的一个函数,用于移除字符串中由magic_quotes_gpc
添加的反斜杠。trim()
: PHP函数,用于移除字符串首尾的空白字符。
wp_validate_redirect()
: 验证重定向目标,才是重头戏!
这才是整个验证过程的核心! 咱们来看看 wp_validate_redirect()
的源码(简化版,去掉了部分不常用的参数处理):
function wp_validate_redirect( $location, $default = '' ) {
$location = wp_sanitize_redirect( $location );
if ( ! $location ) {
return $default;
}
$home_url = parse_url( home_url() );
if ( ! is_array( $home_url ) ) {
return $default;
}
$valid = true;
try {
$parsed_url = wp_parse_url( $location );
} catch ( Exception $e ) {
return $default;
}
if ( ! is_array( $parsed_url ) ) {
return $default;
}
// Absolute URL.
if ( isset( $parsed_url['host'] ) ) {
// Compare the hostnames.
if ( strtolower( $parsed_url['host'] ) !== strtolower( $home_url['host'] ) ) {
$valid = false;
}
// Compare the schemes.
if ( isset( $parsed_url['scheme'] ) && isset( $home_url['scheme'] ) && strtolower( $parsed_url['scheme'] ) !== strtolower( $home_url['scheme'] ) ) {
$valid = false;
}
}
/**
* Filters whether the redirect location is valid.
*
* @since 2.3.0
*
* @param bool $valid Whether the redirect location is valid.
* @param string $location The redirect location.
* @param string $default The fallback redirect location.
*/
$valid = apply_filters( 'wp_validate_redirect', $valid, $location, $default );
if ( $valid ) {
return $location;
}
return $default;
}
咱们一步一步来解读这段代码:
-
wp_sanitize_redirect()
: 清理重定向 URL$location = wp_sanitize_redirect( $location );
首先,使用
wp_sanitize_redirect()
函数对 URL 进行清理。 这个函数会移除 URL 中一些不安全的字符,比如换行符、回车符等,防止 URL 注入攻击。 -
检查 URL 是否为空
if ( ! $location ) { return $default; }
如果清理后的 URL 为空,说明原始的
HTTP_REFERER
可能包含一些恶意字符,直接返回默认值。 -
解析站点 URL
$home_url = parse_url( home_url() ); if ( ! is_array( $home_url ) ) { return $default; }
使用
parse_url()
函数解析 WordPress 站点的 URL,获取主机名、协议等信息。home_url()
函数返回的是站点首页的 URL。 如果解析失败,说明站点 URL 配置有问题,返回默认值。 -
解析
HTTP_REFERER
URLtry { $parsed_url = wp_parse_url( $location ); } catch ( Exception $e ) { return $default; } if ( ! is_array( $parsed_url ) ) { return $default; }
同样使用
parse_url()
函数解析HTTP_REFERER
的 URL。 如果解析失败,说明HTTP_REFERER
不是一个有效的 URL,返回默认值。 -
比较主机名和协议
// Absolute URL. if ( isset( $parsed_url['host'] ) ) { // Compare the hostnames. if ( strtolower( $parsed_url['host'] ) !== strtolower( $home_url['host'] ) ) { $valid = false; } // Compare the schemes. if ( isset( $parsed_url['scheme'] ) && isset( $home_url['scheme'] ) && strtolower( $parsed_url['scheme'] ) !== strtolower( $home_url['scheme'] ) ) { $valid = false; } }
这是验证的核心部分。 如果
HTTP_REFERER
是一个绝对 URL(包含主机名),则比较它的主机名和协议是否与站点 URL 的主机名和协议一致。 如果不一致,则认为HTTP_REFERER
无效。注意: 这里只比较主机名和协议,不比较路径。 也就是说,只要
HTTP_REFERER
的主机名和协议与站点 URL 一致,即使路径不同,也认为它是有效的。 -
过滤器
wp_validate_redirect
$valid = apply_filters( 'wp_validate_redirect', $valid, $location, $default );
WordPress 提供了一个过滤器
wp_validate_redirect
,允许开发者自定义验证逻辑。 通过这个过滤器,你可以添加自己的验证规则,比如检查HTTP_REFERER
是否在白名单中,或者检查HTTP_REFERER
是否包含特定的参数。 -
返回结果
if ( $valid ) { return $location; } return $default;
如果
HTTP_REFERER
通过了所有验证,就返回它;否则,返回默认值。
总结: wp_validate_redirect()
的验证逻辑
咱们用一个表格来总结一下 wp_validate_redirect()
的验证逻辑:
步骤 | 描述 |
---|---|
1. 清理 URL | 使用 wp_sanitize_redirect() 函数移除 URL 中不安全的字符。 |
2. 检查 URL 是否为空 | 如果 URL 为空,返回默认值。 |
3. 解析站点 URL | 使用 parse_url() 函数解析站点 URL,获取主机名和协议。 |
4. 解析 HTTP_REFERER URL |
使用 parse_url() 函数解析 HTTP_REFERER 的 URL。 |
5. 比较主机名和协议 | 如果 HTTP_REFERER 是一个绝对 URL,则比较它的主机名和协议是否与站点 URL 的主机名和协议一致。 如果不一致,则认为 HTTP_REFERER 无效。 |
6. 应用过滤器 | 应用 wp_validate_redirect 过滤器,允许开发者自定义验证逻辑。 |
7. 返回结果 | 如果 HTTP_REFERER 通过了所有验证,就返回它;否则,返回默认值。 |
wp_sanitize_redirect()
: 清理 URL 的小能手
咱们再简单看看 wp_sanitize_redirect()
函数的源码:
function wp_sanitize_redirect( $location ) {
$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!@*'()[]\x80-\xff]|i', '', $location );
$location = wp_kses_no_null( $location );
// Remove any remaining invalid protocol relative URLs.
$location = _wp_http_validate_url( $location );
return $location;
}
这个函数主要做了三件事:
- 移除不安全的字符: 使用正则表达式移除 URL 中除了字母、数字、特殊字符以外的所有字符。
- 移除 NULL 字符: 使用
wp_kses_no_null()
函数移除 URL 中的 NULL 字符,防止 NULL 字符截断 URL。 - 验证 URL 的协议: 使用
_wp_http_validate_url()
函数验证 URL 的协议是否安全。
wp_kses_no_null()
: 移除 NULL 字符
function wp_kses_no_null( $string ) {
$string = preg_replace( '/+/', '', $string );
$string = str_replace( array( '%00', "x0" ), '', $string );
return $string;
}
这个函数非常简单,就是使用正则表达式和字符串替换函数移除字符串中的 NULL 字符。
_wp_http_validate_url()
: 验证 URL 协议
function _wp_http_validate_url( $url ) {
$allowed_protocols = wp_allowed_protocols();
$url = trim( $url );
if ( empty( $url ) ) {
return $url;
}
if ( strpos( $url, ':' ) === false ) {
return $url;
}
$url_parts = explode( ':', $url, 2 );
$scheme = trim( $url_parts[0] );
if ( in_array( strtolower( $scheme ), $allowed_protocols, true ) ) {
return $url;
}
return '';
}
这个函数主要用于验证 URL 的协议是否在白名单中。
wp_allowed_protocols()
: 获取允许的协议列表, 默认情况下,允许的协议包括http
,https
,ftp
,ftps
,mailto
,news
,irc
,gopher
,nntp
,telnet
,mms
,rtsp
,svn
,tel
,fax
,xmpp
,webcal
,webcal+
.- 如果 URL 的协议不在白名单中,则返回空字符串。
wp_get_referer_if_valid()
的应用场景
了解了 wp_get_referer_if_valid()
函数的原理,咱们来看看它在 WordPress 中有哪些应用场景:
-
重定向: 在用户登录、注册、找回密码等操作后,可以使用
wp_get_referer_if_valid()
函数获取有效的HTTP_REFERER
,然后将用户重定向到该页面。$redirect_to = wp_get_referer_if_valid(); if ( ! $redirect_to ) { $redirect_to = home_url(); } wp_safe_redirect( $redirect_to ); exit;
-
评论: 在评论系统中,可以使用
wp_get_referer_if_valid()
函数验证HTTP_REFERER
,防止垃圾评论。 -
表单提交: 在表单提交处理程序中,可以使用
wp_get_referer_if_valid()
函数验证HTTP_REFERER
,防止 CSRF 攻击。
总结
wp_get_referer_if_valid()
函数是 WordPress 中一个重要的安全函数,用于验证 HTTP_REFERER
的有效性。 它通过一系列的验证步骤,包括清理 URL、比较主机名和协议、应用过滤器等,确保 HTTP_REFERER
是一个有效的重定向目标。 了解 wp_get_referer_if_valid()
函数的原理,可以帮助我们更好地理解 WordPress 的安全机制,并编写更安全的代码。
好了,今天的讲座就到这里。 感谢各位观众老爷的观看! 希望大家有所收获!