功能:
物理验证,系统安全性验证,提高系统安全性。
准备工作
根证书(存在服务端,以basic64字符串格式为例),u盾(包含客户端ca证书信息,编号等),浏览器对应服务(包含获取客户端ca证书信息以及对字符串进行加密两个方法)。
概览图:
具体实现:
1.服务端生成随机字符串(当前时间 yyyy-MM-dd HH:mm:ss格式)、唯一标识(guid)以键值对(key-value)方式缓存在服务端(可设置缓存过期时间),客户端通过接口获取唯一标识和随机字符串。
2.客户端获取服务端的唯一标识和随机字符串。调用浏览器对应服务获取客户端ca证书(basic64字符串为例),并再次调用接口利用客户端ca证书信息对随机字符串进行加密。加密完成后将客户端ca证书信息、唯一标识(guid)以及加密结果(字符串)回传给服务端。
3.服务端获取客户端证书信息(basic64字符串)、唯一标识以及加密结果。
3.1 通过回传的唯一标识在服务端缓存中查找对应的键,没找到则验证失败。
3.2 加载根证书和客户端证书。
/// <summary>
/// 加载X.509证书
/// </summary>
/// <param name="cerStr"></param>
/// <returns></returns>
private X509Certificate2 LoadCert(string cerStr)
{
return new X509Certificate2(HexBytes(cerStr));
}
/// <summary>
/// 转16进制字节数组
/// </summary>
/// <param name="hexStr"></param>
/// <returns></returns>
private byte[] HexBytes(string hexStr)
{
hexStr = hexStr.Replace(" ", "");
if (hexStr.Length % 2 != 0)
{
hexStr += " ";
}
var retBytes = new byte[hexStr.Length / 2];
for (int i = 0; i < retBytes.Length; i++)
{
retBytes[i] = Convert.ToByte(hexStr.Substring(i * 2, 2), 16);
}
return retBytes;
}
3.3 利用根证书验证客户端证书是否为根证书签发。
/// <summary>
/// 验证返回true为根证书签发
/// </summary>
/// <param name="root"></param>
/// <param name="client"></param>
/// <returns></returns>
private bool VertityCertificate(X509Certificate2 root, X509Certificate2 client)
{
X509Chain x509Chain = new X509Chain();
x509Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
x509Chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
x509Chain.ChainPolicy.ExtraStore.Add(root);
if(!x509Chain.Build(client))
{
return false;
}
var valid = x509Chain.ChainElements
.Cast<X509ChainElement>()
.Any(x => x.Certificate.Thumbprint == root.Thumbprint);
return valid;
}
3.4 利用客户端证书信息验证服务端随机字符串的签名是否为客户端加密结果(以rsa验证为例)。
private bool VerifySign(X509Certificate2 cerStr,string signature,string timeStr)
{
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cerStr.PublicKey.Key;
using(var sha256=new SHA256CryptoServiceProvider())
{
return rsa.VerifyData(Encoding.UTF8.GetBytes(timeStr), sha256, HexBytes(signature));
}
}
3.5 以上为所有验签过程。用户可以将个人信息与客户端证书编号之类的信息绑定(Subject包含一些证书的基本信息)。
//
// 摘要:
// Gets the subject distinguished name from the certificate.
//
// 返回结果:
// The subject distinguished name from the certificate.
//
// 异常:
// T:System.Security.Cryptography.CryptographicException:
// The certificate handle is invalid.
public string Subject { get; }
4.所有验证通过后,用户可以放心的在系统中对一些敏感信息进行操作。