FRP在WINDOWS下实现TLS

发布于 2023-01-20  578 次阅读


frp实现tls认证(双向认证)

  • frp可以由客户端向服务器单向认证ssl,但是单向认证有什么意思,使用双向认证,再控制ssl证书的有效期,就可以保证frp服务被彻底控制了,因为token可以被破解,但是证书很快就会过期,只要根证书在手,还不是想怎么签就怎么签(不清楚ssl证书的机制,可以看看我下一篇关于ssl证书认证机制的讲解和使用方法的博客)
  • 下面是服务端的配置
# 服务端配置
[common]
bind_addr = 0.0.0.0
bind_port = 7000
bind_udp_port = 7001    #xtcp才会用

# 开启控制面板
dashboard_port = 7500
dashboard_user = 服务端dashboard用户名
dashboard_pwd = 服务端dashboard密码
token = drinkfire
tls_only = true     #禁止没有证书的客户端

#下面是服务端证书的地址,文章后面会提如何生成这些证书
tls_cert_file = C:\Users\Administrator\Desktop\frpsafe\server.crt
tls_key_file = C:\Users\Administrator\Desktop\frpsafe\server.key
tls_trusted_ca_file = C:\Users\Administrator\Desktop\frpsafe\ca.crt
  • 下面是客户端配置文件
[common]
server_addr = 服务端ip
server_port = 7000
token = 密钥
admin_addr = 127.0.0.1  #最好还是ipconfig看一下内网ip吧,感觉这么填不保险
admin_port = 7400
admin_user = 本地dashboard用户名
admin_pwd = 本地dashboard密码
tls_enable = true   #允许tls认证

#下面是客户端证书地址
tls_cert_file = C:\Users\client.crt
tls_key_file = C:\Users\client.key
tls_trusted_ca_file = C:\ca.crt

[客户端名称]#这里随便填
type = tcp
local_ip = 127.0.0.1
local_port = 80
remote_port = 4340
use_encryption = true   #启用加密
use_compression = true  #启用压缩
  • 接下来就是最恶心的证书生成了(网上压根找不到windows下的操作方法),本文只记录操作步骤,原理请移步下一篇关于ssl证书认证机制的讲解和使用方法的博客
  • 首先要下openssl证书生成工具,这里我提供一份链接:https://pan.baidu.com/s/1bRY_Mxsci6bB_50Az144ZQ 提取码:vb1k
  • 下载完成后解压,将文件移动到c盘的program file文件夹下面(注意openssl文件夹里面不能再嵌套一层openssl文件夹)
  • 网上的教程一般让配环境变量,不经常用其实可以不用配的,直接点start.bat进入命令行,注意,工作文件夹默认是c://user/你的用户名,也就是说生成的证书都在这个目录
  • 先要生成ca,ca.key需要保存到安全的地方,后续生成服务端证书和客户端证书都需要ca.crt和ca.csr,而由同一个ca生成的证书互相是可信的(可以设置过期时间),如果ca.crt和ca.key都被别人拿到了,就可以以此生成可信的证书了
生成默认 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
  • 这时候c://user/你的用户名这个目录下面应该多了两个ca的文件,接下来要根据ca生成服务端证书,最坑的地方来了,不管是官方,还是搜遍全网,都只能找到这样一段代码,然后输入运行会报错找不到文件,我尝试改文件名等操作,也尝试过生成my-openssl.cnf文件,但是都不起作用,因为完全不懂ssl,还以为是ssl的问题,又去学ssl的机制,学完发现,,,,,这是一段linux的代码,,,,
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
  • 代码向my-openssl.cnf输入了一些信息(不知道为啥要这样,提前在文件里面写不好嘛),使用了cat.printf等windows没有的命令所以报错,只需要提前写好配置文件,并且导入就可以了
  • 在openssl的工作目录下(ca证书生成的地方)新建4个文件,命名为server1.cnf,server2.cnf,client1.cnf,client2.cnf,分别写入以下内容
server1.cnf:
注意把最下面ip处改成你的服务器ip
(不要把上面这些写进去了)

