防止HttpURLConnection收到未经请求的CONNECT方法调用

6

我正在使用类似以下代码的HttpURLConnection:

String strURL = "https://example.herokuapp.com";
Bitmap bmImage = null;
HttpURLConnection connection = null;
InputStream in = null;
showMessage(context.getString(R.string.message_preparing));
try {
    int timeoutMS = 15000;
    URL url = new URL(strURL);
    connection = (HttpURLConnection) url.openConnection();
    connection.setDoInput(true);
    connection.setConnectTimeout(timeoutMS);
    connection.setReadTimeout(timeoutMS);
    connection.connect();
    in = connection.getInputStream();
    BitmapFactory.Options options = new BitmapFactory.Options();
    bmImage = BitmapFactory.decodeStream(in, null, options);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (connection != null)
        connection.disconnect();
    if (in != null) {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

return bmImage;

这段代码定义了一个URL并返回一个bmp图片,再由上述代码解码使用。对于一般用户而言,这段代码可正常工作,但对于某个用户,尽管该代码能够成功获取bmp图像,但在服务器(Heroku上的node.js服务器)中,他们的设备似乎还会发送一个CONNECT请求。虽然此请求会被自动拒绝并返回503响应,所以它本身不是问题,bmp图像仍将被发送到他们的设备,但我想知道为什么会发送这些CONNECT请求以及如何阻止它们。难道应该只有GET请求?

我已经尝试了这个解决方案,看起来与我的问题类似,但对我没有任何影响。

请注意,strURL是指向https服务器的,并且我正在使用HttpURLConnection(而不是Https)——不确定是否有任何重要性。

我也不能百分之百确定CONNECT请求来自上述调用,但它们肯定发生在传送bmp图像的GET请求前后。也许它可以通过操作系统在我的代码之外生成?不确定。

如果有帮助,下面是来自Heroku的一个示例日志消息,针对其中的一个CONNECT请求:

Oct 27 14:14:25 example heroku/router: at=error code=H13 desc="Connection closed without response" method=CONNECT path="example.herokuapp.com:443" host=example.herokuapp.com request_id=353e623x-dec4-42x5-bcfb-452add02ecef fwd="111.22.333.4" dyno=web.1 connect=0ms service=1ms status=503 bytes=0

编辑:这也可能与设备有关,因为该设备实际上在短时间内进行了两个独立的GET请求(完全不同且合法的请求),但是只有一个CONNECT请求显然存在(大约在一对GET请求的同时)。 因此,并非每个GET请求都有一个CONNECT请求。


这是代理的有意使用示例:https://dev59.com/mGUo5IYBdhLWcg3wmASi - Alex Nauda
在我看来,你可以删除“connection.connect();”这行代码,因为它将在“getInputStream”中被调用。 - BNK
1
很难说,但需要考虑的另一个变量是连接是否来自于限制网络,这可能会强制通过代理进行出站连接。 - bimsapi
有趣的想法。 我对移动网络的了解有些有限。 我的理解是使用代理只是通过指定的中介(代理)与您打算通信的节点进行通信。 因此,如果受限制的网络强制通过代理进行连接,那么不会直接从设备发送GET请求到我的节点应用程序,而是从代理发送。 使用代理如何导致向我的设备发送CONNECT请求呢? - drmrbrewer
这是对代理服务器(SSL隧道)进行的首次检查。客户端和代理之间进行握手,以通过代理建立客户端和远程服务器之间的连接。为了使此扩展与旧版本兼容,握手必须与HTTP/1.x请求(CONNECT)具有相同的格式,以便不支持此功能的代理仍可以确定请求对其来说不可服务,并提供适当的错误响应(而不会在连接上挂起)[3.1](http://curl.haxx.se/rfc/draft-luotonen-web-proxy-tunneling-01.txt)。 - JavaGhost
显示剩余3条评论
1个回答

2
CONNECT 方法可以用于向 HTTP 服务器(无论是代理服务器还是源服务器)发出请求,它的基本含义是:

"顺便说一下,伙计,你能不能原封不动地把我说的这些东西转达给我所提到的那个主机/端口呢?其实不需要真正关注我所说的内容。"

通常,这是针对代理的指令,要求代理“让路”,让请求者(可能是用户代理或另一个代理)直接与上游服务器交流。

这是一个很好的功能,如果你和源服务器之间有一个不合作(也许过时)的代理服务器的话。如果你是一个黑客,并且想让一个配置错误的源服务器毫不费力地帮助你进入内部网络,它也很方便。

然而,除非你对网络有完美的了解并且"知道"在你的路径中只有一个代理,否则你需要堆叠 CONNECT 头直到得到拒绝。

例如:

CONNECT site.example.com 80 HTTP/1.1
CONNECT site.example.com 80 HTTP/1.1
GET /foo HTTP/1.1
Host: site.example.com

这段内容要么帮助你通过两个互相干扰、无用的上游代理;要么只帮助你通过实际存在的一个代理,但会从源服务器那里得到一个503错误……然后你需要去掉一个CONNECT前缀方法并重复请求。

这就解释了到目前为止所看到的行为。

但是,不清楚的是是谁添加了CONNECT前缀,他们为什么不喜欢代理?

可能有以下几种情况:

  1. 用户代理上的代码(客户端智能手机上使用HttpUrlConnectionHttpsUrlConnection的Android应用程序(如果URL具有https://方案,则openConnection()将自动使用它);
  2. 在用户代理和源服务器之间的任何代理,由于某些原因不信任其上游代理或者需要通过代理隧道传输HTTPS,否则只支持HTTP(这就是CONNECT的作用);
  3. 被黑客攻击的代理,正在寻找愚蠢的源服务器来利用……但为什么要等到有人真正需要东西才麻烦源服务器呢?

完整的CONNECT方法内容和数据包的源IP很有趣。我猜是情况2,并预测如果您通过http:// URL访问网站,则不会看到CONNECT

你无法对此做任何事。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - drmrbrewer
看起来我实际上无法检查这些 CONNECT 请求,因为它们被 Heroku 服务器在我的应用之外捕获。所以我可能无法了解更多信息,但是理解可能的原因真的非常有用。谢谢。 - drmrbrewer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接