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

释放双眼,带上耳机,听听看~!

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

HTTPS介绍

  1. 窃听隐私:使用明文传输的HTTP协议,传输过程中的信息都可能会被攻击者窃取到,例如你登录网站的用户名和密码、在电商的购买记录、搜索记录等,这就会造成例如账号被盗、各种隐私泄漏的风险。而使用HTTPS对通信内容加密过后,即使被攻击者窃取到也无法破解其中的内容。

  2. 篡改内容:HTTP使用明文传输,不但消息会被窃取,还可能被篡改,例如常见的运营HTTP商劫持。你是否曾经浏览http协议的百度时,时不时会在页面下方弹出小广告,这些小广告并不是百度放上去的,而是电信网通等运营商干的,运营商通过篡改服务器返回的页面内容,加入一段HTML代码就可以轻松实现小广告。而使用HTTPS的百度,就不再会出现这样的小广告,因为攻击者无法对传输内容解密和加密,就无法篡改。

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

生成私钥和证书


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

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

HTTPS服务器实现

MINA


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
1public class MinaServer {
2
3    public static void main(String[] args) throws Exception {
4
5        String certPath = "/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt";  // 证书
6        String privateKeyPath = "/Users/wucao/Desktop/https/private.der";  // 私钥
7
8        // 证书
9        // https://docs.oracle.com/javase/7/docs/api/java/security/cert/X509Certificate.html
10        InputStream inStream = null;
11        Certificate certificate = null;
12        try {
13            inStream = new FileInputStream(certPath);
14            CertificateFactory cf = CertificateFactory.getInstance("X.509");
15            certificate = cf.generateCertificate(inStream);
16        } finally {
17            if (inStream != null) {
18                inStream.close();
19            }
20        }
21
22        // 私钥
23        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Files.readAllBytes(new File(privateKeyPath).toPath()));
24        PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
25
26        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
27        ks.load(null, null);
28        Certificate[] certificates = {certificate};
29        ks.setKeyEntry("key", privateKey, "".toCharArray(), certificates);
30
31        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
32        kmf.init(ks, "".toCharArray());
33
34        SSLContext sslContext = SSLContext.getInstance("TLS");
35        sslContext.init(kmf.getKeyManagers(), null, null);
36
37
38
39        IoAcceptor acceptor = new NioSocketAcceptor();
40        DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
41        chain.addLast("ssl", new SslFilter(sslContext));  // SslFilter + HttpServerCodec实现HTTPS
42        chain.addLast("codec", new HttpServerCodec());
43        acceptor.setHandler(new HttpServerHandle());
44        acceptor.bind(new InetSocketAddress(8080));
45    }
46}
47
48class HttpServerHandle extends IoHandlerAdapter {
49
50    @Override
51    public void exceptionCaught(IoSession session, Throwable cause)
52            throws Exception {
53        cause.printStackTrace();
54    }
55
56    @Override
57    public void messageReceived(IoSession session, Object message)
58            throws Exception {
59
60        if (message instanceof HttpRequest) {
61
62            // 请求,解码器将请求转换成HttpRequest对象
63            HttpRequest request = (HttpRequest) message;
64
65            // 获取请求参数
66            String name = request.getParameter("name");
67            if(name == null) {
68                name = "World";
69            }
70            name = URLDecoder.decode(name, "UTF-8");
71
72            // 响应HTML
73            String responseHtml = "<html><body>Hello, " + name + "</body></html>";
74            byte[] responseBytes = responseHtml.getBytes("UTF-8");
75            int contentLength = responseBytes.length;
76
77            // 构造HttpResponse对象,HttpResponse只包含响应的status line和header部分
78            Map<String, String> headers = new HashMap<String, String>();
79            headers.put("Content-Type", "text/html; charset=utf-8");
80            headers.put("Content-Length", Integer.toString(contentLength));
81            HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK, headers);
82
83            // 响应BODY
84            IoBuffer responseIoBuffer = IoBuffer.allocate(contentLength);
85            responseIoBuffer.put(responseBytes);
86            responseIoBuffer.flip();
87
88            session.write(response); // 响应的status line和header部分
89            session.write(responseIoBuffer); // 响应body部分
90        }
91    }
92}
93

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
1public class NettyServer {
2
3    public static void main(String[] args) throws InterruptedException, SSLException {
4
5        File certificate = new File("/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt");  // 证书
6        File privateKey = new File("/Users/wucao/Desktop/https/private.pem");  // 私钥
7        final SslContext sslContext = SslContextBuilder.forServer(certificate, privateKey).build();
8
9        EventLoopGroup bossGroup = new NioEventLoopGroup();
10        EventLoopGroup workerGroup = new NioEventLoopGroup();
11        try {
12            ServerBootstrap b = new ServerBootstrap();
13            b.group(bossGroup, workerGroup)
14                    .channel(NioServerSocketChannel.class)
15                    .childHandler(new ChannelInitializer<SocketChannel>() {
16                        @Override
17                        public void initChannel(SocketChannel ch) throws Exception {
18                            ChannelPipeline pipeline = ch.pipeline();
19
20                            // 加入SslHandler实现HTTPS
21                            SslHandler sslHandler = sslContext.newHandler(ch.alloc());
22                            pipeline.addLast(sslHandler);
23
24                            pipeline.addLast(new HttpServerCodec());
25                            pipeline.addLast(new HttpServerHandler());
26                        }
27                    });
28            ChannelFuture f = b.bind(8080).sync();
29            f.channel().closeFuture().sync();
30        } finally {
31            workerGroup.shutdownGracefully();
32            bossGroup.shutdownGracefully();
33        }
34    }
35}
36
37class HttpServerHandler extends ChannelInboundHandlerAdapter {
38
39    @Override
40    public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
41
42        if (msg instanceof HttpRequest) {
43
44            // 请求,解码器将请求转换成HttpRequest对象
45            HttpRequest request = (HttpRequest) msg;
46
47            // 获取请求参数
48            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());
49            String name = "World";
50            if(queryStringDecoder.parameters().get("name") != null) {
51                name = queryStringDecoder.parameters().get("name").get(0);
52            }
53
54            // 响应HTML
55            String responseHtml = "<html><body>Hello, " + name + "</body></html>";
56            byte[] responseBytes = responseHtml.getBytes("UTF-8");
57            int contentLength = responseBytes.length;
58
59            // 构造FullHttpResponse对象,FullHttpResponse包含message body
60            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseBytes));
61            response.headers().set("Content-Type", "text/html; charset=utf-8");
62            response.headers().set("Content-Length", Integer.toString(contentLength));
63
64            ctx.writeAndFlush(response);
65        }
66    }
67
68    @Override
69    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
70        cause.printStackTrace();
71        ctx.close();
72    }
73}
74

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1# -*- coding:utf-8 –*-
2
3from twisted.internet import reactor, ssl
4from twisted.web import server, resource
5
6sslContext = ssl.DefaultOpenSSLContextFactory(
7    '/Users/wucao/Desktop/https/2_gw2.vsgames.cn.key',  # 私钥
8    '/Users/wucao/Desktop/https/1_gw2.vsgames.cn_bundle.crt',  # 证书
9)
10
11class MainResource(resource.Resource):
12
13    isLeaf = True
14
15    # 用于处理GET类型请求
16    def render_GET(self, request):
17
18        # name参数
19        name = 'World'
20        if request.args.has_key('name'):
21            name = request.args['name'][0]
22
23        # 设置响应编码
24        request.responseHeaders.addRawHeader("Content-Type", "text/html; charset=utf-8")
25
26        # 响应的内容直接返回
27        return "<html><body>Hello, " + name + "</body></html>"
28
29
30site = server.Site(MainResource())
31reactor.listenSSL(8080, site, sslContext)
32reactor.run()
33

客户端测试 


1
2
1127.0.0.1 gw2.vsgames.cn
2

MINA、Netty、Twisted一起学系列

源码

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

安全资讯

再获2亿融资,老虎证券国际如何用一年把交易规模做到1200亿

2016-12-27 6:10:20

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索