CSharp使用WebRequest请求HTTPS遇到的问题

起因

由于前几天心血来潮,升级了Linux系统和Jexus,阿里云ecs购买了四年,一直都是测试练手的.又重新配置了Jexus,将tls版本改为tls 1.2.今天在用WebRequest请求的时候.遇到身份验证失败的错误.

由于项目设置的是.Net Framework 4.0

string url = "https://www.qiufengblog.com/sitemap.xml";      
if (url.StartsWith("https"))
{
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
    ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };
}

SecurityProtocolType枚举下,只有两项

public enum SecurityProtocolType
{
    //
    // 摘要:
    //     指定安全套接字层 (SSL) 3.0 安全协议。
    Ssl3 = 48,
    //
    // 摘要:
    //     指定传输层安全 (TLS) 1.0 安全协议。
    Tls = 192
}

所以上面请求代码,选择SecurityProtocol.Tls,在请求的时候,还是要报身份验证失败.才想起是不是Framework版本太低.将Framework版本改为4.6.2.发现SecurityProtocol枚举有Tls12选项.

完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.IO;
using System.Text;

namespace qiufeng.tools
{
    static class Program
    {
        static void Main(string[] args)
        {
            string url = "https://www.qiufengblog.com/sitemap.xml";
            if (url.StartsWith("https"))
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;   //主要选择对应tls版本
                ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };
            }
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse response = null;
            try
            {
                response = request.GetResponse() as HttpWebResponse;
                using (Stream stream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                    {
                        string content = reader.ReadToEnd();
                        string file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sitemap.xml");
                        File.WriteAllText(file, content, Encoding.UTF8);
                    }
                }
            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
                Console.WriteLine("statuscode ={0}", response.StatusCode);
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }
        }
    }
}

以上代码,在Windows是没问题的.在Linux运行的时候,还要在多执行一步.是因为Linux默认没又根证书.使用mono自带的mozroots工具.如果系统没有安装mono,使用的是Jexus独立版,在Jexus执行的根目录中带有这个工具.

这里以mono安装为例: 先手动查找mozroots所在位置

查找mozroots所在目录

使用mozroots导入根证书

编译执行csharp源文件

若是在想web程序全局配置的话

如果你是在web程序中,只想配置一次的话,请求其他https地址的话,代码要设置tls版本和验证证书回调.

webform和mvc(不包含asp.net core mvc):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

namespace WebApplication1
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;  //根据自己需要选择对应的
            ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };
        }
    }
}

Nancy的话在Bootstrapper配置ApplicationStartup:

protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;  //根据自己需要选择对应的
    ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => { return true; };

    //其他处理
    //.....
}
秋风 2018-04-22