在我的 Cinnamon (linux) 桌面上,我在 NetworkManager 中设置了一个 openconnect VPN 连接。连接时,我似乎没有遇到任何问题:连接已建立,网络流量通过它路由。但是,我的系统日志包含一个令人担忧的条目:
openconnect[2935]: SSL negotiation with (...)
openconnect[2935]: Server certificate verify failed: signer not found
openconnect[2935]: Connected to HTTPS on (...)
openconnect[2935]: Got CONNECT response: HTTP/1.1 200 OK
我尝试openconnect
从命令行使用,它没有打印任何有关证书问题的信息(即使在详细模式下)。此外,在 Firefox 或使用中该网站没有证书错误wget
(我不知道 openconnect 使用哪个证书存储...)。
这是否意味着该连接容易受到中间人攻击?如果无法验证证书,为什么在连接和发送我的凭据之前没有确认提示要求我信任证书?为什么只有在使用 NetworkManager 连接时才会出现此问题?
命令行openconnect
是
/usr/sbin/openconnect --servercert sha1:bee140657db50a73ee69f47fee9e4d670905206e --syslog --cookie-on-stdin --script /usr/lib/NetworkManager/nm-openconnect-service-openconnect-helper --interface vpn0 (ip):443
如果我没有在 NetworkManager 中明确设置 CA 证书,也会出现警告。
答案1
该问题在 Ubuntu 18.04 中仍然存在network-manager-openconnect
。
我认为这里的问题是连接到 VPN 服务器的 IP 地址,而不是它的 DNS 名称:
$ ps aux | grep openconnect
/usr/sbin/openconnect --servercert sha256:<hash> --syslog --cookie-on-stdin --script /usr/lib/NetworkManager/nm-openconnect-service-openconnect-helper --interface vpn0 <ip>:443
手动运行命令,不带--servercert参数:
$ /usr/sbin/openconnect <ip>:443 --authenticate
POST https://<ip>/
Connected to <ip>:443
SSL negotiation with <ip>
Server certificate verify failed: certificate does not match hostname
Certificate from VPN server "<ip>" failed verification.
Reason: certificate does not match hostname
To trust this server in future, perhaps add this to your command line:
--servercert sha256:<hash>
Enter 'yes' to accept, 'no' to abort; anything else to view:
注意证书验证失败。
现在使用主机名而不是 IP:
$ /usr/sbin/openconnect <hostname>:443 --authenticate
POST https://<hostname>/
Connected to <ip>:443
SSL negotiation with <hostname>
Connected to HTTPS on <hostname>
XML POST enabled
Please enter your username and password.
没有证书错误。
现在,使用带有 servercert 参数的 IP:
$ /usr/sbin/openconnect <ip>:443 --authenticate --servercert sha256:<hash>
POST https://<ip>/
Connected to <ip>:443
SSL negotiation with <ip>
Server certificate verify failed: signer not found
Connected to HTTPS on <ip>
XML POST enabled
Please enter your username and password.
将错误与第一个示例进行比较 - 这是一个不同的错误。这个错误失败是因为找不到签名者。考虑到我们只是指定一个哈希,我想这是有道理的,因为没有信任链可以遵循。
对我来说,我认为根本原因是网络管理器出于某种原因连接到 IP 地址而不是主机名。不确定它为什么会这样做?
答案2
我在 Arch Linux 中使用 networkmanager-connect 和 network-manager-applet 时遇到了同样的问题。我通过手动下载 ca 证书解决了这个问题:
echo -n | openssl s_client -connect <HOST>:<PORTNUMBER> \
| sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/vpn.crt
然后我在 Gnome 的网络设置中的 VPN 配置菜单中选择了该文件。这会将以下行添加到配置文件 /etc/NetworkManager/system-connections/MyVpn.nmconnection:
[vpn]
...
cacert=/home/<my username>/vpn.crt
它可能会更改配置文件中的其他一些行。我没有运行 diff 来找出原因。但无论如何,我随后能够通过网络管理器连接到我的 vpn。
答案3
正如@curvy所述,network-manager-openconnect 使用 ip 地址而不是主机名。这是提供仅主机名证书的 vpn 网关的问题。
为了避免这个问题,你可以重新编译https://gitlab.gnome.org/GNOME/NetworkManager-openconnect应用这个简单的补丁。
diff --git a/src/nm-openconnect-service.c b/src/nm-openconnect-service.c
index 348c19a..273efb5 100644
--- a/src/nm-openconnect-service.c
+++ b/src/nm-openconnect-service.c
@@ -415,9 +415,10 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
return -1;
}
- /* The actual gateway to use (after redirection) comes from the auth
- dialog, so it's in the secrets hash not the properties */
- props_vpn_gw = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY);
+ /* Replaced nm_setting_vpn_get_secret with nm_setting_vpn_get_data_item
+ because if we use ip to get connection we may have problems with
+ certificates signed only with hostnames */
+ props_vpn_gw = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_GATEWAY);
if (!props_vpn_gw || !strlen (props_vpn_gw) ) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
@@ -596,7 +597,7 @@ real_need_secrets (NMVpnServicePlugin *plugin,
}
/* We just need the WebVPN cookie, and the final IP address of the gateway
- (after HTTP redirects, which do happen). All the certificate/SecurID
+ (after HTTP redirects, which do happen). All the certificate/SecurID
nonsense can be handled for us, in the user's context, by auth-dialog */
if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY)) {
*setting_name = NM_SETTING_VPN_SETTING_NAME;