[ 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
[SAN]
subjectAltName = DNS:localhost,IP:0.0.0.0,DNS:example.server.com
server2.cnf:
和上面一样,把ip改成你的服务器ip
(不要把上面这些写进去了)

subjectAltName=DNS:localhost,IP:0.0.0.0,DNS:example.server.com
client1.cnf:
(不要把上面这些写进去了)

[ 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
[SAN]
subjectAltName=DNS:localhost,DNS:example.server.com
client2.cnf:
(不要把上面这些写进去了)

subjectAltName=DNS:client.com,DNS:example.client.com
  • 配置文件准备完成,openssl命令行中依次输入以下命令(第3条和第6条的365是证书有效期)
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 server1.cnf -out server.csr
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile server2.cnf -out server.crt
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 client1.cnf -out client.csr
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile client2.cnf -out client.crt
  • 这时候文件夹里面就有以下文件辣
ca.crt
ca.key
ca.srl
server.key
server.crt
server.csr
cilent.key
cilent.crt
cilent.csr
server1.cnf
server2.cnf
cilent1.cnf
cilent2.cnf
  • 以下文件用于生成受信任的证书,不能泄露
ca.crt
ca.key
server1.cnf
server2.cnf
cilent1.cnf
cilent2.cnf
  • 以下文件要给客户端,按本文开头的方法将证书路径写入配置文件
ca.crt
cilent.key
cilent.crt
  • 以下文件要给服务端,按本文开头的方法将证书路径写入配置文件
ca.crt
server.key
server.crt
  • 以下这些文件没有什么用,可以删掉
cilent.csr
server.csr
ca.srl
  • 开启客户端和服务端即可,你的通信已经受到ssl的加密辣

配置文件详解

[common]                        # 通用配置段
bind_addr = 0.0.0.0             # 绑定的IP地址,支持IPv6,不指定默认0.0.0.0;
bind_port = 7000                # 服务端口;
bind_udp_port = 7001            # 是否使用udp端口,不使用删除或注释本行;
kcp_bind_port = 7000            # 是否使用kcp协议,不使用删除或注释本行;
# proxy_bind_addr = 127.0.0.1   # 代理监听地址,默认和bind_addr相同;

# 虚拟主机
vhost_http_port = 80            # 是否启用虚拟主机,端口可以和bind_port相同;
vhost_https_port = 443
vhost_http_timeout = 60         # 后端虚拟主机响应超时时间,默认为60s;

# 开启frps仪表盘可以检查frp的状态和代理的统计信息。
dashboard_addr = 0.0.0.0        # frps仪表盘绑定的地址;
dashboard_port = 7500           # frps仪表盘绑定的端口;
dashboard_user = admin          # 访问frps仪表盘的用户;     
dashboard_pwd = admin           # 密码;
assets_dir = ./static           # 仪表盘页面文件目录,只适用于调试;

# 日志配置文件
log_file = ./frps.log           # 日志文件,不指定日志信息默认输出到控制台;
log_level = info                # 日志等级,可用等级“trace, debug, info, warn, error”;
log_max_days = 3                # 日志保存最大保存时间;

token = 12345678                # 客户端与服务端通信的身份验证令牌

heartbeat_timeout = 90          # 心跳检测超时时间,不建议修改默认配置,默认值为90;?

# 指定允许客户端使用的端口范围,未指定则没有限制;
allow_ports = 2000-3000,3001,3003,4000-50000

max_pool_count = 5              # 每个客户端连接服务端的最大连接数;
max_ports_per_client = 0        # 每个客户端最大可以使用的端口,0表示无限制

authentication_timeout = 900    # 客户端连接超时时间(秒),默认为900s;

subdomain_host = frps.com       # 自定义子域名,需要在dns中将域名解析为泛域名;

tcp_mux = true                  # 是否使用tcp复用,默认为true;
                                # frp只对同意客户端的连接进行复用;
[common]                        # 通用配置段

server_addr = 0.0.0.0           # server的IP地址;支持IPv6
server_port = 7000              # server的端口;

# 如果要通过http或socks5代理连接frps,可以在此处或在全局环境变量中设置代理,只支持tcp协议;
# http_proxy = http://user:passwd@192.168.1.128:8080
# http_proxy = socks5://user:passwd@192.168.1.128:1080

# 客户端日志
log_file = ./frpc.log       # 指定日志文件;
log_level = info            # 指定日志等级;
log_max_days = 3

token = 12345678            # 客户端与服务端通信的身份验证令牌

# 设置管理地址,用于通过http api控制frpc的动作,如重新加载;
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_passwd = admin

pool_count = 5              # 初始连接池的数量,默认为0;

tcp_mux = true              # 是否启用tcp复用,默认为true;

user = your_name            # frpc的用户名,用于区别不用frpc的代理;

login_fail_exit = true      # 首次登录失败时退出程序,否则连续重新登录到frps;

protocol = tcp              # 用于连接服务器的协议,支持tcp、kcp、websocket;

dns_server = 8.8.8.8        # 为frp 客户端指定一个单独的DNS服务器;

# start = ssh,dns           # 要启用的代理的名字,默认为空表示所有代理;

# 心跳检查
# heartbeat_interval = 30   # 失败重试次数
# heartbeat_timeout = 90    # 超时时间

# 配置示例
[ssh]                       # 代理配置段名称,如果配置user=your_name,则显示为your_name.ssh;
type = tcp                  # 协议默认tcp,可选tcp,udp,http,https,stcp,xtcp;
local_ip = 127.0.0.1        # 本地地址
local_port = 22             # 本地端口
use_encryption = false      # 是否加密服务端和客户端的通信信息,默认为不加密;
use_compression = false     # 是否开启压缩,默认不开启;
remote_port = 6001          # 在服务器端开启的远程端口;
# 负载均衡配置
group = test_group          # 负载均衡组名,会将同一组内的客户端进行负载;
group_key = 123456          # 负载均衡组密钥; 
# web示例
[web01]
type = http                 # 使用http
local_ip = 127.0.0.1        
local_port = 80
use_encryption = false
use_compression = true
http_user = admin           # 访问web01页面启用认证,用户名admin
http_pwd = admin            # 密码
subdomain = web01           # 子域名,需要服务端配置了subdomain_host参数;
custom_domains = web02.example.com # web01的域名,和subdomain二选一
locations = /,/pic          # 指定用于路由的URL前缀;
host_header_rewrite = example.com   # 配置http包头域名重写;
header_X-From-Where = frp           # 添加包头信息X-From-Where: frp;
届ける言葉を今は育ててる
最后更新于 2024-02-13