[GH-ISSUE #520] Https 代理模式对证书的处理可能有问题 #400

Closed
opened 2026-05-05 12:12:55 -06:00 by gitea-mirror · 21 comments
Owner

Originally created by @sxul on GitHub (Nov 13, 2017).
Original GitHub issue: https://github.com/fatedier/frp/issues/520

Issue is only used for submiting bug report and documents typo. If there are same issues or answers can be found in documents, we will close it directly.
(为了节约时间,提高处理问题的效率,不按照格式填写的 issue 将会直接关闭。)

Use the commands below to provide key information from your environment:
You do NOT have to include this information if this is a FEATURE REQUEST

What version of frp are you using (./frpc -v or ./frps -v)?
0.13.0

What operating system and processor architecture are you using (go env)?
CentOS 7 Server + Nginx 1.13.5 (built with OpenSSL 1.0.2l) / Debian 9 Client

Configures you used:

/frpc.ini

[web01]
type = tcp
local_ip = 127.0.0.1
local_port = 443
use_encryption = false
use_compression = false
remote_port = 7443
subdomain = web

[web02]
type = https
local_ip = 127.0.0.1
local_port = 443
use_encryption = false
use_compression = false 
subdomain = web

/frps.ini

[common]
bind_port = 7000
kcp_bind_port = 7000

vhost_http_port = 8080
vhost_https_port = 8443

privilege_token = xxxxx

subdomain_host = xxx.com

nginx vhost config

server {
    listen       80;
    listen       443 ssl http2;
    server_name  web.xxx.com;

    ssl_certificate  /root/keys/xxx.crt;
    ssl_certificate_key  /root/keys/xxx.key;

    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;
    
    ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED';
    ssl_prefer_server_ciphers  on;

    if ( $ssl_protocol = "" ) {
        rewrite ^ https://$host$request_uri?;
    }
    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_pass https://127.0.0.1:8443;
    }
}


Steps to reproduce the issue:

  1. 使用以上配置 用 https://web.xxx.com 访问服务器端 Nginx会报 502 Bad Gateway
  2. 查阅 Nginx 的错误日志找到了以下内容:
    2017/11/13 07:51:16 [error] 32703#32703: *6 peer closed connection in SSL handshake while SSL handshaking to upstream,
  3. 在服务器运行 openssl s_client -connect 127.0.0.1:8443 -tls1 的结果显示的证书信息是空的

snipaste_2017-11-13-01

PS: 浏览器直接访问 https://web.xxx.com:7443https://web.xxx.com:8443 都是可以的 但是似乎使用https模式的 8443 端口 页面载入会稍慢一些

Describe the results you received:
proxy_pass 修改为 https://127.0.0.1:7443 就可以正常访问 https://web.xxx.com

openssl s_client -connect 127.0.0.1:7443 -tls1 也可以返回正确信息
snipaste_2017-11-13_02
snipaste_2017-11-13_03

Describe the results you expected:
https 模式无法证书的话就只能使用 tcp 模式进行反代,这样的话 8443 端口无法复用,每次新增站点也要手动配置 nginx 很麻烦。

Additional information you deem important (e.g. issue happens only occasionally):

Can you point out what caused this issue (optional)

