最近抽了点时间把wordpress最新版的源码翻了翻,记录一下其中的安全机制,BTW:wordpress源码看着真的很蛋疼。
1、认证模块 涉及到wordpress认证安全方面的主要有认证方式,密码保存方式。其中密码保存方式又分为安装时管理员密码生成和后台添加用户。 首先,wordpress采用的是cookie方式认证,cookie生成过程相对比较复杂,salt多次加密且不是简单的随机数salt,默认采用MD5,当然也可以采用sha。 [code lang=“php”] $pass_frag = substr($user->user_pass, 8, 4); $key = wp_hash($user->user_login . $pass_frag . ‘|’ . $expiration, $scheme);//salt:用户名.密码8-12位|cookie时长.auth $hash = hash_hmac(‘md5’, $user->user_login . ‘|’ . $expiration, $key);////md5($opad . pack($pack, md5($ipad . $data))); opad ipad 都是key异或后的值 $cookie = $user->user_login . ‘|’ . $expiration . ‘|’ . $hash;[/code] 详细流程:wp_set_auth_cookie–>wp_generate_auth_cookie–>hash_hmac–>_hash_hmac 函数源码如下: [code lang=“php”]function wp_generate_auth_cookie($user_id, $expiration, $scheme = ‘auth’) { $user = get_userdata($user_id);
$pass_frag = substr($user->user_pass, 8, 4);
$key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
$hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
$cookie = $user->user_login . '|' . $expiration . '|' . $hash;
return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
}
function hash_hmac($algo, $data, $key, $raw_output = false) { return hash_hmac($algo, $data, $key, $raw_output); }[/code] [code lang=“php”]function hash_hmac($algo, $data, $key, $raw_output = false) { $packs = array(‘md5’ => ‘H32’, ‘sha1’ => ‘H40’);
if ( !isset($packs[$algo]) )
return false;
$pack = $packs[$algo];
if (strlen($key) > 64)
$key = pack($pack, $algo($key));
$key = str_pad($key, 64, chr(0));
$ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64)); //char(0x36)=6
$opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64)); //char(0x5c)=
$hmac = $algo($opad . pack($pack, $algo($ipad . $data)));
if ( $raw_output )
return pack( $pack, $hmac );
return $hmac;
}[/code] 其次,安装时生成管理员密码时,采用的是salt md5加密。函数调用流程如下。 函数流程:wp_create_user–>wp_insert_user–>wp_hash_password–>HashPassword–>crypt_private
创建用户时采用的加密方式是一样的,但是实现上有点区别,创建用户后生成激活码,然后激活用户。 函数流程:current_user_can–>wpmu_signup_user–>wpmu_activate_signup–>wpmu_create_user–>wp_create_user–>wp_insert_user–>wp_hash_password
加密方式中重要的函数如下: [code lang=“php”]function wp_hash_password($password) { global $wp_hasher;
if ( empty($wp_hasher) ) {
require_once( ABSPATH . 'wp-includes/class-phpass.php');
// By default, use the portable hash from phpass
$wp_hasher = new PasswordHash(8, TRUE);
}
return $wp_hasher->HashPassword($password);
}[/code] [code lang=“php”] function HashPassword($password) { $random = ‘’;
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}[/code]
2、过滤模块 过滤模块这里主要想谈防注入、跨站、文件名攻击这几个方面。 首先看防注入方式,wordpress里面有地方会采用过滤后采用addslashes进行转义,但是有一个封装得比较好的转义方式是,采用vsprintf方式进行变量输入,然后过滤编码,最后通过判定mysql类型进行mysql_real_escape_string或者进行addslashes转义。 一个较为复杂的流程:select–>wpdb::prepare–>vsprintf–>escape_by_ref–>_real_escape–>mysql_real_escape_string/addslashes
其次防跨站方式采用了两种方式:普通文本过滤方式和富文本过滤方式。普通文本过滤方式采用htmlspecialchars进行过滤,富文本则采用自定义函数wp_specialchars_decode进行操作。 具体流程:esc_html–>_wp_specialchars–>htmlspecialchars/wp_specialchars_decode
最后文件名这块通过过滤文件名中的特殊字符和文件信息进行操作。 $special_chars = array(“?”, “[”, “]”, “/”, “\”, “=”, “<”, “>”, “:”, “;”, “,”, “‘”, “”“, ”&“, ”$“, ”#“, ”*“, ”(“, ”)“, ”|“, ”~“, ”`“, ”!“, ”{“, ”}“, chr(0));
3、其他 wordpress的Hook机制:http://www.mrmu.com.tw/2011/10/10/wordpress-hook/