天天做Tor数据采集,今天我也把网站搭建到Tor网络上得了。
其实之前是搭过一次的,但是当时只是简单测试了一下,访问成功后就没有再维护了,这次我打算认真搞一搞。
(标题的梗来自于“发到暗网上管理员说要弄死我”)

啥是暗网?

暗网实际上是一种隐秘网络的统称,其定义(大概,如果要用书面语言准确描述我就不太清楚了)是需要通过特殊方式访问,不会被常规搜索引擎索引的网络。常见的暗网网络包括洋葱网络(Tor)、I2P以及freenet、zeronet、Yggdrasil、Lokinet以及偏geeker一点的GNUnet和Riffle等,其中活跃度最高度属洋葱网络。这几种网络都需要特殊的接入方式,无法通过正常的互联网直接访问,不过他们都有各自的目标和特点,从技术实现上来说也有较大区别。不过今天我们暂时只讨论洋葱网络。

谈到暗网,似乎所有人第一反应都会是毒品和黑卡交易、枪支贩卖、人口及人体器官贩卖、邪教组织宣传等。暗网的高度匿名和难以溯源的特点确实为上述黑灰产提供了高度便利的环境,但实际上隐秘网络本质上只是一种工具,其功能并不仅为黑灰产提供方便,主要还是看其使用方法,比如今天我们的目标网站就不存在上述内容😋。

注意:


本文有小部分内容由AI辅助创作,部分内容的真实性存疑,请自行判断,完整的AIGC内容我会特殊标注。
本文会使用到一些方法绕过GFW,请在使用互联网时遵守当地的相关法律法规。
本文涉及到匿名网络及相关网站的搭建,请注意在实践过程中的法律问题。
根据2026新版《中华人民共和国治安管理处罚法》第八十条:
制作、运输、复制、出售、出租淫秽的书刊、图片、影片、音像制品等淫秽物品或者利用信息网络、电话以及其他通讯工具传播淫秽信息的,处十日以上十五日以下拘留,可以并处五千元以下罚款;情节较轻的,处五日以下拘留或者一千元以上三千元以下罚款。
前款规定的淫秽物品或者淫秽信息中涉及未成年人的,从重处罚。
根据《中华人民共和国反恐怖主义法》第八十条:
参与下列活动之一,情节轻微,尚不构成犯罪的,由公安机关处十日以上十五日以下拘留,可以并处一万元以下罚
款:
(一)宣扬恐怖主义、极端主义或者煽动实施恐怖活动、极端主义活动的;
(二)制作、传播、非法持有宣扬恐怖主义、极端主义的物品的;
根据《计算机信息网络国际联网安全保护管理办法》第五条:
任何单位和个人不得利用国际联网制作、复制、查阅和传播下列信息:
(一)煽动抗拒、破坏宪法和法律、行政法规实施的;
(二)煽动颠覆国家政权,推翻社会主义制度的;
(三)煽动分裂国家、破坏国家统一的;
(四)煽动民族仇恨、民族歧视,破坏民族团结的;
(五)捏造或者歪曲事实,散布谣言,扰乱社会秩序的;
(六)宣扬封建迷信、淫秽、色情、赌博、暴力、凶杀、恐怖,教唆犯罪的;
(七)公然侮辱他人或者捏造事实诽谤他人的;
(八)损害国家机关信誉的;
(九)其他违反宪法和法律、行政法规的。
以及其他可能出现的违规违法行为。
匿名网络可以让你的网络匿名,但不会让你匿名,你需要靠自己保护好你的个人隐私。

Tor 架构及访问流程

在实际动手操作之前,先来了解一些理论内容。

Tor 缩写自 The onion route,也就是洋葱路由,由于文章重点在于技术方面,其历史背景就不过多讨论了,总之其最初是被用于美国情报通信1加密而研发出来的。首先需要知道的是,Tor网络和Tor Bowser是两个东西,Tor Bowser用于便捷访问Tor网络,但接入Tor网络并不一定需要Tor Bowser的支持。

接入Tor后,通过Tor访问目标网站服务器,Tor会对信息进行多层加密2,从客户端到服务端之间不会直接连接3,而是会经过三个节点,分别为入口节点、中间节点和出口节点,这些节点都称为中继节点,Tor会在中继节点中随机选择三个节点组成一条链路。除此之外,数据在离开客户端之前还会被进行三次加密,每每层加密对应一个中继节点,中继节点只能解开其中一层加密4,但其不会知道数据的起始来源(客户端)和最终目的地(目标服务器)。

