自定义 TLS 协议加密

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

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

注意:启用此功能后除 xtcp ,可以不用再设置 use_encryption 重复加密

TLS 默认开启方式

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

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

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

frpc 单向校验 frps 身份

# frpc.toml
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    
    # frps.toml
    transport.tls.certFile = "/to/cert/path/server.crt"
    transport.tls.keyFile = "/to/key/path/server.key"
    

frpc 需要额外加载 ca 证书,frps 需要额外指定 TLS 配置。frpc 通过 ca 证书单向验证 frps 的身份。这就要求 frps 的 server.crt 对 frpc 的 ca 是合法的。

合法: 如果证书是 ca 签发的,或者证书是在 ca 的信任链中,那即认为: 该证书对 ca 而言是合法的。

frps 单向验证 frpc 的身份

# frpc.toml
    transport.tls.certFile = "/to/cert/path/client.crt"
    transport.tls.keyFile = "/to/key/path/client.key"
    
    # frps.ini
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    

frpc 需要额外加载 TLS 配置,frps 需要额外加载 ca 证书。frps 通过 ca 证书单向验证 frpc 的身份。这就要求 frpc 的 client.crt 对 frps 的 ca 是合法的。

双向验证

# frpc.toml
    transport.tls.certFile = "/to/cert/path/client.crt"
    transport.tls.keyFile = "/to/key/path/client.key"
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    
    # frps.toml
    transport.tls.certFile = "/to/cert/path/server.crt"
    transport.tls.keyFile = "/to/key/path/server.key"
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    

双向验证即 frpc 和 frps 通过本地 ca 证书去验证对方的身份。理论上 frpc 和 frps 的 ca 证书可以不同,只要能验证对方身份即可。

OpenSSL 生成证书示例

x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

如果出现上述报错,是因为 go 1.15 版本开始废弃 CommonName,因此推荐使用 SAN 证书。

下面简单示例如何用 openssl 生成 ca 和双方 SAN 证书。

准备默认 OpenSSL 配置文件于当前目录。此配置文件在 linux 系统下通常位于 /etc/pki/tls/openssl.cnf,在 mac 系统下通常位于 /System/Library/OpenSSL/openssl.cnf

如果存在,则直接拷贝到当前目录,例如 cp /etc/pki/tls/openssl.cnf ./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:

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

生成 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.com" \
        -reqexts SAN \
        -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com")) \
        -out server.csr
    
    openssl x509 -req -days 365 -sha256 \
      -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
      -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com") \
      -out server.crt
    

生成 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.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 365 -sha256 \
        -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
      -extfile <(printf "subjectAltName=DNS:client.com,DNS:example.client.com") \
      -out client.crt
    

在本例中,server.crt 和 client.crt 都是由默认 ca 签发的,因此他们对默认 ca 是合法的。

最后修改 November 15, 2023: fix 404 (#71) (626ce4d)

Custom TLS protocol encryption

transport.useEncryptionSTCP The wait function can effectively prevent traffic content from being stolen during communication, but it cannot determine whether the other party's identity is legitimate, and there is a risk of being attacked by intermediaries. to this end FRP supports traffic between FRPC and FRPS through TLS Protocol encryption and support for client or server side Unidirectional verification, bidirectional verification, and other functions.

When infrps. toml Whentransport. tls. force=true, it represents the server The client only accepts TLS connections on the end, which is also FRPS verification FRPC The prerequisite for identity. If infrps. toml transport. tls. trustedCaFile If the content is valid, it will be enabled by default transport. tls. force=true.

Note: After enabling this feature, except for xtcp, there is no need to set use again_ Encryption Repeat encryption

TLS default activation method

Starting from v0.50.0,transport. tls. enable The default value of will be true, and TLS protocol encryption will be enabled by default.

If frps If there is no Configuration certificate on the end, the randomly generated certificate will be used to encrypt traffic.

By default, frpc enables TLS encryption, but does not verify the certificate of frps.

frpc 单向校验 frps 身份

# frpc.toml
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    
    # frps.toml
    transport.tls.certFile = "/to/cert/path/server.crt"
    transport.tls.keyFile = "/to/key/path/server.key"
    

FRPC requires additional loading of CA certificate, while FRPS requires additional TLS specification Configuration. FRPC verifies the identity of FRPS one-way through CA certificate. This requires FRPS server. crtThe CA for FRPC is legal.

Legal: If the certificate is issued by CA, or if the certificate is in CA In the trust chain, it is considered that the certificate is legal for CA.

FRPS one-way authentication of FRPC identity

# frpc.toml
    transport.tls.certFile = "/to/cert/path/client.crt"
    transport.tls.keyFile = "/to/key/path/client.key"
    
    # frps.ini
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    
FRPC requires additional loading of TLS Configuration, while FRPS requires additional loading of CA Certificate. FRPS verifies the identity of FRPC one-way through CA certificate. This requires FRPC's client. crtThe CA for FRPS is legal.

Bidirectional Verification

# frpc.toml
    transport.tls.certFile = "/to/cert/path/client.crt"
    transport.tls.keyFile = "/to/key/path/client.key"
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    
    # frps.toml
    transport.tls.certFile = "/to/cert/path/server.crt"
    transport.tls.keyFile = "/to/key/path/server.key"
    transport.tls.trustedCaFile = "/to/ca/path/ca.crt"
    

Bidirectional verification, i.e. FRPC and FRPS pass through local CA Use certificates to verify the identity of the other party. Theoretically, the CA of FRPC and FRPS Certificates can be different, as long as the identity of the other party can be verified.

OpenSSL Generate Certificate Example

X509: Certificate releases on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

If the above error occurs, it is because the go 1.15 versionAbandoned CommonNameTherefore, it is recommended to use SAN certificates.

Here is a simple example of how to use OpenSSL to generate CA and mutual SAN certificates

Prepare the default OpenSSL Configuration file in the current directory. This Configuration File is usually located in the Linux system /etc/pki/tls/openssl. cnf, typically located on Mac systems /System/Library/OpenSSL/openssl. cnf.

If it exists, copy it directly to the current directory, for example cp/etc/pki/tls/openssl.cnf./my openssl. cnf. If it does not exist, you can use the following command to create it.

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
    

generate default ca:

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

生成 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.com" \
        -reqexts SAN \
        -config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com")) \
        -out server.csr
    
    openssl x509 -req -days 365 -sha256 \
      -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
      -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1,DNS:example.server.com") \
      -out server.crt
    

Generate a certificate for 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.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 365 -sha256 \
        -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
      -extfile <(printf "subjectAltName=DNS:client.com,DNS:example.client.com") \
      -out client.crt
    

In this example, both server.crt and client.crt are created by the default ca. Signed, so they are legal for the default ca.

Last modified November 15, 2023: fix 404 (#71) (626ce4d)