如何在 PHP 中使用 cURL 连接到 Tor 隐藏服务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15445285/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 09:14:59  来源:igfitidea点击:

How can I connect to a Tor hidden service using cURL in PHP?

phpcurlproxytor

提问by frosty

I'm trying to connect to a Tor hidden service using the following PHP code:

我正在尝试使用以下 PHP 代码连接到 Tor 隐藏服务:

$url = 'http://jhiwjjlqpyawmpjx.onion/'
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "http://127.0.0.1:9050/");
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);

print_r($output);
print_r($curl_error);

When I run it, I get the following error:

当我运行它时,出现以下错误:

Couldn't resolve host name

无法解析主机名

However, when I run the following command from my command line in Ubuntu:

但是,当我从 Ubuntu 的命令行运行以下命令时:

curl -v --socks5-hostname localhost:9050 http://jhiwjjlqpyawmpjx.onion

I get a response as expected

我得到了预期的回应

The PHP cURLdocumentations says this:

PHP cURL文档是这样说的:

--socks5-hostname
Use  the  specified  SOCKS5 proxy (and let the proxy resolve the host name).

I believe the reason it works from the command line is because Tor (the proxy) is resolving the .onion hostname, which it recognizes. When running the PHP code above, my guess is that cURL or PHP is trying to resolve the .onion hostname and doesn't recognize it. I've searched for a way to tell cURL/PHP to let the proxy resolve the hostname, but I can't find a way.

我相信它从命令行工作的原因是因为 Tor(代理)正在解析它识别的 .onion 主机名。运行上面的 PHP 代码时,我猜测是 cURL 或 PHP 试图解析 .onion 主机名但无法识别它。我已经搜索了一种方法来告诉 cURL/PHP 让代理解析主机名,但我找不到方法。

There is a very similar Stack Overflow question, cURL request using socks5 proxy fails when using PHP, but it works through the command line.

有一个非常相似的 Stack Overflow 问题,使用 socks5 代理的 cURL 请求在使用 PHP 时失败,但它可以通过命令行工作

回答by dr.scre

You need to set option CURLOPT_PROXYTYPEto CURLPROXY_SOCKS5_HOSTNAME, which sadly wasn't defined in old PHP versions, circa pre-5.6; if you have earlier in but you can explicitly use its value, which is equal to 7:

您需要将选项设置CURLOPT_PROXYTYPECURLPROXY_SOCKS5_HOSTNAME,遗憾的是在旧的 PHP 版本中没有定义,大约在 5.6 之前;如果你之前有但你可以明确地使用它的值,它等于7

curl_setopt($ch, CURLOPT_PROXYTYPE, 7);

回答by FattyPotatoes

I use Privoxyand cURL to scrape Tor pages:

我使用Privoxy和 cURL 来抓取 Tor 页面:

<?php
    $ch = curl_init('http://jhiwjjlqpyawmpjx.onion'); // Tormail URL
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
    curl_setopt($ch, CURLOPT_PROXY, "localhost:8118"); // Default privoxy port
    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
    curl_exec($ch);
    curl_close($ch);
?>

After installing Privoxy you need to add this line to the configuration file (/etc/privoxy/config). Note the space and '.' a the end of line.

安装 Privoxy 后,您需要将此行添加到配置文件 ( /etc/privoxy/config) 中。注意空格和“.” a 行尾。

forward-socks4a / localhost:9050 .

Then restart Privoxy.

然后重新启动 Privoxy。

/etc/init.d/privoxy restart

回答by Anthony Garcia-Labiad

Try to add this:

尝试添加这个:

curl_setopt($ch, CURLOPT_HEADER, 1); 
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1); 

回答by Meitar

TL;DR: Set CURLOPT_PROXYTYPEto use CURLPROXY_SOCKS5_HOSTNAMEif you have a modern PHP, the value 7otherwise, and/or correct the CURLOPT_PROXYvalue.

TL;DR:如果您有现代 PHP,则设置CURLOPT_PROXYTYPE为使用CURLPROXY_SOCKS5_HOSTNAME7否则使用该值,和/或更正该CURLOPT_PROXY值。

As you correctly deduced, you cannot resolve .oniondomains via the normal DNS system, because this is a reserved top-level domain specifically for use by Torand such domains by design have no IP addresses to map to.

正如您正确推断的那样,您无法.onion通过正常的 DNS 系统解析域,因为这是一个专门供 Tor 使用的保留顶级域,并且这些域在设计上没有 IP 地址可映射。

Using CURLPROXY_SOCKS5will direct the cURL command to send its traffic to the proxy, but will notdo the same for domain name resolution. The DNS requests, which are emitted beforecURL attempts to establish the actual connection with the Onion site, will still be sent to the system's normal DNS resolver. These DNS requests will surely fail, because the system's normal DNS resolver will not know what to do with a .onionaddress unless it, too, is specifically forwarding such queries to Tor.

使用CURLPROXY_SOCKS5将指示 cURL 命令将其流量发送到代理,但不会对域名解析执行相同操作。cURL 尝试与 Onion 站点建立实际连接之前发出的 DNS 请求仍将发送到系统的正常 DNS 解析器。这些 DNS 请求肯定会失败,因为系统的普通 DNS 解析器不知道如何.onion处理地址,除非它也专门将此类查询转发到 Tor。

Instead of CURLPROXY_SOCKS5, you must use CURLPROXY_SOCKS5_HOSTNAME. Alternatively, you can also use CURLPROXY_SOCKS4A, but SOCKS5 is much preferred. Either of these proxy types informs cURL to perform both its DNS lookups and its actual data transfer via the proxy. This is required to successfully resolve any .oniondomain.

取而代之的是CURLPROXY_SOCKS5,您必须使用CURLPROXY_SOCKS5_HOSTNAME. 或者,您也可以使用CURLPROXY_SOCKS4A,但 SOCKS5 更受欢迎。这些代理类型中的任何一种都会通知 cURL 通过代理执行其 DNS 查找和实际数据传输。这是成功解析任何.onion域所必需的。

There are also two additional errors in the code in the original question that have yet to be corrected by previous commenters. These are:

原始问题中的代码中还有两个额外的错误尚未被之前的评论者更正。这些是:

  • Missing semicolon at end of line 1.
  • The proxy address value is set to an HTTP URL, but its type is SOCKS; these are incompatible. For SOCKS proxies, the value must be an IP or domain name and port number combination without a scheme/protocol/prefix.
  • 第 1 行末尾缺少分号。
  • 代理地址值设置为HTTP URL,但其类型为SOCKS;这些是不相容的。对于 SOCKS 代理,该值必须是 IP 或域名和端口号组合,没有方案/协议/前缀。

Here is the correct code in full, with comments to indicate the changes.

这是完整的正确代码,并附有注释以指示更改。

<?php
$url = 'http://jhiwjjlqpyawmpjx.onion/'; // Note the addition of a semicolon.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1:9050"); // Note the address here is just `IP:port`, not an HTTP URL.
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME); // Note use of `CURLPROXY_SOCKS5_HOSTNAME`.
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);

print_r($output);
print_r($curl_error);

You can also omit setting CURLOPT_PROXYTYPEentirely by changing the CURLOPT_PROXYvalue to include the socks5h://prefix:

您还可以CURLOPT_PROXYTYPE通过更改CURLOPT_PROXY值以包含socks5h://前缀来完全省略设置:

// Note no trailing slash, as this is a SOCKS address, not an HTTP URL.
curl_setopt(CURLOPT_PROXY, 'socks5h://127.0.0.1:9050');