安全的数据库图形管理工具(1):准备密钥

年底了,该干大事了,就问你怕不怕?!

为什么要做一个安全的数据库图形管理工具?

我们都知道,在正式的生产环境下,数据库并不在你工作的电脑上,而是位于机房的实体服务器,或者是位于传说中的云服务器。因此,远程连接数据库是很有必要的。但是,数据库一般安装配置好后是不允许远程连接的,要想允许远程连接,就需要去修改它的连接权限(以MySQL为例)。

当我们通过远程连接工具XShell或者SecureCRT连接到远程服务器之后,输入命令mysql -uroot -p回车输入MySQL的root密码就进入了MySQL交互界面。然后就可以输入SQL语句进行操作了,每输入完SQL语句之后,必须要给一个结束符(英文分号或者\g)。然后我们就可以修改它的权限了,首先执行SQL语句:GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'IDENTIFIED BY 'password' WITH GRANT OPTION;然后执行SQL语句:FLUSH PRIVILEGES;使修改生效。

我们来看一下第一个SQL语句,‘root’@‘%’表示任何机器都可以以root用户名登录数据库,其中%表示任何机器,‘password’是root账户的密码。像这样任何人都有访问服务器数据库的权限太不安全了,这种方式简直就是瞎胡闹!有些人会想,既然%表示所有机器,那么我把%改成我工作的电脑的IP就行了吧,如果服务器在公司那没啥问题,因为毕竟只会从公司内网连过去,公司外的不法分子很难抓到数据(如果这都被抓到了,只能说明公司的安全系统出问题了)。

但是如果你人不在公司,又或者服务器不是公司内的实体服务器,而是传说中的云服务器,这样连接的到服务器数据库会通过好多个路由器,在通过路由器期间一旦被中间人将密码窃取并破解后果不堪设想。有些人可能会想,在把密码发过去之前已经加密了,难道这还会被破解?依旧是有可能会,因为MySQL数据库密码使用的是SHA1加密算法,这个算法现在已经非常不安全了,所以被破解很有可能。

难道真的没有办法远程连接数据库了吗?办法还是有的,在给出解决方案之前,我们来想一下这样两个问题:为什么我可以通过远程连接工具实现连接?远程连接工具真的安全吗?说实话,这还真的是安全的,因为这些工具使用了更强的加密算法——非对称加密

非对称加密

在网络通信中,主机A发送一个消息到达主机B,大部分情况下,这个消息并不是直接到达的,而是中间经过了好多的分组转发,在分组转发期间,如果消息被中间人窃取后果不堪设想!因此,加密传输的技术诞生了。加密算法目前分为两种——对称加密和非对称加密。对称加密是发送方用某种加密算法加密,接收方接收到密文之后再使用对应的解密算法解密,也就是加密和解密使用同一个密钥,如果中间人窃取了密文并破解那后果不堪设想。因此,更安全的非对称加密诞生了。非对称加密与对称加密不同的是它有两个密钥——公钥和私钥。公钥是公开的,可以给任何人;私钥只能你自己保管。

同样的还是A和B两个主机发送数据,当A要给B发送数据,A必须要有B的公钥才行,A将发送的数据使用B的公钥加密后发送,然后B接收到之后使用自己的私钥解密就行了。这样的话中间人即使窃取到了也还是无能为力,因为中间人没有B的私钥!

难道只能通过终端操作远程数据库?

通过远程连接工具数据传输确实得到了安全的保证,但是有些人会觉得不爽,因为没有图形化管理工具(实际上有图形化管理工具,但现有的MySQL图形化管理工具都是使用的对称加密)。既然没有可靠的图形化管理工具,那我们就自己做一个!

准备密钥

既然知道了为什么要自己做一个数据库图形管理工具,就可以开始做前期的准备工作了!我们首先来想这样一个问题,我们能不能从远程连接工具里面获取密钥呢?当然可以!但这太繁琐了,所以我们通过编写程序来获取。

公钥给对方,私钥自己留!

在编写程序之前,我们先想一下非对称加密的过程——发送方要有接收方的公钥才能够正确的加密!因此客户端服务器交换公钥成了准备密钥的核心操作!

用程序生成公钥私钥我们需要使用模块rsa,如果没有该模块,请使用pip安装。

客户端程序

客户端需要生成自己的公钥私钥,并把公钥交给服务器保管,私钥自己留着。具体实现的细节我就不讲了,代码中有注释!下面我直接给出客户端代码:

  import rsa
  import socket
  host = ""  # 服务器的IP地址
  port = 1234  # 服务器程序的端口号
  public_key, private_key = rsa.newkeys(256)  # 生成公钥和私钥
  private_key = private_key.save_pkcs1()  # 获取私钥使用对应存储格式的字符串
  public_key = public_key.save_pkcs1()  # 获取公钥使用对应存储格式的字符串
  open("self_private_key.pem", "wb").write(private_key)  # 将自己的私钥保存起来
  s = socket.socket()  # 创建套接字对象
  s.connect((host, port))  # 与服务器建立连接
  s.send(public_key)  # 将公钥发送给服务器
  server_public_key = s.recv(512)  # 将服务器的公钥接收回来
  open("server_public_key.pem", "wb").write(server_public_key)  # 保存服务器的公钥

通过注释,我相信大家很容易理解这段代码,我就不做解释了。下面我开始讲解服务器代码!

