Https之安全Socket
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Https之安全Socket相关的知识,希望对你有一定的参考价值。
参考技术A 最近在做Https和wss安全连接,它们都是基于安全套接字SSLSocket的。
我们知道,网络协议是分层次的,从HTTP ->TCP/UDP ->IP ->MAC层,实现了对数据的封装和分发。而套接字Socket,实际上是以门面模式实现对TCP/IP协议的封装。所谓安全Socket,即在Socket上实现身份认证和网络通道加密。在建立连接的过程中,可以使用 证书进行身份验证 (客户端对服务器的身份验证,或者相互验证),并生成后续连接通道上对称加密的密钥(通过在握手过程中产生的三个随机数和约定好的密钥算法),从而建立安全的连接。而这个安全连接,实际上,就是http区别https,ws区别wss的重点和关键。
基于安全套接字的通信,它背后的运行机制是这样的:
SSLContext这个类是对安全套接字协议的实现,并扮演了一个安全套接字工厂的角色。我们可以通过
来获得一个SSLContext实例,其中参数为protocol,即要使用的协议名。这些协议名可以是SSL,TLS(其中TLS是SSL的继任者,TLS1.0相当于SSL3.1)等。
通过SSLContext实例,我们可以得到SSLSocketFactory或者SSLServerSocketFactory, 从而最终获取客户端使用的SSLSocket和相对应的服务器所使用的SSLServerSocket。
拿到SSLSocket和SSLServerSocket,实际上我们已经可以直接在服务器和客户端之间进行通信了。
重点关注上面的 init 过程。
如果服务器不需要根据证书验证客户端身份的合法性,那么通常在客户端中,km设置为null,主要通过tm验证服务器的合法性;
如果需要设置双向认证,则需要在本地km管理本地key,即不为空。
无论如何对tm和km设置,我们注意到它们的工厂类初始化过程,都需要传入keystore,但是这两个KeyStore是有区别的。
KeyManager实际上管理的是自己的KeyStore,而TrustManager管理的是对方的KeyStore。自己的KeyStore可以用来让对方验证自己的身份,而对方的KeyStore用来验证对方身份的合法性。
客户端单向验证
证书生成
server.xml中connector配置:
python安全攻防之socket网络编程
一、网络结构体系
1. OSI协议是由ISO(国际标准化组织)制定的,用于提供给开发者一个必须的、通用的概念以便开发完善、可以用来解释连接不同系统的框架。OSI协议将网络体系结构划分为7层:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
2. TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)体系结构是指能够在多个不同网络间实现的协议簇。TCP/IP传输协议包含4层体系结构,应用层、传输层、网络层和网络接口层。
1、应用层
应用层协议定义了运行在不同端系统上的应用程序进程如何相互传递报文。
- DNS:域名系统(Domain Name System),用来实现域名与IP地址的转换,运行在UDP之上,默认使用53端口;
- FTP:文件传输协议(File Transfer Protocol),可以通过网络在不同平台之间实现文件的传输,是一种基于TCP的明文传输协议,默认工作在21端口;
- HTTP:超文本传输协议(HyperText Transfer Protocol),运行于TCP之上,默认端口为80;
- SMTP:简单邮件传输协议(Simple Mail Transfer Protocol),建立在TCP的基础上,使用明文传递邮件和发送命令,默认使用25端口。
- TELNET:远程登陆协议,运行于TCP之上,默认使用23端口。
2、传输层
传输层主要负责向两个主机中进程之间的通信提供服务。包括:传输控制协议(Transmission Control Protocol,TCP)和用户数据报协议(User Datagram Protocol,UDP)。
- TCP:为两台计算机之间提供面向连接、可靠的字节流服务。一台计算机发出的字节流无差错地发往网络上的其他计算机,由于其可靠的传输方式,故传输速度较慢。
- UDP:是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故传输速度很快。
(1)TCP三次握手协议:
- 客户端送一个SYN包作为建立连接的请求等待确认应答。
- 服务器接收到请求数据包后,发送ACK确认应答,发送SYN包请求连接。
- 客户端针对SYN包发送ACK包确认应答。
3、网络层
IP运行于网络层,是网络互联的重要基础。通过IP地址(IPV4:64位,IPV6:128位)用来标识网络上的主机,在公开网络上或者局域网内部,每台主机都必须使用不同的IP地址。由于网络地址转换(NAT)和代理服务器等技术的广泛应用,不同内网之间的主机可以使用相同的公网IP地址。IP地址与端口共同来标识网络上特定主机上的特定应用程序,俗称Socket。
局域网地址范围分三类,以下IP段为内网IP段:
C类:192.168.0.0 - 192.168.255.255
B类:172.16.0.0 - 172.31.255.255
A类:10.0.0.0 - 10.255.255.255
4、拓展——pygeolist
作用:关联ip地址与地理位置
先使用pyp安装pygeoip
GeoLiteCity.dat: https://github.com/mbcc2006/GeoLiteCity-data
使用的是一个随便找的代理ip
import pygeoip
geo = pygeoip.GeoIP('F:\\TOOLS\\GeoLiteCity-data-master\\GeoLiteCity.dat')
geo.record_by_name('183.141.110.74')
详细使用以及字段含义:
https://www.cnblogs.com/ssooking/p/6097436.html
4、网络接口层
MAC地址也称为网卡物理地址,具有唯一性,是一个48位的二进制数,用来标识不同的网卡物理地址。
使用ipconfig/all或ifconfig可以查询
(1)更改mac地址
可以用来隐藏自己,或者解决ip封禁问题
更改随机mac
- ifconfig wlan0 down //关掉网卡
- macchanger -r wlan0 //随机生成mac地址
- ifconfig wlan0 up //开启网卡
- ifconfig //查询mac
更改指定mac
-m 指定自定义的mac地址
- ifconfig wlan0 down //关掉网卡
- macchanger -m 01:23:45:67:89:10 wlan0
- ifconfig wlan0 up //开启网卡
- ifconfig //查询mac、
二、socket编程
1、简介
套接字(Socket)是计算机之间进行通信的一种约定。通过 Socket,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。套接字(Socket)是计算机之间进行通信的一种约定。通过 Socket,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
通信过程如下:
- 服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),等待客户端连接。
- 客户端初始化一个Socket,客户端的套接字必须首先指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求(connect)。
- 当服务器端套接字接收到客户端套接字的连接请求,响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,由此连接建立成功。
2、UDP编程
UDP属于无连接协议,在编程时不需要建立连接,而是直接向接收方发送信息。UDP不提供应答重传机制,无法保证数据一定能够到达目的地。
- socket(family[,type[,proto]]):创建一个Socket对象,family为socket.AF_INET表示使用IPV4,socket.AF_INET6表示使用IPV6;type为SOCK_STREAM表示使用TCP,SOCK_DGRAM表示使用UDP。
- sendto(string,address):把string指定的内容发送给address指定的地址,其中address是一个包含接收方主机IP地址和应用进程端口号的元组,格式为(IP地址,端口号)。
- recvfrom(bufsize[,flags]):接收数据。
UDP协议优点:效率高、首部中只包含双方地址与校验和等很少的字段,额外开销小。
1、udp_socket_server.py
import socket
ip= input('请输入要连接的ip:')
port = input('请输入要连接的端口:')
ip_addr = (ip,int(port))
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#连接
s.bind(ip_addr)#绑定 ip为str,port为int
print('绑定ip:'+ ip)
print('绑定端口:'+ port)
while True:
data,addr = s.recvfrom(1024)#接收数据
print('接收数据来自:'+str(addr))
print('接收数据:'+data.decode())#解密数据
send_info = input('请输入:')#传输数据
s.sendto(send_info.encode(),addr)
if data.decode().lower() == 'q':
break
s.close()
2、udp_socket_client.py
import socket
ip = input('请输入连接的ip:')
port = input('请输入要连接的端口:')
ip_addr = (ip,int(port))
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
info = input('请输入:')#发送数据
s.sendto(info.encode(),ip_addr)
data,addr = s.recvfrom(1024)#接收数据
print('接收数据来自:'+str(addr))
print('接收数据:'+ data.decode())
if data.decode().lower() == 'q':
break
s.close()
3、TCP编程
TCP一般用于可靠数据传输的场合, UDP编程经常用到socket模块方法如下所示:
① socket(family[,type[,proto]]) :创建一个 Socket 对象, family 为 socket.AF_INET 表示使用 IPV4 , socket.AF_INET6 表示使用 IPV6 ; type为SOCK_STREAM表示使用TCP,SOCK_DGRAM表示使用UDP。 ②connect(address):连接远程主机; ③ send(bytes[,flags]) :发送数据; ④ recv ( bufsize [,flags]) :接收数据; ⑤ bind(address) :绑定地址; ⑥ listen(backlog) :开始监听,等待客户端连接, blacklog 排队数, backlog+1 表示允许的最大连接数; ⑦ accept() :响应客户端的请求,接收一个连接;1、tcp_socket_server.py
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_addr = ('127.0.0.1',8888)
s.bind(ip_addr) #传入一个元组,(str,int)
s.listen(1)
print('监听中...')
print('监听端口号:8888')
conn,addr = s.accept()
print('已连接到:',addr)
while True:
data = conn.recv(1024)
data = data.decode()
print('接收:'+data)
info = input('请输入:')
conn.sendall(info.encode())
if data.lower() == 'q':
break
conn.close()
s.close()
2、tcp_socket_client.py
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_addr = ('127.0.0.1',8888)
try:
s.connect(ip_addr)
except:
print('服务器未开启...')
while True:
info = input('请输入:')
s.sendall(info.encode())
data = s.recv(1024).decode()
print('接收:'+ data)
if data.lower() == 'q':
break
s.close()
3、tcp编程拓展
① Gethostname () :获取本地主机名; ② Gethostbyname () :根据主机名获取 ip 地址; ③ Gethostbyaddr () :根据 ip 地址获取主机名; ④ Getservbyport () :根据端口号获取主机名; ⑤ Getservbyname () :根据服务名获取对应的端口号;import socket
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
addr = socket.gethostbyname("www.baidu.com")
host = socket.gethostbyaddr(ip)
sername = socket.getservbyport(3389, "tcp")
port = socket.getservbyname('http')
print("gethostname:",hostname)
print("gethostbyname:",ip)
print("gethostbyname:",addr)
print("gethostbyaddr:",host)
print("getservbyport:",sername)
print("getservbyname:",port)
三、socket传输文件
fileServer.py
import socketserver
import sys
import re
import json
from optparse import OptionParser
import struct
import os
def operafile(filename):
file_size = os.path.getsize(filename)#获取文件大小
rex = re.compile(r'([^<>/\\\\\\|:""\\*\\?]+\\.\\w+$)')#匹配文件名
data = rex.findall(filename)
head_dir=
'filename':data,
'file_size':file_size
head_info = json.dumps(head_dir) #json.dump把一个python数据结构转化成json
head_info_len = struct.pack('i',len(head_info))
return head_info_len, head_info
def sendFile(conn,head_info,head_info_len,filename):
try:
conn.send(head_info_len)
conn.send(head_info.encode('utf-8'))
with open(filename,'rb') as f:
conn.sendall(f.read())
print('[+]发送文件成功:' + filename )
except:
print('[+]发送文件失败:'+ filename)
class MyServer(socketserver.BaseRequestHandler):
buffersize = 1024
def handle(self):
print('[+]客户端连接到:',self.client_address[0],'\\n')
while True:
filename = input('请输入要发送的文件名>>>').strip()#移除字符串头尾的空格
if filename =='exit':
break
head_info_len, head_info = operafile(filename)#提取文件名
sendFile(self.request,head_info, head_info_len,filename)#文件发送
self.request.close()
def main():
parser = OptionParser("Usage:%prog -p <ip port>")
parser.add_option('-p', type='int', dest='port', help='input the ip port')
options, args = parser.parse_args()
target_port = options.port
print('[+]正在监听端口:',target_port)
s = socketserver.ThreadingTCPServer(('127.0.0.1',target_port), MyServer)#myserever是类
s.serve_forever()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('interrupted by user,killing all threads...')
fileClient.py
import socket
import os
import sys
import json
import struct #python与c中的数据类型转化
from optparse import OptionParser
def recv_file(head_dir,tcp_client):
filename = head_dir['filename']
file_size = head_dir['file_size']
print('[+]文件名:' + filename[0])
print('[+]文件大小:' + str(file_size))
print('*'*10 + '文件传输中' + '*'*10)
recv_len = 0
f = open(filename[0],'wb')
while recv_len < file_size:
if file_size > 1024:
recv_mg = tcp_client.recv(1024)
recv_len += len(recv_mg)
f.write(recv_mg)
else:
recv_mg = tcp_client.recv(file_size)
recv_len = len(recv_mg)
f.write(recv_mg)
f.close()
print('[+]文件传输完成...')
def main():
parser = OptionParser("Usage: %prog -u <target ip address> -p <target port>")
parser.add_option('-u',type='string',dest='ip',help='input the ip address')
parser.add_option('-p',type='int',dest='port',help='input the port of ip address')
options,args = parser.parse_args()
target_ip = options.ip
target_port = options.port
#print(target_ip , target_port)
#socket初始化
tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip_port = (target_ip,target_port)
tcp_client.connect_ex(ip_port)#有返回值的连接socket
print('[+]等待服务器应答......')
struct_len = tcp_client.recv(4)#int类型本机占4位
struct_info_len = struct.unpack('i',struct_len)[0]#i 代表C struct中的int类型,解析得到头部信息
print('[+]接收头部信息长度是:'+ str(struct_info_len))
head_info = tcp_client.recv(struct_info_len)#获取报头内容
head_dir = json.loads(head_info.decode('utf-8'))#报头反序列化
print('[+]接收头部信息:'+str(head_dir))
#接收文件具体内容
recv_file(head_dir,tcp_client)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('interrupted by user,killing all threads...')
以上是关于Https之安全Socket的主要内容,如果未能解决你的问题,请参考以下文章