Java实现SSL双向认证的方法

本文实例讲述了Java实现SSL双向认证的方法。分享给大家供大家参考,具体如下:

我们常见的SSL验证较多的只是验证我们的服务器是否是真实正确的,当然如果你访问的URL压根就错了,那谁也没有办法。这个就是所谓的SSL单向认证。

但是实际中,我们有可能还会验证客户端是否符合要求,也就是给我们每个用户颁发一个证书,比且每个数字证书都是唯一的,不公开的。这样就能通过这个数字证书保证当前访问我服务器的这个用户是经过服务器认可的,其他人不可访问。

双向认证 从第一个层面上 确保了服务器 与客户端 都是互相认可的。那么他们之间要进行通信,就会在通信协议上附加SSL协议,确保通信的内容是加密的,即使是sniffer这样的网络嗅探工具看到的都是乱码。以后给大家演示下不加密的情况下,用sniffer看到的是什么。恐怕这样你就能提高警惕了。

以下内容从网络上摘抄 加以实际验证后修改的。

模拟场景:

Server端和Client端通信,需要进行授权和身份的验证,即Client只能接受Server的消息,Server只能接受Client的消息。

实现技术:

JSSE(Java Security Socket Extension)

是Sun为了解决在Internet上的安全通讯而推出的解决方案。它实现了SSL和TSL(传输层安全)协议。在JSSE中包含了数据加密,服务器验证,消息完整性和客户端验证等技术。通过使用JSSE,开发人员可以在客户机和服务器之间通过TCP/IP协议安全地传输数据。

为了实现消息认证。

Server需要:

1)KeyStore: 其中保存服务端的私钥
2)Trust KeyStore:其中保存客户端的授权证书

同样,Client需要:

1)KeyStore:其中保存客户端的私钥
2)Trust KeyStore:其中保存服务端的授权证书
在这里我还是推荐使用Java自带的keytool命令,去生成这样信息文件。当然目前非常流行的开源的生成SSL证书的还有OpenSSL。OpenSSL用C语言编写,跨系统。但是我们可能在以后的过程中用java程序生成证书的方便性考虑,还是用JDK自带的keytool。

1)生成服务端私钥,并且导入到服务端KeyStore文件中

keytool -genkey -alias serverkey -keystore kserver.keystore
过程中,分别需要填写,根据需求自己设置就行

keystore密码:123456
名字和姓氏:jin
组织单位名称:none
组织名称:none
城市或区域名称:BJ
州或省份名称:BJ
国家代码:CN

serverkey私钥的密码,不填写和keystore的密码一致。这里千万注意,直接回车就行了,不用修改密码。否则在后面的程序中以及无法直接应用这个私钥,会报错。

就可以生成kserver.keystore文件

server.keystore是给服务端用的,其中保存着自己的私钥

2)根据私钥,导出服务端证书

keytool -export -alias serverkey -keystore kserver.keystore -file server.crt
server.crt就是服务端的证书

3)将服务端证书,导入到客户端的Trust KeyStore中

keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
tclient.keystore是给客户端用的,其中保存着受信任的证书

采用同样的方法,生成客户端的私钥,客户端的证书,并且导入到服务端的Trust KeyStore中

1)keytool -genkey -alias clientkey -keystore kclient.keystore
2)keytool -export -alias clientkey -keystore kclient.keystore -file client.crt
3)keytool -import -alias clientkey -file client.crt -keystore tserver.keystore

如此一来,生成的文件分成两组

服务端保存:kserver.keystore tserver.keystore
客户端保存:kclient.keystore  tclient.kyestore

以下是通过Java Socket通信程序来验证我们生成的证书是否可用。

客户端:

package examples.ssl;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
/**
 * SSL Client
 *
 */
