由于HTTPS协议是由HTTP协议加上SSL/TLS协议组合而成,在阅读本文前可以先阅读一下HTTP服务器和SSL/TLS两篇博文,本文中的代码也是由这两篇博文中的代码组合而成。

HTTPS介绍

上一篇博文中介绍了SSL/TLS协议,我们平时接触最多的SSL/TLS协议的应用就是HTTPS协议了,现在可以看到越来越多的网站已经是https开头了,百度搜索也由曾经的http改为https。有关百度为什么升级https推荐阅读:http://zhanzhang.baidu.com/wiki/383

HTTPS即HTTP over SSL,实际上就是在原来HTTP协议的底层加入了SSL/TLS协议层,使得客户端(例如浏览器)与服务器之间的通信加密传输,攻击者无法窃听和篡改。相对而言HTTP协议则是明文传输,安全性并不高。

HTTPS主要可以避免以下几个安全问题:
1. 窃听隐私:使用明文传输的HTTP协议,传输过程中的信息都可能会被攻击者窃取到,例如你登录网站的用户名和密码、在电商的购买记录、搜索记录等,这就会造成例如账号被盗、各种隐私泄漏的风险。而使用HTTPS对通信内容加密过后,即使被攻击者窃取到也无法破解其中的内容。
2. 篡改内容:HTTP使用明文传输,不但消息会被窃取,还可能被篡改,例如常见的运营HTTP商劫持。你是否曾经浏览http协议的百度时,时不时会在页面下方弹出小广告,这些小广告并不是百度放上去的,而是电信网通等运营商干的,运营商通过篡改服务器返回的页面内容,加入一段HTML代码就可以轻松实现小广告。而使用HTTPS的百度,就不再会出现这样的小广告,因为攻击者无法对传输内容解密和加密,就无法篡改。

3. 冒充:例如DNS劫持,当你输入一个http网址在浏览器打开时,有可能打开的是一个假的网站,连的并不是真网站的服务器,假的网站可能给你弹出广告,还可能让你输入用户名密码来盗取账户。使用HTTPS的话,服务器都会有数字证书和私钥,数字证书公开的,私钥是网站服务器私密的,假网站如果使用假的证书,浏览器会拦截并提示,如果使用真的证书,由于没有私钥也无法建立连接。

生成私钥和证书

浏览器信任的证书一般是CA机构(证书授权中心)颁发的,证书有收费的也有免费的,本文使用免费证书用于测试。可以在腾讯云https://www.qcloud.com/product/ssl申请一个免费证书,申请证书前需要提供一个域名,即该证书作用的域名。

我在本文中使用的是我自己的域名gw2.vsgames.cn在腾讯云申请的免费证书,如果没有自己的域名无法申请免费证书,可以在本文的末尾下载源码,其中有我生成好的证书用于测试。

证书生成好下载后包含一个私钥文件(.key)和一个证书文件(.crt),腾讯云生成的证书可以在Nginx目录下找到这两个文件。

这两个文件在Twisted中可以直接使用,但是Java只能使用PKCS#8私钥文件,需要对上面的.key文件用openssl进行转换(如果你是在我提供的源码中获取证书和私钥文件,我已经提供了转换好的私钥,可以跳过这一步)。

转换成DER二进制格式私钥文件,供MINA使用:

openssl pkcs8 -topk8 -inform PEM -in 2_gw2.vsgames.cn.key -outform DER -nocrypt -out private.der

转换成PEM文本格式私钥文件,供Netty使用:

openssl pkcs8 -topk8 -inform PEM -in 2_gw2.vsgames.cn.key -outform PEM -nocrypt -out private.pem

除了在CA机构申请证书,还可以通过自签名的方式生成私钥和证书,上一篇博文中采用的就是这种方式。不过由于自签名的证书不是CA机构颁发,不受浏览器信任,在浏览器打开HTTPS地址时会有安全提示,测试时可以忽略提示。

HTTPS服务器实现