初始化及准备工作

在启动Tor客户端时,客户端会连接到中继节点目录服务器,下载一份包含全球所有在线中继节点的列表5及其详细信息6共识文档。不过由于其功能的敏感性,包括部分国家地区对网络的封锁,对中继节点的访问很有可能会被当地网络阻止7,此时就需要通过网桥来作为入口节点接入访问Tor网络8,这些节点都是不公开的9

建立链路

获取到中继节点后,客户端会随机挑选三个分别作为入口节点、中间节点和出口节点,客户端请求会经过三跳到目标服务器,每一跳都会通过上一跳的节点建立连接,并获取到一个单独的密钥10

  • 第一跳:客户端接入入口节点,与节点握手,通过DH密钥交换11建立一个加密通道,并协商一个对称密钥。
  • 第二跳:客户端通过已建立的第一跳通道,通过入口节点向中间节点发起连接。客户端再次与第二个节点握手,获取到第二个密钥。
  • 类似地,客户端通过前两个节点与出口节点协商密钥。此时,完整的 3 跳链路建立完成。

访问互联网

首先需要知道的是,Tor并不是脱离互联网工作的,其最多算是给互联网进行了一个高层次的“封装”,也就是说,其实可以将Tor网络作为一个正常的上网工具使用12的。所以实际上Tor并不只用于访问.onion域名,正常的明网也可以通过Tor来匿名访问13

以访问google.com为例,在通过Tor访问google时,你需要:

  1. 三重加密:客户端会按照第三跳、第二跳、第一跳的顺序得到的密钥来进行加密。
  2. 经过三个节点:首先进入入口节点,由于其协商的密钥是最后一层加密,所以其可以通过密钥解密出来后两次加密后的数据,解密后的数据会携带下一个目标节点,也就是中间节点。然后数据被入口节点发送到中间节点,此时中间节点是不知道客户端信息的,其只知道入口节点的信息。中间节点再尝试进行第二层解密,然后得到出口节点的信息。对于出口节点也是以此类推,在出口节点解密后,就可以得到未经加密的请求14了,此时由出口节点访问目标服务器。
  3. 返回数据:由服务器返回客户端的数据会按照上一步的相反顺序,被逐层加密,最后客户端得到的仍是三重加密的数据,按照1、2、3的顺序解密后获取到最终返回信息。

访问隐藏服务(.onion网站)

访问洋葱网站会比访问明网更加复杂,因为其需要保证双方的匿名性,整个流程一共会涉及到6个跳点:

  1. 服务发布:这一步是服务上线的步骤15,隐藏服务会随机选择几个中继节点作为引入点,然后建立服务器到这些引入点的长连接,并创建一个隐藏服务描述符,包含其公钥的引入点列表。最后将描述符上传到一个分布式哈希表目录(DHT)中16,这个DHT有点类似于明网互联网系统中的DNS。
  2. 用户获取地址:用户需要获取到网站的 onion 域名地址,该地址是一串哈希字符串,本质上就是该服务公钥的哈希值。
  3. 建立汇合点:Tor客户端随机选择一个中继节点作为汇合点,并建立 3 跳链路通往该汇合点。
  4. 请求连接:客户端从DHT中下载描述符,找到其引入点,并通过引入点17把汇合点的地址发送给隐藏服务18
  5. 服务响应:接上一个步骤,引入点将汇合点信息发送给隐藏服务,然后由隐藏服务建立一条新线路到汇合点,此时引入点的工作就完成了,隐藏服务会在汇合点和客户端进行通信。当然,隐藏服务也会经过三跳链路。
  6. 双向通信:隐藏服务和客户端分别经过三跳后在汇合点进行通信,简单来说一条信息会先在客户端进行六次加密,经过三跳和三次解密到汇合点,再经过三跳和三次解密到隐藏服务,反之亦然,汇合点也不会看到明文信息,其只负责转发。

域名获取方法

和普通明网域名不同,Tor网络的域名是计算得到的,也就是说想要一个好的域名19必须要先有一台高算力服务器。不过普通的随机哈希域名也不是不能用,所以我们直接来了解其到底是怎么得到的。

简单来说,获得域名的流程为:先生成一对公私钥,然后对公钥进行哈希运算,对其哈希值进行 Base32 编码,加上 .onion 后缀,最后得到的就是域名。所以要获得一个好的域名,必须进行哈希碰撞(毕竟也没可能根据最终哈希值逆向算出公私钥)而且必须碰撞出进行base32编码后是需要的结果的密钥才行20

