加密 frp 配置教程

本篇文章中,记录了如何对 frpc 和 frps 之间的通信内容进行加密,从而有效防止传输内容被截取,保证系统的安全性。

从 v0.52.0 版本开始,frp 开始支持 TOML、YAML 和 JSON 作为配置文件格式。

请注意,INI 已被弃用,并将在未来的发布中移除。新功能只能在 TOML、YAML 或 JSON 中使用。

建议使用 TOML 作为配置文件格式。

应始终使用最新的 frpc 和 frps 的软件版本,新版本通常修复了已知的安全漏洞和问题。

0 提高安全性的方法

0.1 为 token 配置强密码

可以使用 随机密码生成器 来生成包含大小写字母、数字和特殊字符的组合,并定期更改 token。

0.2 修改默认端口

frps 的配置文件中默认使用 7000 端口,建议改为高位端口号。

0.3 限制访问来源

一种方式是可以设置 frp 服务端只接受目标范围的 IP 进行链接,但不适合客户端经常更新 IP 的情形。

另一种方式是只允许特定用户与 frp 服务端进行链接,frp 还支持受控端进行用户访问控制。

0.4 使用 stcp

某些内网服务如果直接暴漏在公网可能存在安全风险,使用 stcp(secret tcp) 类型的代理可以实现将内网服务暴漏给经过授权的用户,但是访问者也需要运行另外一个 frpc 客户端。

0.5 自定义 TLS 加密

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

frps.tomltransport.tls.force = true 时,表示 server 端只接受 TLS 连接的客户端,这也是 frps 验证 frpc 身份的前提条件。如果 frps.tomltransport.tls.trustedCaFile 内容是有效的话,那么默认就会开启 transport.tls.force = true

从 v0.50.0 开始,transport.tls.enable 的默认值将会为 true,默认开启 TLS 协议加密。

如果 frps 端没有配置证书,则会使用随机生成的证书来加密流量。

默认情况下,frpc 开启 TLS 加密功能,但是不校验 frps 的证书。

1 下载

frp 采用 Golang 编写,支持跨平台,仅需下载对应平台的二进制文件即可执行,没有额外依赖。

可以在 Github 的 Release 页面中下载到最新版本的客户端和服务端二进制文件,所有文件被打包在一个压缩包中。

2 生成加密证书

双向验证应该是目前最安全的方案。启用双向验证需要先生成证书。

首先建立一个文件夹,后续在该目录内进行操作。

1
2
mkdir -p /path/to/save
cd /path/to/save

2.1 准备 my-openssl.cnf 文件

将以下配置写入 my-openssl.cnf 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[ 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

2.2 生成 CA

1
2
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.ca.com" -days 5000 -out ca.crt

2.3 生成服务端证书

1
2
3
4
5
6
7
8
9
10
11
12
openssl genrsa -out server.key 2048

openssl req -new -sha256 -key server.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=server.com" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP: 你的服务端公网ip,DNS:example.server.com")) \
-out server.csr

openssl x509 -req -days 5000 -sha256 \
-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:localhost,IP: 你的服务端公网ip,DNS:example.server.com") \
-out server.crt

subjectAltName 中的 IP 地址改为服务端的公网 IP,否则客户端连接时会报如下错误:

[W] [service.go:133] login to server failed: tls: failed to verify certificate: x509: certificate is valid for 127.0.0.1, not x.x.x.x

如果需要绑定域名,将 example.server.com 改为域名。

2.4 生成客户端证书

1
2
3
4
5
6
7
8
9
10
11
12
openssl genrsa -out client.key 2048

openssl req -new -sha256 -key client.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=client.com" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:client.com,DNS:example.client.com")) \
-out client.csr

openssl x509 -req -days 5000 -sha256 \
-in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:client.com,DNS:example.client.com") \
-out client.crt

2.5 文件使用说明

最终文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── ca.crt
├── ca.key
├── ca.srl
├── client.crt
├── client.csr
├── client.key
├── my-openssl.cnf
├── server.crt
├── server.csr
└── server.key

1 directory, 8 file

需要上传到服务端的文件:

1
2
3
4
.
├── ca.crt
├── server.crt
└── server.key

需要上传到客户端的文件:

1
2
3
4
.
├── ca.crt
├── client.crt
└── client.key

3 使用

内网待访问设备(受控端)和本地设备(控制端)都需要启动 frpc 客户端,且需要使用不同的启动配置。

3.1 解压缩

解压下载的压缩包,Linux 通过命令tar -zxvf 包名.tar.gz,Windows 直接通过解压软件解压 zip 包。

将其中的 frpc 拷贝到内网服务所在的机器上,将 frps 拷贝到具有公网 IP 的机器上,放置在任意目录。

3.2 编写配置文件

3.2.1 启动服务端

配置文件示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# frps.toml
# frp 监听的端口,默认是7000,可以改成其他的
bindPort = 7000
# 授权方式,默认为token
auth.method = "token"
# 授权码,请改成更复杂的
auth.token = "aaaaa"

