0x00:主要是三个原因:
1、wp-login.php天天被刷密码,之前一段时间一直被迫加了一层windows登陆验证。
2、不想经常输wordpress的密码了。
3、SSL研究实验。
0x01:申请证书
自签证书虽然是可行的,但自慰并不好,也不符合安全签发标准。这里选用cacert.org给我签发了一张email证书。cacert.org是一家数十年历史的非营利组织,力求让每个人能够使用上PKI安全体系,但因为其非免费签发的性质,根证书并未得到商业系统的承认。
同时搜索到comodo签发免费的email的证书,也去申请了一张,但发现证书用途中只有电子邮件加密,没有客户端认证,故无法运用在SSL中。
如果有读者知道哪家机构还能签发免费的email兼客户端认证证书,希望能在评论中分享,不胜感激。
0x02:Windows Server设置
SSL协议中请求客户端证书时,服务端会向客户端发送一个CA的列表,只有列表中出现的CA签发的证书才会在浏览器证书选择对话框中显示。这点很重要,开始一直不明白为什么电脑上装好的证书浏览器没有提示就报证书验证失败。
另外,需要设置IIS不检查证书吊销列表,因为CACert的吊销列表太大了,网不好经常访问不到导致IIS返回403。
cscript c:\inetpub\adminscripts\adsutil.vbs set w3svc/网站ID/certcheckmode 1
(设为1为不检查吊销,0为检查)
需要做的是把cacert的根证书导入服务器,需要注意导入的是本机存储区而不是用户存储区,所以不能直接双击导入或使用certmgr.msc导入,而要打开一个空的mmc,添加管理单元时选择本地计算机。
最后就是在IIS中把wp-login.php设为接受客户端证书。
0x03:PHP部分
用phpinfo可以看到,$_SERVER[‘CERT_SUBJECT’]存放了证书使用者的信息,我们提取其中email字段即可。
以wordpress插件的形式写一段简单的代码:(参考了client-certificate-authentication插件的代码)
add_filter('authenticate', 'cert_authenticate'); function cert_authenticate($user, $username, $password) { if (preg_match('/E=([^,]+)/', $_SERVER['CERT_SUBJECT'], $matches)) { $email = $matches[1]; $user = get_user_by('email', $email); if ($user) return $user; } wp_die('You must provide a certificate to login.'); }
0x04:安全性
只用验证证书中的email就可以登陆是否安全?也就是说是否存在伪造证书的可能?
上面已经提到,必须是存在于服务端CA列表中的信任机构签发的证书才能够识别,所以安全性依赖于是否有CA在签发email证书时出现漏洞,未成功验证邮箱所有权就给冒充者颁发了证书。之前wosign就被查出了类似的问题(未严格验证域名所有权就颁发了ssl证书)。
所以只要保持服务端根证书列表的权威性即没有什么大的问题。如果需要更安全,也可以在PHP中验证$_SERVER[‘CERT_ISSUER’]中的颁发机构,强制使用特定一家签发的证书。