如何利用SSH隧道连接远程MySQL数据库

 更新时间:2024年11月07日 09:39:47   作者:搬山境KL攻城狮  
为保护MySQL数据库安全,可通过SSH隧道连接,服务端仅需开放SSH端口,加强密码策略,客户端可使用Navicat等工具,或通过编程(如SpringBoot)实现端口转发,推荐使用密钥建立SSH隧道,以免密码泄露风险,详述了端口转发的手动设置方法及自动化脚本配置

一、前言

MySQL数据库漏洞频出,不适合直接将3306端口开放到公网。

而实际情况,可能通过公网访问数据库的需求,可考虑利用SSH隧道连接远程MySQL数据库。

二、MySQL服务端

MySQL服务端无须额外配置,只需要开放ssh公网端口即可!

为了进一步增加安全性,强烈建议,增加密码重试策略、密码复杂度规则。

另外,确认MySQL访问权限,mysql.user表中是否存在host=’%’;的记录,删除并刷新权限。

delete from mysql.user where host='%';
flush privileges;

示例:

  • 服务器IP(公网IP): 192.168.1.200
  • SSH端口:10022
  • SSH用户名:test1
  • SSH密码:flzx3000c
  • MySQL端口:3306
  • MySQL用户名:root
  • MySQL密码:ysyhl9t

三、MySQL客户端

1.通过navicat工具利用SSH隧道连接MySQL数据库

注意:127.0.0.1为192.168.1.200的本地地址,而非客户端的本地地址,此地址必须在mysql.user表中host里存在。

2.手动建立端口转发规则(以linux为例)

# 端口转发
ssh -NCPf test1@192.168.1.200 -p 10022 -L 3388:127.0.0.1:3306
# 查看端口状态
netstat -ano |grep 3388
# 测试MySQL连接
mysql -P 3388 -u root -p
>show databases;

参数解释:

  • C 使用压缩功能,是可选的,加快速度。
  • P 用一个非特权端口进行出去的连接。
  • f SSH完成认证并建立port forwarding后转入后台运行。
  • N 不执行远程命令。该参数在只打开转发端口时很有用(V2版本SSH支持)

3.使用jsch进行端口转发(springboot 代码示例)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.55</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3388/mysql
    username: root
    password: ysyhl9t
    driver-class-name: com.mysql.jdbc.Driver
package com.example.demo;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class Runner implements CommandLineRunner {

    /**
     * 测试代码变量暂不提取
     * @param args
     */
    @Override
    public void run(String... args) throws Exception {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("test1", "192.168.1.200", 10022);
            session.setPassword("flzx3000c");
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            // 设置SSH本地端口转发,本地转发到远程
            session.setPortForwardingL(3388, "127.0.0.1", 3306);
        } catch (Exception e) {
            if (null != session) {
                //关闭ssh连接
                session.disconnect();
            }
            e.printStackTrace();
        }
    }

}
package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@SpringBootTest
class DemoApplicationTests {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Test
    void contextLoads() {
        String sql = "select host from mysql.user";
        final List<String> list = jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getString("host"));
		System.out.println(list);
    }

}

四、SSH隧道的建立方式

方式1.用户名和密码

方式2.密钥(推荐)

免密登录(客户端):

ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub test1@192.168.1.200

免密登录原理

1.在A上生成公钥私钥。

2.将公钥拷贝给server B,要重命名成authorized_keys(从英文名就知道含义了)

3.Server A向Server B发送一个连接请求。

4.Server B得到Server A的信息后,在authorized_key中查找,如果有相应的用户名和IP,则随机生成一个字符串,并用Server A的公钥加密,发送给Server A。

5.Server A得到Server B发来的消息后,使用私钥进行解密,然后将解密后的字符串发送给Server B。Server B进行和生成的对比,如果一致,则允许免登录。

6.得到server B发来的消息后,会使用私钥进行解析,然后将机密后的字符串发给server B。

7.接收到机密后的字符串会跟先前生成的字符串进行对比,如果一致就允许免密登陆。

总之:A要免密码登录到B,B首先要拥有A的公钥,然后B要做一次加密验证。对于非对称加密,公钥加密的密文不能公钥解开,只能私钥解开。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MySQL中临时表的基本创建与使用教程

    MySQL中临时表的基本创建与使用教程

    这篇文章主要介绍了MySQL中临时表的基本创建与使用教程,注意临时表中数据的清空问题,需要的朋友可以参考下
    2015-12-12
  • Mysql中NTILE()函数的具体使用

    Mysql中NTILE()函数的具体使用

    NTILE()函数用于将分区中的有序数据分为n个等级,本文主要介绍了Mysql中NTILE()函数的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • MySQL select查询之LIKE与通配符用法

    MySQL select查询之LIKE与通配符用法

    这篇文章主要介绍了MySQL select查询之LIKE与通配符用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • mysql 8.0.15 安装图文教程及数据库基础

    mysql 8.0.15 安装图文教程及数据库基础

    这篇文章主要为大家详细介绍了mysql 8.0.15 安装方法图文教程,及数据库基础知识,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • mysql 10w级别的mysql数据插入

    mysql 10w级别的mysql数据插入

    几天前做了一个短信发送东东,一次性要插入10w以上的手机号码。我的个天啊。
    2011-08-08
  • DROP TABLE在不同数据库中的写法整理

    DROP TABLE在不同数据库中的写法整理

    这篇文章主要介绍了DROP TABLE在不同数据库中的写法整理的相关资料,需要的朋友可以参考下
    2017-04-04
  • mysql慢查询优化之从理论和实践说明limit的优点

    mysql慢查询优化之从理论和实践说明limit的优点

    今天小编就为大家分享一篇关于mysql慢查询优化之从理论和实践说明limit的优点,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • mysql提示[Warning] Invalid (old?) table or database name问题的解决方法

    mysql提示[Warning] Invalid (old?) table or database name问题的解决方

    今天一个朋友的上服务器出现[Warning] Invalid (old?) table or database name问题,通过分析binlog日志发现,在以下sql语句中出现问题,由于涉及敏感内容,用sql语法表示
    2012-07-07
  • MySQL分区表的基本入门教程

    MySQL分区表的基本入门教程

    这篇文章主要给大家介绍了关于MySQL分区表的基本入门教程,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • 解决Mysql Binlog文件太大导致无法解析问题

    解决Mysql Binlog文件太大导致无法解析问题

    这篇文章主要为大家介绍了解决Mysql Binlog文件太大导致无法解析问题,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11

最新评论