HTTPS学习(二):原理与实践
div.example { background-color: rgba(229, 236, 243, 1); color: rgba(0, 0, 0, 1); padding: 0.5em; margin: 1em 2em 1em 1em }
div.warning { border: 1px solid rgba(255, 0, 0, 1) }
本文是《大型分布式网站架构设计与实践》 3.5节HTTPS协议的学习笔记。
HTTPS和SSL
HTTPS的全称是Hypertext Transfer Protocol over Secure Socket Layer,即 SSL之上的HTTP。 SSL及其继任者TLS是应用层(HTTP)和传输层(TCP)之间的安全协议层。它可以实现通信双方的认证、通信内容的加密传输。下图是SSL协议的示意图:
上面的握手过程看起来非常复杂,其实这个过程中主要就做了两件事:
1. 证书的认证
2. 通信双方协议产生一个通信秘钥。
关于第二点需要说明的是: 通信双方真正通信时使用的是对称加密。 在通信开始之前,通信双方会协商出一个对称加密的秘钥,而在这个协商过程中会使用非对称加密来传输信息。这样就既能保证通信的效率又解决了对称加密秘钥分发存在风险的问题。
在握手完成之后,通信双方就可以加密传输了。
使用JSSE实现SSL/TSL
JSSE全称是 java security socket extension,我们下面将使用JSSE来实现SSL。
我们首先需要使用上一篇中的生成的证书导出为Java环境可用的keystore文件。
客户端证书导出:
服务器端证书导出:
将CA根证书导出为信任库:
使用SSLServerSocket 、SSLSocket和普通socket并没有太大的不同,只不过需要在使用之前加载证书和信任库而已,如下代码:
SSL服务端:
package server; import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyStore; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory; public class Server {
public static SSLServerSocket serverSocket; public static void init() throws Exception{
int port = 1234; //服务端keystore文件
String keystorePath = "/home/massclouds/keystores/server.keystore";
String keystorePassword = "1234"; //由根证书导出的信任库
String trustKeystorePath = "/home/massclouds/keystores/ca-trust.keystore";
String trustKeystorePassword = "123456"; //========= 加载服务端keystore文件和根证书信任库 begin ===============
SSLContext sslContext = SSLContext.getInstance("SSL"); KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509"); TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
KeyStore trustKeystore = KeyStore.getInstance("jks"); FileInputStream keyStoreFis = new FileInputStream(keystorePath);
keyStore.load(keyStoreFis, keystorePassword.toCharArray()); FileInputStream trustKeyStoreFis = new FileInputStream(trustKeystorePath);
trustKeystore.load(trustKeyStoreFis, trustKeystorePassword.toCharArray()); kmf.init(keyStore, keystorePassword.toCharArray());
tmf.init(trustKeystore); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(port);
//========= 加载服务端keystore文件和根证书信任库 end =============== //是否需要客户端认证
serverSocket.setNeedClientAuth(true); } public static void process() throws Exception{
String bye = "bye bye !"; while(true){
Socket socket = serverSocket.accept();
byte[] inputBytes = new byte[1024];
InputStream input = socket.getInputStream();
input.read(inputBytes); System.out.println(new String(inputBytes)); OutputStream out = socket.getOutputStream();
out.write(bye.getBytes(), 0, bye.getBytes().length);
out.flush();
}
} public static void main(String[] args) throws Exception {
init();
process();
}
}
SSL客户端:
package client; import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory; public class Client {
public static SSLSocket sslSocket ; public static void init() throws Exception{
String host = "localhost";
int port = 1234; //客户端
String keystorePath = "/home/massclouds/keystores/client.keystore";
String keystorePassword = "1234"; //CA
String trustKeystorePath = "/home/massclouds/keystores/ca-trust.keystore";
String trustKeystorePassword = "123456"; SSLContext sslContext = SSLContext.getInstance("SSL"); KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509"); TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
KeyStore trustKeyStore = KeyStore.getInstance("jks"); FileInputStream keyStoreFis = new FileInputStream(keystorePath);
keyStore.load(keyStoreFis, keystorePassword.toCharArray()); FileInputStream trustKeyStoreFis = new FileInputStream(trustKeystorePath);
trustKeyStore.load(trustKeyStoreFis, trustKeystorePassword.toCharArray()); kmf.init(keyStore, keystorePassword.toCharArray());
tmf.init(trustKeyStore); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(host, port);
} public static void process() throws Exception{
String hello = "do what you love and keep doing !";
OutputStream output = sslSocket.getOutputStream();
output.write(hello.getBytes(), 0, hello.getBytes().length);
output.flush(); byte[] inputBytes = new byte[1024];
InputStream input = sslSocket.getInputStream();
input.read(inputBytes); System.out.println(new String(inputBytes));
} public static void main(String[] args) throws Exception{
init();
process();
} }
在tomcat中部署HTTPS
实验环境是centos 7,tomcat所在目录是/usr/local/tomcat 。
我们将上面导出的keystore文件放在/root/keystore目录下
下面我们来配置 服务端单向认证
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/root/keystore/server.keystore"
keystorePass="1234"
keystoreType="pkcs12"
/>
配置完成后如果希望我们的服务器证书通过浏览器的验证还需要两步:
1. 讲在第一篇中生产的CA根证书导入到操作系统中。
2. 通过服务器证书中使用者的CN来配置客户端机器的域名映射,例如我的环境中需要配置
然后通过www.server.com来访问。这样就可以让服务器证书通过认证了。
在apache http server中配置https
实验环境 centos 7 Apache/2.4.6
默认情况下httpd是没有mod_ssl模块的,我们首先安装mod_ssl。
这个时候其实就已经支持https了,此时使用的证书和私钥是(配置文件是/etc/httpd/conf.d/ssl.conf):
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
此时服务器证书肯定是无法通过客户端认证的,启动服务访问:
我们从/etc/httpd/conf.d/ssl.conf中可以看到配置了一个443端口的virtual host,我们可以将这个虚拟主机中的 SSLCertificateFile SSLCertificateKeyFile 这两个指令配置为我们前面所讨论的服务器证书和私钥,这里有个问题是:我们上面在产生私钥时都使用 -aes256 参数加密了,所以每次在启动httpd时都会要求我们输入这个秘钥。 我们可以不用这个参数重新生产一遍服务器的私钥和证书(过程不再赘述)。
SSLCertificateKeyFile /etc/pki/tls/private/server-key.pem
剩下的工作和tomcat中就一样了,在客户端操作系统中导入根证书,配置服务器证书中对应的域名,然后就可以安全访问了。
将所有http请求重定向到https
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule .* https://%{HTTP_HOST}/%{REQUEST_URI} [R=301,L,QSA]
</IfModule>
HTTPS学习(二):原理与实践的更多相关文章
- Canal和Otter讨论二(原理与实践)
上次留下的问题 问题一: 跨公网部署Otter 参考架构图 解析 a. 数据涉及网络传输,S/E/T/L几个阶段会分散在2个或者更多Node节点上,多个Node之间通过zookeeper进行协同工 ...
- 深入浅出深度学习:原理剖析与python实践_黄安埠(著) pdf
深入浅出深度学习:原理剖析与python实践 目录: 第1 部分 概要 1 1 绪论 2 1.1 人工智能.机器学习与深度学习的关系 3 1.1.1 人工智能——机器推理 4 1.1.2 机器学习—— ...
- kafka原理和实践(二)spring-kafka简单实践
系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...
- WebSocket原理与实践(二)---WebSocket协议
WebSocket原理与实践(二)---WebSocket协议 WebSocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信问题而设计的.协议定义ws和wss协议,分别为普通请求和基 ...
- 20145308 《网络对抗》 MAL_免杀原理及实践 学习总结
20145308 <网络对抗> MAL_免杀原理及实践 学习总结 实践内容 (1)理解免杀技术原理 (2)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免 ...
- 【百度】大型网站的HTTPS实践(一)——HTTPS协议和原理
大型网站的HTTPS实践(一)——HTTPS协议和原理 原创 网络通信/物联网 作者:AIOps智能运维 时间:2018-11-09 15:07:39 349 0 前言 百度于2015年上线了全站 ...
- 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解
深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...
- C++学习书籍推荐《C++程序设计原理与实践》下载
百度云及其他网盘下载地址:点我 编辑推荐 <C++程序设计原理与实践>是经典程序设计思想与C++开发实践的完美结合,是C++之父回归校园后对C++编程原理和技巧的全新阐述.书中全面地介绍了 ...
- Spring Boot自动配置原理与实践(二)
前言 在之前的博文(Spring Boot自动配置原理与实践(一))中,已经介绍了Spring boot的自动配置的相关原理与概念,本篇主要是对自动配置的实践,即自定义Starter,对原理与概念加深 ...
- 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等
1.引言 HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.本文,就来深入介绍下其 ...
随机推荐
- Flowable学习入门
一.Flowable简介 1.Flowable是什么 Flowable是一个使用Java编写的轻量级业务流程引擎.Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标 ...
- MD5,BASE64Encoder加密
package com.cn.peitest; import java.io.UnsupportedEncodingException; import java.security.MessageDig ...
- [Deep Learning] 神经网络编程基础 (Basics of Neural Network Programming) - 逻辑回归-梯度下降-计算图
在神经网络中,假如有m个训练集,我们想把他们加入训练,第一个想到得就是用一个for循环来遍历训练集,从而开始训练.但是在神经网络中,我们换一个计算方法,这就是 前向传播和反向传播. 对于逻辑回归,就是 ...
- C语言输入字符串
首先强调一点,C语言没有字符串的概念!所谓的字符串实际上还是以数组形式保存的. 方法1 -- 通过"%s"输入 优点:简单明了,输入字符只要不大于数组长度都可以. #includ ...
- 1. 内存分区模型以及new、delete操作
C++程序在执行时,将内存大方向分为 4 个区域,不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程 代码区:存放函数二进制代码,由操作系统进行管理 全局区:存放全局变量和静态数据以及常量, ...
- 2020再见&新的计划(建立Android体系架构)
2020,再见 关于2020,我心中有四个关键词: 疫情 年初突如其来的疫情,打破了原本生活的节奏,也没想到会笼罩全世界整整一年,希望这个世界早点好起来吧. 科比 初三的早晨,噩耗传来,我一度不敢相信 ...
- SpringBoot整合Shiro完成验证码校验
SpringBoot整合Shiro完成验证码校验 上一篇:SpringBoot整合Shiro使用Redis作为缓存 首先编写生成验证码的工具类 package club.qy.datao.utils; ...
- java8新特性之stream流
Stream 流是 Java 8 提供给开发者一套新的处理集合的API,他把我们将要处理的集合作为流,就像流水线一样,我们可以对其中的元素进行筛选,过滤,排序等中间操作,只不过这种操作更加简洁高效. ...
- Assuming that agent dropped connection because of access permission
Assuming that agent dropped connection because of access permission
- 汇编学习笔记——DOS及DEBUG介绍
转自:https://www.shiyanlou.com/courses/running/332 一.课程简介 声明:该课程基于<汇编语言(第2版)>郑晓薇 编著,机械工业出版社.本节实验 ...