Originally created by @sxul on GitHub (Nov 13, 2017). Original GitHub issue: https://github.com/fatedier/frp/issues/520 Issue is only used for submiting bug report and documents typo. If there are same issues or answers can be found in documents, we will close it directly. (为了节约时间,提高处理问题的效率,不按照格式填写的 issue 将会直接关闭。) Use the commands below to provide key information from your environment: You do NOT have to include this information if this is a FEATURE REQUEST **What version of frp are you using (./frpc -v or ./frps -v)?** 0.13.0 **What operating system and processor architecture are you using (`go env`)?** CentOS 7 Server + Nginx 1.13.5 (built with OpenSSL 1.0.2l) / Debian 9 Client **Configures you used:** # /frpc.ini ``` [web01] type = tcp local_ip = 127.0.0.1 local_port = 443 use_encryption = false use_compression = false remote_port = 7443 subdomain = web [web02] type = https local_ip = 127.0.0.1 local_port = 443 use_encryption = false use_compression = false subdomain = web ``` # /frps.ini ``` [common] bind_port = 7000 kcp_bind_port = 7000 vhost_http_port = 8080 vhost_https_port = 8443 privilege_token = xxxxx subdomain_host = xxx.com ``` # nginx vhost config ``` server { listen 80; listen 443 ssl http2; server_name web.xxx.com; ssl_certificate /root/keys/xxx.crt; ssl_certificate_key /root/keys/xxx.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 DES-CBC3-SHA +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED'; ssl_prefer_server_ciphers on; if ( $ssl_protocol = "" ) { rewrite ^ https://$host$request_uri?; } location / { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass https://127.0.0.1:8443; } } ``` # --- **Steps to reproduce the issue:** 1. 使用以上配置 用 https://web.xxx.com 访问服务器端 Nginx会报 `502 Bad Gateway` 2. 查阅 Nginx 的错误日志找到了以下内容: `2017/11/13 07:51:16 [error] 32703#32703: *6 peer closed connection in SSL handshake while SSL handshaking to upstream,` 3. 在服务器运行 `openssl s_client -connect 127.0.0.1:8443 -tls1` 的结果显示的证书信息是空的 ![snipaste_2017-11-13-01](https://user-images.githubusercontent.com/10028157/32704929-8349b970-c848-11e7-8793-730521107559.png) PS: 浏览器直接访问 https://web.xxx.com:7443 和 https://web.xxx.com:8443 都是可以的 但是似乎使用https模式的 8443 端口 页面载入会稍慢一些 **Describe the results you received:** 将 `proxy_pass` 修改为 `https://127.0.0.1:7443` 就可以正常访问 https://web.xxx.com `openssl s_client -connect 127.0.0.1:7443 -tls1` 也可以返回正确信息 ![snipaste_2017-11-13_02](https://user-images.githubusercontent.com/10028157/32704967-20661f5a-c849-11e7-8af3-8cb52305b336.png) ![snipaste_2017-11-13_03](https://user-images.githubusercontent.com/10028157/32704968-21af2910-c849-11e7-8317-dae110598293.png) **Describe the results you expected:** https 模式无法证书的话就只能使用 tcp 模式进行反代,这样的话 8443 端口无法复用,每次新增站点也要手动配置 nginx 很麻烦。 **Additional information you deem important (e.g. issue happens only occasionally):** **Can you point out what caused this issue (optional)**
Author
Owner

@fatedier commented on GitHub (Nov 13, 2017):

frp 的 https 类型的代理是接收浏览器发送过来的 https 连接,然后探测到其中的域名,之后根据域名将这个连接路由到后端的 https 服务。

你通过 nginx 接收 https 请求,进行了加解密,再转发给 frp,这时候这个请求已经不是标准的 https 请求了,frp 当然无法处理。

frp 本身不关心证书,也不会进行相关的处理,只是解析 https 协议其中的域名部分。

<!-- gh-comment-id:343798027 --> @fatedier commented on GitHub (Nov 13, 2017): frp 的 https 类型的代理是接收浏览器发送过来的 https 连接,然后探测到其中的域名,之后根据域名将这个连接路由到后端的 https 服务。 你通过 nginx 接收 https 请求,进行了加解密,再转发给 frp,这时候这个请求已经不是标准的 https 请求了,frp 当然无法处理。 frp 本身不关心证书,也不会进行相关的处理,只是解析 https 协议其中的域名部分。
Author
Owner

@sxul commented on GitHub (Nov 13, 2017):

也就是说如果没有带正确的域名信息的话就不会转发到后端的https服务,导致证书信息会是空的 是这样吗?

<!-- gh-comment-id:343860743 --> @sxul commented on GitHub (Nov 13, 2017): 也就是说如果没有带正确的域名信息的话就不会转发到后端的https服务,导致证书信息会是空的 是这样吗?
Author
Owner

@fatedier commented on GitHub (Nov 13, 2017):

通常新的浏览器都会带上的,比如 Chrome 最新版。你的问题是中间放了一个 nginx,你要确定经过 nginx 后这个 https 请求没有被修改?还和直接通过浏览器发送的一致?

<!-- gh-comment-id:343865169 --> @fatedier commented on GitHub (Nov 13, 2017): 通常新的浏览器都会带上的,比如 Chrome 最新版。你的问题是中间放了一个 nginx,你要确定经过 nginx 后这个 https 请求没有被修改?还和直接通过浏览器发送的一致?
Author
Owner

@sxul commented on GitHub (Nov 13, 2017):

