安全SOCKET
导语
要使用安全Socket需要对密码学有一定的了解。在阅读本文之前最好能阅读一下下面几个网站的内容
http://kb.cnblogs.com/page/194742/
http://kb.cnblogs.com/page/162080/
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html
http://geek.csdn.net/news/detail/188003
创建安全客户端Socket
创建一个安全Socket很简单,首先从javax.net.ssl.SSLSocketFactory获取一个默认的工厂对象。然后通过该工厂的createSocket()方法得到一个具体的Socket对象。下面是一个简单的例子
SocketFactory factory = SSLSocketFactory.getDefault();
Socket socket = factory.createSocket("www.xdysite.cn", 7000);
代码中返回的Socket实际上是javax.net.ssl.SSLSocket,这是java.net.Socket的一个子类。不过,我们不需要了解这些细节。我们就把他当成普通的socket来使用即可,即通过其getInputStream(),getOutputStream()和其它方法加以使用。
一个简单的小案例
假设有一个接受订单的服务器在www.xdysite.cn的7000端口监听连接。每个订单使用一个TCP连接以ASCII字符串的形式发送。服务器接受订单并关闭这个连接(这里我们省略大量细节)。客户端发送的订单形式如下:
Name: liming
Product: 67x-89
Address: 1280 XiDian University
Card number: 4000-1234-5678-901
Expires: 2016/12/29
这个消息中包含了大量的信息,足以让某个监听数据包的人恶意地使用liming的信用卡号码。因此,在发送这个订单之前,应当对它加密。下面的代码将通过安全Socket发送订单:
SocketFactory factory = SSLSocketFactory.getDefault();
try {
Socket socket = factory.createSocket("www.xdysite.cn", 7000);
Writer out = new OutputStreamWriter(socket.getOutputStream(), "ASCII");
out.write("Name: liming\r\n");
out.write("Product: 67x-89\r\n");
out.write("Address: 1280 XiDian University\r\n");
out.write("Card number: 4000-1234-5678-901\r\n");
out.write("Expires: 2016/12/29\r\n");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
下面是一个HTTPS客户端的示例代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class HTTPSClient {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java HTTPSClient host");
return;
}
int port = 443;
String host = args[0];
SocketFactory factory = SSLSocketFactory.getDefault();
SSLSocket socket = null;
try {
socket = (SSLSocket) factory.createSocket(host, port);
//启用所有密码组
String[] supported = socket.getSupportedCipherSuites();
socket.setEnabledCipherSuites(supported);
Writer out = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
//https在GET行中需要完全URL
out.write("GET / HTTP/1.1\r\n");
out.write("Host: " + host + "\r\n\r\n");
out.flush();
//读取响应
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取首部
String s;
while (!(s = in.readLine()).equals("")) {
System.out.println(s);
}
System.out.println();
//读取长度
String contentLength = in.readLine();
int length = Integer.MAX_VALUE;
try {
length = Integer.parseInt(contentLength.trim(), 16);
} catch (NumberFormatException e) {
//这个服务器在响应体的第一行
//没有发送content-length
}
System.out.println(contentLength);
int c;
int i = 0;
while ((c = in.read()) != -1 && i++ < length) {
System.out.write(c);;
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过上面的程序,我们可以访问类似https://www.baidu.com网站的内容。
HTTPS服务的实现
HTTPS服务器实现起来比较复杂,要创建一个安全服务器Socket,必须要完成下面的步骤:
- 使用keytool工具生成公钥和证书
- 花钱请可信的第三方(权威CA)认证证书
- 为使用的加密算法创建SSLContext
- 为使用的证书源创建一个TrustManagerFactory
- 为使用的密钥类型创建一个KeyManagerFactory
- 为密钥和证书数据库创建一个KeyStor对象
- 用密钥和证书填充KeyStore对象
- 用KeysStore及其口令短语初始化KeyManagerFactory
- 用KeyManagerFactory中的密钥管理器(必要),TrustManagerFactory中的信任管理器和一个随机源来初始化上下文
前两步我们要么自己去做,要么找一个CA机构帮我们直接生成。为了完成测试,我们去https://www.pianyissl.com/网站获取一个免费的SSL证书。获取的是一个压缩包,解压后可以从Tomcat目录下找到keystore.jks文件通过JDK中的keytool工具可以查看证书的信息。
keytool -list -v -keystore /root/javaTest/Tomcat/keystore.jks
图片中显示的是证书的部分信息,那么接下来如何将该证书加载到服务器呢?
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
public class SSLServer {
public final static int PORT = 7000;
public final static String algorithm ="SSL";
public static void main(String[] args) {
try {
SSLContext context = SSLContext.getInstance("SSL");
//设置只支持X.509标准的密钥
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
//Oracle的默认密钥库类型
KeyStore ks = KeyStore.getInstance("JKS");
//加载证书,在读取jks类型的证书时需要输入密码(这里是123456)
char[] password = "123456".toCharArray();
ks.load(new FileInputStream("keystore.jks"), password);
kmf.init(ks, password);
context.init(kmf.getKeyManagers(), null, null);
//删除密码
Arrays.fill(password, '0');
SSLServerSocketFactory factory = context.getServerSocketFactory();
SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(PORT);
while(true) {
try(
Socket client = server.accept();
Writer writer = new OutputStreamWriter(client.getOutputStream());
){
writer.write("HTTP/1.1 200 OK\r\n");
writer.write("Server: SSlServer\r\n");
writer.write("Content-lenght: 10\r\n\r\n");
writer.write("hello ssl!");
}catch(IOException e){}
}
} catch (NoSuchAlgorithmException | IOException
| UnrecoverableKeyException | KeyManagementException
| CertificateException| KeyStoreException e) {
}
}
}
访问http://www.xdysite.cn:7000端口就可以使用SSL安全链接的HTTP了
安全SOCKET的更多相关文章
- socket读写返回值的处理
在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- Socket聊天程序——客户端
写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...
- Socket聊天程序——服务端
写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- Android Socket连接PC出错问题及解决
最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.
- Linux下的C Socket编程 -- server端的继续研究
Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...
- Mono 3.2.3 Socket功能迎来一稳定的版本
由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
随机推荐
- img与特殊布局下对浏览器渲染的剖析
补白 在内联元素中,分为替换元素和非替换元素(不了解的同学可以百度一下),非替换元素是不可以设置尺寸的,而替换元素作为特殊的内联元素,由于其自身拥有尺寸属性,所以其的尺寸是可以进行再次设置的. 此文适 ...
- Spring_day01--注入对象类型属性(重点)_P名称空间注入_注入复杂类型属性_IOC和DI区别_Spring整合web项目原理
注入对象类型属性(重点) Action要new一个service对象,Service中又要new一个Dao对象,现在把new的过程交给spring来操作 1 创建service类和dao类 (1)在s ...
- com.mysql.jdbc.MysqlDataTruncation: Data trunca...
连接的是mysql数据库,插入数据时,控制台报: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for colu ...
- cxGrid 锁定列
cxGrid锁定列 第1步: 双击cxGrid -> 点击页签“Bands”->点击“Add”加入2个tcxGridBrand, 将1个锁定在左边,最后一个锁定在右边. 如下图 第2步: ...
- 【BZOJ3425】Poi2013 Polarization 猜结论+DP
[BZOJ3425]Poi2013 Polarization Description 给定一棵树,可以对每条边定向成一个有向图,这张有向图的可达点对数为树上有路径从u到达v的点对(u,v)个数.求最小 ...
- android RelativeLayout属性和布局实例
// 相对于给定ID控件 android:layout_above 将该控件的底部置于给定ID的控件之上; android:layout_below 将该控件的底部置于给定ID的控件之下; andro ...
- quartz 防止上一任务未执行完毕,下一时间点重复执行
/** * 订单监控类 * 定时扫描所有待付款订单,超时自动取消 * Created by huangbaidong * 2017/3/29. */ @Component public class O ...
- Zabbix使用SMTP发送邮件报警并且制定报警内容
接上篇Zabbix监控介绍及安装配置 选择报警项 创建一个报警项 选择到刚刚自定义的80端口 定义报警方法 定义告警级别 一些报警方法 diff 比较是否有修改 last 最低值 nodata 没有数 ...
- base64图片解析
大家可能注意到了,网页上有些图片的src或css背景图片的url后面跟了一大串字符,比如:data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAAk ...
- JS获取时间戳+C#水煎戳转换
JS获取了当前毫秒的时间戳. var timestamp=new Date().getTime(); //第二种方法: //var timestamp = (new Date()).valueOf() ...