searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

MITM介绍及预防

2024-11-04 09:32:48
8
0

中间人攻击 (Man-In-The-Middle Attack, MITM) 是一种网络攻击形式,攻击者通过在客户端和服务器之间劫持通信来读取、篡改数据。这种攻击可以让攻击者拦截和修改客户端与服务器间的流量。

不过,本文章出于教育与防范目的,介绍 MITM 攻击的原理及如何防范,而非用于实施此类攻击。

一、MITM 的流程步骤详解

1. MITM 攻击原理

MITM 攻击的核心流程是攻击者将自己伪装为服务器和客户端的中间节点,以窃取或篡改通信内容。实现这一过程的关键步骤如下:

  1. 监听​:在网络中侦听数据包,通过工具(如 Wireshark)收集客户端和服务器之间的通信数据。
  2. 截取通信​:中间人攻击者通过 DNS 欺骗、ARP 欺骗等手段,将数据流劫持到自身设备上。
  3. 转发请求​:攻击者将客户端发送的请求转发至服务器,假装客户端正在与服务器直接通信。
  4. 篡改或窃取数据​:攻击者读取数据包内容并可能篡改信息(如更改交易金额或劫持敏感信息)。
  5. 将响应返回客户端​:攻击者从服务器接收到响应后,将其转发给客户端。

2. MITM 攻击流程图解

以下是一个典型的 MITM 攻击流程图示:

Client         Attacker           Server
      |               |                 |
      |  Request -->  |                 |
      |               |  Request -->    |
      |               |                 |
      |               | <--- Response   |
      | <--- Response |                 |
      |               |                 |
  1. 客户端发送请求​:客户端向服务器发起 HTTP/HTTPS 请求。
  2. 攻击者截取请求​:攻击者通过中间人设备拦截请求,充当“伪服务器”。
  3. 请求转发到服务器​:攻击者以客户端身份将请求转发到服务器。
  4. 服务器响应​:服务器将响应数据发回给攻击者,认为请求来自客户端。
  5. 攻击者篡改或窃取响应​:攻击者可以选择篡改或记录该响应。
  6. 攻击者转发响应​:攻击者以服务器身份将响应发给客户端,完成 MITM 攻击。

在一个典型的 MITM 代理中,如果要拦截 HTTPS 通信,需要处理以下步骤:

  1. 生成和使用自签名证书​:攻击者需要伪造服务器证书,使客户端以为它在连接真实的服务器。可以使用自签名证书,代理每次拦截请求时生成与真实服务器域名匹配的证书。
  2. 双向 TLS 会话​:代理必须同时建立两条 TLS 会话,一条用于连接客户端,另一条用于连接目标服务器。代理服务器充当客户端时连接到目标服务器,充当服务器时响应客户端的请求。

下面是一个实现双向 TLS 会话的 Golang 示例,适用于教育和防范目的。

完整 MITM 双向 TLS Golang 示例

以下代码包含如何生成和使用自签名证书,并实现双向 TLS 建立的代理流程:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"io"
	"log"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"
)

// 生成自签名证书
func generateCertificate(host string) (tls.Certificate, error) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return tls.Certificate{}, err
	}

	// 设置证书的属性
	template := x509.Certificate{
		SerialNumber: big.NewInt(time.Now().UnixNano()),
		Subject: pkix.Name{
			Organization: []string{"MITM Proxy"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(365 * 24 * time.Hour), // 有效期1年
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}

	// 添加主机名到证书
	template.DNSNames = append(template.DNSNames, host)

	// 使用私钥签署证书
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return tls.Certificate{}, err
	}

	// 编码证书和私钥
	certOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	keyOut := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return tls.X509KeyPair(certOut, keyOut)
}

// HTTPS劫持处理
func handleHTTPS(clientConn net.Conn, host string) {
	// 生成自签名证书
	cert, err := generateCertificate(host)
	if err != nil {
		log.Println("生成证书失败:", err)
		clientConn.Close()
		return
	}

	// 使用自签名证书建立TLS连接
	config := &tls.Config{Certificates: []tls.Certificate{cert}}
	serverTLSConn := tls.Server(clientConn, config)
	err = serverTLSConn.Handshake()
	if err != nil {
		log.Println("客户端TLS握手失败:", err)
		serverTLSConn.Close()
		return
	}

	// 与目标服务器建立TLS连接
	targetConn, err := tls.Dial("tcp", host, &tls.Config{InsecureSkipVerify: true})
	if err != nil {
		log.Println("连接目标服务器失败:", err)
		serverTLSConn.Close()
		return
	}

	// 进行双向传输
	go transferData(serverTLSConn, targetConn)
	go transferData(targetConn, serverTLSConn)
}

// 双向数据传输
func transferData(dst io.WriteCloser, src io.ReadCloser) {
	defer dst.Close()
	defer src.Close()
	io.Copy(dst, src)
}

