知识大全 用J2SE1.4进行Internet安全编程
Posted 知
篇首语:志不强者智不达,言不信者行不果。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 用J2SE1.4进行Internet安全编程相关的知识,希望对你有一定的参考价值。
用J2SE1.4进行Internet安全编程 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
服务器端任何在计算机网络或者 Internet 中传输的消息都可能被拦截 其中不乏一些比较敏感的内容 如信用卡号或者其它一些私人数据 为了更好的在企业环境和电子商务中使用 Internet 应用软件必须使用加 密 验证和安全的通信协议来保护用户的数据安全 安全超文本传输协议 (secure Hypertext Transfer Protocol HTTPS) 是建立于安全套接层 (Secure Sockets Layer SSL) 上的 HTTP 它已经成功的应用于电子商务
Java 安全套接扩展 (Java Secure Socket Extension JSSE) 使 Internet 安全通信成为现实 它是 % 纯 Java 实现的 SSL 框架 这个包让 Java 开发人员能够开发安全的网络应用 为基于 TCP/IP 的何应用协议 如 HTTP FTP Telnet 或者 NTTP 在客户端和服务器端之间建立安全的数据通道
JSSE 已经整合在 Java SDK 标准版本 (J SE ) 中了 这真是一个好消息 这意味着只要你安装了 J SE 不需要再下载其它的包 就可以创建基于 SSL 的 Internet 应用程序了 这个系列的文章共有 篇 它是一本关于为今后的市场开发安全 Interent 应用的手册 这篇文章主要是讲的服务器端 而下一篇是讲客户端的 这篇文章从概览 SSL 开始 然后告诉你如何进行下列内容
使用 JSSE 的 API
在你的 C/S 应用程序中结合 JSSE
开发一个简单的 HTTP 服务器
让 HTTP 服务器能够处理 HTTPS 请求
使用包含在 J SE 中的 keytool 产生自己的证书
开发 配置和运行一个安全的 HTTP 服务器
概览 SSL
SSL 协议是 Netscape 在 年开发出来的 以允许服务端 (典型的如浏览器) 和 HTTP 服务器之间能通过安全的连接来通信 它加密 来源验证 数据完整性等支持 以保护在不安全的公众网络上交换的数据 SSL 有这样一些版本 SSL 有安全隐患 现在已经几本上不用了 SSL 应用则比较广泛 最后 由 SSL 改进而来的传输层加密 (Transport Layer Security TLS) 已经成为 Internet 标准并应用于几乎所有新近的软件中
在数据传播之前 加密技术通过将数据转变成看起来毫无意义的内容来保护数据不被非法使用 其过程是 数据在一端 (客户端或者服务器端) 被加密 传输 再在另一端解密
来源认证是验证数据发送者身份的一种办法 浏览器或者其它客户端第一次尝试与网页服务器进行安全连接之上的通信时 服务器会将一套信任信息以证书的形式呈现出来
证书由权威认证机构 (CA)——值得信赖的授权者发行和验证 一个证书描述一个人的公钥 一个签名的文档会作出如下保证 我证明文档中的这个公钥属于在该文档中命名的实体 签名(权威认证机构) 目前知名的权威认证机构有 Verisign Entrust 和 Thawte 等 注意现在使用的 SSL/TLS 证书是 X 证书
数据完整性就是要确保数据在传输过程中没有被改变
SSL 和 TCP/IP 协议的层次
SSL 是名符其实的安全套接层 它的连接动作和 TCP 的连接类似 因此 你可以想象 SSL 连接就是安全的 TCP 连接 因为在协议层次图中 SSL 的位置正好在 TCP 之上而在应用层之下 如图 所示 注意到这点很重要 但是 SSL 不支持某些 TCP 的特性 比如频带外数据
图 SSL 和 TCP/IP 协议的的层次
可交流的加密技术
SSL 的特性之一是为电子商务的事务提供可交流的加密技术和验证算法提供标准的方法 SSL 的开发者认识到不是所有人都会使用同一个客户端软件 从而不是所有客户端都会包括任何详细的加密算法 对于服务器也是同样 位于连接两端的的客户端和服务器在初始化 握手 的时候需要交流加密和解密算法(密码组) 如果它们没有足够的公用算法 连接尝试将会失败
注意当 SSL 允许客户端和服务器端相互验证的时候 典型的作法是只有服务器端在 SSL 层上进行验证 客户端通常在应用层 通过 SSL 保护通道传送的密码来进行验证 这个模式常用于银行 股份交易和其它的安全网络应用中
SSL 完全 握手 协议如图 所示 它展示了在 SSL 握手 过程中的信息交换顺序
图 SSL 握手 协议
这些消息的意思如下
ClientHello 发送信息到服务器的客户端 这些信息如 SSL 协议版本 会话 ID 和密码组信息 如加密算法和能支持的密匙的大小
ServerHello 选择最好密码组的服务器并发送这个消息给客户端 密码组包括客户端和服务器支持
Certificate 服务器将包含其公钥的证书发送给客户端 这个消息是可选的 在服务器请求验证的时候会需要它 换句话说 证书用于向客户端确认服务器的身分
Certificate Request: 这个消息仅在服务器请求客户端验证它自身的时候发送 多数电子商务应用不需要客户端对自身进行
Server Key Exchange 如果证书包含了服务器的公钥不足以进行密匙交换 则发送该消息
ServerHelloDone 这个消息通知客户端 服务器已经完成了交流过程的初始化
Certificate 仅当服务器请求客户端对自己进行验证的时候发送
Client Key Exchage 客户端产生一个密匙与服务器共享 如果使用 Rivest Shamir Adelman (RSA) 加密算法 客户端将使用服务器的公钥将密匙加密之后再发送给服务器 服务器使用自己的私钥或者密钥对消息进行解密以得到共享的密匙 现在 客户端和服务器共享著一个已经安全分发的密匙
Certificate Verify 如果服务器请求验证客户端 这个消息允许服务器完成验证过程
Change Cipher Spec 客户端要求服务器使用加密模式
Finished 客户端告诉服务器它已经准备好安全通信了
Change Cipher Spec 服务器要求客户端使用加密模式
Finished 服务器告诉客户端它已经准备好安全通信了 这是 SSL 握手 结果的标志
Encrypted Data 客户端和服务器现在可以开发在安全通信通道上进行加密信息的交流了
JSSE
Java 安全套接扩展 (JSSE) 提供一个框架及一个 % 纯 Java 实现的 SSL 和 TLS 协议 它提供了数据加密 服务器验证 消息完成性和可选的客户端验证等机制 JSSE 的引人之外就是将复杂的 根本的加密算法抽象化了 这样就降低了受到敏感或者危险的安全性攻击的风险 另外 由于它能将 SSL 无缝地结合在应用当然 使安全应用的开发变得非常简单 JSSE 框架可以支撑许多不同的安全通信协议 如 SSL 和 以及 TLS 但是 J SE v 只实现了 SSL 和 TLS
JSSE 编程
JSSE API 提供了扩充的网络套接字类 信用和密匙管理 以及为简化套接字创建而设计的套接字工厂框架 以此扩充 java security 和 两个包 这些类都包含在 和 ssl 包中
SSLSocket 和 SSLServerSocket
ssl SSLSocket 是 Socket 的子类 因此他支持所有标准 Socket 的方法 和一些为安全套接字新增加的方法 ssl SSLServerSocket 类与 SSLSocket 类相似 只是它用于创建服务器套接子 而 SSLSocket 不是
创建一个 SSLSocket 实例有如何两种方法
用 SSLSocketFactory 实例执行 createSocket 方法来创建
通过 SSLServerSocket 的 accept 方法获得
SSLSocketFactory 和 SSLServerSocketFactory
ssl SSLSocketFactory 类是用于创建安全套接字的对象工厂 ssl SSLServerSocketFactory 也是这样的工厂 但它用于创建安全的服务器套接字
可以通过如下方法获得 SSLSocketFactory 实例
执行 SSLSocketFactory getDefault 方法获得一个默认的工厂
通过特定的配置行为构造一个新的工厂
注意默认的工厂的配置只允许服务器验证
使现有的 Client/Server 应用变得安全
在现有的 C/S 应用中整合 SSL 以使其变得安全比较简单 使用几行 JSSE 代码就可以做到 为了使服务器变得安全 下面的例子中加黑显示的内容是必须的
import java io *;
import ssl *;
public class Server
int port = portNumber;
SSLServerSocket server;
try
SSLServerSocketFactory factory =
(SSLServerSocketFactory) SSLServerSocketFactory getDefault();
server = (SSLServerSocket)
factory createServerSocket(portNumber);
SSLSocket client = (SSLSocket)
server accept();
// Create input and output streams as usual
// send secure messages to client through the
// output stream
// receive secure messages from client through
// the input stream
catch(Exception e)
为了使客户端变得安全 下面的例子中加黑显示的内容是必须的
import java io *;
import ssl *;
public class Client
try
SSLSocketFactory factory = (SSLSocketFactory)
SSLSocketFactory getDefault();
server = (SSLServerSocket)
factory createServerSocket(portNumber);
SSLSocket client = (SSLSOcket)
factory createSocket(serverHost port);
// Create input and output streams as usual
// send secure messages to server through the
// output stream receive secure
// messages from server through the input stream
catch(Exception e)
SunJSSE 提供者
J SE v 和一个 JSSE 提供者 SunJSSE 一起发布 SunJSSE 安装并预登记了 Java 的加密体系 请把 SunJSSE 作为一个实现的名字来考虑 它提供了 SSL v 和 TLS v 的实现 也提供了普通的 SSL 和 TLS 密码组 如果你想找到你的实现 (这里是 SunJSSE) 所支持的密码组列表 可以调用 SSLSocket 的 getSupportedCipherSuites 方法 然而 不是所有这些密码组都是可用的 为了找出那些是可用的 调用 getEnabledCipherSuites 方法 这个列表可以用 setEnabledCipherSuites 方法来更改
一个完整的例子
我发现使用 JSSE 开发最复杂的事情关系到系统设置以及管理证书和密匙 在这个例子中 我演示了如何开发 配置和运行一个完整的支持 GET 请求方法的 HTTP 服务器应用
HTTP 概览
超文本传输协议 (Hypertext Transfer Protocol HTTP) 是一个 请求 回应 的应用协议 这个协议支持一套固定的方法如 GET POST PUT DELETE 等 一般用 GET 方法向服务器请求资源 这里有两个 GET 请求的例子
GET / HTTP/
GET /l HTTP/
不安全的 HTTP 服务器
为了开发一个 HTTP 服务器 你得先搞明白 HTTP 协议是如何工作的 这个服务器是一个只支持 GET 请求方法的简单服务器 代码示例 是这个例子的实现 这是一个多线程的 HTTP 服务器 ProcessConnection 类用于执行不同线程中新的请求 当服务器收到一个来自浏览器的请求时 它解析这个请求并找出需要的文档 如果被请求的文档在服务器上可用 那么被请求的文档会由 shipDocument 方法送到服务器 如果被请求的文档没有打开 那么送到服务器的就是出错消息
代码示例 HttpServer java
import java io *;
import *;
import java util StringTokenizer;
/**
* This class implements a multithreaded simple HTTP
* server that supports the GET request method
* It listens on port waits client requests and
* serves documents
*/
public class HttpServer
// The port number which the server
// will be listening on
public static final int HTTP_PORT = ;
public ServerSocket getServer() throws Exception
return new ServerSocket(HTTP_PORT);
// multi threading create a new connection
// for each request
public void run()
ServerSocket listen;
try
listen = getServer();
while(true)
Socket client = listen accept();
ProcessConnection cc = new
ProcessConnection(client);
catch(Exception e)
System out println( Exception:
+e getMessage());
// main program
public static void main(String argv[]) throws
Exception
HttpServer erver = new HttpServer();
();
class ProcessConnection extends Thread
Socket client;
BufferedReader is;
DataOutputStream os;
public ProcessConnection(Socket s) // constructor client = s;
try
is = new BufferedReader(new InputStreamReader
(client getInputStream()));
os = new DataOutputStream(client getOutputStream());
catch (IOException e)
System out println( Exception: +e getMessage());
this start(); // Thread starts here this start()
will call run()
public void run()
try
// get a request and parse it
String request = is readLine();
System out println( Request: +request );
StringTokenizer st = new StringTokenizer( request );
if ( (untTokens() >= ) &&
st nextToken() equals( GET ) )
if ( (request =
st nextToken()) startsWith( / ) )
request = request substring( );
if ( request equals( ) )
request = request + l ;
File f = new File(request);
shipDocument(os f);
else
os writeBytes( Bad Request );
client close();
catch (Exception e)
System out println( Exception: +
e getMessage());
/**
* Read the requested file and ships it
* to the browser if found
*/
public static void shipDocument(DataOutputStream out
File f) throws Exception
try
DataInputStream in = new
DataInputStream(new FileInputStream(f));
int len = (int) f length();
byte[] buf = new byte[len];
in readFully(buf);
in close();
out writeBytes( HTTP/ OK\\r\\n );
out writeBytes( Content Length: + f length() + \\r\\n );
out writeBytes( Content Type: text/\\r\\n\\r\\n );
out write(buf);
out flush();
catch (Exception e) out writeBytes( \\r\\n\\r\\n );
out writeBytes( HTTP/ + e getMessage() + \\r\\n );
out writeBytes( Content Type: text/\\r\\n\\r\\n );
out writeBytes( );
out flush();
finally
out close();
实验一下 HttpServer 类
将 HttpServer 的代码保存在文件 HttpServer java 中 并选择一个目录把它存放在那里
使用 javac 编译 HttpServer java
建立一些 HTML 文件作为例子 要有一个 l 因为它是这个例子中默认的 HTML 文档
运行 HttpServer 服务器运行时使用 端口
打开网页浏览器 并发出请求//localhost: 或者
注意 你能想到 HttpServer 可能接收到一些恶意的 URL 吗?比如像 或者 等 作为一个练习 修改 HttpServer 以使其不允许这些 URL 的访问 提示 写你自己的 SecurityManager 或者使用 java lang SecurityManager 你可以在 main 方法的第一行添加语句 System setSecurityManager(new Java lang SecurityManager) 来安装这个安全的管理器 试试吧!
扩展 HttpServer 使其能够处理 //URL
现在 我要们修改 HttpServer 类 使它变得安全 我希望 HTTP 服务器能处理 //URL 请求 我在前面就提到过 JSSE 让你可以很容易的把 SSL 整合到应用中去
创建一个服务器证书
就像我前面提到的那样 SSL 使用证书来进行验证 对于需要使用 SSL 来保证通信安全的客户端和服务器 都必须创建证书 JSSE 使用的证书要用与 J SE 一起发布的 Java keytool 来创建 用下列命令来为 HTTP 服务器创建一个 RSA 证书
prompt> keytool genkey keystore serverkeys keyalg rsa alias qusay
这个命令会产生一个由别名 qusay 引用的证书 并将其保存在一个名为 serverkeys 的文件中 产生证书的时候 这个工具会提示我们一些信息 如下面的信息 其中加黑的内容是我写的
Enter keystore password: hellothere
What is your first and last name?
[Unknown]:
What is the name of your anizational unit?
[Unknown]: Training and Consulting
What is the name of your anization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]: Toronto
What is the name of your State or Province?
[Unknown]: Ontario
What is the o letter country code for this unit?
[Unknown]: CA
Is CN=ultra OU=Training and Consulting
O= L=Toronto ST=Ontario C=CA correct?
[no]: yes
Enter key password for
(RETURN if same as keystore password): hiagain
正如你所看到的 keytool 提示为 keystore 输入密码 那是因为让服务器能访问 keystore 就必须让它知道密码 那工具也要求为别名输入一个密码 如果你愿意 这些密码信息能由 keytool 从命令行指定 使用参数 storepass 和 keypass 就行了 注意我使用了 作为姓名 这个名字是为我的机器假想的一个名字 你应该输入服务器的主机名或者 IP 地址
在你运行 keytool 命令的时候 它可能会花几秒钟的时间来产生你的密码 具体速度得看你机器的速度了
既然我为服务器创建了证书 现在可以修改 HttpServer 使其变得安全了 如果你检查 HttpServer 类 你会注意到 getServer 方法用来返回一个服务器套接子 也就是说 只需要修改 getServer 方法让它返回一个安全的服务器套接字就可以了 在代码示例 中加黑的部分就是所做的改变 请注意我将端口号改成了 这是 默认的端口号 还有一点非常值得注意 到 之间的端口号都是保留的 如果你在不同的端口运行 HttpsServer 那么 URL 应该是 //localhost:portnumber 但如果你在 端口运行 HttpsServer 那么 URL 应该是 //localhost
示例代码 HttpsServer java
import java io *;
import *;
import *;
import ssl *;
import java security *;
import java util StringTokenizer;
/**
* This class implements a multithreaded simple HTTPS
* server that supports the GET request method
* It listens on port waits client requests
* and serves documents
*/
public class HttpsServer
String keystore = serverkeys ;
char keystorepass[] = hellothere toCharArray();
char keypassword[] = hiagain toCharArray();
// The port number which the server will be listening on
public static final int HTTPS_PORT = ;
public ServerSocket getServer() throws Exception
KeyStore ks = KeyStore getInstance( JKS );
ks load(new FileInputStream(keystore) keystorepass);
KeyManagerFactory kmf =KeyManagerFactory getInstance( SunX );
kmf init(ks keypassword);
SSLContext sslcontext =SSLContext getInstance( SSLv );
sslcontext init(kmf getKeyManagers() null null);
ServerSocketFactory ssf =sslcontext getServerSocketFactory();
SSLServerSocket serversocket = (SSLServerSocket)
ssf createServerSocket(HTTPS_PORT);
return serversocket;
// multi threading create a new connection
// for each request
public void run()
ServerSocket listen;
try
listen = getServer();
while(true)
Socket client = listen accept();
ProcessConnection cc = new ProcessConnection(client);
catch(Exception e)
System out println( Exception: +e getMessage());
// main program
public static void main(String argv[]) throws Exception
HttpsServer = new HttpsServer();
();
这几行 String keystore = serverkeys ;
char keystorepass[] = hellothere toCharArray();
char keypassword[] = hiagain toCharArray();
指定了 keystore 的名字 密码和密匙密码 直接在代码中写出密码文本是个糟糕的主意 不过我们可以在运行服务器的时候在命令行指定密码
getServer 方法中的其它 JSSE 代码
它访问 serverkeys keystore JSK 是 Java KeyStore (一种由 keytool 产生的 keystore)
用 KeyManagerFactory 为 keystore 创建 X 密匙管理
SSLContext 是实现 JSSE 的环境 用它来创建可以创建 SSLServerSocket 的 ServerSocketFactory 虽然我们指定使用 SSL 但是返回来的实现常常支持其它协议版本 如 TLS 旧的浏览器中更多时候使用 SSL
注意默认情况下不需要客户端的验证 如果你想要服务器请求客户端进行验证 使用
serversocket setNeedClientAuth(true)
现在用 HttpsServer 类做个实验
将 HttpsServer 和 ProcessConnection 两个类 (上面的代码) 保存在文件 HttpsServer java 中
让HttpsServer java 与 keytool 创建的 serverkyes 文件在同一目录
使用 javac 编译 HttpsServer
运行 HttpsServer 默认情况下它应该使用 端口 不过如果你不能在这个端口上使用它 请选择另一个大于 的端口号
打开网页浏览器并输入请求 //localhost 或者 这是假译服务器使用 端口的情况 如果不是这个端口 那么使用 use: //localhost:port
你在浏览器中输入 //URL 的时候 你会得到一个安全警告的弹出窗口 就像图 那样 这是因为 HTTP 服务器证书是自己产生的 换句话说 它由未知的 CA 创建 在你的浏览器保存的 CA 中没有找到这个 CA 有一个选项让你显示证书 (检查它是不是正确的证书以及是谁签的名) 和安装该证书 拒绝该证书或者接受该证书
图 由未知 CA 颁发的服务器证书
注意 在内部的私有系统中产生你自己的证书是个很好的主意 但在公共系统中 最好从知名的 CA 处获得证书 以避免浏览器的安全警告
如果你接受证书 你就可以看到安全连接之后的页面 以后访问同一个网站的时候浏览器就不再会弹出安全警告了 注意有许多网站使用 HTTPS 而证书是自己产生或者由不知名的 CA 产生的 例如 如果你没访问过这个网页 你会看到一个像图 一样的安全警告
注意 你接受证书以后 它只对当前的会话有效 也就是说 如果你完全退出浏览器后 它就失效了 Netscape 和 Microsoft Internet Explorer (MSIE) 都允许你永久保证证书 在 MSIE 中的作法是 选择图 所示的 View Certificate 并在新开的窗口中选择 Install Certificate
这篇文章谈到了 SSL 并描述了 JSSE 框架及其实现 文中的例子可以说明把 SSL 整合到你的 C/S 应用中是一件很容易的事情 文中给出了一个安全 HTTP 服务器的例子 你可以使用它来进行实验 文中还介绍了 JSSE API 以及可以发生 HTTPS 请求的网页浏览器
用J SE 进行Internet安全编程(下)
客户端
Java 安全套接扩展 (Java Secure Socket Extension JSSE) 使 Internet 安全通信成为现实 它是 SSL (Secure Socket Layer) 及 TLS (Transport Layer Security 由 SSL 改善而来) 的框架和实现 这个包让 Java 开发人员能够开发安全的网络应用 为基于 TCP/IP 的何应用协议 如 HTTP FTP Telnet 或者 NTTP 在客户端和服务器端之间建立安全的数据通道
在这篇文章的第一部分 (服务器端) 作者已经详细说明了 SSL 和 JSSE 并且说明了如何开发服务器端支持 SSL 应用程序 那一部分中我们开发了一个 HTTPS 服务器 这是一个非常有用的应用程序 在这一部分中同样会用到它
在这篇文章涉及到客户端的内容 它首先简述 JSSE 然后会做这样一些事情
l在客户端使用 JSSE API
l一步步的开发一个支持 SSL 的客户端应用程序
l开发简单的支持 SSL 的客户端应用程序
l从服务器端导出证书并在客户端导入
l开发一个支持 SSL 的网页浏览器
JSSE
Java 安全套接扩展 (JSSE) 提供了 SSL 和 TLS 协议的框架及实现 JSSE 将复杂的 根本的加密算法抽象化了 这样就降低了受到敏感或者危险的安全性攻击的风险 正如你在本文中看到的那样 由于它能将 SSL 无缝地结合在应用当然 使安全应用的开发变得非常简单 JSSE 框架可以支撑许多不同的安全通信协议 如 SSL 和 以及 TLS 但是 J SE v 只实现了 SSL 和 TLS
用 JSSE 编写客户端应用程序
JSSE API 提供了扩充的网络套接字类 信用和密匙管理 以及为简化套接字创建而设计的套接字工厂框架 以此扩充 java security 和 两个包 这些类都包含在 和 ssl 包中
sll SSLSocketFactory 类是一个创建安全套接字的对象工厂 可以通过下面两种方法获得 SSLSocketFactory 的实例
调用 SSLSocketFactory getDefault 来获得默认的工厂 默认的工厂被配置为只允许服务器端验证 (不允许客户端验证) 注意许多电子商务网站不需要客户端验证
使用指定的配置来构造一个新的工厂 (这不在本文讲述的范围内)
建立 SSLSocketFactory 实例之后 你就可以通过 SSLSocketFactory 实例的 createSocket 方法创建 SSLSocket 对象了 这里有一个例子 该例通过 SSL 端口 (这是 HTTPS 的默认端口) 创建套接字并连接到 Sun 的 WWW 服务器
// Get a Socket factory
SocketFactory factory = SSLSocketFactory getDefault();
// Get Socket from factory
Socket socket = factory createSocket( );
使用低层的 SSL 套接字
现在 让我们看一个使用低层套接字在 HTTPS 服务器上打开一个 SSL 套接字连接的完整例子 在这个例子中 打开了一个到 HTTPS 服务器的 SSL 套接字连接 并且读入默认文档的内容 示例代码 展示了这个应用程序 其中用于打开 SSL 套接字的代码已经加黑显示了 你将会看到 应用程序中其余代码就是常规的输入/输出流代码
代码示例 ReadHttpsURL
import *;
import *;
import ssl *;
public class ReadHttpsURL
static final int HTTPS_PORT = ;
public static void main(String argv[]) throws Exception
if (argv length != )
System out println( Usage: java ReadHttpsURL );
System exit( );
// Get a Socket factory
SocketFactory factory = SSLSocketFactory getDefault();
// Get Socket from factory
Socket socket = factory createSocket(argv[ ] HTTPS_PORT);
BufferedWriter out
= new BufferedWriter(new OutputStreamWriter(
socket getOutputStream()));
BufferedReader in
= new BufferedReader(new InputStreamReader(socket getInputStream()));
out write( GET / HTTP/ \\n\\n );
out flush();
String line;
StringBuffer sb = new StringBuffer();
while((line = in readLine()) != null)
sb append(line);
out close();
in close();
System out println(sb toString());
用这个应用程序进行实验
拷贝 ReadHttpsURL 类的代码并粘贴到一个新文件中 将该文件改名为 ReadHttpsURL java 并保存在一个你指定的目录下
使用 javac 编译 ReadHttpsURL java
运行 ReadHttpsURL 并提供一个域名作为参数 如
Prompt> java ReadHttpsURL
几秒种后 你会看到许多 HTML 代码显示在屏幕上 注意 即使我们提供的是域名 我们打开的连接也是 这是因为我们使用的端口号 是 HTTPS 的默认端口号
再试试另一个例子 如
Prompt> java ReadHttpsURL jam ca
这次运行会抛出如下所示的异常 你能猜到是为什么吗?
Exception in thread main ssl SSLHandshakeException: java security cert CertificateException: Couldn t find trusted certificate at ssl internal ssl BaseSSLSocketImpl a(DashoA )
缘于一个很好的理由 它不能运行——因为远端的服务器发送了一个客户端不认识的证书 我在本文的第一部分提到过 当客户端连接服务器的时候 服务器发送它的证书到客户端请求验证 这样 第一个例子中 你进入了 服务器的确发送了证书 但 Java 检查了默认的证书库并认出了这个证书是由可信任的 CA 产生的 默认情况下 Java 信任这个 CA 第二个例子中 你进入的是 jam ca 那个网端的证书不是它自己产生的 就是由一个 Java 不知道的 CA 产生的 因此不受信任
注意 如果系统时钟没有设置正确 那么它的时间就可能在证书的有效期之外 服务器会认为证书无效并抛出 CertificateException 异常
为了让示例正确运行 你得从 jam ca 导入证收到 Java 信任的证书库中
导出和导入证书
为了解释清楚如何输出和输入证书 我会使用我自己的 HTTPS 服务器 这个服务器在第一部分中讨论过 然后 跟着下面的内容开始
运行 HTTPS 服务器 像在第一部分中讨论的那样
运行 ReadHttpsURL java ReadHttpsURL localhost 你同样会得到上面所述的异常
使用下面的 keytool 命令导出服务器证书
o 从 serverkeys 文件中导出别名为 qusay 的证书
o 将导出的证书保存在 server cert 文件中 这个文件会由 keytool 创建
如你看到的那样 我根据要求输入了密码 成功输入密码之后 服务器证书被成功的导出并保存在 server cert 中
Prompt> keytool export keystore serverkeys alias qusay file server cert
Enter keystore password: hellothere
Certificate stored in file
将文件 server cert 拷贝到 ReadHttpsURL 所在的目录 使用 keytool 创建一个新的 keystore 并将服务器的 server cert 证书导入其中 这里的命令示例
Prompt> keytool import keystore trustedcerts alias qusay file server cert
这个命令会产生下面那样的输出 它要求输入密码 这是一个新的密码 用于 trustedcerts 这个 keystore 的 这个 keystore 由 keytool 创建 在输出信息的最后 它询问我是否愿意相信这个证书 我回答 yes
Enter keystore password: clientpass
Owner: CN=localhost OU=Training and Consulting O= L=Toronto ST=Ontario C=CA
Issuer: CN=localhost OU=Training and Consulting O= L=Toronto ST=Ontario C=CA
Serial number: dcf a
Valid from: Mon Nov : : EST until: Sun Feb : : EST
Certificate fingerprints:
MD : : : D: A: B: E:B : :A : :B :FA:E : C: D:C
SHA : CB: C: : : :A : : :E : : :C : D: : : :
:F :B : B
Trust this certificate? [no]: yes
Certificate was added to keystore
现在运行 ReadHttpsURL 并告诉它哪里能找到证书 使用下面的命令
Prompt> java ssl trustStore=trustedcerts ReadHttpsURL localhost
这将会与你的 HTTPS 服务器联接 校验证书 如果正确 它会下载默认页面 l
注意 信任管理器负责决定远端的证书是否值得信任 它使用下面的规则
如果 sll trustStore 系统属性指定了信任库 那么信任管理器会使用提供的文件来检查证书 如果那个系统属性存在但指定的文件不存在 那么就没有使用任何信任库 会抛出一个 CertificateException 异常
如果 sll trustStore 系统属性没有定义 那么它会去寻找默认的信任库
如果在你的 java home 目录的 lib/security 子目录下存在名为 jssecacerts 的信任库 那么使用的就是它
如果 jssecacerts 不存在 但是 cacerts 存在 (它随 J SDK 一起发行 含有数量有限的可信任的基本证书) 使用的就是 cacerts
在我的 Windows 客户机中 java home 目录是 c:\\Program File\\java\\jre \\lib\\security 在上例中 如果你将 trustedcerts 更名为 jssecacerts 并将其移动到 lib/security 子目录中 那么你以后就不需要在命令行指定 ssl trustStore 属性了
如果你不知道 java home 在哪里 这里有一小段代码可以让你找到它
public class FindJavaHome
public static void main(String argv[])
System out println(System getProperty( java home ));
URL 类
示例代码 中的 ReadHttpsURL 使用低层的套接字打开到 SSL 服务器的连接 这样做有一个缺点 如果不进行一番解析 我们就不能在命令行清楚的写出像 这样的 URL 这里有一个更简单的办法在客户端应用程序中使用 SSL 和 JSSE
URL 类支持 HTTPS 地址 例如 下面的代码段创建一个 HTTPS 地址并建立一个输入流的读入器
URL url = new URL( );
BufferedReader in
= new BufferedReader(new InputStreamReader(url openStream()));
是不是很简单?我希望当你学习 Java 的新东西时 你能欣赏到它的美好之处
示例代码 中的 ReadHttpsURL 可以由下面使用了 URL 类的示例代码 代替
示例代码 ReadHttpsURL java
import *;
import java io *;
public class ReadHttpsURL
public static void main(String argv[]) throws Exception
if(argv length != )
System out println( Usage: java ReadHttpsURL );
System exit( );
URL url = new URL(argv[ ]);
BufferedReader in
= new BufferedReader(new InputStreamReader(url openStream()));
String line;
StringBuffer sb = new StringBuffer();
while ((line = in readLine()) != null)
sb append(line);
in close();
System out println(sb toString());
如果你想试试 ReadHttpsURL 执行它的命令和上面讨论的类似 注意 无论如何 既然我们使用 URL 类 你就能在命令行指定 URL 包括协议的名称 这里是一个例子
Prompt> java ReadHttpsURL //localhost
开发一个支持 SSL 的网页浏览器
我们开发一个支持 SSL 的网页浏览器作为一个完整的例子 该浏览器要做下面的工作
用户输入 URL 浏览器能接收它
浏览器能打开到 URL 指定主机的连接
浏览器能发送 HTTP 命令
浏览器会等待 HTTP/HTTPS 服务器的回应
浏览器能接收 HTML 回应
浏览器能解析 HTML 并显示出页面
我们创建的浏览器要能处理任何 URL 如 HTTP HTTPS FTP 等 注意我使用工具类 l HTMLEditorKit 来解析 HTML 它提供了对 HTML 的支持
示例代码 中展示了这个浏览器 QBrowser 的代码 注意 QBrowser 实现了 Runnable 接口 我这样做是因为这个浏览器没有提供 停止 按钮
示例代码 QBrowser java
import java io *;
import *;
import java awt *;
import java awt event *;
import javax swing *;
public class QBrowser implements ActionListener Runnable
private JFrame frame;
private JButton go;
private JEditorPane content;
private JTextField url;
private JLabel statusLine;
// default constructor
public QBrowser ()
buildBrowserInterface();
private void buildBrowserInterface()
frame = new JFrame( Q s Browser );
// on close exit the application using System exit( );
frame setDefaultCloseOperation ( );
url = new JTextField( );
go = new JButton( Go Get It );
go addActionListener(this);
JPanel controls = new JPanel(new FlowLayout ());
controls add(new JLabel( URL: ));
controls add(url);
controls add(go);
content = new JEditorPane();
content setEditable(false);
content setContentType( text/ );
content setText(
> );statusLine = new JLabel( Initialization Complete );
JPanel panel = new JPanel(new BorderLayout ( ));
frame setContentPane(panel);
panel add(controls North );
panel add(new JScrollPane (content) Center );
panel add(statusLine South );
frame pack();
frame setVisible(true);
/**
* You cannot stop a download with QBrowser
* The thread allows multiple downloads to start
* concurrently in case a download freezes
*/
public void actionPerformed (ActionEvent event)
Thread thread = new Thread(this);
thread start();
// this is the Thread s run method
public void run ()
try
String str = url getText();
URL url = new URL(str);
readURL(url);
catch (IOException ioe)
statusLine setText( Error: +ioe getMessage());
showException(ioe);
private void showException(Exception ex)
StringWriter trace = new StringWriter ();
ex printStackTrace (new PrintWriter (trace));
content setContentType ( text/ );
content setText ( + ex +
+ trace +
);
/**
* The URL class is capable of // and // URLs
*/
private void readURL(URL url) throws IOException
statusLine setText( Opening + url toExternalForm());
URLConnection connection = url openConnection();
StringBuffer buffer = new StringBuffer();
BufferedReader in=null;
try
in = new BufferedReader(new InputStreamReader
(connection getInputStream()));
String line;
while ((line = in readLine()) != null)
buffer append(line) append( \\n );
statusLine setText( Read + buffer length () + bytes );
finally
if(in != null) in close();
String type = connection getContentType();
if(type == null) type = text/plain ;
statusLine setText( Content type + type);
content setContentType(type);
content setText(buffer toString());
statusLine setText( Done );
public static void main (String[] args)
QBrowser browser = new QBrowser();
既然 QBrowser 使用 URL 类 它就可以处理 HTTP 和 HTTPS 请求 你可以使用 HTTP 和 HTTPS 地址测试 QBrowser 这里是一些测试
请求 你会看到如图 所示的内容
图
请求 结果抛出了异常 因为这个网页服务器的证书不受信任并且不能在默认页中找到 所以它抛出如图 所示的异常
图
请求 //localhost 这里运行着第一部分中写的 HttpServer 注意 如果你使用命令 java QBrowser 来运行 QBrowser 而服务器的证书导出后被导入默认文件 jssecacerts 那么应该将该文件拷贝到 java home 目录的 lib/security 子目录中 如果证书被导入了其它文件 你可以使用 trustStore 选项 如 java ssl trustStore=file QBrowser 使用其实任何一种方法 浏览器都会工作 并且你可以看到如图 所示的默认页面
图 //localhost
HttpsURLConnection 类
这个类存在于 ssl 包中 它扩展了 HttpURLConnection 以支持 HTTPS 描述的一些特性 它能够通过 SSL/TLS 套接字建立安全通道来请求/获取数据 示例代码 展示了一个小型客户端 它使用 HttpsURLConnection 类从 HTTPS 服务器下载文档
示例代码 ReadHttpsURL java
import java io *;
import *;
import ssl *;
public class ReadHttpsURL
public static void main(String[] argv) throws Exception
URL url = new URL(argv[ ]);
HttpsURLConnection connection = (HttpsURLConnection) url openConnection();
connection setDoOutput(true);
BufferedReader in
= new BufferedReader(new InputStreamReader(connection getInputStream()));
String line;
while ((line = in readLine()) != null)
System out println(line);
in close();
现在试试 ReadHttpsURL 完成上面讨论的内容 注意 无论如何 既然我们使用 URL 类 你就能在命令行指定 URL 包括协议的名称 这里是一个例子
Prompt> java ReadHttpsURL
HttpsURLConnection 有一个非常有趣的特点 一旦获得了连接 你就可以在网络连接之前使用一些有用的参数对其进行配置 如 HostnameVerifier HostnameVerifier 是一个接口 它申明了方法 public boolean verify (String hostname SSLSession session) 而且 它像下面所述的那样工作
如果 SSL/TLS 标准主机名校验逻辑失败 执行过程中会调用回调类的 verify 方法 回调类是实现了 HostnameVerifier 接口的类
如果回调类检查到主机名可以接受 则允许连接 否则 连接会被终止
回调类遵循的规则即可以是基本的验证方法 也可以依赖其它验证方法 这里说明了如何实现
public class MyVerified implements HostnameVerifier
public boolean verify(String hostname SSLSession session)
// pop up a dialog box
//
// return either true or false
现在 可以这样使用它
HttpsURLConnection connection = (HttpsURLConnection) url openConnection();
connection setHostnameVerifier(new MyVerifier());
信任管理器
一个 SSL 客户端 如网页浏览器 连接到 SSL 服务器 (如 HTTPS 服务器) 的时候 HTTPS 服务器将自己的证书链交给客户端验证 SSL 规范规定 如果在证书链中发现有无效的证书 客户端应该立即终止连接 一些网页浏览器 如 Netscape Communicator 和 Microsoft Internet Explorer 询问用户是否忽略无效的证书并继续检查证书链 以确定是否有可能验证通过 HTTPS 服务器 使用 sll TrustManager 可以很好的消除这种矛盾 它是 JSSE 信任管理器的基础接口 而这些信任管理器则是用来管理可信任的资料以及决定是否接受某个凭证的 典型的信任管理器都支持基于 X 的证书 它是 J DK 的 keytool 可以管理的一个普通的证书格式
X TrustManager 接口
sll X TrustManager 接口扩展了普通的 TrustManager 接口 使用基于 X 公钥证书验证方案时 信任管理器必须实现该接口 实现 X TrustManager 可以创建信任管理器 这里有一个空实现
public class MyTrustManager implements X TrustManager
MyTrustManager() // constructor
// create/load keystore
public void checkClientTrusted(
X Certificate chain[] String authType)
throws CertificatException
public void checkServerTrusted(
X Certificate chain[] String authType)
throws CertificationException
// special handling such as poping dialog boxes
public X Certificate[] getAcceptedIssuers()
为了支持远端套接字 X 证书 实现了 X TrustManager 接口的类 其实例要传递给 SSLContext 对象的 init 方法 它作为 SSL 套接字工厂 换句话说 一旦创建了信任管理器且通过 init 方法将其分配给了一个 SSLSocket 以后从 SSLContext 创建的 SocketFactories 在作信任决策时将使用新的信任管理器 下面的代码段就是个示例
X TrustManager xtm = new MyTrustManager()
TrustManager mytm[] = xtm;
SSLContext ctx = SSLContext getInstance( SSL );
ctx init(null mytm null );
SSLSocketFactory sf = ctx getSocketFactory();
JSSE 调试工具
Sun 的 JSSE 实现提供了动态调试跟踪支持 使用系统属性 debug 即可 JSSE 并不正式支持这个特性 但它可以让你看到在 SSL 通信过程中幕后在干什么 这个工具可以通过如下命令使用
Prompt> java debug=option[debugSpecifiers] MySSLApp
如果你使用了 help 参数 它就会显示调试选项列表 J SE 中 选项如下
all turn on all debugging
ssl turn on ssl debugging
The following can be used with ssl:
record enable per record tracing
handshake print each handshake message
keygen print key generation data
session print session activity
defaultctx print default SSL initialization
sslctx print SSLContext tracing
sessioncache print session cache tracing
keymanager print key manager tracing
trustmanager print trust manager tracing
handshake debugging can be widened with:
data hex dump of each handshake message
verbose verbose handshake message printing
record debugging can be widened with:
plaintext hex dump of record plaintext
你必须指定参数 ssl 或者 all 中的一个 紧跟 debug 符号 可以使用一个或多个调试说明符 使用 : 或者 作为分隔符 说明符不是必须的 但可以增强可读性 这里是一些例子
Prompt> java debug=all MyApp
Prompt> java debug=ssl MyApp
Prompt> java debug=ssl:handshake:trustmanager MyApp
这篇文章展示了如何使用 JSSE (SSL 协议的框架和实现) 开发安全的客户端应用程序 这篇文章中的例子展示了将 SSL 整合到 C/S 应用程序是多么简单的事情 这篇文章中讲到一个网页浏览器 QBrowser 可以处理 HTTP 和 HTTPS 请求
QBrowser 中 如果服务器上 按输入 HTTPS 的地址中不存在有效的证书 则会抛出一个异常 你也许想修改 QBrowser 使其能够处理这个异常并且弹出一个窗口询问用户是否愿意下载安装证书 那么你可以把它做为一个练习 x 的 Java 插件使用了 JSSE 它有自己的的信任管理器 如果它不能在信任库里找到证书 而弹出窗口提示
原文 Secure Internet Programming with Java Standard Edition (J SE) (Part II: The Client Side)
cha138/Article/program/Java/hx/201311/27135相关参考
知识大全 用J2SE 1.4进行Internet安全编程(三)
用J2SE1.4进行Internet安全编程(三) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
探讨J2SE1.4发行版中的安全性变化 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 安全性是当
知识大全 克服J2SE 1.3 ~ 1.4不兼容问题 HK2000c
克服J2SE1.3~1.4不兼容问题HK2000c 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
J2SE简介 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 多数编程语言都有预选编译好的类库以支
Java网络编程从入门到精通(1):Internet地址概述 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看
用JAVA编制Internet电子白板软件 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 前言
知识大全 电脑win10 手机能连wifi 但是电脑不能连。显示无internet 安全 有木有大神啊
电脑win10手机能连wifi但是电脑不能连。显示无inter安全有木有大神啊win10连wifi显示“无Inter,安全”需要设置,方法如下:“开始”->“运行”,输入“services.ms
用Delphi进行OpenGL编程学习心得 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在开发
用PHP与XML联手进行网站编程 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一小序 
用PHP与XML联手进行网站编程[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一小序