public class SSLClient {
 private static final String DEFAULT_HOST     = "127.0.0.1";
 private static final int DEFAULT_PORT     = 7777;
 private static final String CLIENT_KEY_STORE_PASSWORD  = "123456";
 private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
 private SSLSocket   sslSocket;
 /**
  * 启动客户端程序
  *
  * @param args
  */
 public static void main(String[] args) {
  SSLClient client = new SSLClient();
  client.init();
  client.process();
 }
 /**
  * 通过ssl socket与服务端进行连接,并且发送一个消息
  */
 public void process() {
  if (sslSocket == null) {
   System.out.println("ERROR");
   return;
  }
  try {
   InputStream input = sslSocket.getInputStream();
   OutputStream output = sslSocket.getOutputStream();
   BufferedInputStream bis = new BufferedInputStream(input);
   BufferedOutputStream bos = new BufferedOutputStream(output);
   bos.write("Client Message".getBytes());
   bos.flush();
   byte[] buffer = new byte[20];
   bis.read(buffer);
   System.out.println(new String(buffer));
   sslSocket.close();
  } catch (IOException e) {
   System.out.println(e);
  }
 }
 /**
  * <ul>
  * <li>ssl连接的重点:</li>
  * <li>初始化SSLSocket</li>
  * <li>导入客户端私钥KeyStore,导入客户端受信任的KeyStore(服务端的证书)</li>
  * </ul>
  */
 public void init() {
  try {
   SSLContext ctx = SSLContext.getInstance("SSL");
   KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
   TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
   KeyStore ks = KeyStore.getInstance("JKS");
   KeyStore tks = KeyStore.getInstance("JKS");
   ks.load(new FileInputStream("E://kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
   tks.load(new FileInputStream("E://tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
   kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
   tmf.init(tks);
   ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
   sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket(DEFAULT_HOST, DEFAULT_PORT);
  } catch (Exception e) {
   System.out.println(e);
  }
 }
}

服务器端:

package examples.ssl;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory;
/***********************************************************************************************************************
 * <ul>
 * <li>1)生成服务端私钥</li>
 * <li>keytool -genkey -alias serverkey -keystore kserver.keystore</li>
 * <li>2)根据私钥,到处服务端证书</li>
 * <li>keytool -exoport -alias serverkey -keystore kserver.keystore -file server.crt</li>
 * <li>3)把证书加入到客户端受信任的keystore中</li>
 * <li>keytool -import -alias serverkey -file server.crt -keystore tclient.keystore</li>
 * </ul>
 **********************************************************************************************************************/
/**
 * SSL Server
 *
 */
public class SSLServer {
 private static final int DEFAULT_PORT     = 7777;
 private static final String SERVER_KEY_STORE_PASSWORD  = "123456";
 private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "123456";
 private SSLServerSocket  serverSocket;
 /**
  * 启动程序
  *
  * @param args
  */
 public static void main(String[] args) {
  SSLServer server = new SSLServer();
  server.init();
  server.start();
 }
 /**
  * <ul>
  * <li>听SSL Server Socket</li>
  * <li> 由于该程序不是演示Socket监听,所以简单采用单线程形式,并且仅仅接受客户端的消息,并且返回客户端指定消息</li>
  * </ul>
  */
 public void start() {
  if (serverSocket == null) {
   System.out.println("ERROR");
   return;
  }
  while (true) {
   try {
    Socket s = serverSocket.accept();
    InputStream input = s.getInputStream();
    OutputStream output = s.getOutputStream();
    BufferedInputStream bis = new BufferedInputStream(input);
    BufferedOutputStream bos = new BufferedOutputStream(output);
    byte[] buffer = new byte[20];
    bis.read(buffer);
    System.out.println(new String(buffer));
    bos.write("Server Echo".getBytes());
    bos.flush();
    s.close();
   } catch (Exception e) {
    System.out.println(e);
   }
  }
 }
 /**
  * <ul>
  * <li>ssl连接的重点:</li>
  * <li>初始化SSLServerSocket</li>
  * <li>导入服务端私钥KeyStore,导入服务端受信任的KeyStore(客户端的证书)</li>
  * </ul>
  */
 public void init() {
  try {
   SSLContext ctx = SSLContext.getInstance("SSL");
   KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
   TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
   KeyStore ks = KeyStore.getInstance("JKS");
   KeyStore tks = KeyStore.getInstance("JKS");
   ks.load(new FileInputStream("E://kserver.keystore"), SERVER_KEY_STORE_PASSWORD.toCharArray());
   tks.load(new FileInputStream("E://tserver.keystore"), SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
   kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
   tmf.init(tks);
   ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
   serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(DEFAULT_PORT);
   serverSocket.setNeedClientAuth(true);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

更多关于java相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

(0)

相关推荐

  • php curl常见错误:SSL错误、bool(false)

    症状:php curl调用https出错 排查方法:在命令行中使用curl调用试试. 原因:服务器所在机房无法验证SSL证书. 解决办法:跳过SSL证书检查. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 症状:php curl调用curl_exec返回bool(false),命令行curl调用正常. 排查方法: var_dump(curl_error($ch)); 返回: string(23) "Empty reply from server

  • windows服务器中检测PHP SSL是否开启以及开启SSL的方法

    一.检测服务器是否开启了SSL 复制代码 代码如下: <?phpphpinfo();?> 检查页面的openssl栏目,如果该栏目的OpenSSL support的值为enabled就说明SSL处于开启状态了,否则是关闭状态. 二.开启SSL的方法 1. 打开php.ini  把:extension=php_openssl.dll把前面的符号去掉.2. 重新启动 apache 或 iis ,重新检查 SSL 开启状态.如果以上操作无效的话,则还需要进行下一步操作(这一步在很多情况下不是必须的,

  • Tomcat ssl报错Connector attribute SSLCertificateFile must be defined when using SSL with APR解决方法

    今天同事要求帮忙配置tomcat ssl,直接把linux下tomcat配置ssl这篇文章发给他了,没想到他居然说启动tomcat的时候,报Connector attribute SSLCertificateFile must be defined when using SSL with APR的错误,马上跑过去看,原来他的tomcat版本是7.0的,我发给他的是tomcat6的,检查了key,检查了配置文件,因为他直接复制的我发他文章的配置,折腾了2-3个小时,终于把问题给解决了. 系统:wi

  • 给APACHE开启SSL服务

    1.首先请确认您的Apache服务器已经安装有加密模块,可以是OpenSSL,或是OpenSSL+ModSSL. 如果您的Apache web服务器安装在Unix或linux平台上,您可以通过以下网址获得OpenSSL: http://www.openssl.org/source/ 如果您的Apache web服务器运行在Windows平台上,您可以通过以下网址获得OpenSSL + ModSSL: http://www.modssl.org/contrib/ 2.通过OpenSSL给Apach

  • nginx环境下配置ssl加密(单双向认证、部分https)

    nginx下配置ssl本来是很简单的,无论是去认证中心买SSL安全证书还是自签署证书,但最近公司OA的一个需求,得以有个机会实际折腾一番.一开始采用的是全站加密,所有访问http:80的请求强制转换(rewrite)到https,后来自动化测试结果说响应速度太慢,https比http慢慢30倍,心想怎么可能,鬼知道他们怎么测的.所以就试了一下部分页面https(不能只针对某类动态请求才加密)和双向认证.下面分节介绍. 默认nginx是没有安装ssl模块的,需要编译安装nginx时加入--with

  • Nginx 下配置SSL证书的方法

    1.Nginx 配置 ssl 模块 默认 Nginx 是没有 ssl 模块的,而我的 VPS 默认装的是 Nginx 0.7.63 ,顺带把 Nginx 升级到 0.7.64 并且 配置 ssl 模块方法如下: 下载 Nginx 0.7.64 版本,解压 进入解压目录: 复制代码 代码如下: wget http://sysoev.ru/nginx/nginx-0.7.64.tar.gz tar zxvf nginx-0.7.64.tar.gz cd nginx-0.7.64 如果要更改heade

  • Apache SSL服务器配置SSL详解

    1.安装必要的软件 引用 我用的是apahce2.0.61版,可以直接官方提供的绑定openssl的apache. 文件名是:apache_2.0.61-win32-x86-openssl-0.9.7m.msi 否则单独安装windows下的openssl比较麻烦,要么找到一个第三方的编译结果,要么自己编译 2. 生成服务器证书 引用 安装好在bin目录下有一个 openssl.exe文件,用来生成证书和密钥. 1). 生成服务器用的私钥文件server.key 进入conf目录,执行命令行 o

  • 利用keytools为tomcat 7配置ssl双向认证的方法

    SSL简单介绍 SSL(Secure Sockets Layer 安全套接层)就是一种协议(规范),用于保障客户端和服务器端通信的安全,以免通信时传输的信息被窃取或者修改. 1.怎样保障数据传输安全? 客户端和服务器端在进行握手(客户端和服务器建立连接和交换参数的过程称之为握手)时会产生一个"对话密钥"(session key),用来加密接下来的数据传输,解密时也是用的这个"对话密钥",而这个"对话密钥"只有客户端和服务器端知道.也就是说只要这个

  • Nginx服务器中关于SSL的安全配置详解

    本文向你们展示如何在nginx的web服务器上设置更强的SSL.我们是通过使SSL无效来减弱CRIME攻击的这种方法实现.不使用在协议中易受攻击的SSLv3以及以下版本并且我们会设置一个更强的密码套件为了在可能的情况下能够实现Forward Secrecy,同时我们还启用HSTS和HPKP.这样我们就有了一个更强.不过时的SSL配置并且我们在Qually Labs SSL 测试中得到了A等级. 我们在nginx的设置文档中如下编辑 复制代码 代码如下: /etc/nginx/sited-enab

  • Java实现SSL双向认证的方法

    本文实例讲述了Java实现SSL双向认证的方法.分享给大家供大家参考,具体如下: 我们常见的SSL验证较多的只是验证我们的服务器是否是真实正确的,当然如果你访问的URL压根就错了,那谁也没有办法.这个就是所谓的SSL单向认证. 但是实际中,我们有可能还会验证客户端是否符合要求,也就是给我们每个用户颁发一个证书,比且每个数字证书都是唯一的,不公开的.这样就能通过这个数字证书保证当前访问我服务器的这个用户是经过服务器认可的,其他人不可访问. 双向认证 从第一个层面上 确保了服务器 与客户端 都是互相

  • Java实现基于token认证的方法示例

    随着互联网的不断发展,技术的迭代也非常之快.我们的用户认证也从刚开始的用户名密码转变到基于cookie的session认证,然而到了今天,这种认证已经不能满足与我们的业务需求了(分布式,微服务).我们采用了另外一种认证方式:基于token的认证. 一.与cookie相比较的优势: 1.支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的: 2.无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的

  • nginx配置ssl双向验证的方法

    1.安装nginx略 http://www.jb51.net/article/49479.htm 2.使用openssl实现证书中心 由于是使用openssl架设私有证书中心,因此要保证以下字段在证书中心的证书.服务端证书.客户端证书中都相同 Country Name State or Province Name Locality Name Organization Name Organizational Unit Name 编辑证书中心配置文件 vim /etc/pki/tls/openssl

  • 详解Nginx SSL快速双向认证配置(脚本)

    目前遇到一个项目有安全性要求,要求只有个别用户有权限访问.本着能用配置解决就绝不用代码解决的原则,在Nginx上做一下限制和修改即可. 这种需求其实实现方式很多,经过综合评估考虑,觉得SSL双向认证方案对用户使用最简单,遂决定用此方案. 注: 本方案在Ubuntu Server 16.04 LTS实施,其他操作系统请酌情修改 SSL双向认证 绝大多数SSL应用都以单向认证为主,即客户端只要信任服务端,就可以使用服务端的公钥加密后向服务端发起请求,由服务端的私钥解密之后获得请求数据. 如果这个过程

  • Java使用JDBC实现Oracle用户认证的方法详解

    本文实例讲述了Java使用JDBC实现Oracle用户认证的方法.分享给大家供大家参考,具体如下: 两天时间写的小品,以前的J2EE环境基本使用框架.现在使用JDBC配合Oracle存储过程模拟了一下用户注册和用户认证. 一.添加必须的jar包 需要JDBC连接Oracle的包和shiro-core依赖,添加shiro-core主要为了方便使用SHA-256散列算法. 二.编写JDBC连接 import java.sql.Connection; import java.sql.DriverMan

  • Nginx+SSL实现双向认证的示例代码

    首先创建一个目录 cd /etc/nginx mkdir ssl cd ssl CA与自签名 制作CA私钥 openssl genrsa -out ca.key 2048 制作 CA 根证书(公钥) openssl req -new -x509 -days 3650 -key ca.key -out ca.crt 注意: 1.Common Name 可以随意填写 2.其他需要填写的信息为了避免有误,都填写 . 吧 服务器端证书 制作服务器端私钥: openssl genrsa -out serv

  • Openssl实现双向认证教程(附服务端客户端代码)

    一.背景说明 1.1 面临问题 最近一份产品检测报告建议使用基于pki的认证方式,由于产品已实现https,商量之下认为其意思是使用双向认证以处理中间人形式攻击. <信息安全工程>中接触过双向认证,但有两个问题. 第一个是当时最终的课程设计客户端是浏览器,服务端是tomcat双向认证只需要对两者进行配置并不需要自己真的实现代码. 第二个是虽然课程也有接近双向认证的实现代码,但当时是Java+JCE环境现在要用C+++OpenSSL环境,总体意思确实还是差不多但具体函数和参数差别还是不少. 所以

  • 使用Nginx实现HTTPS双向验证的方法

    https单向验证应用广泛想必大家都很熟悉,我已经在一篇博文中分享过,这次来看看Nginx如何实现双向验证. 单向验证与双向验证的区别: 单向验证: 指客户端验证服务器端证书,服务器并不需要验证客户端证书. 双向验证:指客户端验证服务器端证书,而服务器也需要通过CA的公钥证书来验证客户端证书. 详细的握手过程: 单向验证 浏览器发送一个连接请求给安全服务器. 1.服务器将自己的证书,以及同证书相关的信息发送给客户浏览器. 2.客户浏览器检查服务器送过来的证书是否是由自己信赖的CA中心所签发的.如

随机推荐