golang的socket的安全(传输安全)

前面的实现完全是在网络上裸奔的,通过抓包工具很容易看到传输的内容是什么,接下来我们利用现成的TLS来实现一个更为安全的服务.

生成服务器端的私钥

openssl genrsa -out server.key 2048

生成服务器端证书

openssl req -new -x509 -key server.key -out server.pem -days 3650

服务端代码如下

package main

/*
* tls服务端
 */

import (
	"bufio"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"math/rand"
	"net"
	"strings"
	"sync"
	"time"
)

//保存连接
var connList sync.Map

//消息结构{"from":"aaa","to":"bbb","body":"aaa","cmd":"sendMsg"}
type UserMsg struct {
	From string `json:"from"`
	To   string `json:"to"`
	Body string `json:"body"`
	Cmd  string `json:"cmd"`
}

//随机字符串
func randName() string {
	var letterRunes = []rune("123456789")
	rand.Seed(time.Now().UnixNano())
	b := make([]rune, 6)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func DealConn(conn net.Conn) {
	// 处理完关闭连接
	defer conn.Close()
	fmt.Println("new conn\n")
	conn.Write([]byte("hello\n"))
	//安全认证+读取超时
	conn.SetReadDeadline(time.Now().Add(20 * time.Second))
	reader := bufio.NewReader(conn)
	str, err := reader.ReadString('\n')
	if err == nil {
		str = strings.TrimSpace(str)
		var strStruct UserMsg
		err := json.Unmarshal([]byte(str), &strStruct)
		if err != nil {
			fmt.Printf("msg json error, err:%v\n", err)
			return
		} else {
			if strStruct.Cmd == "auth" {
				if strStruct.Body != "123456" {
					fmt.Println("not auth")
					return
				}
			} else {
				fmt.Println("not auth")
				return
			}
		}
	} else {
		return
	}

	name := randName()
	connList.Store(name, conn)
	conn.Write([]byte("you is  : " + name + "\r\n"))

	// 针对当前连接做发送和接受操作
	for {
		conn.SetReadDeadline(time.Now().Add(3600 * time.Second))
		reader := bufio.NewReader(conn)
		// 读取字符串, 直到碰到回车返回
		str, err := reader.ReadString('\n')
		// 数据读取正确
		if err == nil {
			// 去掉字符串尾部的回车
			str = strings.TrimSpace(str)
			var strStruct UserMsg
			err := json.Unmarshal([]byte(str), &strStruct)
			if err != nil {
				fmt.Printf("msg json error, err:%v\n", err)
			} else {
				to := strStruct.To
				cmd := strStruct.Cmd
				if cmd == "sendMsg" {
					toUser, ok := connList.Load(to)
					if !ok {
						fmt.Println("to user is not\n")
					} else {
						toUserConn, ok := toUser.(net.Conn)
						if !ok {
							fmt.Println("to user type wrong\n")
						} else {
							toUserConn.Write([]byte(strStruct.From + " say : " + strStruct.Body + "\r\n"))
						}
					}
				} else {
					fmt.Println("unkonw msg")
				}
			}
		} else {
			//删除保存的连接
			connList.Delete(name)
			fmt.Println("conn close\n")
			break
		}
	}
}

func main() {
	cert, err := tls.LoadX509KeyPair("server.pem", "server.key")
	if err != nil {
		fmt.Println(err)
		return
	}
	config := &tls.Config{Certificates: []tls.Certificate{cert}}
	// 建立tcp 服务
	listen, err := tls.Listen("tcp", "0.0.0.0:1215", config)
	if err != nil {
		fmt.Printf("listen failed, err:%v\n", err)
		return
	}

	for {
		// 等待客户端建立连接
		fmt.Printf("accept conn ...... \n")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Printf("accept failed, err:%v\n", err)
			continue
		}

		// 启动一个单独的 goroutine 去处理连接
		go DealConn(conn)
	}
}

生成客户端的私钥

openssl genrsa -out client.key 2048

生成客户端的证书

openssl req -new -x509 -key client.key -out client.pem -days 3650

客户端的代码如下:

package main

import (
	"crypto/tls"
	"log"
	"time"
)

func main() {
	conf := &tls.Config{
		InsecureSkipVerify: true,
	}
	conn, err := tls.Dial("tcp", "127.0.0.1:1215", conf)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()
	conn.Write([]byte("{\"from\":\"aaa\",\"to\":\"678292\",\"body\":\"123456\",\"cmd\":\"auth\"}\n"))
	conn.Write([]byte("{\"from\":\"aaa\",\"to\":\"678292\",\"body\":\"123456\",\"cmd\":\"sendMsg\"}\n"))
	buf := make([]byte, 100)
	n, err := conn.Read(buf)
	if err != nil {
		log.Println(n, err)
		return
	}
	println(string(buf[:n]))
	time.Sleep(time.Second * 10)
}

通过使用tls我们就快速实现了一个更为安全的socket服务.

此条目发表在 网站开发 分类目录,贴了 标签。将固定链接加入收藏夹。

golang的socket的安全(传输安全)》有 1 条评论

  1. xtgxiso 说:

    除去这种方式是不是还有其他方式呢?