首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MYSQL SSL连接 (含mysql流量镜像脚本)

MYSQL SSL连接 (含mysql流量镜像脚本)

原创
作者头像
大大刺猬
发布2023-03-24 15:51:26
7K0
发布2023-03-24 15:51:26
举报
文章被收录于专栏:大大刺猬大大刺猬

之前讲了mysql的连接, 但是排除了SSL的情况. 这次就来看看有SSL的情况咋连接

连接过程

连接过程比较简单, 就是发送密码之前,告诉server我要使用ssl

client ->>  server : connect
server ->>  client : salt
client -->>  server : SSL(36byte)
client ->>  server : password
server ->> client: OK/ERR

SSL包

就是正常CLIENT_PROTOCOL_41包的前面部分(前32字节, 加上header一共36字节)

名字

大小(字节)

描述

client_flag

4

https://cloud.tencent.com/developer/article/2243951

max_packet_size

4

最大包大小

character_set

1

字符集

filler

23

填充字段

测试

本次就不光连接mysql server了, 没得意思, 我们模拟个mysql server , 转发client发来的数据, 同时把数据再克隆一份到其它服务器, 但是本次实验没得其它服务器, 所以就print出来瞧瞧吧

原理

大概就是这么个样子
大概就是这么个样子

和之前的差不多, 只是多了个支持SSL

使用

self.server #REAL SERVER 就是真实的mysql服务器
self.host 监听地址
self.port 监听端口
self.cert 证书 使用的mysql自己的, 也可以使用openssl去生成
self.key

官方生成证书教程: https://dev.mysql.com/doc/refman/5.7/en/creating-ssl-files-using-openssl.html

执行脚本

python mysql_monitor.py
发现确实使用的SSL
发现确实使用的SSL

注: TLS继承自SSL

看下我们Print出来的流量

S->C : 表示该数据包是真实服务器发往客户端的(实际上是我们转发的)
C->S : 表示该数据包是客户端发往真实服务器的(实际上是我们转发的)
后面的序号表示 seq.
seq在每个query里面都会重置为0,  最大255, 超过255的就又从0开始( seq %= 255)
感兴趣的可以看下超过seq超过255的时候的效果
感兴趣的可以看下超过seq超过255的时候的效果

非ssl连接也是可以的, 这里就不演示了.

这里看到的是明文是因为, 我们读取包之后就已经解析为明文了, 方便处理数据. 如果你使用抓包软件(tcpdump/wireshark)之类的看到的就是加密之后的数据

为了方便观察, mysql连接的时候使用的127.0.0.1  转发的数据是192.168.101.21
为了方便观察, mysql连接的时候使用的127.0.0.1 转发的数据是192.168.101.21

总结

1. 封装SSL

		if len(bdata) < 38: #封装为SSL (32+4)
			#封装 客户端的SSL (因为相对于client, 这是server角色)
			context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
			context.load_cert_chain(certfile=self.cert, keyfile=self.key)
			conn = context.wrap_socket(conn, server_side=True)
			client_rf = conn.makefile('rb')

			#封装 到server的SSL
			sock = ssl.wrap_socket(sock)
			server_rf = sock.makefile('rb')

2. 如果使用的是makefile的话, 注意封装完ssl后要重新makefile, 不然会报错pipe broken

附脚本

可以自定义输出, 比如包大小, 包类型等.

import struct
from threading import Thread
from multiprocessing import Process
import socket
import time
import sys
import ssl

def btoint(bdata,t='little'):
        return int.from_bytes(bdata,t)

def read_pack(rf):
	pack_header = rf.read(4)
	if len(pack_header) < 4:
		print(pack_header,' bye!')
		sys.exit(2)
	btrl, btrh, packet_seq = struct.unpack("<HBB", pack_header)
	pack_size = btrl + (btrh << 16)
	bdata = rf.read(pack_size)
	return pack_header+bdata

class mmonitor(object): 
	def __init__(self):
		self.host = '0.0.0.0'
		self.port = 3306
		self.server = ('192.168.101.21',3308,)
		self.cert = '/data/mysql_3306/mysqldata/server-cert.pem'
		self.key = '/data/mysql_3306/mysqldata/server-key.pem'
		
	def handler_msg(self,rf,sock,f):
		#print(f'{f} start')
		while True:
			bdata = read_pack(rf)
			sock.sendall(bdata)
			print(f'{f}',btoint(bdata[3:4]),bdata)

	def handler(self,conn,addr):
		sock = socket.create_connection((self.server[0], self.server[1]))
		server_rf = sock.makefile('rb')
		bdata = read_pack(server_rf)
		conn.sendall(bdata)
		print('S->C: ',btoint(bdata[3:4]),bdata)

		client_rf = conn.makefile('rb')
		bdata = read_pack(client_rf)
		print('C->S: ',btoint(bdata[3:4]),bdata)
		sock.sendall(bdata)

		if len(bdata) < 38: #封装为SSL (32+4)
			#print('SSL')
			#封装客户端的SSL (因为相对于client, 这是server角色)
			context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
			context.load_cert_chain(certfile=self.cert, keyfile=self.key)
			conn = context.wrap_socket(conn, server_side=True)
			client_rf = conn.makefile('rb')

			#封装到server的SSL
			sock = ssl.wrap_socket(sock)
			server_rf = sock.makefile('rb')
		
		t1 = Process(target=self.handler_msg,args=(client_rf,sock,'C->S: ')) #监控客户端数据, 然后发往server端
		t2 = Process(target=self.handler_msg,args=(server_rf,conn,'S->C: '))
		t1.start()
		t2.start()
		t1.join()
		t2.join()

	def init(self):
		socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		socket_server.bind((self.host, self.port))
		socket_server.listen(12345) #设置连接数
		self.socket_server = socket_server

		accept_client_thread = Thread(target=self.accept_client,)
		accept_client_thread.start()
		accept_client_thread.join()
		
	def accept_client(self,):
		while True:
			conn, addr = self.socket_server.accept()
			p = Process(target=self.handler,args=(conn,addr),)
			p.start()
	
aa = mmonitor()
aa.init()

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 连接过程
  • SSL包
  • 测试
    • 原理
      • 使用
      • 总结
      • 附脚本
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档