官方教程网址:https://stem.torproject.org/tutorials.html
隐藏服务顾名思义,就是可以为你提供一种不会暴露本人地址的服务。这些服务只能通过Tor或者Tor2web进行访问,足以让你大开眼界。
1,托管一个匿名网站。这大概是我们想到的第一件事,我将会很快将他演示。
2,在不退出Tor网络的前提下,提供一个Tor使用者能够访问的终端。我们将排除不可靠的或者恶意退出等的风险。本文以Facebook和DuckDuckGo为例。
3,私人服务。比如你可以托管的自己的SSH服务作为一个隐藏服务,用以防止自己地址信息的泄露。
Tor2web提供了一个快速而简单的方式来兼职你的隐藏服务是否在工作。只需要用.tor2web.org来代替你的.onion地址
一,运行一个隐藏服务
隐藏服务可以通过torrc进行配置,但是Stem提供了一些更为简易的方法。
1 create_hidden_service()
2 remove_hidden_service()
3 get_hidden_service_conf()
4 set_hidden_service_conf()
运行隐藏服务时匿名的最主要的威胁来源于服务本身。例如,调试信息可能会泄露你真正的地址,破坏Tor所提供的便利。下面是一个示例,别指望它不泄露。
尽管如此,让我们看一下下面这个示例,基于Jordan Wright:
import os
import shutil
from stem.control import Controller
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hi Grandma!
"
print(' * Connecting to tor')
with Controller.from_port() as controller:
controller.authenticate()
# All hidden services have a directory on disk. Lets put ours in tor's data
# directory.
hidden_service_dir = os.path.join(controller.get_conf('DataDirectory', '/tmp'), 'hello_world')
# Create a hidden service where visitors of port 80 get redirected to local
# port 5000 (this is where Flask runs by default).
print(" * Creating our hidden service in %s" % hidden_service_dir)
result = controller.create_hidden_service(hidden_service_dir, 80, target_port = 5000)
# The hostname is only available when we can read the hidden service
# directory. This requires us to be running with the same user as tor.
if result.hostname:
print(" * Our service is available at %s, press ctrl+c to quit" % result.hostname)
else:
print(" * Unable to determine our service's hostname, probably due to being unable to read the hidden service directory")
try:
app.run()
finally:
# Shut down the hidden service and clean it off disk. Note that you *don't*
# want to delete the hidden service directory if you'd like to have this
# same *.onion address in the future.
print(" * Shutting down our hidden service")
controller.remove_hidden_service(hidden_service_dir)
shutil.rmtree(hidden_service_dir)
下面开始运行:
% python example.py
* Connecting to tor
* Creating our hidden service in /home/atagar/.tor/hello_world
* Our service is available at uxiuaxejc3sxrb6i.onion, press ctrl+c to quit
* Running on http://127.0.0.1:5000/
127.0.0.1 - - [15/Dec/2014 13:05:43] "GET / HTTP/1.1" 200 -
* Shutting down our hidden service
二,短暂隐藏服务
在上面的示例中,你可能注意到了注释部分:
# The hostname is only available when we can read the hidden service
# directory. This requires us to be running with the same user as tor.
这是隐藏服务多年以来的局限性,然而,从0.2.7.1版本后,tor提供了一个名为短暂隐藏服务的服务。
短暂隐藏服务只能通过控制器创建,而且仅仅存在于你的控制器连接的时候,除非你提供分离标志。控制器仅仅能够监视他们自己的短暂服务以及分离的短暂服务。换句话说,连接的短暂服务仅仅能够被他们自己的控制器管理。
Stem提供了三种方法运行短暂隐藏服务:
list_ephemeral_hidden_services()
create_ephemeral_hidden_service()
remove_ephemeral_hidden_service()
下面是一个很简单的例子:
from stem.control import Controller
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hi Grandma!
"
print(' * Connecting to tor')
with Controller.from_port() as controller:
controller.authenticate()
# Create a hidden service where visitors of port 80 get redirected to local
# port 5000 (this is where Flask runs by default).
response = controller.create_ephemeral_hidden_service({80: 5000}, await_publication = True)
print(" * Our service is available at %s.onion, press ctrl+c to quit" % response.service_id)
try:
app.run()
finally:
print(" * Shutting down our hidden service")
短暂隐藏服务不接触磁盘,因此更容易使用。如果你想要重复使用‘.onion’作为自己的地址,你需要牢记自己的服务密匙。
import os
from stem.control import Controller
key_path = os.path.expanduser('~/my_service_key')
with Controller.from_port() as controller:
controller.authenticate()
if not os.path.exists(key_path):
service = controller.create_ephemeral_hidden_service({80: 5000}, await_publication = True)
print("Started a new hidden service with the address of %s.onion" % service.service_id)
with open(key_path, 'w') as key_file:
key_file.write('%s:%s' % (service.private_key_type, service.private_key))
else:
with open(key_path) as key_file:
key_type, key_content = key_file.read().split(':', 1)
service = controller.create_ephemeral_hidden_service({80: 5000}, key_type = key_type, key_content = key_content, await_publication = True)
print("Resumed %s.onion" % service.service_id)
raw_input('press any key to shut the service down...')
controller.remove_ephemeral_hidden_service(service.service_id)
三,隐藏服务描述符
就像是继电器(relays?),隐藏服务发布关于他们自己的文档,叫做隐藏服务描述符。这包括建立连接的底层服务的细节。隐藏服务描述符可以通过方法get_hidden_service_descriptor()
从tor获得。
from stem.control import Controller
with Controller.from_port(port = 9051) as controller:
controller.authenticate()
# descriptor of duck-duck-go's hidden service (http://3g2upl4pq6kufc4m.onion)
print(controller.get_hidden_service_descriptor('3g2upl4pq6kufc4m'))
下面输出结果:
% python print_duck_duck_go_descriptor.py
rendezvous-service-descriptor e5dkwgp6vt7axoozixrbgjymyof7ab6u
version 2
permanent-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE
aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg
I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=
-----END RSA PUBLIC KEY-----
secret-id-part bmsctib2pzirgo7cltlxdm5fxqcitt5e
publication-time 2015-05-11 20:00:00
protocol-versions 2,3
introduction-points
-----BEGIN MESSAGE-----
aW50cm9kdWN0aW9uLXBvaW50IHZzcm4ycGNtdzNvZ21mNGo3dGpxeHptdml1Y2Rr
NGtpCmlwLWFkZHJlc3MgMTc2LjkuNTkuMTcxCm9uaW9uLXBvcnQgOTAwMQpvbmlv
... etc...
隐藏服务的说明节点是可能加密的base64编码字段。 这些可以使用描述符的introduction_points()
方法进行解码(如果必要的话)进行解密。
示例代码如下:
from stem.control import Controller
with Controller.from_port(port = 9051) as controller:
controller.authenticate()
desc = controller.get_hidden_service_descriptor('3g2upl4pq6kufc4m')
print("DuckDuckGo's introduction points are...\n")
for introduction_point in desc.introduction_points():
print(' %s:%s => %s' % (introduction_point.address, introduction_point.port, introduction_point.identifier))
结果如下:
% python print_duck_duck_go_introduction_points.py
DuckDuckGo's introduction points are...
176.9.59.171:9001 => vsrn2pcmw3ogmf4j7tjqxzmviucdk4ki
104.131.106.181:9001 => gcl2kpqx5qnkpgxjf6x7ulqncoqj7ghh
188.166.58.218:443 => jeymnbhs2d6l2oib7jjvweavg45m6gju