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的安全版.本文,就来深入介绍下其 ...
随机推荐
- Java 类型转换精度问题
基本数据类型占用内存大小 最近项目中修复了一个关于类型转换精度丢失的问题,以前对于类型转换会丢失精度只知其然,不知其所以然,这次了解了下相关原理,也分享给大家.先来回顾一下 Java 的基本数据类型中 ...
- java斐波纳契数列
//斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.-- 这个数列从第三项开始,每一项都等于前两项之和. public class DiGui { public ...
- 破解版IDM使用问题
正版的IDM一般下载安装后有30天的免费使用期,过了就需要买正版序列号才能使用,网上一般提供的破解版的IDM安装后又存在无法添加到chrome插件的问题 这里针对这个问题给出解决方案: 首先下载破解版 ...
- 冒泡排序算法JAVA实现版
/***关于冒泡排序,从性能最低版本实现到性能最优版本实现*/public class BubbleSortDemo { public static void sort(int array[]) { ...
- Mysql 实战关于date,datetime,timestamp类型使用
最近在做一个项目 项目中 不同的小伙伴同时在不同的业务模块中用到了date,datetime,timestamp这三个类型 特别是datetime,timestamp这两个 如果不能理解到位 其实很 ...
- 使用IDEA构建Spring Boot项目简单实例
一.介绍 它的目标是简化Spring应用和服务的创建.开发与部署,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用的微服务功能,可以和spring cloud联合部署. Spring Boot ...
- python之shelve、xml、configparser模块
一.shelve模块 shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型 import shelve ...
- vue element 表单验证不通过,滚动到固对应位置
我们在使用elementIUI实现表单验证,内容比较多的时候,提示内容会被遮挡,这时候用户不清楚什么情况,还会连续点击提交按钮.这个时候需求来啦:我们需要在表单验证不通过的时候,页面滚动到对应的位置. ...
- [不止于代码]Unraid基本使用速记
1.Unraid简介 Unraid是一个虚拟机系统,类似于VM.PVE,但又区别于前二者.通过Unraid的Dokcer可以快速构建类Nas及虚拟机环境,也可虚拟黑群晖使用,可以使用磁盘阵列,保护你的 ...
- Nginx集成Naxsi防火墙
前言 因工作原因,接触到了WAF,今天部署了一下Naxsi,记录一下 GitHub 正文 环境 Centos 7 下载 更新yum yum update -y 安装必要依赖 yum install g ...