HTTPS 数字签名 证书
HTTPS
先来看一下HTTPS的定义:
HTTPS(Hyper Text Transfer Protocol Secure)是一种经过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份验证,保护交换数据的隐私与完整性。
也就是说,HTTPS就是在HTTP协议的基础上加入了TLS协议。为什么用TLS协议而不是SSL协议呢?
TLS是传输层加密协议,前身是SSL协议。常用的TLS协议版本有: TLS1.2, TLS1.1, TLS1.0和SSL3.0。其中,SSL3.0已经被证实不安全,TLS1.0也存在部分安全漏洞。
HTTPS相对HTTP提供了更安全的数据传输保障,主要体现在三个方面:
(1)内容加密
客户端到服务器的内容都是以加密形式传输,中间者无法直接查看明文内容
(2)身份认证
通过校验保证客户端访问的是自己的服务器
(3)数据完整性
防止内容被第三方冒充或者篡改
SSL/TLS协议及握手过程
和TCP在建立连接时的三次握手一样,SSL/TLS也需要客户端和服务器之间进行握手,但是目的不一样。在SSL/TLS握手的过程中,客户端和服务器彼此交换并验证证书,并协商出一个"对话密钥",后续的所有通信都是用这个"对话密钥"进行加密,保证通信安全。
用一张图来简单的说明一下握手的过程:
为了提高安全性和效率,HTTPS结合了对称和非对称两种加密方式。客户端使用对称加密生成密钥key对传输数据进行加密,然后使用非对称加密的公钥对key再次加密。因此网络上传输的数据是被key加密的密文和用公钥加密后的密文key,即使被黑客截获,由于没有私钥便无法获取明文key,也就无法获取原始数据,因此HTTPS的加密方式是安全的。
以TLS1.2为例来认识HTTPS的握手过程:
(1)客户端发送client_hello,包含了一个随机数random1
(2)服务器回复server_hello,包含一个随机数random2,携带证书公钥P
(3)客户端拿到这个random2之后做两件事,第一件事是生成对称加密的密钥key,并用该密钥对要传输的数据加密;第二件事就是用公钥P对key加密,并将加密后的key和数据都发送给服务器
(4)服务器使用私钥得到key,并用key对数据加密,在相同的输入参数下能得到跟客户端传来的一样的数据。
在访问某些HTTPS站点时可能会遇到下面的异常:
javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这个异常就是HTTPS握手的过程中出现了问题。
数字证书
HTTPS通过对称加密和非对称加密实现数据的安全传输,在非对称加密的过程中需要用公钥来加密,这里的公钥实际上就被包含在数字证书中。
数字证书通常来说是由受信任的数字证书颁发机构CA,在验证了服务器身份后颁发,证书中包含了一个密钥对(公钥和私钥)和所有者识别信息。数字证书被放到服务器端,具有服务器身份验证和数据传输加密的功能。
来看一下证书的申请流程:
如果一个用户想要得到一份属于自己的证书,首先应该向CA提出申请。在CA判明申请者的身份之后,便为他分配一个公钥,并且将该公钥与申请者的身份信息绑在一起,并为之签字,便形成了数字证书发给申请者。
如果一个用户想要鉴别另一个证书的真伪,就用CA的公钥对那个证书上的签字进行验证。一旦验证通过,该证书就被认为是有效的。
通过这种方式,黑客就不能简单的修改证书中的公钥了,因为公钥有了CA的数字签名,由CA证明公钥的有效性,不能被轻易篡改。
CA证书具有层级结构,它建立了自上而下的信任链。下级CA信任上级CA,下级CA由上级CA颁发证书并认证。那么根证书由谁来验证呢?根证书自己证明自己,换句话说,根证书不需要被证明。根证书是整个证书链的安全之本,如果根证书被篡改,那么整个证书体系的安全将受到威胁。所以不要轻易相信根证书,当下次访问某个网站遇到提示说,请安装我们的根证书,最好留个心眼。
除了CA机构颁发的证书之外,还有非CA机构颁发的证书和自签名证书:
(1)非CA机构即不受信任的机构颁发的证书
(2)自签名证书,就是自己给自己颁发的证书
比如12306网站在首页都会标明:
为保障您顺畅购票,请下载安装根证书。
关于12306的安装根证书的问题,可以看网上的几篇博客:
在线买票为什么要安装根证书
12306的证书问题
浏览器验证证书
浏览器保存了一个常用的CA证书列表,在验证证书链的有效性时,直接使用保存的证书里的公钥进行校验。如果在证书列表中没有找到或者找到了但是校验不通过,那么浏览器会警告用户,由用户决定是否继续。
浏览器主要从三个方面验证证书,任何一个不满足都会给出警告:
(1)证书的颁发者是否在"根受信任的证书颁发机构列表"中
(2)证书是否过期
(3)证书的持有者是否和访问的网站一致
另外,浏览器还会定期查看证书颁发者公布的"证书吊销列表",如果某个证书符合上面的三个条件,但是被它的颁发者在"证书吊销列表"中列出,那么也将给出警告。Windows对这个列表是不敏感的,也就是说windows的api会缓存这个列表,直到设置的缓存过期才会再次去下载最新的列表。
操作系统验证证书
同样,操作系统也保存了一份可信的证书列表,可以运行certmgr.msc打开证书管理器查看,这些证书实际上是存储在Windows的注册表中,一般在\SOFTWARE\Microsoft\SystemCertificates\下。
JAVA验证证书
在Java平台下,证书常常被存储在KeyStore文件中,KeyStore不仅可以存储数字证书,还可以存储密钥。存储在KeyStore文件中的对象有三类:
Certificate: 证书
PrivateKey: 非对称加密中的私钥
SecretKey: 对称加密中的密钥
KeyStore文件根据用途有很多种不同的格式:JKS, JCEKS, PKCS12, DKS等等。
Java里的KeyStore文件分成两种类型:KeyStore和TrustStore,不过这两个从文件格式上来看是一样的。KeyStore保存私钥,用来加解密或为别人做签名。TrustStore保存一些可信任的证书,访问HTTPS时对被访问者进行认证,以确保它是可信任的。
除了KeyStore和TrustStore,Java还有两个类KeyManager和TrustManager与此相关。看下面一张图说明各个类之间的关系:
那么具体的编程就可以包括以下几个步骤:
(1)使用KeyStore类将证书库或信任库加载进来
(2)使用KeyManagerFactory和加载了证书库的KeyStore实例,生成KeyManager实例数组
(3)使用TrustManagerFactory和加载了信任库的KeyStore实例,生成TrustManager实例数组
(4)使用SSLContext初始化KeyManager实例数组和TrustManager实例数组,从而设定好通信的环境
(5)利用SSLContext产生的SSLSocket和SSLServerSocket进行通信
HTTPS单向认证
单向认证是指只要服务器配置证书,客户端在请求服务器时验证服务器的证书即可。上述讲到的内容大部分都是HTTPS单向认证,对于安全性要求不高的网站单向认证即可。
在Android系统中已经内置了所有CA机构的根证书,也就是说,只要是CA机构颁发的证书,Android是直接信任的。对于这种情况,虽然能正常访问到服务器,但是仍然存在安全隐患。如果黑客自家搭建了一个服务器并申请到了CA证书,那么黑客仍然能发起中间人攻击劫持我们的请求到黑客的服务器,实际上就成了我们的客户端和黑客的服务器建立起了连接。
对于非CA机构颁发的证书和自签名证书,我们是无法直接访问到服务器的,直接访问通常会抛出异常:
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor forcertification path not found.
有两种方法可以通过忽略证书直接调用:
方法一:自定义TrustManager绕过证书检查
@Test
public void basicHttpsGetIgnoreCertificateValidation() throws Exception { String url = "https://kyfw.12306.cn/otn/"; // Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// don't check
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// don't check
}
}
}; SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, trustAllCerts, null); LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(ctx); CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.build(); HttpGet request = new HttpGet(url);
request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) ..."); CloseableHttpResponse response = httpclient.execute(request);
String responseBody = readResponseBody(response);
System.out.println(responseBody);
}
方法二:信任所有证书
@Test
public void basicHttpsGetIgnoreCertificateValidation() throws Exception { SSLContextBuilder builder = new SSLContextBuilder();
//JAVA8支持的新语法
//TrustStrategy acceptingTrustStrategy = ((X509Certificate[] certificate,String type) -> true);
//builder.loadTrustMaterial(null, acceptingTrustStrategy); //上面这两步可以这么写:
builder.loadTrustMaterial(new TrustStrategy(){
@Override
public boolean isTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
return true;
}
}); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet("https://some-server");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
}
finally {
response.close();
}
}
方法二虽然解决了SSHHandshakeException异常,但是由于客户端信任所有的证书,反而存在更大的隐患。
单向验证且服务器证书可信
package com.ydd.study.hello.httpclient;
/**
* @COPYRIGHT (C) 2018 Schenker AG
* <p/>
* All rights reserved
*/ import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils; import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; public class oneWayAuthTest {
public static CloseableHttpClient httpclient; // 获得池化得HttpClient
static {
// 设置truststore
SSLContext sslcontext = null;
try {
sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File("D://https//ca//cl.jks"),
"123456".toCharArray(), new TrustSelfSignedStrategy())
.build();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 客户端支持TLSV1,TLSV2,TLSV3这三个版本
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext, new String[]{"TLSv1", "TLSv2", "TLSv3"}, null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());// 客户端验证服务器身份的策略 // Create a registry of custom connection socket factories for supported
// protocol schemes.
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(sslcontext))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
// Configure total max or per route limits for persistent connections
// that can be kept in the pool or leased by the connection manager.
connManager.setMaxTotal(100);
connManager.setDefaultMaxPerRoute(10);
// 个性化设置某个url的连接
connManager.setMaxPerRoute(new HttpRoute(new HttpHost("www.y.com",
80)), 20);
httpclient = HttpClients.custom().setConnectionManager(connManager)
.build(); } /**
* 单向验证且服务端的证书可信
* @throws IOException
* @throws ClientProtocolException
*/
public static void oneWayAuthorizationAccepted() throws ClientProtocolException, IOException {
// Execution context can be customized locally.
HttpClientContext context = HttpClientContext.create();
HttpGet httpget = new HttpGet("https://www.yunzhu.com:8443");
// 设置请求的配置
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(5000).setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).build();
httpget.setConfig(requestConfig); System.out.println("executing request " + httpget.getURI());
CloseableHttpResponse response = httpclient.execute(httpget, context);
try {
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
System.out.println("----------------------------------------"); // Once the request has been executed the local context can
// be used to examine updated state and various objects affected
// by the request execution. // Last executed request
context.getRequest();
// Execution route
context.getHttpRoute();
// Target auth state
context.getTargetAuthState();
// Proxy auth state
context.getTargetAuthState();
// Cookie origin
context.getCookieOrigin();
// Cookie spec used
context.getCookieSpec();
// User security token
context.getUserToken(); } catch (Exception e) {
e.printStackTrace();
} }
public static void main(String[] a) throws KeyManagementException,
NoSuchAlgorithmException, KeyStoreException, CertificateException,
IOException {
oneWayAuthorizationAccepted();
} }
HTTPS 数字签名 证书的更多相关文章
- https数字证书交换过程介绍
文章转自:https://www.2cto.com/kf/201804/739010.html,感谢原作者的辛苦整理,讲解的很清楚,谢谢. [https数字证书交换过程介绍] 注意:该问的背景用到了非 ...
- TLS、SSL、HTTPS以及证书
转自:http://www.cnblogs.com/kyrios/p/tls-and-certificates.html 最近在研究基于ssl的传输加密,涉及到了key和证书相关的话题,走了不少弯路, ...
- java获取https网站证书,附带调用https:webservice接口
一.java 获取https网站证书: 1.创建一个java工程,新建InstallCert类,将以下代码复制进去 package com; import java.io.BufferedReader ...
- 微信支付HTTPS服务器证书验证指引
1. 背景介绍 2. 常见问题 3. 验证证书 4. 安装证书 背景介绍 微信支付使用HTTPS来保证通信安全, 在HTTPS服务器上部署了由权威机构签发的证书, 用于证明微信支付平台的真实身份. 商 ...
- nginx安装Lets Encrypt SSL免费HTTPS加密证书
Linux Nginx网站:Certbot安装配置Lets Encrypt SSL免费HTTPS加密证书 原文地址:https://renwole.com/archives/157 实验环境:Cent ...
- Let's Encrypt 免费通配 https 签名证书 安装方法2 ,安卓签名无法认证!
Let's Encrypt 免费通配 https 签名证书 安装方法 按照上文 配置完毕后你会发现 在pc浏览器中正常访问,在手机浏览器中无法认证 你只需要安装一个或多个中级证书 1.查看Nginx ...
- mkcert本地 HTTPS 加密证书生成工具
软件介绍: mkcert 是一个生成本地 HTTPS 加密证书的工具,一个命令就可以生成证书,不需要任何配置. 下载地址: https://github.com/FiloSottile/mkcert/ ...
- Java访问HTTPS时证书验证问题
为了尽可能避免安全问题,公司的很多系统服务都逐步https化,虽然开始过程会遇到各种问题,但趋势不改.最完美的https应用是能实现双向认证,客户端用私钥签名用服务端公钥加密,服务端用私钥签名客户端都 ...
- 全球可信并且唯一免费的HTTPS(SSL)证书颁发机构:StartSSL
全球可信并且唯一免费的HTTPS(SSL)证书颁发机构:StartSSL http://blog.s135.com/startssl/ 购买权威机构的证书一年大概得七八千元,其实这是不值得的,所以一直 ...
随机推荐
- UINavigationController便于pop的category
UINavigationController便于pop的category 效果图: 这个category是为了方便UINavigationController用于跳转到指定的控制器当中,用于跳级,如果 ...
- django中的权限控制(form增删改)
Django默认提供了权限控制,但只能对使用了其自带的登录认证的用户进行权限控制,说白了就是只能对存储在auth_user表中的用户进行权限控制,但不能对未登录过的用户进行权限控制.但如果通过集成LD ...
- 安装oracle 11g时,报启动服务出现错误,找不到OracleMTSRecoveryService的解决方法
很多人在安装orcl数据库时,出现很多报错,我也不例外,因上次数据库出现问题,无法修复,只能从新安装,无奈的是,安装时报启动服务出现错误,找不到OracleMTSRecoveryService错MMP ...
- Http协议浅析
目录 Http协议浅析 http协议简介 http协议特性 http请求协议与响应协议 请求协议 响应协议 响应状态码 请求URI定位资源 HTTP方法 GET:获取资源 POST:传输实体主体 PU ...
- October 03rd 2017 Week 40th Tuesday
Don't make promises you can't keep. But those are the best kind. 不要许下做不到的承诺,但是我们做不到的承诺往往是最好的. The be ...
- 关于RSA、公钥、私钥、加密、签名的那些概念
前言 作为一名程序员,经常会听到加密解密之类的词.而非对称加密技术,应用的非常广泛.本文不写加密技术的原理,只是希望以一个简单的类比,让大家了解非对称加密中常见词的概念,以及它的作用. 介绍 在RSA ...
- PHP设计模式系列 - 策略模式
策略模式: 策略模式设计帮助构建的对象不必自身包含逻辑,而是能够根据需要利用其他对象中的算法. 使用场景: 例如有一个CD类,我们类存储了CD的信息. 原先的时候,我们在CD类中直接调用getCD方法 ...
- OpenStack虚拟机快照和增量备份实现
1 快照的概念一般对快照的理解就是能够将系统还原到某个瞬间,这就是快照的作用.快照针对要保存的数据分为内存快照和磁盘快照,内存快照就是保存当前内存的数据,磁盘快照就是保存硬盘的数据.快照针对保存方式又 ...
- 我的开源项目——Jerry
在日常工作中,经常会碰到一些问题,比如数字金额要写成千分位形式(1234 -> 123,4.00).要写成汉字大写形式(123 -> 壹佰贰拾叁圆),又比如要进行 cookie 读写操作, ...
- Hadoop学习之路(一)理论基础和逻辑思维
三个题目 第一题 问题描述 统计出当前这个一行一个IP的文件中,到底哪个IP出现的次数最多 解决思路 //必须要能读取这个内容 BufferedReader br = new BuffedReader ...