1. 单向认证和双向认证的区别
一般web应用都是采用单向认证的,原因很简单,用户数目广泛,且无需做在通讯层做用户身份验证,一般都在应用逻辑层来保证用户的合法登入。
但如果是企业应用对接,情况就不一样,可能会要求对client(相对而言)做身份验证。这时需要做双向认证。
2. SSL安全证书包括:
CA证书,也叫根证书或中间级证书。单向认证的https,CA证书是可选的。主要目的是使证书构成一个证书链,以达到浏览器信任证书的目的。如果使用了CA证书,服务器证书和客户证书都使用CA证书来签名。如果不安装CA证书,浏览器默认认为是不安全的。
服务器证书。必选。通过服务器私钥,生成证书请求文件CSR,再通过CA证书签名生成服务器证书。
客户证书。可选。如果有客户证书,就是双向认证的HTTPS,否则就是单向认证的HTTPS。生成步骤和服务器证书类似。
上面几种证书都可以自己生成。商业上,一般自己提供服务器或客户证书端的私钥和证书请求CSR,向第三方机构付费申请得到通过CA证书签名的服务器证书和客户证书。
为什么需要CA认证,因为如果不进行CA认证,第三方攻击可以伪装,无法确认服务器的身份,百度、阿里、google走了https,进行了CA认证,就相当于公民去公安局办理了身份证,进行了登记,如果验证身份证的合法性时,可以看签发机关,以及根据签发号向公安机关核对真实性,这是一个道理,就是走了https的向CA机构进行登记。
3. 自定义证书
CA证书是大家都公认的机构颁发的,像:百度、阿里、Google使用的https就是通过CA认证的,如果不进行CA认证,也可以自定义证书。 jdk中提供了生成自定义证书的工具:如下,就是生成自定义证书的命令:关键字解释:
keytool -genkey -keyalg RSA -dname "cn=118.144.155.21,ou=inspur,o=none,l=beijing,st=chaoyang,c=cn" -alias server -keypass 111111 -keystore server.keystore -storepass 111111 -validity 3650
-genkeypair:生成一对非对称密钥。-alias:指定密钥对的别名,该别名是公开的。-keyalg:指定加密算法,本例中的采用通用的RAS加密算法
keypass 为密码
-keystore 代表证书存储位置和名称,以上命令是当前目录存储
OU 表示组织单位名称
O 表示组织名称
L 您所在城市或区域
ST 表示省份或州
c 表示国家代码
4. 什么是CA认证,为什么要CA认证?
自定义的证书没给第三方认证,肯定弹warn, 于是出现如下图:
如果继续前往:
如果是通过CA认证的,显示如下:
5. 自定义证书如何显示如上呢?
需要通过JDK命令生成自定义证书,导入到浏览器中,浏览器认为是一个受信任的证书,所以需要安装证书: 即可:
keytool -export -alias server -keystore server.keystore -file ca.cer -storepass 111111
这个ca.cer是为了解决不信任时要导入的
如果导入了,就会产生如上绿色安全锁标志
6. SSL 认证通信的步骤:
① 客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。
② 服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。
③ 客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过,通讯将断开;如果合法性验证通过,将继续进行第四步。
④ 用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。
⑤ 如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。
⑥ 如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行 CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。
⑦ 服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。
⑧ 客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
⑨ 服务器向客户端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
⑩ SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。
上面所述的是双向认证 SSL 协议的具体通讯过程,这种情况要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的(这并不影响 SSL 过程的安全性)密码方案。 这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用 128 位加密通讯的原因。
以上已经生成了认证,而且说明了认证的理论,下面谈谈实际应用操作:
7. tomcat中配置 ssl
打开 server.xml 文件,修改配置为:
其中: keystoreFile代表了生成认证文件的存放地址:
8. 服务器端进行访问认证:
public class HttpHandle { // server ip request base url private static final String BASE_URL = "https://118.144.155.21:8443/api/v1/accounts/"; private static final String USERS = "/users/"; private static final String SLASH = "/"; private static final String SIGN = "?sign="; private static final String VALIDATE = "/validate"; /** * assemble //http://127.0.0.1:8080/api/v1/accounts/10/users/3/validate?sign=3E50C44AAC99B222072A08EF2AD938F6 * @param sign use secret and MD5 generate * @param accountId account id * @param userId user id * @return response infomation */ public static String validateSecret(String sign, String accountId, String userId) { String targetUrl = BASE_URL + accountId + USERS + userId + VALIDATE; //System.out.println("target url:"+targetUrl); URL url = null; HttpsURLConnection connection = null; String params = "sign=" +sign; try { // Create connection url = new URL(targetUrl); connection = (HttpsURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("Content-Length", "" + Integer.toString(params.getBytes().length)); connection.setRequestProperty("Content-Language", "en-US"); connection.setConnectTimeout(1*1000); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); // Send request// OutputStream os = connection.getOutputStream();// BufferedWriter writer = new BufferedWriter(// new OutputStreamWriter(os, "UTF-8"));// writer.write(URLEncoder.encode(params, "UTF-8")// );//// writer.flush();// writer.close();// os.close(); DataOutputStream wr = new DataOutputStream( connection.getOutputStream()); wr.writeBytes(params); wr.flush(); wr.close(); // Get Response int responseCode=connection.getResponseCode(); // the normal response http return 200 if (responseCode == HttpsURLConnection.HTTP_OK){ InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); String line; StringBuffer response = new StringBuffer(); while ((line = rd.readLine()) != null) { response.append(line); response.append('\r'); } rd.close(); String responseStr = response.toString(); return responseStr; }else{ return new String("false : "+responseCode); } } catch (Exception e) { e.printStackTrace(); return new String("Exception: " + e.getMessage()); } finally { if (connection != null) { connection.disconnect(); } } } /** * this is a single test methon * @param args no args * @throws Exception connection http will occur exception */ public static void main(String[] args) throws Exception { String key ="583590FF9FCED6A333099981CA6C5BE5D716E85A5918F9AD927B404C4C8E205D60E47A09CF5C8FCCF86AE6AF4F2A2327A2ECD83FAA77D654071BCBFC8B6A1648D75F965F5DCD7F2EC2EC615BDCEC18121D0F0A92AE9F9EEE4783E4228E86C06CF6DC74B6B1C0A6788EA49181C4A5EA6106DCF95DCFA7ED4DC8F405D0FDF0C34F"; TreeMap
其中有一段代码是不进行验证的,因为当用浏览器访问的时候,会弹出是不安全的链接(因为是自定义证书没有进行认证,所以浏览器会提示是不安全的链接,点击继续可以继续访问,如果消除这个提示,需要在浏览器中导入自定义的证书即可,以上有说明:在代码中如果不需要验证,需要把验证disable掉,代码如下:)
这段代码为:参考文章
显示结果如下:
如果去掉以上代码会出现如下异常:
以上就是在程序端或者浏览器端进行https的整个过程。
参考
- 重要参考
- 破解Gmail的新方式
- 12306为什么需要根证书
- 通过生成自定义证书,在程序中指定进行Https测试
- https单双向认证
- 单双向认证
- https原理
7.https原理介绍