# frp HTTPS TLS配置,按需配置
transport.tls.certFile = "/path/to/server.crt"
transport.tls.keyFile = "/path/to/server.key"
transport.tls.trustedCaFile = "/path/to/ca.crt"

# frp 日志配置,按需配置
log.to = "/path/to/frps.log"
log.level = "info"
log.maxDays = 5

配置并保存后,在当前目录下输入启动命令 ./frps -c ./frps.toml 启动服务端,查看日志文件,检查是否包含类似输出:

1
2024/12/08 13:47:45 [I] [root.go:204] Start frps success

3.2.2 启动客户端

3.2.2.1 启动受控端(内网服务器)

配置文件示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# frpc.toml
# 服务器公网 IP
serverAddr = "1.1.1.1"
# frp 监听的端口,与服务端一致
serverPort = 7000

# 客户端用户名,用于后续权限管理
user = "cli0"

# 授权方式,默认为token
auth.method = "token"
# 授权码,请改成更复杂的
auth.token = "aaaaa"

# frp HTTPS TLS配置,按需配置
transport.tls.certFile = "/path/to/client.crt"
transport.tls.keyFile = "/path/to/client.key"
transport.tls.trustedCaFile = "/path/to/ca.crt"

# frp 日志配置,按需配置
log.to = "./frpc.log"
log.level = "info"
log.maxDays = 5

# frp 代理设置
[[proxies]]
# 代理名
name = "ssh-stcp"
# 代理类型
type = "stcp"
# 仅供本代理使用的安全密钥
secretKey = "bbbbb"
# 允许控制本节点的控制端用户
allowUsers = ["cli1", "cli2", "cli3"]
# 代理地址 IP
localIP = "127.0.0.1"
# 需要对外提供服务的端口
localPort = 22

配置并保存后,在当前目录下输入启动命令 ./frpc -c ./frpc.toml 启动客户端,查看日志文件,检查是否包含类似输出:

1
2024/12/08 20:58:06 [I] [control.go:143] [ssh] start proxy success

3.2.2.3 启动控制端(本地客户端)

配置文件示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# frpc.toml
# 服务器公网 IP
serverAddr = "1.1.1.1"
# frp 监听的端口,与服务端一致
serverPort = 7000

# 客户端用户名,用于后续权限管理
user = "cli1"

# 授权方式,默认为token
auth.method = "token"
# 授权码,请改成更复杂的
auth.token = "aaaaa"

# frp HTTPS TLS配置,按需配置
transport.tls.certFile = "/path/to/client.crt"
transport.tls.keyFile = "/path/to/client.key"
transport.tls.trustedCaFile = "/path/to/ca.crt"

# frp 日志配置,按需配置
log.to = "./frpc.log"
log.level = "info"
log.maxDays = 5

# frp 代理设置
[[visitors]]
# 代理名
name = "ssh-stcp-vistor"
# 代理类型
type = "stcp"
# 目标连接的受控端用户名
serverUser = "cli0"
# 目标连接的受控端代理名
serverName = "ssh-stcp"
# 仅供与目标连接的受控端代理匹配的安全密钥
secretKey = "bbbbb"
# visitor 监听的本地地址,通过访问监听的地址和端口,连接到远端代理的服务。
bindAddr = "127.0.0.1"
# visitor 监听的本地端口
bindPort = 10000

配置并保存后,在当前目录下输入启动命令 ./frpc -c ./frpc.toml 启动客户端,查看日志文件,检查是否包含类似输出:

1
2024/12/08 20:58:06 [I] [control.go:143] [ssh] start proxy success

4 开机自启动设置

在 Linux 系统下,使用 systemd 可以方便地控制 frp 服务端 frps 的启动和停止、配置后台运行和开启自启。

4.1 服务端

使用文本编辑器,如 vim 创建并编辑 frps.service :

1
vim /etc/systemd/system/frps.service

写入内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
# 服务名称,可自定义
Description = frp server
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令
ExecStart = /path/to/frps -c /path/to/frps.toml

[Install]
WantedBy = multi-user.target

管理 frps

1
2
3
4
5
6
7
8
# 启动frp
systemctl start frps # frps就是您上面创建的文件名
# 停止frp
systemctl stop frps
# 重启frp
systemctl restart frps
# 查看frp状态
systemctl status frps

配置 frps 开机自启

1
systemctl enable frps

4.2 客户端

使用文本编辑器,如 vim 创建并编辑 frpc.service :

1
vim /etc/systemd/system/frpc.service

写入内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
# 服务名称,可自定义
Description = frp client
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令
ExecStart = /path/to/frpc -c /path/to/frpc.toml

[Install]
WantedBy = multi-user.target

管理 frpc

1
2
3
4
5
6
7
8
# 启动frp
systemctl start frpc # frpc就是您上面创建的文件名
# 停止frp
systemctl stop frpc
# 重启frp
systemctl restart frpc
# 查看frp状态
systemctl status frpc

配置 frpc 开机自启

1
systemctl enable frpc

加密 frp 配置教程
https://zdawng.github.io/posts/e8847680/
作者
ZDawnG
发布于
2024年12月8日
许可协议