由于上述因素,Tor协议会自动验证连接的服务器是否拥有其对应私钥,避免了网站劫持。

目前使用的v3协议域名长度为56位,几乎避免了目录节点枚举的情况,相比v2协议,在安全性和可扩展性上都有极大提升。

有专门用于碰撞计算域名的工具:mkp224o,我们可以使用该工具来算一个稍微看得过去一点的域名,我花了几分钟算了一个以kalinote开头的域名:

1
kalinote7mwuxkpre7adpfuuzhn2zfpfsnyk2vb5dkrwhb4lcbtrhiid.onion

至于工具的使用方式很简单,用一用就会了,没啥可多说的。

安全性问题

虽然Tor网络有复杂的通信流程,但目前仍有一些已知的安全性问题。

比如最为常见的就是女巫攻击,攻击者在网络中布置大量由自己控制的节点,增加用户链路中同时出现多个其控制节点的概率。如果一条链路的入口和出口都被攻击者控制,关联攻击将变得轻而易举。由于 Tor 网络是全球志愿者共同维护运行的,所以任何人都可以向Tor网络内加入节点,包括黑客组织或是政府21

上述女巫攻击实施后,攻击者对出入口流量特征进行分析,即使数据是加密的,通过指纹22比对,攻击者有极高概率将特定用户与特定访问行为关联起来,从而实现一定程度上的去匿名化。

将网站接入Tor网络

安装

首先我们需要在服务器上安装Tor,需要使用Tor官方自己维护的软件包仓库,Ubuntu和Debain等系统自带的软件包没有最新的软件更新,安全性和稳定性都不可靠。

接下来就按照官方建议的软件安装流程来走一遍。

首先判断系统架构,包仓库只提供amd64和arm64架构的二进制文件,其他架构可能需要通过源代码自行编译。

1
$ sudo dpkg --print-architecture

只要是amd64或arm64即可,接下来需要安装一个 apt-transport-https 包,这个包是让apt可以使用https协议安全下载的,APT 1.5及以上版本都是自带的,不过手动安装一下也没啥。

接下来添加 Tor 官方 GPG 密钥:

1
curl -fsSL https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | sudo gpg --dearmor -o /usr/share/keyrings/tor-archive-keyring.gpg

然后添加Tor官方的软件源:

1
2
echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org bookworm main" | sudo tee /etc/apt/sources.list.d/tor.list
echo "deb-src [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org bookworm main" | sudo tee -a /etc/apt/sources.list.d/tor.list

接下来就可以更新和安装Tor了:

1
2
3
4
5
sudo apt update
sudo apt install tor deb.torproject.org-keyring -y

# 安装完成后检查版本:
tor --version
截至目前(20260206),最新版本为0.4.8.22

配置

首先需要编辑配置文件,安装后应该是会自动生成这个文件的:

1
sudo vim /etc/tor/torrc

在末尾增加以下内容:

1
2
3
4
5
6
7
8
# 定义隐藏服务
# 所有的私钥和域名文件都将存储在这里
HiddenServiceDir /var/lib/tor/tor_site/

# 定义转发规则
# 其中前面的 80 是对外的端口,也就是Tor服务在Tor网络中的端口,后面的是本地机器的网站端口
# 这个配置将会把Tor网络中对80端口的请求转发到8080端口
HiddenServicePort 80 127.0.0.1:8080

Tor服务不需要配置SSL证书,因为Tor 协议本身已经完成了 HTTPS 该干的事情。回顾上面的访问隐藏服务一节你就会发现,从客户端到服务端是全程多层加密,且域名获取方法一节说明了Tor域名是无法被篡改攻击的。

完成配置后重启Tor服务,可以查看一下Tor服务状态。

1
2
sudo systemctl restart tor
sudo systemctl status tor

成功运行后,继续下一步,给网站配置Nginx,由于我的blog是暗网和明网同时运行的,所以我分为两个server块来配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 明网配置
server {
    listen 80;
    listen 443 ssl;
    server_name kalinote.top;
   
    # 可以设置一个请求头,表明暗网网站地址,Tor 浏览器会建议用户跳转到暗网地址
    add_header Onion-Location "http://kalinote7mwuxkpre7adpfuuzhn2zfpfsnyk2vb5dkrwhb4lcbtrhiid.onion$request_uri";
   
    # ... 其他配置
}

