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. 磁盘IO工作机制

    磁盘IO工作机制 ref: <深入分析java web 技术内幕> by:许令波 几种访问文件的方式 文件读取和写入的 IO 操作都是调用操作系统提供的接口,因为磁盘设备是由操作系统管理的 ...

  2. vue3系列:vue3.0自定义弹框组件V3Popup|vue3.x手机端弹框组件

    基于Vue3.0开发的轻量级手机端弹框组件V3Popup. 之前有分享一个vue2.x移动端弹框组件,今天给大家带来的是Vue3实现自定义弹框组件. V3Popup 基于vue3.x实现的移动端弹出框 ...

  3. SM4

    整体结构 T变换 SM4解密的合理性证明 秘钥扩展

  4. ubuntu安装nfs服务

    安装: sudo apt-get install nfs-kernel-server 修改配置文件 /etc/exports 增加以下内容: /NFS *(rw,sync,no_root_squash ...

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

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

  6. 如何解决git创建密匙时报错Too many arguments

    如题:git创建密匙时报错Too many arguments. 前几天我遇见了一个问题,git需要重新创建密匙,运行命令ssh-keygen -t rsa -b 4096 -C " you ...

  7. Linux 网卡 bonding配置

    网卡 bonding配置 目录 网卡 bonding配置 一.bonding技术 bonding的七种工作模式 总结: 二.Centos7配置bonding 1.关闭和停止NetworkManager ...

  8. git merge了错误分支,如何优雅的回退到merge前的状态?

    git merge了错误分支,如何优雅的回退到merge前的状态? 没push的话 git reset --hard (a分支5点那个时候commit之后的sha1) 然后重新 git merge

  9. Elastisearch在kibana下批量处理(mget和bulk)

    一.批量查询 有点:能够大大减少网络的请求次数,减少网络开销 1.自定义设置index.type以及document id,进行查询 GET /_mget { "docs":[ { ...

  10. CSS_rules

    CSS 特性 1)控制灵活,功能强大 元素-->标签 针对html的元素 2)可以设置html元素的属性,与html框架的进行分离 3)执行效率更高 CSS语法 text-indent 文字缩进 ...