以下是有关我的问题的一些背景信息:
- 我在 Heroku 上运行了一个 Web 服务,它有一个动态 IP 地址。Heroku 上没有静态 IP 选项。
- 我需要连接到防火墙后面的外部 Web 服务。运营外部 Web 服务的人员只会向特定的静态 IP 开放防火墙。
我尝试的解决方案是在具有静态 IP 的单独服务器上使用 Squid 将请求从 Heroku 转发到外部服务。这样,外部服务始终看到的是代理服务器的静态 IP,而不是 Heroku 服务的动态 IP。
由于我的代理服务器不能依赖 IP 地址进行身份验证(这才是问题所在!),因此它必须依赖用户名和密码。此外,用户名和密码不能以明文形式传输,因为如果攻击者截获该明文,他们就可以冒充我连接到我的代理,使用我的代理的静态 IP 发出出站请求,从而避开外部 Web 服务的防火墙。
因此,Squid 代理必须仅接受通过 HTTPS 而非 HTTP 的连接。(与外部 Web 服务的连接可能是 HTTP 或 HTTPS。)
我在 CentOS 6.5.x 上运行 Squid 3.1.10,以下是我squid.conf
目前的情况。出于故障排除目的,我暂时启用了 HTTP 和 HTTPS 代理,但我只想使用 HTTPS。
#
# Recommended minimum configuration:
#
acl manager proto cache_object
acl localhost src 127.0.0.1/32 ::1
acl to_localhost dst 127.0.0.0/8 0.0.0.0/32 ::1
# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network
acl localnet src 172.16.0.0/12 # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
# Authorization
auth_param digest program /usr/lib64/squid/digest_pw_auth -c /etc/squid/squid_passwd
auth_param digest children 20 startup=0 idle=1
auth_param digest realm squid
auth_param digest nonce_garbage_interval 5 minutes
auth_param digest nonce_max_duration 30 minutes
auth_param digest nonce_max_count 50
acl authenticated proxy_auth REQUIRED
#
# Recommended minimum Access Permission configuration:
#
# Only allow cachemgr access from localhost
http_access allow manager localhost
http_access deny manager
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost
#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
#http_access allow localnet
#http_access allow localhost
http_access allow authenticated
# And finally deny all other access to this proxy
http_access deny all
# Squid normally listens to port 3128
http_port 3128
https_port 3129 cert=/etc/squid/ssl/cert.pem key=/etc/squid/ssl/key.pem
# We recommend you to use at least the following line.
hierarchy_stoplist cgi-bin ?
# Disable all caching
cache deny all
# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/spool/squid 100 16 256
# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid
# Add any of your own refresh_pattern entries above these.
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
使用此设置,HTTP 代理可以正常工作,但 HTTPS 代理则不行。
以下是来自本地的 HTTP 代理请求:
$ curl --proxy http://my-proxy-server.example:3128 \
--proxy-anyauth --proxy-user redacted:redacted -w '\n' \
http://urlecho.appspot.com/echo?body=OK
OK
很好,这正是我所期望的。结果如下/var/log/squid/access.log
:
1390250715.137 41 my.IP.address.redacted TCP_MISS/200 383 GET http://urlecho.appspot.com/echo? redacted DIRECT/74.125.142.141 text/html
这是另一个请求,这次使用 HTTPS:
$ curl --proxy https://my-proxy-server.example:3129 \
--proxy-anyauth --proxy-user redacted:redacted -w '\n' \
http://urlecho.appspot.com/echo?body=OK
curl: (56) Recv failure: Connection reset by peer
此内容之后没有任何内容access.log
,但是cache.log
:
2014/01/20 20:46:15| clientNegotiateSSL: Error negotiating SSL connection on FD 10: error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request (1/-1)
以下是上述内容的更详细版本:
$ curl -v --proxy https://my-proxy-server.example:3129 \
--proxy-anyauth --proxy-user redacted:redacted -w '\n' \
http://urlecho.appspot.com/echo?body=OK
* Adding handle: conn: 0x7f9a30804000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7f9a30804000) send_pipe: 1, recv_pipe: 0
* About to connect() to proxy my-proxy-server.example port 3129 (#0)
* Trying proxy.server.IP.redacted...
* Connected to my-proxy-server.example (proxy.server.IP.redacted) port 3129 (#0)
> GET http://urlecho.appspot.com/echo?body=OK HTTP/1.1
> User-Agent: curl/7.30.0
> Host: urlecho.appspot.com
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer
看起来像是 SSL 错误。但是,我正在重复使用子域通配符 SSL 证书,如上面的配置所示cert.pem
,key.pem
该证书已成功部署到其他 Web 服务器上。此外,使用 curl 直接访问代理服务器是可行的,或者至少在 SSL 阶段之后建立了连接:
$ curl https://my-proxy-server.example:3129
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ERROR: The requested URL could not be retrieved</title>
[--SNIP--]
<div id="content">
<p>The following error was encountered while trying to retrieve the URL: <a href="/">/</a></p>
<blockquote id="error">
<p><b>Invalid URL</b></p>
</blockquote>
<p>Some aspect of the requested URL is incorrect.</p>
<p>Some possible problems are:</p>
<ul>
<li><p>Missing or incorrect access protocol (should be <q>http://</q> or similar)</p></li>
<li><p>Missing hostname</p></li>
<li><p>Illegal double-escape in the URL-Path</p></li>
<li><p>Illegal character in hostname; underscores are not allowed.</p></li>
</ul>
[--SNIP--]
你知道我做错了什么吗?我尝试的事情有可能实现吗?提前致谢。
答案1
你可以在这个小型 Docker 镜像中看到它是如何完成的:yegor256/squid-代理。您的代码存在问题,配置在acl
指令之后。只需交换它们,一切即可开始工作。
答案2
@David,按照你的Squid ML 中的线程- 我建议使用 Stunnel 解决方案。您的身份验证将是隧道两端的 SSL 证书,其余部分在该隧道内以“明文”形式进行,或者您可以根据需要进行 Digest。
我已经使用类似的解决方案来“验证” NFS 端点并取得巨大成功。
LinuxGazette 的使用 stunnel 进行安全通信