// HTTP 劫持处理
func handleHTTP(w http.ResponseWriter, req *http.Request) {
	// 代理请求到目标服务器
	client := &http.Client{}
	req.RequestURI = ""
	resp, err := client.Do(req)
	if err != nil {
		http.Error(w, "请求失败", http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	// 返回响应给客户端
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

func main() {
	// 处理 HTTP/HTTPS 请求
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodConnect {
			// HTTPS 劫持
			host := r.Host
			if !strings.Contains(host, ":") {
				host += ":443"
			}
			conn, _, err := w.(http.Hijacker).Hijack()
			if err != nil {
				http.Error(w, "连接劫持失败", http.StatusInternalServerError)
				return
			}
			handleHTTPS(conn, host)
		} else {
			// HTTP 劫持
			handleHTTP(w, r)
		}
	})

	// 启动代理服务器
	fmt.Println("启动 MITM 代理服务,监听端口 :8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("代理服务启动失败:", err)
	}
}

代码解析

  1. 生成自签名证书​:generateCertificate 函数为指定的主机名生成一个自签名的 X.509 证书。这里利用了 Go 标准库的 x509rsa 包来生成证书。
  2. HTTPS 劫持处理​:handleHTTPS 函数建立双向 TLS 会话:
    • 首先使用生成的自签名证书对客户端进行 TLS 握手。
    • 然后,使用 tls.Dial 与目标服务器建立 TLS 连接,配置为跳过证书验证(InsecureSkipVerify),允许连接不受信任的证书。
  3. 数据传输​:transferData 函数用于将数据从客户端传输到服务器,再将服务器响应数据传回客户端,从而实现中间人攻击的双向流量传输。
  4. 代理 HTTP 请求​:handleHTTP 函数用于处理 HTTP 请求,并直接将请求转发到目标服务器,同时返回服务器响应数据。
  5. 启动代理服务器​:在 main 函数中,使用 http.HandleFunc 定义 HTTP 和 HTTPS 劫持的处理逻辑,监听本地端口 :8080

防范措施

  1. 使用可信的 CA 证书​:通过安装和验证可信的证书可以识别伪造的证书。
  2. 双向 TLS 验证​:在敏感系统中配置双向认证,确保服务器和客户端身份都经过验证。
  3. ​**HTTPS 严格传输安全 (HSTS)**​:HSTS 可以防止中间人攻击降级到 HTTP。

请注意​:本代码仅用于教育和学习目的,帮助了解 MITM 原理及其防范措施。未经授权的网络拦截和攻击行为是违法的。

0条评论
作者已关闭评论
郑****辉
6文章数
0粉丝数
郑****辉
6 文章 | 0 粉丝
郑****辉
6文章数
0粉丝数
郑****辉
6 文章 | 0 粉丝
原创

MITM介绍及预防

2024-11-04 09:32:48
8
0

中间人攻击 (Man-In-The-Middle Attack, MITM) 是一种网络攻击形式,攻击者通过在客户端和服务器之间劫持通信来读取、篡改数据。这种攻击可以让攻击者拦截和修改客户端与服务器间的流量。

不过,本文章出于教育与防范目的,介绍 MITM 攻击的原理及如何防范,而非用于实施此类攻击。

一、MITM 的流程步骤详解

1. MITM 攻击原理

MITM 攻击的核心流程是攻击者将自己伪装为服务器和客户端的中间节点,以窃取或篡改通信内容。实现这一过程的关键步骤如下:

  1. 监听​:在网络中侦听数据包,通过工具(如 Wireshark)收集客户端和服务器之间的通信数据。
  2. 截取通信​:中间人攻击者通过 DNS 欺骗、ARP 欺骗等手段,将数据流劫持到自身设备上。
  3. 转发请求​:攻击者将客户端发送的请求转发至服务器,假装客户端正在与服务器直接通信。
  4. 篡改或窃取数据​:攻击者读取数据包内容并可能篡改信息(如更改交易金额或劫持敏感信息)。
  5. 将响应返回客户端​:攻击者从服务器接收到响应后,将其转发给客户端。

2. MITM 攻击流程图解

以下是一个典型的 MITM 攻击流程图示:

Client         Attacker           Server
      |               |                 |
      |  Request -->  |                 |
      |               |  Request -->    |
      |               |                 |
      |               | <--- Response   |
      | <--- Response |                 |
      |               |                 |
  1. 客户端发送请求​:客户端向服务器发起 HTTP/HTTPS 请求。
  2. 攻击者截取请求​:攻击者通过中间人设备拦截请求,充当“伪服务器”。
  3. 请求转发到服务器​:攻击者以客户端身份将请求转发到服务器。
  4. 服务器响应​:服务器将响应数据发回给攻击者,认为请求来自客户端。
  5. 攻击者篡改或窃取响应​:攻击者可以选择篡改或记录该响应。
  6. 攻击者转发响应​:攻击者以服务器身份将响应发给客户端,完成 MITM 攻击。

在一个典型的 MITM 代理中,如果要拦截 HTTPS 通信,需要处理以下步骤:

  1. 生成和使用自签名证书​:攻击者需要伪造服务器证书,使客户端以为它在连接真实的服务器。可以使用自签名证书,代理每次拦截请求时生成与真实服务器域名匹配的证书。
  2. 双向 TLS 会话​:代理必须同时建立两条 TLS 会话,一条用于连接客户端,另一条用于连接目标服务器。代理服务器充当客户端时连接到目标服务器,充当服务器时响应客户端的请求。

下面是一个实现双向 TLS 会话的 Golang 示例,适用于教育和防范目的。

完整 MITM 双向 TLS Golang 示例

以下代码包含如何生成和使用自签名证书,并实现双向 TLS 建立的代理流程:

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"io"
	"log"
	"math/big"
	"net"
	"net/http"
	"strings"
	"time"
)