# --- 新增暗网配置 (专门适配 Tor) ---
server {
    # 对应 torrc 里的转发端口
    listen 127.0.0.1:8080;
   
    # 填写洋葱域名 .onion 地址
    server_name kalinote7mwuxkpre7adpfuuzhn2zfpfsnyk2vb5dkrwhb4lcbtrhiid.onion;

    root /www/sites/kalinote.top/index;
    index index.php index.html;

    # 关闭访问日志,防止记录 Tor 出口节点 IP
    access_log off;
   
    # 再次强调不要配置SSL证书

    # 引用原本的 PHP 配置
    location ~ [^/]\.php(/|$) {
        fastcgi_pass 127.0.0.1:9000;
        include fastcgi-php.conf;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       
        fastcgi_param REMOTE_ADDR 127.0.0.1;
    }

    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {
        return 404;
    }
   
    include /www/sites/kalinote.top/rewrite/kalinote.top.conf;
}

保存应用以下nginx配置,就可以先测试一下是否能通过Tor域名访问站点了,Tor会生成一个随机的域名,域名在你上面配置的HiddenServiceDir路径的hostname文件中,先试试能不能用,使用洋葱浏览器访问域名:

看起来已经跑通了

确认可以访问后,我们就可以把之前通过mkp244o工具生成的域名换上去了,如果想保留Tor生成的随机域名,可以直接上传到新的文件夹中:

直接整个文件夹上传

然后修改配置文件中的HiddenServiceDir,并替换为新的目录:

原来的目录就不用管它了

然后再重启一下Tor服务:

1
2
sudo systemctl restart tor
sudo systemctl status tor

最后就可以使用新的Tor域名来访问这个blog了:

记得备份域名的公私钥文件

同时如果你使用明网的地址访问,右上角就会弹出一个弹框,提示你该站点存在洋葱服务:

点击即可跳转到里站(bushi)

WordPress适配工作

本来文章到这里就应该结束了的,byd wordpress在数据库中存储的是绝对地址,导致点击任何连接都会从onion域名跳转到明网域名,这非常不安全,也不太onion,所以我们需要继续往下,来解决这个问题。

注意:

从此处往下的代码都是Gemini生成的!

首先我们需要修改 wp-config.php 来实现动态域名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 在 define('WP_DEBUG', false); 之后添加以下代码
// 获取当前访问的主机名
$current_host = $_SERVER['HTTP_HOST'];

// 定义允许的域名白名单
$allowed_domains = array(
    'kalinote.top',
    'www.kalinote.top',
    'kalinote7mwuxkpre7adpfuuzhn2zfpfsnyk2vb5dkrwhb4lcbtrhiid.onion'
);

// 判断协议,Onion 访问是 http 协议,不需要强制 https
$protocol = 'http://';
if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ||
     (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') ) {
    $protocol = 'https://';
}

// 如果当前访问的域名在白名单内
if (in_array($current_host, $allowed_domains)) {
   
    // 定义站点地址
    define('WP_SITEURL', $protocol . $current_host);
    define('WP_HOME',    $protocol . $current_host);
   
    // 强制资源使用相对路径,避免让图片之类的走明网域名
    define('WP_CONTENT_URL', '/wp-content');
   
    // 强制修正插件目录,防止某些插件读取绝对路径出错
    define('WP_PLUGIN_URL',  '/wp-content/plugins');
}

同时我们需要根据域名来判断是否使用超级缓存,避免缓存明网或暗网的静态页,同样修改 wp-config.php:

1
2
3
4
5
6
7
8
9
10
// 原来的 define('WP_CACHE', true); 替换为:
$is_onion = (strpos($_SERVER['HTTP_HOST'], '.onion') !== false);

// 只有在非 onion 域名下才开启缓存,防止 onion 读到明网的缓存文件
if (!$is_onion) {
    define('WP_CACHE', true);
    define('WPCACHEHOME', '网站文件路径/index/wp-content/plugins/wp-super-cache/' );
} else {
    define('WP_CACHE', false);
}

在某些文章中,我还在某些地方使用了明网网站的超链接(比如本文的11号注释👇),需要修改主题工具,进入WordPress 后台 -> 外观 -> 主题文件编辑器 -> 选择 functions.php (主题函数文件),在文件末尾添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * 实时替换文章内容和摘要中的旧域名为当前访问域名
 * 专为 Onion/多域名环境设计
 */