nginx应该不是直接转发的https 他只是相当于作为客户端去访问https服务 再把获得的数据转发出去 所以在后端(frp)是拿不到浏览器的请求的。现在问题是经过frp转发的https,openssl认不出证书信息了,导致nginx还没去访问直接就报错了

<!-- gh-comment-id:344021398 --> @sxul commented on GitHub (Nov 13, 2017): nginx应该不是直接转发的https 他只是相当于作为客户端去访问https服务 再把获得的数据转发出去 所以在后端(frp)是拿不到浏览器的请求的。现在问题是经过frp转发的https,openssl认不出证书信息了,导致nginx还没去访问直接就报错了
Author
Owner

@fatedier commented on GitHub (Nov 14, 2017):

你把 nginx 去掉,直接浏览器请求 frp 的 https 端口,如果仍然有问题,再反馈一下相关信息。

<!-- gh-comment-id:344123361 --> @fatedier commented on GitHub (Nov 14, 2017): 你把 nginx 去掉,直接浏览器请求 frp 的 https 端口,如果仍然有问题,再反馈一下相关信息。
Author
Owner

@sxul commented on GitHub (Nov 14, 2017):

是这样的,我现在的情况是 用 浏览器直接请求frp的https和frp的tcp都是没问题的,但是经过nginx转发的话只有tcp模式可以工作,https模式会因为nginx读不到https证书信息而直接终止请求然后报502错误。现在的解决方式是一个https站点用一个端口 再让frp一个一个的tcp转出去,但是这样就不能让frp处理域名了,比较麻烦,所以想请作者考虑一下能不能对这方面的做一下优化0.0

<!-- gh-comment-id:344268442 --> @sxul commented on GitHub (Nov 14, 2017): 是这样的,我现在的情况是 用 浏览器直接请求frp的https和frp的tcp都是没问题的,但是经过nginx转发的话只有tcp模式可以工作,https模式会因为nginx读不到https证书信息而直接终止请求然后报502错误。现在的解决方式是一个https站点用一个端口 再让frp一个一个的tcp转出去,但是这样就不能让frp处理域名了,比较麻烦,所以想请作者考虑一下能不能对这方面的做一下优化0.0
Author
Owner

@fatedier commented on GitHub (Nov 15, 2017):

明确一个问题,你是通过 frp 转发给 nginx,还是 nginx 接收浏览器的请求转发给 frp。
如果是后者,那么问题出在 nginx 的使用上,如果是前者,我们再继续讨论。

<!-- gh-comment-id:344463491 --> @fatedier commented on GitHub (Nov 15, 2017): 明确一个问题,你是通过 frp 转发给 nginx,还是 nginx 接收浏览器的请求转发给 frp。 如果是后者,那么问题出在 nginx 的使用上,如果是前者,我们再继续讨论。
Author
Owner

@sxul commented on GitHub (Nov 15, 2017):

