各位观众老爷们,大家好! 今天咱们来聊聊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_REFERERURLtry { $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 的安全机制,并编写更安全的代码。
好了,今天的讲座就到这里。 感谢各位观众老爷的观看! 希望大家有所收获!