HTTPS访问中证书的处理
2015-07-01 10:33
471 查看
现在基本大家都在使用HTTPS,比如REST API, 或者其他类似的SOAP啥的。因为HTTP是明文传输太不安全了。使用HTTPS会有个比较麻烦的问题就是证书的处理。这里有几种证书的问题:
1. 如果判断HTTPS中的证书是否是正确的?所谓的正确有2种意思:
a. 证书是假的,并非权威机构签发的,比如自己做的测试证书。
b. 证书也是权威机构签发的,但并不是自己公司的。比如某个人向verisign公司买了一个证书,然后通过域名劫持啥的把某https站点引导到自己的服务器,并且使用自己购买的证书,从而收集用户的密码啥的。
2. 通常在开发阶段用的都是测试证书,那么很多https访问库,一看这个证书并不在当前机器的信任区,可能会直接丢出错误。
对于这些问题,其实解决起来还是蛮简单的,基本思路就是:获取证书信息,然后自己根据需求来进行处理。
这里使用C#做一个简单演示:
可以看到这里有一堆的信任根证书,其中就有verisign公司的根证书(verisign公司是权威的,世界上用的大多数证书都是他们签发的,当然微软,苹果,谷歌等大公司也有一些权威根证书)。
百度的证书也是verisign公司签发的,所以没有问题。
我们可以创建来看一下百度的证书。为了查看百度的证书,需要自己提供一个System.Net.ICertificatePolicy的子类,重写虚函数
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
如:
我们可以打出证书信息。
在访问https之前,替换成我们自己的类实例:
运行一下,就可以看到百度的证书信息:
可以看到百度的证书确实是verisign公司签发的,而verisign公司的根证书在信任区。所以验证没问题。
那么如果是自己的测试证书呢?
如果我们不提供自己的certificatePolicy类,那么怕是会丢出异常,说是证书不合法啥的。
其实原因很简单,因为默认的CertificatePolicy类会去检查证书是不是合法机构签发的。看上去类似:
然后就出错了。
如果我们自己重写了CheckValidationResult,如:
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
{
System.Console.WriteLine("name: " + cert.Subject);
System.Console.WriteLine("issuer name: " + cert.Issuer);
return true;
}如何什么证书都返回true那就ok了。如果我们在测试开发阶段使用测试证书,那么就可以这么做。然后等正式发布的时候(有正式证书了),就把这段代码去掉,这样程序就只认权威机构签发的证书了。另外还有个问题,如果为了防止域名被劫持,然后使用一个权威机构签发的另外一个证书。解决问题也很简单,就是重写CheckValidationResult函数,然后在里面得到证书的信息,看一下subject里面是不是自己公司的,如果是就返回true,否则返回false,这样就防止公司的https被中途拦截了。
完整代码:
这个例子里实现了GET和POST。可以直接运行,并且看百度的证书信息。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace TestHTTPS
{
public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
{
public TrustAllCertificatePolicy()
{ }
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
{
System.Console.WriteLine("name: " + cert.Subject);
System.Console.WriteLine("issuer name: " + cert.Issuer);
return true;
}
}
class Program
{
static public string ReadHTTPorHTTPSWithGet(string URL)
{
try
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
// combine HTTP request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
// HTTP request header
request.Method = "get";
request.ContentType = "text/plain,charset=UTF-8";
// try to get response from HTTP/HTTPS
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ss = response.GetResponseStream();
using (StreamReader reader = new StreamReader(ss, Encoding.UTF8))
{
string data = reader.ReadToEnd();
return data;
}
}
catch (Exception e)
{
string err = e.Message;
}
return "";
}
static public string ReadHTTPorHTTPSWithPost(string URL, string strPostdata)
{
try
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
// combine HTTP request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
// HTTP request header
request.Method = "post";
request.ContentType = "text/plain,charset=UTF-8";
// HTTP request body
byte[] buffer = Encoding.UTF8.GetBytes(strPostdata);
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
// try to get response from HTTP/HTTPS
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ss = response.GetResponseStream();
using (StreamReader reader = new StreamReader(ss, Encoding.UTF8))
{
string data = reader.ReadToEnd();
return data;
}
}
catch (Exception e)
{
string err = e.Message;
}
return "";
}
static void Main(string[] args)
{
string ret = ReadHTTPorHTTPSWithGet("https://www.baidu.com");
string ret2 = ReadHTTPorHTTPSWithGet("http://www.baidu.com");
if (ret.Equals(ret2))
{
System.Console.WriteLine("success, results for http and https are same.");
}
else
{
System.Console.WriteLine("failed");
}
}
}
}
1. 如果判断HTTPS中的证书是否是正确的?所谓的正确有2种意思:
a. 证书是假的,并非权威机构签发的,比如自己做的测试证书。
b. 证书也是权威机构签发的,但并不是自己公司的。比如某个人向verisign公司买了一个证书,然后通过域名劫持啥的把某https站点引导到自己的服务器,并且使用自己购买的证书,从而收集用户的密码啥的。
2. 通常在开发阶段用的都是测试证书,那么很多https访问库,一看这个证书并不在当前机器的信任区,可能会直接丢出错误。
对于这些问题,其实解决起来还是蛮简单的,基本思路就是:获取证书信息,然后自己根据需求来进行处理。
这里使用C#做一个简单演示:
static public string ReadHTTPorHTTPSWithGet(string URL) { try { // combine HTTP request HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL); // HTTP request header request.Method = "get"; request.ContentType = "text/plain,charset=UTF-8"; // try to get response from HTTP/HTTPS HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream ss = response.GetResponseStream(); using (StreamReader reader = new StreamReader(ss, Encoding.UTF8)) { string data = reader.ReadToEnd(); return data; } } catch (Exception e) { string err = e.Message; } return ""; }如果使用上面的代码来访问https://www.baidu.com,没有问题可以成功得到结果,因为百度的证书是正式的,它是由verisign公司签发的,而verisign公司的根证书都是默认在机器的信任区的,大家可以打开证书管理器看一下(certmgr.msc)
可以看到这里有一堆的信任根证书,其中就有verisign公司的根证书(verisign公司是权威的,世界上用的大多数证书都是他们签发的,当然微软,苹果,谷歌等大公司也有一些权威根证书)。
百度的证书也是verisign公司签发的,所以没有问题。
我们可以创建来看一下百度的证书。为了查看百度的证书,需要自己提供一个System.Net.ICertificatePolicy的子类,重写虚函数
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
如:
public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy { public TrustAllCertificatePolicy() { } public bool CheckValidationResult(ServicePoint sp, System.Security.Cryptography.X509Certificates.X509Certificate cert, WebRequest req, int problem) { System.Console.WriteLine("name: " + cert.Subject); System.Console.WriteLine("issuer name: " + cert.Issuer); return true; } }
我们可以打出证书信息。
在访问https之前,替换成我们自己的类实例:
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
运行一下,就可以看到百度的证书信息:
可以看到百度的证书确实是verisign公司签发的,而verisign公司的根证书在信任区。所以验证没问题。
那么如果是自己的测试证书呢?
如果我们不提供自己的certificatePolicy类,那么怕是会丢出异常,说是证书不合法啥的。
其实原因很简单,因为默认的CertificatePolicy类会去检查证书是不是合法机构签发的。看上去类似:
public bool CheckValidationResult(ServicePoint sp, System.Security.Cryptography.X509Certificates.X509Certificate cert, WebRequest req, int problem) { System.Console.WriteLine("name: " + cert.Subject); System.Console.WriteLine("issuer name: " + cert.Issuer); if (cert is in trusted area) return true; else return false; }
然后就出错了。
如果我们自己重写了CheckValidationResult,如:
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
{
System.Console.WriteLine("name: " + cert.Subject);
System.Console.WriteLine("issuer name: " + cert.Issuer);
return true;
}如何什么证书都返回true那就ok了。如果我们在测试开发阶段使用测试证书,那么就可以这么做。然后等正式发布的时候(有正式证书了),就把这段代码去掉,这样程序就只认权威机构签发的证书了。另外还有个问题,如果为了防止域名被劫持,然后使用一个权威机构签发的另外一个证书。解决问题也很简单,就是重写CheckValidationResult函数,然后在里面得到证书的信息,看一下subject里面是不是自己公司的,如果是就返回true,否则返回false,这样就防止公司的https被中途拦截了。
完整代码:
这个例子里实现了GET和POST。可以直接运行,并且看百度的证书信息。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace TestHTTPS
{
public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
{
public TrustAllCertificatePolicy()
{ }
public bool CheckValidationResult(ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
WebRequest req, int problem)
{
System.Console.WriteLine("name: " + cert.Subject);
System.Console.WriteLine("issuer name: " + cert.Issuer);
return true;
}
}
class Program
{
static public string ReadHTTPorHTTPSWithGet(string URL)
{
try
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
// combine HTTP request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
// HTTP request header
request.Method = "get";
request.ContentType = "text/plain,charset=UTF-8";
// try to get response from HTTP/HTTPS
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ss = response.GetResponseStream();
using (StreamReader reader = new StreamReader(ss, Encoding.UTF8))
{
string data = reader.ReadToEnd();
return data;
}
}
catch (Exception e)
{
string err = e.Message;
}
return "";
}
static public string ReadHTTPorHTTPSWithPost(string URL, string strPostdata)
{
try
{
System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
// combine HTTP request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
// HTTP request header
request.Method = "post";
request.ContentType = "text/plain,charset=UTF-8";
// HTTP request body
byte[] buffer = Encoding.UTF8.GetBytes(strPostdata);
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
// try to get response from HTTP/HTTPS
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ss = response.GetResponseStream();
using (StreamReader reader = new StreamReader(ss, Encoding.UTF8))
{
string data = reader.ReadToEnd();
return data;
}
}
catch (Exception e)
{
string err = e.Message;
}
return "";
}
static void Main(string[] args)
{
string ret = ReadHTTPorHTTPSWithGet("https://www.baidu.com");
string ret2 = ReadHTTPorHTTPSWithGet("http://www.baidu.com");
if (ret.Equals(ret2))
{
System.Console.WriteLine("success, results for http and https are same.");
}
else
{
System.Console.WriteLine("failed");
}
}
}
}
相关文章推荐
- Linux实现https方式访问站点
- HTTPS的七个误解
- Centos 5下配置https服务器的方法
- apache https配置详细步骤讲解
- php使用curl打开https网站的方法
- win2003 https 网站的图文配置教程
- 安卓APP测试之使用Burp Suite实现HTTPS抓包方法
- android教程使用webview访问https的url处理sslerror示例
- PHP简单实现HTTP和HTTPS跨域共享session解决办法
- php之curl实现http与https请求的方法
- apache中使用mod_gnutls模块实现多个SSL站点配置(多个HTTPS协议的虚拟主机)
- Apache mod_rewrite实现HTTP和HTTPS重定向跳转
- jdk中密钥和证书管理工具keytool常用命令详解
- 在服务器上配置仅使用HTTPS通信的教程
- php curl 获取https请求的2种方法
- php使用curl获取https请求的方法
- 在 Django/Flask 开发服务器上使用 HTTPS
- python利用hook技术破解https的实例代码
- 在服务器上启用HTTPS的详细教程
- windows下部署免费ssl证书(letsencrypt)的方法