前者。通过frp转发给nginx,在这个过程中丢失了可以被openssl读取的证书信息,导致nginx报错了( 具体的我不是很清楚https的工作顺序,猜测大概是frp转发https的时候漏处理了一些请求

<!-- gh-comment-id:344481029 --> @sxul commented on GitHub (Nov 15, 2017): 前者。通过frp转发给nginx,在这个过程中丢失了可以被openssl读取的证书信息,导致nginx报错了( 具体的我不是很清楚https的工作顺序,猜测大概是frp转发https的时候漏处理了一些请求
Author
Owner

@fatedier commented on GitHub (Nov 15, 2017):

前一种的话 nginx 里为什么要设置 proxy_pass 到 frp 的端口?

<!-- gh-comment-id:344511451 --> @fatedier commented on GitHub (Nov 15, 2017): 前一种的话 nginx 里为什么要设置 proxy_pass 到 frp 的端口?
Author
Owner

@sxul commented on GitHub (Nov 15, 2017):

比如我有 Server1 和 Server2 两台机器,以下简称 S1 和 S2, S1是长时间开机并且暴露在公网的正常服务器,S2可能是一台在内网的机器,我现在想要在 Server1 部署一个https 服务,地址是 https://xxx.com/ ,同时我又想让 https://xxx.com/s2/ 能访问到 S2 上的服务(也有可能是 aaa.xxx.com)。

我现在采用的方案就是在 S1 运行 nginx 和 frps,在 S2 运行一个 https 服务和 frpc。然后在 S1 的 nginx 处理 443 端口的请求,把对应的请求转发给 S2 的 https 服务。 就是这样

<!-- gh-comment-id:344525624 --> @sxul commented on GitHub (Nov 15, 2017): 比如我有 Server1 和 Server2 两台机器,以下简称 S1 和 S2, S1是长时间开机并且暴露在公网的正常服务器,S2可能是一台在内网的机器,我现在想要在 Server1 部署一个https 服务,地址是 https://xxx.com/ ,同时我又想让 https://xxx.com/s2/ 能访问到 S2 上的服务(也有可能是 aaa.xxx.com)。 我现在采用的方案就是在 S1 运行 nginx 和 frps,在 S2 运行一个 https 服务和 frpc。然后在 S1 的 nginx 处理 443 端口的请求,把对应的请求转发给 S2 的 https 服务。 就是这样
Author
Owner

@sxul commented on GitHub (Nov 15, 2017):

我遇到的问题就是在 S1 的 nginx 在直接转发请求到 frp 用 https 方法转发上来的端口的时候 会报错,虽然把 frp 的转发方式改成 tcp, 或者把 frpc 上的服务降级成 http 都是可以正常使用的 😭

<!-- gh-comment-id:344526989 --> @sxul commented on GitHub (Nov 15, 2017): 我遇到的问题就是在 S1 的 nginx 在直接转发请求到 frp 用 https 方法转发上来的端口的时候 会报错,虽然把 frp 的转发方式改成 tcp, 或者把 frpc 上的服务降级成 http 都是可以正常使用的 😭
Author
Owner

@fatedier commented on GitHub (Nov 15, 2017):

明确一个问题,你是通过 frp 转发给 nginx,还是 nginx 接收浏览器的请求转发给 frp。
如果是后者,那么问题出在 nginx 的使用上,如果是前者,我们再继续讨论。

所以你用 nginx 接收浏览器发送过来的请求,转发给 frp,那么属于后者,问题出在 nginx 的使用上,需要你自行查找相关的解决方案。

<!-- gh-comment-id:344527883 --> @fatedier commented on GitHub (Nov 15, 2017): > 明确一个问题,你是通过 frp 转发给 nginx,还是 nginx 接收浏览器的请求转发给 frp。 如果是后者,那么问题出在 nginx 的使用上,如果是前者,我们再继续讨论。 所以你用 nginx 接收浏览器发送过来的请求,转发给 frp,那么属于后者,问题出在 nginx 的使用上,需要你自行查找相关的解决方案。
Author
Owner

@sxul commented on GitHub (Nov 15, 2017):

你是不是误解了什么…请求是发给frp的 但是在发送的时候他会读取证书信息 而经过frp转发的https端口没有这个数据 导致nginx报错,这种情况你告诉我不应该在frp上完善对https请求的处理,而是想办法让nginx无视这个错误吗?

<!-- gh-comment-id:344558537 --> @sxul commented on GitHub (Nov 15, 2017): 你是不是误解了什么…请求是发给frp的 但是在发送的时候他会读取证书信息 而经过frp转发的https端口没有这个数据 导致nginx报错,这种情况你告诉我不应该在frp上完善对https请求的处理,而是想办法让nginx无视这个错误吗?
Author
Owner

@fatedier commented on GitHub (Nov 15, 2017):

你需要自己理清整个流程,从你的回复以及你贴的 frp 和 nginx 配置来看
是这样的,我现在的情况是 用 浏览器直接请求frp的https和frp的tcp都是没问题的,但是经过nginx转发的话只有tcp模式可以工作
我遇到的问题就是在 S1 的 nginx 在直接转发请求到 frp 用 https 方法转发上来的端口的时候 会报错

frp 反代 https 没有问题(我本地测试通过 frp 转发请求给 nginx,通过浏览器请求 frp 的 https 端口,没有问题),通过 nginx 在前端转发后有问题,请自行搜索 nginx 的相关解决方案。除非有明确指出存在的问题,这个 issue 不再回复了。

<!-- gh-comment-id:344569948 --> @fatedier commented on GitHub (Nov 15, 2017): 你需要自己理清整个流程,从你的回复以及你贴的 frp 和 nginx 配置来看 `是这样的,我现在的情况是 用 浏览器直接请求frp的https和frp的tcp都是没问题的,但是经过nginx转发的话只有tcp模式可以工作` `我遇到的问题就是在 S1 的 nginx 在直接转发请求到 frp 用 https 方法转发上来的端口的时候 会报错` frp 反代 https 没有问题(我本地测试通过 frp 转发请求给 nginx,通过浏览器请求 frp 的 https 端口,没有问题),通过 nginx 在前端转发后有问题,请自行搜索 nginx 的相关解决方案。除非有明确指出存在的问题,这个 issue 不再回复了。
Author
Owner

@sxul commented on GitHub (Nov 16, 2017):

你还是没懂吗…frp的https模式转发上来的请求是用浏览器访问没问题,但是用nginx转发会报错,并且我用openssl进行对https模式的frp端口测试的时候返回的证书信息是空的… 使用tcp模式就能读到证书信息…所以是frp转发https请求的时候有问题难道不对吗???

<!-- gh-comment-id:344945177 --> @sxul commented on GitHub (Nov 16, 2017): 你还是没懂吗…frp的https模式转发上来的请求是用浏览器访问没问题,但是用nginx转发会报错,并且我用openssl进行对https模式的frp端口测试的时候返回的证书信息是空的… 使用tcp模式就能读到证书信息…所以是frp转发https请求的时候有问题难道不对吗???
Author
Owner

@sxul commented on GitHub (Nov 16, 2017):

https模式会因为nginx读不到https证书信息而直接终止请求然后报502错误

你是看到前面的一句说直接访问frp没问题就把这句话无视了吗???

<!-- gh-comment-id:344945888 --> @sxul commented on GitHub (Nov 16, 2017): https模式会因为nginx读不到https证书信息而直接终止请求然后报502错误 你是看到前面的一句说直接访问frp没问题就把这句话无视了吗???
Author
Owner

@jasonhu commented on GitHub (Nov 18, 2017):

可能是,Nginx作为前端向后端frps按照HTTPS协议发送握手请求的时候,还是在用老的标准,导致frps无法解析出域名?

<!-- gh-comment-id:345451673 --> @jasonhu commented on GitHub (Nov 18, 2017): 可能是,Nginx作为前端向后端frps按照HTTPS协议发送握手请求的时候,还是在用老的标准,导致frps无法解析出域名?
Author
Owner

@jasonhu commented on GitHub (Nov 19, 2017):

Nginx配置修改为proxy_pass https://web.xxx.com:8443; 看看

<!-- gh-comment-id:345489039 --> @jasonhu commented on GitHub (Nov 19, 2017): Nginx配置修改为proxy_pass https://web.xxx.com:8443; 看看
Author
Owner

@icksky commented on GitHub (Oct 9, 2018):

我现在也是这个想法, 流程大概这样: 浏览器 -> S1.nginx -> S1.frps -> S2.nginx. 然后https 就502了

<!-- gh-comment-id:428058044 --> @icksky commented on GitHub (Oct 9, 2018): 我现在也是这个想法, 流程大概这样: 浏览器 -> S1.nginx -> S1.frps -> S2.nginx. 然后https 就502了
Author
Owner

@SeaHOH commented on GitHub (Oct 9, 2018):

关键是加密,tcp 模式才能转发加密后的数据。
除非浏览器 -> S1.nginx这个过程不进行 https 握手,才是未加密连接。

<!-- gh-comment-id:428064859 --> @SeaHOH commented on GitHub (Oct 9, 2018): 关键是加密,tcp 模式才能转发加密后的数据。 除非`浏览器 -> S1.nginx`这个过程不进行 https 握手,才是未加密连接。
Author
Owner

@nickfan commented on GitHub (Jan 7, 2019):

@sxul 我用ssh的穿透临时解决的问题:

/usr/bin/ssh -gNR 5743:127.0.0.1:443 user@公网机器ip -p22

由于我不是题主无法reopen这个issue,我就另开了一个 #1035

具体的配置过程可以参考

但问题还请 @fatedier 大神能帮忙解答。

<!-- gh-comment-id:451928336 --> @nickfan commented on GitHub (Jan 7, 2019): @sxul 我用ssh的穿透临时解决的问题: ``` /usr/bin/ssh -gNR 5743:127.0.0.1:443 user@公网机器ip -p22 ``` 由于我不是题主无法reopen这个issue,我就另开了一个 #1035 具体的配置过程可以参考 但问题还请 @fatedier 大神能帮忙解答。
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/frp#400
No description provided.