//用C#的exe程序,搭建HTTPS监听,可用于静态网站、接口、模拟WebApi等等
//由于是客户端EXE,可以正常访问客户端所有硬件资源
//如:web界面上调用http://localhost:xx/+参数,调用本地硬件、本地缓存(内存或文件,可代替cookies)、打开本地程序、调用打印机、扫码墩…
C#的HTTPListen本身就能实现以上功能,本文主要讲述利用证书,将HTTP升级到HTTPS
1. 下载OpenSSL
http://slproweb.com/download/Win64OpenSSL-1_1_1c.exe
2. 安装OpenSSL
3. 使用OpenSSL创建证书:
4. 创建私有CA,然后用该CA给证书进行签名
win+r, cmd, cd C:\Program Files\OpenSSL-Win64\bin
4.1 创建CA私钥
openssl genrsa -des3 -out ca.key 4096
设置CA密码
4.2 生成CA的自签名证书,其实CA证书就是一个自签名证书
openssl req -new -x509 -days 36500 -keyca.key -out ca.crt
输入CA密码
Country Name (2 letter code) [AU]:CN --国家
State or Province Name (full name) [Some-State]:XH --地区
Locality Name (eg, city) []:SH --城市
Organization Name (eg, company) [Internet Widgits Pty Ltd]:公司名称
Organizational Unit Name (eg, section) []:部门名称
Common Name (e.g. server FQDN or YOUR name) []:域名/IP
Email Address []:
-days 为证书有效期(单位:天)
4.3.生成客户端证书私钥
openssl genrsa -des3 -out localhost.key 4096
设置客户端证书密码
4.4.需要签名的对象(服务端)生成证书签名请求
openssl req -new -key localhost.key -out localhost.csr
输入客户端证书密码
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:CN
Locality Name (eg, city) []:CN
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xxx --组织名称
Organizational Unit Name (eg, section) []:xxx --单位、部门,可同组织名称
Common Name (e.g. server FQDN or YOUR name) []:localhost --很关键,必须是url中的ip地址/或域名
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request -- 一些额外的信息
A challenge password []: xxx --证书交换密码(可省略)
An optional company name []:xx --公司名称(可省略)
这里注意证书签名请求当中的Common Name很关键,必须是url中的ip地址/或域名
4.5.用步骤4.2创建的CA证书给步骤4.4生成的签名请求进行签名
openssl x509 -req -days 365 -in localhost.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out localhost.crt
输入CA密码
-days 为证书有效期(单位:天)
4.6.合成 pfx
openssl pkcs12 -export -out localhost.pfx -inkey localhost.key -in localhost.crt
设置密码:证书安装密码
5.使用:
5.1 安装证书,双击pfx文件,安装到:“本地计算机”–>“个人”
5.2 双击打开crt证书,详细信息中可以看到“指纹”(certhash)
5.3 执行端口绑定(默认443端口)
netsh http add sslcert ipport=0.0.0.0:8000 certhash=指纹 appid={程序GUID/newguid} clientcertnegotiation=enable
如:
netsh http add sslcert ipport=0.0.0.0:8000 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF} clientcertnegotiation=enable
【HTTPListen】
using System;
public class test
{
public test()
{
System.Net.HttpListener httpListener = new System.Net.HttpListener();
httpListener.AuthenticationSchemes = System.Net.AuthenticationSchemes.Anonymous;
httpListener.Prefixes.Add("https://*:8000/"); // 支持http (不使用证书)
httpListener.Start();
new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
while (true)
{
try
{
System.Net.HttpListenerContext httpListenerContext = httpListener.GetContext();
new System.Threading.Thread(new System.Threading.ParameterizedThreadStart((input) =>
{
System.Net.HttpListenerContext ctx = (System.Net.HttpListenerContext)input;
System.Net.HttpListenerRequest request = ctx.Request;
string pram = request.QueryString["Data"];//Get入参
string responseMessage = string.Empty;//返回值
if (!string.IsNullOrEmpty(pram))
{
//Get入参,url解 码
pramOrg = pram;
pram = System.Web.HttpUtility.UrlDecode(pram);
}
//POST入参
if (request.HttpMethod == "POST")
{
//处理业务请求
StreamReader reader = new StreamReader(request.InputStream, Encoding.UTF8);
pram = reader.ReadToEnd();
reader.Close();
reader.Dispose();
}
#region 业务处理
try
{
//业务处理
responseMessage = "业务结果";
}
catch (Exception ex)
{
//异常处理
responseMessage = ex.Message;
}
#endregion 业务处理
#region 返回给调用者
//输出类型
httpListenerContext.Response.ContentType = "text/html; charset=UTF-8";
//返回状态
httpListenerContext.Response.StatusCode = 200;
//设置授权,尝试解决Jquery跨域问题
//httpListenerContext.Response.Headers["Access-Control-Allow-Origin"] = "*";
//httpListenerContext.Response.Headers["Access-Control-Allow-Methods"] = "GET,POST";
//httpListenerContext.Response.Headers["Access-Control-Max-Age"] = "1000";
try
{
//输出界面内容
if (!string.IsNullOrEmpty(responseMessage))
{
//返回文本内容
using (StreamWriter writer = new StreamWriter(httpListenerContext.Response.OutputStream))
{
writer.Write(responseMessage);
}
}
}
catch
{
//刷新太快异常,不做处理
}
#endregion 返回给调用者
})).Start(httpListenerContext);
}
catch
{ }
}
})).Start();
}
}