function fix_content_urls_for_onion($content) {
    // 只有在 onion 访问时才处理
    if (strpos($_SERVER['HTTP_HOST'], '.onion') !== false) {
        $main_domain = 'kalinote.top'; // 你的明网主域名
        $onion_domain = $_SERVER['HTTP_HOST']; // 当前的洋葱域名
        $protocol = (is_ssl() ? 'https://' : 'http://');

        // 替换带 http/https 的完整链接
        $content = str_replace('https://' . $main_domain, $protocol . $onion_domain, $content);
        $content = str_replace('http://' . $main_domain, $protocol . $onion_domain, $content);
       
        // 替换转义过的链接 (防止某些插件输出 json 数据时链接没变)
        $content = str_replace('https:\/\/' . $main_domain, $protocol . $onion_domain, $content);
    }
    return $content;
}

// 挂载到文章内容和摘要的输出过滤器上
add_filter('the_content', 'fix_content_urls_for_onion', 99);
add_filter('the_excerpt', 'fix_content_urls_for_onion', 99);
// 如果使用了 Elementor 等编辑器,可能还需要挂载到 widget_text
add_filter('widget_text', 'fix_content_urls_for_onion', 99);

完成上述工作后,就可以尝试访问洋葱网络的网站了:

图片资源也是洋葱链接

到这里就真的结束了,整个网站现在“几乎”已经全部接入Tor网络了,之所以说是几乎,是因为仍有部分外部服务使用的是明网的链接,比如主页的头图图床、js文件cdn、部分由主题生成的链接、以及我从来没用过的网易云BGM功能...

不过无伤大雅,最终目的本是研究技术,本身这个blog的地址也是公开透明的,隐秘度并不高,只是对于对隐私有要求的用户来说,可能就不那么友好了。

  1. 唉,西大怎么这么坏啊😡 ↩︎
  2. 由于一层一层的跟洋葱很像,所以叫onion router. ↩︎
  3. 当然,像什么NAT路由、运营商转发、防火墙规则之类的就不讨论了,Tor的行为和这些设备不是一个概念。 ↩︎
  4. 为了看到数据来自哪里、去往哪里(上一个中继节点和下一个中继节点),这是必要的。 ↩︎
  5. 你也可以在Tor project上对中继服务器节点的速度和稳定性进行评分,高分节点会被优先使用。 ↩︎
  6. 包括带宽、IP、公钥等 ↩︎
  7. 也就是被墙掉了 ↩︎
  8. 当然,部分地区可能也会墙掉网桥,此时就只能再套一层代理网络来接入网桥了。 ↩︎
  9. 这里的“不公开”是相对来说,网桥不会像中继节点一样全部写到一个目录中,但其仍可以通过官方网站获取到,Tor Bowser也自带获取网桥的功能。 ↩︎
  10. 至于为什么不用担心密钥被已经连接的节点获取并利用,可以去了解一下非对称密钥协议↩︎
  11. 迪菲-赫尔曼密钥交换协议,在《以X(Twitter)为例的安卓平台软件逆向及数据采集》中也有提到,在中间人攻击一节。 ↩︎
  12. 当然,你需要忍受其速度、延迟和对中继节点的网络封锁,匿名也是需要代价的。 ↩︎
  13. 但实际上明网的网站会有很多手段来对你进行track。 ↩︎
  14. 只是相对来说,实际上完全解密的信息仍有可能自身就带有加密,比如ssl。 ↩︎
  15. 也就是本文会涉及到的步骤。 ↩︎
  16. DHT被存储在网络中的各个位置,毕竟是“分布式”。 ↩︎
  17. 这里实际已经和服务器交互上了,但引入点会和服务器长期连接,如果所有通信都通过引入点完成,会导致引入点工作“过于繁忙”,所以引入点实际上就起个传话的作用。同时由于汇合点是随机的,使用其作为实际通信点也更加安全。 ↩︎
  18. 除此之外还会发送一些用于验证和建立加密通信的信息。 ↩︎
  19. Facebook的v2洋葱网络地址为facebookcorewwwi.onion,不知道花了多少算力。不过v2已经被全面废弃了。 ↩︎
  20. 所以这玩意儿只能roll dice了,说不定没几轮就给roll出来了呢?虽然比中彩票的概率低得多就是了😋 ↩︎
  21. 很难说得清目前有多少节点是被政府或为政府工作的机构部署的。 ↩︎
  22. 数据包大小、发送时间、频率等 ↩︎


学而不思则罔,思而不学则殆