服务器程序

和客户端程序一样,服务器程序依旧需要生成自己的公钥私钥,公钥给客户端,私钥自己留着。具体实现的细节我页不讲了,代码中有注释!下面我直接给出服务器代码:

  import rsa
  import socket
  host = ""  # 服务器IP地址,什么都不写表示本地
  port = 1234  # 服务器程序端口号
  public_key, private_key = rsa.newkeys(256)  # 生成公钥和私钥
  private_key = private_key.save_pkcs1()  # 获取私钥使用对应存储格式的字符串
  public_key = public_key.save_pkcs1()  # 获取公钥使用对应存储格式的字符串
  open("self_private_key.pem", "wb").write(private_key)  # 将自己的私钥保存起来
  s = socket.socket()  # 创建套接字对象
  s.bind((host, port))  # 捆绑IP地址和端口号,让客户端程序可以找到
  s.listen(1)  # 最大连接数
  c, addr = s.accept()  # 接受客户端连接
  c.send(public_key)  # 将公钥发送给客户端
  client_public_key = c.recv(512)  # 接受客户端发来的公钥
  open("client_public_key.pem", "wb").write(client_public_key)  # 保存客户端的公钥
  c.close()  # 关闭客户端
  s.close()  # 关闭服务器

运行程序

运行程序的过程很简单,先运行服务器程序,然后再运行客户端程序。等运行完之后查看客户端程序对应的目录下会有两个文件——self_private_key.pem(自己的私钥)和server_public_key.pem(服务器的公钥)。如图所示。

同样的,服务器程序所在的目录下也会有两个文件——self_private_key.pem(自己的私钥)和client_public_key.pem(客户端的公钥)。

测试密钥

密钥虽然生成了,但到底能不能用呢?写一个程序验证一下就行了。为什么要验证?因为客户端服务器交换公钥的途中有可能公钥被截获并篡改!验证的过程非常简单,客户端和服务器建立连接之后,客户端用服务器的公钥加密要发送的数据并发送给服务器,在此期间,服务器用客户端公钥加密发送的数据并发送客户端。然后就是双方都接收对方发来的加密数据,最后用自己的私钥解密并输出。

客户端测试程序

客户端测试程序需要加载自己的私钥和对方的公钥,然后把发送的数据用对方的公钥加密并发送给对方,接着接收对方发来的加密的数据。最后解密接收的数据并输出。具体实现的细节我就不讲了,代码中有注释!下面我直接给出客户端测试程序代码:

  import rsa
  import socket
  public_key = open("server_public_key.pem", "rb").read()  # 打开公钥文件并读取
  public_key = rsa.PublicKey.load_pkcs1(public_key)  # 加载公钥
  private_key = open("self_private_key.pem", "rb").read()  # 打开私钥文件并读取
  private_key = rsa.PrivateKey.load_pkcs1(private_key)  # 加载私钥
  send_encode_data = rsa.encrypt(b"client", public_key)  # 用公钥加密要发送的数据
  s = socket.socket()  # 创建套接字对象
  host = "111.230.108.44"  # 服务器的IP地址
  port = 1234  # 服务器程序的端口号
  s.connect((host, port))  # 连接服务器
  s.send(send_encode_data)  # 发送已经加密的数据
  receive_encode_data = s.recv(128)  # 接受已经加密的数据
  print(rsa.decrypt(receive_encode_data, private_key).decode())  # 解密接收到的加密数据并输出

服务器测试程序

与客户端测试程序一样,服务器测试程序依旧需要加载对方的的公钥和自己的私钥,然后把发送的数据用对方的公钥加密并发送给对方,接着接收对方发来的加密的数据。最后解密接收的数据并输出。具体实现的细节我就不讲了,代码中有注释!下面我直接给出服务器测试程序代码:

  import rsa
  import socket
  public_key = open("client_public_key.pem", "rb").read()  # 打开公钥文件并读取
  public_key = rsa.PublicKey.load_pkcs1(public_key)  # 加载公钥
  private_key = open("self_private_key.pem", "rb").read()  # 打开私钥文件并读取
  private_key = rsa.PrivateKey.load_pkcs1(private_key)  # 加载私钥
  send_encode_data = rsa.encrypt(b"server", public_key)  # 用公钥加密要发送的数据
  s = socket.socket()  # 创建套接字对象
  host = ""  # 服务器IP地址
  port = 1234  # 服务器程序端口号
  s.bind((host, port))  # 捆绑IP地址和端口号,让客户端程序可以找到
  s.listen(1)  # 最大连接数
  c, addr = s.accept()  # 接受客户端的连接
  c.send(send_encode_data)  # 发送已经加密的数据
  receive_encode_data = c.recv(128)  # 接收已经加密的数据
  print(rsa.decrypt(receive_encode_data, private_key).decode())  # 解密接收到的加密数据并输出
  c.close()
  s.close()

运行测试程序

运行程序的过程很简单,先运行服务器程序,然后再运行客户端程序。等程序运行完之后,发现客户端程序执行结果如图所示。

同样的,服务器程序执行结果如图所示。

通过结果我们可以看出,客户端测试程序可以解密服务器用客户端公钥加密的数据,服务器测试程序也可以解密客户端用服务器公钥加密的数据。

本文分享自微信公众号 - 小陈学Python(gh_a29b1ed16571)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券