http与https
HTTP
HTTP(HyperText Transfer Protocol,超文本传输协议),是因特网应用最广的协议。
原生的HTTP通信存在如下风险:
- 窃听风险:第三方可以获取通信内容。
- 篡改风险:第三方可以修改通信内容。
- 冒充风险:第三方可以冒充他人身份参与通信。
HTTPS = HTTP+ SSL /TLS
HTTPS是使用HTTP协议和SSL连接构建的可进行加密传输、身份认证的网络协议。
SSL/TLS协议就是为了解决HTTP三大风险而设计的,希望达到:
- 所有信息都是加密传输,第三方无法窃听。
- 具有校验机制,一旦被篡改,通信双方会立刻发现。
- 配备身份证书,防止身份被冒充。
SSL/TLS握手过程
- 客户端发出请求(ClientHello),向服务器提供以下信息:
- 支持的协议版本
- 客户端生成的随机数(用于生成对话密钥)
- 支持的加密方法
- 支持的压缩方法
- 服务器发出回应(ServerHello),向客户端回应以下内容:
- 确认使用的加密通信协议版本
- 服务器生成的随机数(用于生成对话密钥)
- 确认使用的加密方法
- 服务器证书
- 客户端收到服务器回应,首先验证证书,没有问题则从证书中取出服务器公钥,然后向服务器发送以下内容:
- 一个随机数(用于服务器公钥加密)
- 编码改变通知,表示随后的消息都将用双方商定的加密方法和密钥发送
- 客户端握手结束通知,表示客户端的握手阶段已经结束(这一项是前面发送的所有内容的hash值,用于供服务器校验)
- 服务器收到第三个随机数之后,使用协商的加密算法计算出本地会话密钥,然后向客户端发送以下信息:
- 编码改变通知,表示随后的信息都将采用双方商定的加密方法和密钥发送。
- 服务器握手结束通知,表示服务器的握手阶段已经结束。(这一项也是前面发送的所有内容的hash值,用于供客户端校验)
注意:生成会话密钥使用的是非对称加密,会话过程使用的是对称加密。 前者保证计算出的密钥的安全性,后者侧重通信过程中加解密的性能。
CA证书
CA是证书的签发机构,是PKI的核心。
作为负责签发证书、认证证书和管理证书的机关,它要制定政策和具体步骤来验证、识别用户身份,并对用户证书进行签名,以确保证书持有者的身份和公钥的拥有权。
存在的意义:假设不存在认证机构,任何人都可以制作证书,这带来的安全风险便是经典的中间人攻击问题。
CA架构
包含信息
- 颁发机构信息
- 公钥
- 公司信息
- 域名
- 有效期
- 指纹
浏览器验证证书的合法性
- 验证域名和有效期是否正确;
- 判断证书来源是否合法;
- 判断证书是否被篡改;
- 判断证书是否已吊销。
项目准备
使用maven构建项目,使用Tomcat作为服务器:
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.boot.version>2.2.2.RELEASE</spring.boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
生成证书
借助jdk工具:
keytool -genkey
-alias <name>(别名)
-keypass <key_password>(别名密码)
-keyalg <algorithm>(生证书的算法名称,RSA是一种非对称加密算法)
-keysize <size>(密钥长度,证书大小)
-validity <days>(证书有效期,天单位)
-keystore <file_path>(指定生成证书的位置和证书名称)
-storepass <store_password>(获取keystore信息的密码)
- storetype (指定密钥仓库类型)
例如:
> keytool -genkey -alias tomcat -keypass KAG1823 -keyalg RSA -keysize 1024 -validity 365 -keystore K:/tomcat.keystore -storepass KAG1823 -storetype PKCS12
您的名字与姓氏是什么?
[Unknown]: Khighness
您的组织单位名称是什么?
[Unknown]: parak.top
您的组织名称是什么?
[Unknown]: parak
您所在的城市或区域名称是什么?
[Unknown]: Wuhan
您所在的省/市/自治区名称是什么?
[Unknown]: Hubei
该单位的双字母国家/地区代码是什么?
[Unknown]: zh
CN=Khighness, OU=parak.top, O=parak, L=Wuhan, ST=Hubei, C=zh是否正确?
[否]: y
将生成的文件放在resources下面。
项目配置
application.properties
# Server
server.port=11111
server.http-port=22222
spring.application.name=springboot-https
# KeyStore
server.ssl.enabled=true
server.ssl.key-store=classpath:tomcat.keystore
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat
server.ssl.key-store-password=KAG1823
项目编码
HttpsConfiguration
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author KHighness
* @since 2021-04-05
* @apiNote http强制跳转https
*/
@Configuration
public class HttpsConfiguration {
@Value("${server.port}")
private Integer sslPort;
@Value("${server.http-port}")
private Integer httpPort;
@Bean
public TomcatServletWebServerFactory servletWebServerFactory() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
// 设置安全性约束
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
// 设置约束条件
SecurityCollection collection = new SecurityCollection();
// 拦截所有请求
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
// 设置将分配给通过此连接器接收到的请求的方案
connector.setScheme("http");
// true: http使用http, https使用https
// false:http重定向到https
connector.setSecure(false);
// 设置监听请求的端口号
connector.setPort(httpPort);
// 重定向端口号(非SSL到SSL)
connector.setRedirectPort(sslPort);
tomcat.addAdditionalTomcatConnectors(connector);
return tomcat;
}
}
CommonController
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @author KHighness
* @since 2021-04-05
*/
@RestController
public class CommonController {
@GetMapping("/hello/{name}")
public String index(@PathVariable("name") String name) {
return "Hello, " + name;
}
}
KHighnessApplication
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author KHighness
* @since 2021-04-05
*/
@SpringBootApplication
public class KHighnessApplication {
public static void main(String[] args) {
SpringApplication.run(KHighnessApplication.class, args);
}
}
运行测试
打开浏览器,输入:http://localhost:22222/hello/Khighness
一般会提示非安全连接,忽略即可。
直接前往,重定向:https://localhost:11111/hello/Khighness