// 生成自签名证书
func generateCertificate(host string) (tls.Certificate, error) {
	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return tls.Certificate{}, err
	}

	// 设置证书的属性
	template := x509.Certificate{
		SerialNumber: big.NewInt(time.Now().UnixNano()),
		Subject: pkix.Name{
			Organization: []string{"MITM Proxy"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(365 * 24 * time.Hour), // 有效期1年
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}

	// 添加主机名到证书
	template.DNSNames = append(template.DNSNames, host)

	// 使用私钥签署证书
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return tls.Certificate{}, err
	}

	// 编码证书和私钥
	certOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	keyOut := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})

	return tls.X509KeyPair(certOut, keyOut)
}

// HTTPS劫持处理
func handleHTTPS(clientConn net.Conn, host string) {
	// 生成自签名证书
	cert, err := generateCertificate(host)
	if err != nil {
		log.Println("生成证书失败:", err)
		clientConn.Close()
		return
	}

	// 使用自签名证书建立TLS连接
	config := &tls.Config{Certificates: []tls.Certificate{cert}}
	serverTLSConn := tls.Server(clientConn, config)
	err = serverTLSConn.Handshake()
	if err != nil {
		log.Println("客户端TLS握手失败:", err)
		serverTLSConn.Close()
		return
	}

	// 与目标服务器建立TLS连接
	targetConn, err := tls.Dial("tcp", host, &tls.Config{InsecureSkipVerify: true})
	if err != nil {
		log.Println("连接目标服务器失败:", err)
		serverTLSConn.Close()
		return
	}

	// 进行双向传输
	go transferData(serverTLSConn, targetConn)
	go transferData(targetConn, serverTLSConn)
}

// 双向数据传输
func transferData(dst io.WriteCloser, src io.ReadCloser) {
	defer dst.Close()
	defer src.Close()
	io.Copy(dst, src)
}

// HTTP 劫持处理
func handleHTTP(w http.ResponseWriter, req *http.Request) {
	// 代理请求到目标服务器
	client := &http.Client{}
	req.RequestURI = ""
	resp, err := client.Do(req)
	if err != nil {
		http.Error(w, "请求失败", http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	// 返回响应给客户端
	for k, v := range resp.Header {
		w.Header()[k] = v
	}
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

func main() {
	// 处理 HTTP/HTTPS 请求
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodConnect {
			// HTTPS 劫持
			host := r.Host
			if !strings.Contains(host, ":") {
				host += ":443"
			}
			conn, _, err := w.(http.Hijacker).Hijack()
			if err != nil {
				http.Error(w, "连接劫持失败", http.StatusInternalServerError)
				return
			}
			handleHTTPS(conn, host)
		} else {
			// HTTP 劫持
			handleHTTP(w, r)
		}
	})

	// 启动代理服务器
	fmt.Println("启动 MITM 代理服务,监听端口 :8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		log.Fatal("代理服务启动失败:", err)
	}
}

代码解析

  1. 生成自签名证书​:generateCertificate 函数为指定的主机名生成一个自签名的 X.509 证书。这里利用了 Go 标准库的 x509rsa 包来生成证书。
  2. HTTPS 劫持处理​:handleHTTPS 函数建立双向 TLS 会话:
    • 首先使用生成的自签名证书对客户端进行 TLS 握手。
    • 然后,使用 tls.Dial 与目标服务器建立 TLS 连接,配置为跳过证书验证(InsecureSkipVerify),允许连接不受信任的证书。
  3. 数据传输​:transferData 函数用于将数据从客户端传输到服务器,再将服务器响应数据传回客户端,从而实现中间人攻击的双向流量传输。
  4. 代理 HTTP 请求​:handleHTTP 函数用于处理 HTTP 请求,并直接将请求转发到目标服务器,同时返回服务器响应数据。
  5. 启动代理服务器​:在 main 函数中,使用 http.HandleFunc 定义 HTTP 和 HTTPS 劫持的处理逻辑,监听本地端口 :8080

防范措施

  1. 使用可信的 CA 证书​:通过安装和验证可信的证书可以识别伪造的证书。
  2. 双向 TLS 验证​:在敏感系统中配置双向认证,确保服务器和客户端身份都经过验证。
  3. ​**HTTPS 严格传输安全 (HSTS)**​:HSTS 可以防止中间人攻击降级到 HTTP。

请注意​:本代码仅用于教育和学习目的,帮助了解 MITM 原理及其防范措施。未经授权的网络拦截和攻击行为是违法的。

文章来自个人专栏
代理
4 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0