BackIcon使用 TLS 加密 FRPS与 FRPC 通信,并开启服务端与客户端的双向验证

2025年7月12日

Openai logomark

Hello from iCESAMA

一、为什么要使用 TLS 加密 FRPS 与 FRPC 通信

transport.useEncryption 和 STCP 等功能能有效防止流量内容在通信过程中被盗取,但是无法判断对方的身份是否合法,存在被中间人攻击的风险。为此 frp 支持 frpc 和 frps 之间的流量通过 TLS 协议加密,并且支持客户端或服务端单向验证,双向验证等功能。

二、如何使用 TLS 加密 FRPS 与 FRPC 通信

ℹ️
本文使用的frps/frpc版本为 v0.63.0,此时frp的配置文件已转为 toml 而非 ini

2.1、生成证书

ℹ️
go 1.15 版本开始废弃 CommonName,因此推荐使用 SAN 证书。
我部署的环境 Frpc 是通过 IP 地址连接至 Frps ,如你的部署环境与我不同,请自行斟酌。

我已经编写了自动生成 CA 证书、服务端证书、客户端证书的脚本,脚本会生成一个 CA 证书和对应的服务端、客户端证书。你可以直接使用这个脚本生成证书。

#!/bin/bash

set -e

# === 参数 ===
CA_CN="example.ca.com"
SERVER_CN="server.com"
CLIENT_CN="client.com"
SERVER_IP="X.X.X.X" # 将此替换为你的Frps服务端 IP 地址

# === 清理旧文件 ===
rm -f ca.key ca.crt ca.srl \
      server.key server.csr server.crt \
      client.key client.csr client.crt \
      my-openssl.cnf

echo "[+] 创建简化 openssl 配置文件 my-openssl.cnf..."

cat > my-openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
x509_extensions = usr_cert
[ req ]
default_bits        = 2048
default_md          = sha256
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
attributes          = req_attributes
x509_extensions     = v3_ca
string_mask         = utf8only
[ req_distinguished_name ]
[ req_attributes ]
[ usr_cert ]
basicConstraints       = CA:FALSE
nsComment              = "OpenSSL Generated Certificate"
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
[ v3_ca ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints       = CA:true
EOF

# === 生成 CA ===
echo "[+] 生成 CA 证书..."
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${CA_CN}" -days 3650 -out ca.crt

# === 生成服务端证书 ===
echo "[+] 生成 frps 证书..."
openssl genrsa -out server.key 2048
openssl req -new -sha256 -key server.key \
    -subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=${SERVER_CN}" \
    -reqexts SAN \
    -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=IP:${SERVER_IP},DNS:${SERVER_CN}")) \
    -out server.csr

openssl x509 -req -days 825 -sha256 \
    -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -extfile <(printf "subjectAltName=IP:${SERVER_IP},DNS:${SERVER_CN}") \
    -out server.crt

# === 生成客户端证书 ===
echo "[+] 生成 frpc 证书..."
openssl genrsa -out client.key 2048
openssl req -new -sha256 -key client.key \
    -subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=${CLIENT_CN}" \
    -reqexts SAN \
    -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:${CLIENT_CN}")) \
    -out client.csr

openssl x509 -req -days 825 -sha256 \
    -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -extfile <(printf "subjectAltName=DNS:${CLIENT_CN}") \
    -out client.crt

echo "[✓] 所有证书和私钥生成完毕。"
ℹ️
脚本生成的证书和私钥文件会生成在脚本同目录下。

脚本生成的证书和私钥文件指定使用了 2048-bit 密钥与 SHA-256 签名,保证了强加密与安全性。
将生成的证书和私钥文件 CA 文件放到 frps 和 frpc 的配置文件中指定的路径下。

2.2、frps.toml 配置

# frps监听设置


# TLS 加密配置
transport.tls.force = true # 强制frpc连接至frps时使用 TLS 加密并验证证书
transport.tls.certFile = "/etc/frp/ssl/server.crt"
transport.tls.keyFile = "/etc/frp/ssl/server.key"
transport.tls.trustedCaFile = "/etc/frp/ssl/ca.crt"

# 其他配置

2.3、frpc.toml 配置

# frpc连接设置


# TLS 加密配置
transport.tls.certFile = "/to/cert/path/client.crt"
transport.tls.keyFile = "/to/key/path/client.key"
transport.tls.trustedCaFile = "/to/ca/path/ca.crt"

# 其他配置


2.4、启动 frps 和 frpc

这个不用我教了吧。