虽然全站已经 HTTPS 了,但是因为某些原因,不允许明文传输用户名密码,也就意味着需要在客户端做一层加密,然后在服务端解密。 了解下来只能选择 RSA 的方式了。

准备工作,首先需要生成秘钥:

# 生成 1024 位的 RSA 私钥
openssl genrsa -out key.pem 1024
# 导出相对应的公钥
openssl rsa -in key.pem -pubout -out pubkey.pem

# 复制出来备用
cat key.pem
cat pubkey.pem

打开 wp-login.php 文件,将以下代码补充到 loginform 后面,我是放在 $login_script 后面。 主要是为了捕获登录表单,在 submit 的时候,把 user_login 和 user_pass 各自加密后再发送到服务端。

<script src="https://cdn.jsdelivr.net/npm/jsencrypt@3.2.1/bin/jsencrypt.min.js" type="text/javascript"></script>
<script type="text/javascript">
(function($) {
    var user_pass = $("#user_pass");
    var user_login = $("#user_login");
    var loginform = $("#loginform");
    var sign = '公钥';
    var encrypt = new JSEncrypt();
    encrypt.setPublicKey(sign);
    
    // encrypt loginform user_pass
    loginform.submit(function(e) {
        e.preventDefault();
        // get user_login & user_pass value
        var user_login_val = user_login.val();
        var user_pass_val = user_pass.val();
    
        // encrypt user_login & user_pass
        var user_login_encrypted = encrypt.encrypt(user_login_val);
        var user_pass_encrypted = encrypt.encrypt(domprops);

        // set user_login & user_pass
        user_login.val(user_login_encrypted);
        user_pass.val(user_pass_encrypted);

        loginform.unbind('submit').submit();
    });

})(jQuery);
</script>

对应的,服务端拿到加密的 user_login 和 user_pass,需要解密后才能继续走下面的流程。 WordPress 的登录方式在放在 wp-includes/pluggable.php 文件里面。 打开 pluggable.php 找到 wp_authenticate 方法,并修改成类似下面的方式:

function wp_authenticate( $username, $password ) {
    $username = sanitize_user( $username );
    $password = trim( $password );
    
    // -- 开始增加代码 --
    $private_key = "私钥";
    $decrypt_data_user = '';
    $decrypt_data_pass = '';
    // 判断私钥是否是可用的,可用返回资源id
    $pi_key =  openssl_pkey_get_private($private_key);
    // 解密数据, 这里要进行 base64 解码是因为浏览器会默认帮你的数据进行编码
    // 用户名
    openssl_private_decrypt(base64_decode($username), $decrypt_data_user, $private_key);
    $username = $decrypt_data_user;

    // 密码
    openssl_private_decrypt(base64_decode($password), $decrypt_data_pass, $private_key);
    $password = $decrypt_data_pass;

    // -- 增加代码结束 --
    // 后续原有代码
    // ...
}

这样就能完成一次完成的加密解密了,推荐公钥私钥不要硬编码,最好通过配置的形式读进来(题外话,安全建议)。

–EOF–