如何在Windows Store应用程序中进行TLS/SSL通讯

Windows Store应用程序经常需要使用各种Web服务,为了安全起见,这些服务最好是通过https来访问。那么我们如何在Windows Store应用中使用证书来进行安全的通讯呢,我这里就做一个简单的小结。

首先,如果服务端使用了服务端认证,那么Windows Store应用作为客户端连接服务器的时候,需要验证该服务端证书在客户端是受信任的。那么分两种情况:

一.         如果该证书是被受信任的机构签发的,而且该机构的Root证书已经缺省安装到了客户端,那么,Windows Store应用程序只需要在Package.appxmanifest文件中加入对Shared Uer Certigficates这个Capability的支持,应用程序会自动到系统的Certificate Store中找到该Root证书并通过验证。不过这种方法也有一个问题,由于客户端只验证服务端证书是否来自于同一个Root,所以我们可以很容易的伪造一张服务端证书来通过验证。

二.         如果该证书是一张自签名的证书,那么确实情况下客户端是不会安装这张证书的。那么这时候Windows Store应用程序就无法通过证书的验证。这个问题也好解决,向第一种情况靠拢呗。如果在客户端已经手动安装了这张自签名的证书,那就没问题啦。所以我们需要做的就是将这个自签名的证书从服务端下载下来,然后一台一台的安装到客户端Certificate Store的Root目录下。

可是,这个方法也太不靠谱啦!在很多情况下,我是没有办法将自签名证书一台一台安装到客户端的呀。有没有其他办法呢?有的!我们可以将证书放在Windows Store应用程序中,然后通过Package.appxmanifest的Declarations添加这张证书:

  1. 1.       在Available Declarations中选择Certificates,点击Add。
  2. 2.       在右边的Trust flags勾选上Exclusive Trust,加上这个以后,就能够保证不是随随便便用一张服务端证书就能够把客户端应用糊弄过去啦。
  3. 3.       在右边的Certificates中点击Add New, Store Name需填写Root,Content中添加你所要验证的服务端证书。
  4. 4.       在添加以后,该服务端证书会自动添加到你的项目中,我们需要在该证书的文件属性中将Copy to Output Directory改为Copy if newer。

这样,我们就可以很方便的完成服务端验证了,而且也不用担心有人通过伪造服务端证书来截取通讯内容。

接下来我们看一下需要客户端认证的情形。这种情况下,我们需要做两件事:

一.保证客户端已经正确安装了客户端证书。你可以把你的证书文件放在项目中或者远程服务器上。当你的Windows Store应用获得了PKCS12格式的证书数据以后,就可以调用

CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync或者CertificateEnrollmentManager.InstallCertificateAsync来安装该证书。

二.一旦客户端已经正确安装了客户端证书,那么就需要在Windows store应用中获得该证书的实例,这可以通过CertificateStores.FindAllAsync来枚举所有的证书实例,然后找出你所需要的那个,FindAllAsync也支持传入一个CertificateQuery参数来进行筛选。

在获得证书实例之后,我们就可以通过HttpBaseProtocolFilter来设置客户端证书,然后将HttpBaseProtocolFilter作为参数传入HttpClient中实现客户端验证,示例代码如下:

var certificates = await CertificateStores.FindAllAsync();

var certificate = certificates.Where(w => w.Subject.Equals(SUBJECTNAME)).FirstOrDefault();

HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();

filter.ClientCertificate = certificate;

Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient(filter);

var response = await client.GetAsync(uri);

对于需要高度安全的应用,只有双向验证才能保证数据的安全性。在实践过程中,还需要建立CA服务器,通过向CA服务器发送Certificate Request来获得客户端证书,这些大家可以参看文档: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464962.aspx