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文件。

客户端证书导出:

openssl pkcs12 -export -clcerts -name lisi -inkey private/client-key.pem -in certs/client.cer -out /home/massclouds/keystores/client.keystore

服务器端证书导出:

openssl pkcs12 -export -clcerts -name www.server.com -inkey private/server-key.pem -in certs/server.cer -out /home/massclouds/keystores/server.keystore

将CA根证书导出为信任库:

keytool -importcert -trustcacerts -alias *.massclouds.com -file certs/ca.cer -keystore /home/massclouds/keystores/ca-trust.keystore

使用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 。

在linux中启动tomcat,日志卡在INFO: Deploying web application directory .....的解决办法: http://blog.csdn.net/njchenyi/article/details/46641141

我们将上面导出的keystore文件放在/root/keystore目录下

下面我们来配置 服务端单向认证

<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
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来配置客户端机器的域名映射,例如我的环境中需要配置

192.168.107.225 www.server.com

然后通过www.server.com来访问。这样就可以让服务器证书通过认证了。

https能够实现通信的加密,通信双方的认证。但是有一些安全问题https是解决不了的,比如重放攻击,简单的说就是虽然用户登录的时候用户名和密码加密了,但是别人依然可以拦截到这些加密的数据,然后重新发送给服务器端来实现攻击。再比如 客户端证书的盗用。 这些问题随着自己知识的增长再一点点解决吧! ^_^

在apache http server中配置https

实验环境 centos 7 Apache/2.4.6

默认情况下httpd是没有mod_ssl模块的,我们首先安装mod_ssl。

yum install mod_ssl

这个时候其实就已经支持https了,此时使用的证书和私钥是(配置文件是/etc/httpd/conf.d/ssl.conf):

SSLCertificateFile /etc/pki/tls/certs/localhost.crt

SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

此时服务器证书肯定是无法通过客户端认证的,启动服务访问:

我们从/etc/httpd/conf.d/ssl.conf中可以看到配置了一个443端口的virtual host,我们可以将这个虚拟主机中的 SSLCertificateFile SSLCertificateKeyFile 这两个指令配置为我们前面所讨论的服务器证书和私钥,这里有个问题是:我们上面在产生私钥时都使用 -aes256 参数加密了,所以每次在启动httpd时都会要求我们输入这个秘钥。 我们可以不用这个参数重新生产一遍服务器的私钥和证书(过程不再赘述)。

SSLCertificateFile /etc/pki/tls/certs/server.cer
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学习(二):原理与实践的更多相关文章

  1. Canal和Otter讨论二(原理与实践)

    上次留下的问题 问题一: 跨公网部署Otter 参考架构图 解析 ​ a. 数据涉及网络传输,S/E/T/L几个阶段会分散在2个或者更多Node节点上,多个Node之间通过zookeeper进行协同工 ...

  2. 深入浅出深度学习:原理剖析与python实践_黄安埠(著) pdf

    深入浅出深度学习:原理剖析与python实践 目录: 第1 部分 概要 1 1 绪论 2 1.1 人工智能.机器学习与深度学习的关系 3 1.1.1 人工智能——机器推理 4 1.1.2 机器学习—— ...

  3. kafka原理和实践(二)spring-kafka简单实践

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  4. WebSocket原理与实践(二)---WebSocket协议

    WebSocket原理与实践(二)---WebSocket协议 WebSocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信问题而设计的.协议定义ws和wss协议,分别为普通请求和基 ...

  5. 20145308 《网络对抗》 MAL_免杀原理及实践 学习总结

    20145308 <网络对抗> MAL_免杀原理及实践 学习总结 实践内容 (1)理解免杀技术原理 (2)正确使用msf编码器,veil-evasion,自己利用shellcode编程等免 ...

  6. 【百度】大型网站的HTTPS实践(一)——HTTPS协议和原理

    大型网站的HTTPS实践(一)——HTTPS协议和原理 原创 网络通信/物联网 作者:AIOps智能运维 时间:2018-11-09 15:07:39  349  0 前言 百度于2015年上线了全站 ...

  7. 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解

    深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...

  8. C++学习书籍推荐《C++程序设计原理与实践》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <C++程序设计原理与实践>是经典程序设计思想与C++开发实践的完美结合,是C++之父回归校园后对C++编程原理和技巧的全新阐述.书中全面地介绍了 ...

  9. Spring Boot自动配置原理与实践(二)

    前言 在之前的博文(Spring Boot自动配置原理与实践(一))中,已经介绍了Spring boot的自动配置的相关原理与概念,本篇主要是对自动配置的实践,即自定义Starter,对原理与概念加深 ...

  10. 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

    1.引言 HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.本文,就来深入介绍下其 ...

随机推荐

  1. codeblocks opengl glew freeglut 2020.11.15

    https://wenku.baidu.com/view/28cd5ebfaf1ffc4fff47accf.html 一下为测试代码 /* ============================== ...

  2. 论文翻译:2018_Deep Learning for Acoustic Echo Cancellation in Noisy and Double-Talk Scenarios

    论文地址:深度学习用于噪音和双语场景下的回声消除 博客地址:https://www.cnblogs.com/LXP-Never/p/14210359.html 摘要 传统的声学回声消除(AEC)通过使 ...

  3. nginx二级域名配置[CentOS]

    目录 背景 域名配置 服务器配置 Nginx配置 页面访问生效 背景 只有一台云服务器,部署了自己写的后端管理系统,又需要部署下自己的个人博客平台,但是只有一个域名,想要合理的利用下二级域名. 域名配 ...

  4. flink集群模式安装配置

    一.手动下载安装包 wget http://mirrors.tuna.tsinghua.edu.cn/apache/flink/flink-1.6.1/flink-1.6.1-bin-hadoop27 ...

  5. linux系统搭建ftp服务器及创建用户使用

    linux 系统下搭建ftp服务器 ftp是什么 FTP是 File Transfer Protocol 文件传输协议的英文名称,用于在Internet上控制文件的双向传输. 同时它也是一个应用程序. ...

  6. ping 路由跟踪

    pathping: pathping ip地址/网址 C:\Users\Administrator>pathping 119.29.18.11 通过最多 30 个跃点跟踪到 119.29.18. ...

  7. 查找Command

    Find [路径] [匹配表达式] -name filename : 查找指定名称的文件 -user username: 查找属于指定用户的文件 -group grpname: 查找属于指定组的文件 ...

  8. JVM 源码分析(二):搭建 JDK 8 源码调试环境(Windows 上使用 CLion)

    前言 一.准备源码 二.安装 "Bootstrap JDK" 三.配置编译环境 四.编译与测试 五.安装 CMake 和 GDB 五.准备远程调试 六.开始远程调试 前言 上一篇文 ...

  9. LeetCode707 设计链表

    设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...

  10. 【Flutter】功能型组件之跨组件状态共享

    前言   在Flutter开发中,状态管理是一个永恒的话题.   一般的原则是:如果状态是组件私有的,则应该由组件自己管理:如果状态要跨组件共享,则该状态应该由各个组件共同的父元素来管理.   对于组 ...