将MINA、Netty、Twisted一起学(八):HTTP服务器和MINA、Netty、Twisted一起学(十一):SSL/TLS中的代码结合起来,即可实现HTTPS服务器。

MINA

在http://xxgblog.com/2014/09/23/mina-netty-twisted-8/#MINA代码的基础上,在HttpServerCodec之前加上SslFilter即可。

public class MinaServer {public static void main(String[] args) throws Exception {String certPath = "/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt";  // 证书String privateKeyPath = "/Users/wucao/Desktop/https/private.der";  // 私钥// 证书// https://docs.oracle.com/javase/7/docs/api/java/security/cert/X509Certificate.htmlInputStream inStream = null;Certificate certificate = null;try {inStream = new FileInputStream(certPath);CertificateFactory cf = CertificateFactory.getInstance("X.509");certificate = cf.generateCertificate(inStream);} finally {if (inStream != null) {inStream.close();}}// 私钥PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Files.readAllBytes(new File(privateKeyPath).toPath()));PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());ks.load(null, null);Certificate[] certificates = {certificate};ks.setKeyEntry("key", privateKey, "".toCharArray(), certificates);KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());kmf.init(ks, "".toCharArray());SSLContext sslContext = SSLContext.getInstance("TLS");sslContext.init(kmf.getKeyManagers(), null, null);IoAcceptor acceptor = new NioSocketAcceptor();DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();chain.addLast("ssl", new SslFilter(sslContext));  // SslFilter + HttpServerCodec实现HTTPSchain.addLast("codec", new HttpServerCodec());acceptor.setHandler(new HttpServerHandle());acceptor.bind(new InetSocketAddress(8080));}
}class HttpServerHandle extends IoHandlerAdapter {@Overridepublic void exceptionCaught(IoSession session, Throwable cause)throws Exception {cause.printStackTrace();}@Overridepublic void messageReceived(IoSession session, Object message)throws Exception {if (message instanceof HttpRequest) {// 请求,解码器将请求转换成HttpRequest对象HttpRequest request = (HttpRequest) message;// 获取请求参数String name = request.getParameter("name");if(name == null) {name = "World";}name = URLDecoder.decode(name, "UTF-8");// 响应HTMLString responseHtml = "<html><body>Hello, " + name + "</body></html>";byte[] responseBytes = responseHtml.getBytes("UTF-8");int contentLength = responseBytes.length;// 构造HttpResponse对象,HttpResponse只包含响应的status line和header部分Map<String, String> headers = new HashMap<String, String>();headers.put("Content-Type", "text/html; charset=utf-8");headers.put("Content-Length", Integer.toString(contentLength));HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK, headers);// 响应BODYIoBuffer responseIoBuffer = IoBuffer.allocate(contentLength);responseIoBuffer.put(responseBytes);responseIoBuffer.flip();session.write(response); // 响应的status line和header部分session.write(responseIoBuffer); // 响应body部分}}
}

Netty

在http://xxgblog.com/2014/09/23/mina-netty-twisted-8/#Netty代码的基础上,在ChannelPipeline最前边加上SslHandler即可。

public class NettyServer {public static void main(String[] args) throws InterruptedException, SSLException {File certificate = new File("/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt");  // 证书File privateKey = new File("/Users/wucao/Desktop/https/private.pem");  // 私钥final SslContext sslContext = SslContextBuilder.forServer(certificate, privateKey).build();EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 加入SslHandler实现HTTPSSslHandler sslHandler = sslContext.newHandler(ch.alloc());pipeline.addLast(sslHandler);pipeline.addLast(new HttpServerCodec());pipeline.addLast(new HttpServerHandler());}});ChannelFuture f = b.bind(8080).sync();f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}}
}class HttpServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {if (msg instanceof HttpRequest) {// 请求,解码器将请求转换成HttpRequest对象HttpRequest request = (HttpRequest) msg;// 获取请求参数QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());String name = "World";if(queryStringDecoder.parameters().get("name") != null) {name = queryStringDecoder.parameters().get("name").get(0);}// 响应HTMLString responseHtml = "<html><body>Hello, " + name + "</body></html>";byte[] responseBytes = responseHtml.getBytes("UTF-8");int contentLength = responseBytes.length;// 构造FullHttpResponse对象,FullHttpResponse包含message bodyFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseBytes));response.headers().set("Content-Type", "text/html; charset=utf-8");response.headers().set("Content-Length", Integer.toString(contentLength));ctx.writeAndFlush(response);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}

Twisted

将http://xxgblog.com/2014/09/23/mina-netty-twisted-8/#Twisted中reactor.listenTCP改为的reactor.listenSSL,即可从HTTP协议切到HTTPS协议。

# -*- coding:utf-8 –*-from twisted.internet import reactor, ssl
from twisted.web import server, resourcesslContext = ssl.DefaultOpenSSLContextFactory('/Users/wucao/Desktop/https/2_gw2.vsgames.cn.key',  # 私钥'/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt',  # 证书
)class MainResource(resource.Resource):isLeaf = True# 用于处理GET类型请求def render_GET(self, request):# name参数name = 'World'if request.args.has_key('name'):name = request.args['name'][0]# 设置响应编码request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")# 响应的内容直接返回return "<html><body>Hello, " + name + "</body></html>"site = server.Site(MainResource())
reactor.listenSSL(8080, site, sslContext)
reactor.run()

客户端测试

由于浏览器就是最天然的HTTPS客户端,这里可以使用浏览器来测试。

首先,由于我的证书对应的域名是gw2.vsgames.cn,而服务器代码运行在本机上,所以先需要配置hosts将域名解析到localhost上:

127.0.0.1 gw2.vsgames.cn

在浏览器打开https://gw2.vsgames.cn:8080/?name=叉叉哥可以看到测试结果:

证书和私钥正确的HTTPS服务器,在Chrome浏览器左上角会有“安全”提示,其他浏览器也会有相应的提示。

MINA、Netty、Twisted一起学系列

MINA、Netty、Twisted一起学(一):实现简单的TCP服务器

MINA、Netty、Twisted一起学(二):TCP消息边界问题及按行分割消息

MINA、Netty、Twisted一起学(三):TCP消息固定大小的前缀(Header)

MINA、Netty、Twisted一起学(四):定制自己的协议

MINA、Netty、Twisted一起学(五):整合protobuf

MINA、Netty、Twisted一起学(六):session

MINA、Netty、Twisted一起学(七):发布/订阅(Publish/Subscribe)

MINA、Netty、Twisted一起学(八):HTTP服务器

MINA、Netty、Twisted一起学(九):异步IO和回调函数

MINA、Netty、Twisted一起学(十):线程模型

MINA、Netty、Twisted一起学(十一):SSL/TLS

MINA、Netty、Twisted一起学(十二):HTTPS

源码

https://github.com/wucao/mina-netty-twisted

MINA、Netty、Twisted一起学(十二):HTTPS相关推荐

  1. twisted系列教程十二–为server 增加一个service

    One More Server 在第九部分和第十部分我们介绍了关于诗歌的变形引擎的想法,最后我们实现了cummingsifier,我们还让它抛出随机的异常来模拟错误.但是假如这个变形的引擎在另外一台服 ...

  2. python血条游戏代码_零基础快速学十二课Python完整游戏代码,使用「格式符%」来处理...

    十二课Python不同数据类型的拼接方式,使用[格式符%]来处理 不过它还没有全部解决:打印出每局结果,三局两胜打印最终战果.这就是版本3.0需要做的事情. 打印战果,三局两胜. 对比2.0版本,在3 ...

  3. Mina、Netty、Twisted一起学(五):整合protobuf

    protobuf是谷歌的Protocol Buffers的简称,用于结构化数据和字节码之间互相转换(序列化.反序列化),一般应用于网络传输,可支持多种编程语言. protobuf怎样使用这里不再介绍, ...

  4. Mina、Netty、Twisted一起学(一):实现简单的TCP服务器

    MINA.Netty.Twisted为什么放在一起学习?首先,不妨先分别看一下它们官方网站对其的介绍: MINA: Apache MINA is a network application frame ...

  5. MINA、Netty、Twisted一起学(十一):SSL/TLS

    什么是SSL/TLS 不使用SSL/TLS的网络通信,一般都是明文传输,网络传输内容在传输过程中很容易被窃听甚至篡改,非常不安全.SSL/TLS协议就是为了解决这些安全问题而设计的.SSL/TLS协议 ...

  6. 跟我学SpringCloud | 第十二篇:Spring Cloud Gateway初探

    SpringCloud系列教程 | 第十二篇:Spring Cloud Gateway初探 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如 ...

  7. Netty实战 IM即时通讯系统(十二)构建客户端与服务端pipeline

    Netty实战 IM即时通讯系统(十二)构建客户端与服务端pipeline 零. 目录 IM系统简介 Netty 简介 Netty 环境配置 服务端启动流程 客户端启动流程 实战: 客户端和服务端双向 ...

  8. 【零基础学Java】—Java 日期时间(三十二)

    [零基础学Java]-Java 日期时间(三十二) DateFormat 是日期/时间格式化子类的抽象类,它以语言无关的方式格式化和分析日期或时间. 日期/时间格式化子类(如SimpleDateFor ...

  9. 【零基础学Java】—Random的基本概述和使用(十二)

    [零基础学Java]-Random的基本概述和使用(十二) Random类用来生成随机的数字,使用起来也是三个步骤 导包:import java.util.Random; 创建:Random r=ne ...

  10. 零基础入门学Python(十二)—— 魔法方法(下)

    零基础入门学Python系列内容的学习目录→\rightarrow→零基础入门学Python系列内容汇总. 魔法方法(下) 1. 构造和析构 2. 算术运算 3. 简单定制 4. 属性访问 5. 描述 ...

最新文章

  1. 众创汇定制如何革新工业4.0?
  2. linux服务器的日志管理
  3. Win:如何查看自己的电脑是否通过代理服务器进行上网
  4. html怎么显示直线,html怎么用鼠标画出一条直线,鼠标移动时候要能看到线条
  5. cordova报错:Error: Failed to find ‘ANDROID_HOME‘ environment variable. Try setting setting it manually
  6. 实战能力|一文看懂GDB调试上层实现
  7. java中转json字符串_如何在Java中转义JSON字符串-Eclipse IDE技巧
  8. Pandas数据可视化工具:图表工具-Seaborn
  9. C++模板-Traits
  10. 【jQuery笔记Part1】02-jQuery代码风格
  11. GraphX中Pregel单源点最短路径(转)
  12. NFS网络文件系统配置
  13. 数据抽样方式:概率抽样、非概率抽样
  14. 2.(leaflet篇)leaflet加载接入百度地图
  15. 余弦窗cosine window
  16. 解决电脑右侧数字键盘无法打出数字问题
  17. 影视/动漫 短视频专栏来啦!
  18. Makdown编辑器哪个好
  19. 解决window聚焦图片不自动更新,没有“喜欢么”信息提示框问题
  20. 多层感知机预测电池SOH值

热门文章

  1. word安装到计算机的哪里,如何查找word安装目录 如何查找word的路径
  2. wps阶梯表格怎么做?wps阶梯表格制作教程
  3. 使用 virtualBox 安装 ubuntu
  4. Python爬虫实战--小猪短租爬虫
  5. 语音文件格式转换:.amr 转 .MP3, .wav格式
  6. 计算机主机解剖图,电脑主机结构示意图
  7. SAP_ABAP_采购价格条件报表
  8. 我给自己定了个目标,我要看完这95本书
  9. Sendmail和Openwebmail构建Linux下的Emai服务器
  10. 云端架构下的手机浏览器内核演进