在现代网络环境中,内网穿透服务成为越来越重要的需求。而 frp 作为一款功能强大的开源内网穿透工具,为我们提供了便捷的解决方案。然而,安全始终是我们应该关注的重点。在本篇文章中,记录了如何通过合理的配置和措施来提高 frp 的安全性,以确保内网服务在穿透的同时也得到了充分的保护,尽量降低安全风险。
从 v0.52.0 版本开始,frp 开始支持 TOML、YAML 和 JSON 作为配置文件格式。
请注意,INI 已被弃用,并将在未来的发布中移除。新功能只能在 TOML、YAML 或 JSON 中使用。
建议使用 TOML 作为配置文件格式。
更新 frpc 和 frps 的版本
应始终使用最新的 frpc 和 frps 的软件版本,新版本通常修复了已知的安全漏洞和问题。
为 token 配置强密码
在 frp 中,token 是一种简单的身份认证方式,只需要在 frpc 和 frps 配置文件中配置相同的 token 即可。我们可以使用 随机密码生成器 来生成包含大小写字母、数字和特殊字符的组合,并定期更改 token。
修改默认端口
frps 的配置文件中默认使用 7000 端口,建议改为高位端口号。
限制访问来源
通过配置 frps 的 bindAddr
,仅允许特定的 IP 地址或 IP 地址范围访问 frps 服务。这样可以限制对服务的访问,并减少潜在的攻击面。
加密与压缩
每一个代理都可以选择是否启用加密和压缩的功能。
加密算法采用 aes-128-cfb,压缩算法采用 snappy。
在每一个代理的配置中使用如下参数指定:
1 2 3 4 5 6 7 8
| [[proxies]] name = "ssh" type = "tcp" localPort = 22 remotePort = 6000 transport.useEncryption = true transport.useCompression = true
|
通过设置 transport.useEncryption = true
,将 frpc 与 frps 之间的通信内容加密传输,将会有效防止传输内容被截取。
如果传输的报文长度较长,通过设置 transport.useCompression
对传输内容进行压缩,可以有效减小 frpc 与 frps 之间的网络流量,加快流量转发速度,但是会额外消耗一些 CPU 资源。
使用 stcp
某些内网服务如果直接暴漏在公网可能存在安全风险,使用 stcp(secret tcp)
类型的代理可以实现将内网服务暴漏给经过授权的用户,但是访问者也需要运行另外一个 frpc 客户端。
配置 frps.toml
在需要暴露到外网的机器上部署 frpc,且配置如下:
1 2 3 4 5 6 7 8 9 10
| serverAddr = "x.x.x.x" serverPort = 7000
[[proxies]] name = "secret_ssh" type = "stcp"
secretKey = "abcdefg" localIP = "127.0.0.1" localPort = 22
|
在想要访问内网服务的机器上也部署 frpc,且配置如下:
1 2 3 4 5 6 7 8 9 10 11 12
| serverAddr = "x.x.x.x" serverPort = 7000
[[visitors]] name = "secret_ssh_visitor" type = "stcp"
serverName = "secret_ssh" secretKey = "abcdefg"
bindAddr = "127.0.0.1" bindPort = 6000
|
通过 SSH 访问内网机器,假设用户名为 test:
1
| ssh -oPort=6000 test@127.0.0.1
|
自定义 TLS 加密
transport.useEncryption
和 STCP
等功能能有效防止流量内容在通信过程中被盗取,但是无法判断对方的身份是否合法,存在被中间人攻击的风险。为此 frp 支持 frpc 和 frps 之间的流量通过 TLS 协议加密,并且支持客户端或服务端单向验证,双向验证等功能。
当 frps.toml
中 transport.tls.force = true
时,表示 server 端只接受 TLS 连接的客户端,这也是 frps 验证 frpc 身份的前提条件。如果 frps.toml
中 transport.tls.trustedCaFile
内容是有效的话,那么默认就会开启 transport.tls.force = true
。
注意:启用此功能后除 xtcp 外,可以不用再设置 transport.useEncryption 重复加密
从 v0.50.0 开始,transport.tls.enable
的默认值将会为 true,默认开启 TLS 协议加密。
如果 frps 端没有配置证书,则会使用随机生成的证书来加密流量。
默认情况下,frpc 开启 TLS 加密功能,但是不校验 frps 的证书。
启用双向验证
双向验证应该是目前最安全的方案。启用双向验证需要先生成证书,首先建立一个文件夹,将以下配置写入 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
|
生成 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
|
生成服务端证书:
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
改为域名。
生成客户端证书:
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
|
最终的文件:
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
|
将证书上传到服务端并修改配置文件,增加 tls 验证相关配置:
1 2 3 4 5 6 7 8 9
| transport.tls.certFile = "/to/cert/path/client.crt" transport.tls.keyFile = "/to/key/path/client.key" transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
transport.tls.certFile = "/to/cert/path/server.crt" transport.tls.keyFile = "/to/key/path/server.key" transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
|
随后重启服务端和客户端。至此,客户端和服务端的双向验证配置完毕。
启用和检查日志
启用 frps 的日志记录功能,并定期检查日志以检测异常连接或潜在的安全问题。
1 2 3
| log.to = "./frps.log" log.level = "info" log.maxDays = 5
|
强化服务器安全
除了保护 frps 服务本身外,还应采取适当的安全措施来保护整个服务器。这包括使用安全的 SSH 配置、禁用不必要的服务、限制用户访问权限等。
总结
- 始终使用最新版本的 frp
- 配置 token 验证,设置复杂密码
- 若无必要,不要开启 dashboard
- 启用双向 tls 验证
- 强化系统安全
参考资料
https://gofrp.org/docs/overview/