TROJAN-科学上网客户端教程
Trojan基本原理
这个页面将会简单讲述Trojan协议的基本工作原理。如果你对于GFW和Trojan的工作方式不感兴趣,可以跳过这一小节。但为了更好地保护你的通讯安全性和节点的隐蔽性,我还是建议你阅读。
为什么(使用流密码的)Shadowsocks容易遭到封锁
防火墙在早期仅仅只是对出境流量进行截获和审查,也即被动检测。Shadowsocks的加密协议设计使得传输的数据包本身几乎没有任何特征,看起来类似于完全随机的比特流,这在早期的确能有效绕过GFW。
目前的GFW已经开始采用主动探测的方式。具体来说,当GFW发现一个可疑的无法识别的连接时(大流量,随机字节流,高位端口等特征),将会主动连接这个服务器端口,重放之前捕获到的流量(或者经过一些精心修改后重放)。Shadowsocks服务器检测到不正常的连接,将连接断开。这种不正常的流量和断开连接的行为被视作可疑的Shadowsocks服务器的特征,于是该服务器被加入GFW的可疑名单中。这个名单不一定立即生效,而是在某些特殊的敏感时期,可疑名单中的服务器会遭到暂时或者永久的封锁。该可疑名单是否封锁,可能由人为因素决定。
如果你想了解更多,可以参考这篇文章。
Trojan如何绕过GFW
与Shadowsocks相反,Trojan不使用自定义的加密协议来隐藏自身。相反,使用特征明显的TLS协议(TLS/SSL),使得流量看起来与正常的HTTPS网站相同。TLS是一个成熟的加密体系,HTTPS即使用TLS承载HTTP流量。使用正确配置的加密TLS隧道,可以保证传输的
保密性(GFW无法得知传输的内容)
完整性(一旦GFW试图篡改传输的密文,通讯双方都会发现)
不可抵赖(GFW无法伪造身份冒充服务端或者客户端)
前向安全(即使密钥泄露,GFW也无法解密先前的加密流量)
对于被动检测,Trojan协议的流量与HTTPS流量的特征和行为完全一致。而HTTPS流量占据了目前互联网流量的一半以上,且TLS握手成功后流量均为密文,几乎不存在可行方法从其中分辨出Trojan协议流量。
对于主动检测,当防火墙主动连接Trojan服务器进行检测时,Trojan可以正确识别非Trojan协议的流量。与Shadowsocks等代理不同的是,此时Trojan不会断开连接,而是将这个连接代理到一个正常的Web服务器。在GFW看来,该服务器的行为和一个普通的HTTPS网站行为完全相同,无法判断是否是一个Trojan代理节点。这也是Trojan推荐使用合法的域名、使用权威CA签名的HTTPS证书的原因: 这让你的服务器完全无法被GFW使用主动检测判定是一个Trojan服务器。
因此,就目前的情况来看,若要识别并阻断Trojan的连接,只能使用无差别封锁(封锁某个IP段,某一类证书,某一类域名,甚至阻断全国所有出境HTTPS连接)或发动大规模的中间人攻击(劫持所有TLS流量并劫持证书,审查内容)。对于中间人攻击,可以使用Websocket的双重TLS应对,高级配置中有详细讲解。
正确配置Trojan-Go
下面将介绍如何正确配置Trojan-Go以完全隐藏你的代理节点特征。
在开始之前,你需要
一个服务器,且未被GFW封锁
一个域名,可以使用免费的域名服务,如.tk等
Trojan-Go,可以从release页面下载
证书和密钥,可以从letsencrypt等机构免费申请签发
服务端配置
我们的目标是,使得你的服务器和正常的HTTPS网站表现相同。
首先你需要一个HTTP服务器,可以使用nginx,apache,caddy等配置一个本地HTTP服务器,也可以使用别人的HTTP服务器。HTTP服务器的作用是,当GFW主动探测时,向它展示一个完全正常的Web页面。
你需要在remote_addr
和remote_port
指定这个HTTP服务器的地址。remote_addr
可以是IP或者域名。Trojan-Go将会测试这个HTTP服务器是否工作正常,如果不正常,Trojan-Go会拒绝启动。
下面是一份比较安全的服务器配置server.json,需要你在本地80端口配置一个HTTP服务(必要,你也可以使用其他的网站HTTP服务器,如"remote_addr": “example.com”),在1234端口配置一个HTTPS服务,或是一个展示"400 Bad Request"的静态HTTP网页服务。(可选,可以删除fallback_port
字段,跳过这个步骤)
这个配置文件使Trojan-Go在服务器的所有IP地址上(0.0.0.0)监听443端口,分别使用server.crt和server.key作为证书和密钥进行TLS握手。你应该使用尽可能复杂的密码,同时确保客户端和服务端password
是一致的。注意,Trojan-Go会检测你的HTTP服务器http://remote_addr:remote_port
是否正常工作。如果你的HTTP服务器工作不正常,Trojan-Go将拒绝启动。
当一个客户端试图连接Trojan-Go的监听端口时,会发生下面的事情:
如果TLS握手成功,检测到TLS的内容非Trojan协议(有可能是HTTP请求,或者来自GFW的主动探测)。Trojan-Go将TLS连接代理到本地127.0.0.1:80上的HTTP服务。这时在远端看来,Trojan-Go服务就是一个HTTPS网站。
如果TLS握手成功,并且被确认是Trojan协议头部,并且其中的密码正确,那么服务器将解析来自客户端的请求并进行代理,否则和上一步的处理方法相同。
如果TLS握手失败,说明对方使用的不是TLS协议进行连接。此时Trojan-Go将这个TCP连接代理到本地127.0.0.1:1234上运行的HTTPS服务(或者HTTP服务),返回一个展示400 Bad Reqeust的HTTP页面。
fallback_port
是一个可选选项,如果没有填写,Trojan-Go会直接终止连接。虽然是可选的,但是还是强烈建议填写。
你可以通过使用浏览器访问你的域名https://your-domain-name.com
来验证。如果工作正常,你的浏览器会显示一个正常的HTTPS保护的Web页面,页面内容与服务器本机80端口上的页面一致。你还可以使用http://your-domain-name.com:443
验证fallback_port
工作是否正常。
事实上,你甚至可以将Trojan-Go当作你的HTTPS服务器,用来给你的网站提供HTTPS服务。访客可以正常地通过Trojan-Go浏览你的网站,而和代理流量互不影响。但是注意,不要在remote_port
和fallback_port
搭建有高实时性需求的服务,Trojan-Go识别到非Trojan协议流量时会有意增加少许延迟以抵抗GFW基于时间的检测。
配置完成后,可以使用
启动服务端。
客户端配置
对应的客户端配置client.json
这个客户端配置使Trojan-Go开启一个监听在本地1080端口的socks5/http代理(自动识别),远端服务器为your_awesome_server:443,your_awesome_server可以是IP或者域名。
如果你在remote_addr
中填写的是域名,sni
可以省略。如果你在remote_addr
填写的是IP地址,sni
字段应当填写你申请证书的对应域名,或者你自己签发的证书的Common Name,而且必须一致。注意,sni
字段目前的在TLS协议中是明文传送的(目的是使服务器提供相应证书)。GFW已经被证实具有SNI探测和阻断能力,所以不要填写类似google.com
等已经被封锁的域名,否则很有可能导致你的服务器也被遭到封锁。
配置完成后,可以使用
启动客户端。
完整的配置文件
下面是一个完整的配置文件,其中的必填选项有
run_type
local_addr
local_port
remote_addr
remote_port
对于服务器server
,key
和cert
为必填。
对于客户端client
,反向代理隧道forward
,以及透明代理nat
,password
必填
其余未填的选项,用下面给出的值进行填充。
Trojan-Go支持对人类更友好的YAML语法,配置文件的基本结构与JSON相同,效果等价。但是为了遵守YAML的命名习惯,你需要把下划线("_")转换为横杠("-"),如remote_addr
在YAML文件中为remote-addr
说明
一般选项
对于client/nat/forward,remote_xxxx
应当填写你的trojan服务器地址和端口号,local_xxxx
对应本地开放的socks5/http代理地址(自动适配)
对于server,local_xxxx
对应trojan服务器监听地址(强烈建议使用443端口),remote_xxxx
填写识别到非trojan流量时代理到的HTTP服务地址,通常填写本地80端口。
log_level
指定日志等级。等级越高,输出的信息越少。合法的值有
0 输出Debug以上日志(所有日志)
1 输出Info及以上日志
2 输出Warning及以上日志
3 输出Error及以上日志
4 输出Fatal及以上日志
5 完全不输出日志
log_file
指定日志输出文件路径。如果未指定则使用标准输出。
password
可以填入多个密码。除了使用配置文件配置密码之外,trojan-go还支持使用mysql配置密码,参见下文。客户端的密码,只有与服务端配置文件中或者在数据库中的密码记录一致,才能通过服务端的校验,正常使用代理服务。
disable_http_check
是否禁用HTTP伪装服务器可用性检查。
udp_timeout
UDP会话超时时间。
ssl
选项
ssl
选项verify
表示客户端(client/nat/forward)是否校验服务端提供的证书合法性,默认开启。出于安全性考虑,这个选项不应该在实际场景中选择false,否则可能遭受中间人攻击。如果使用自签名或者自签发的证书,开启verify
会导致校验失败。这种情况下,应当保持verify
开启,然后在cert
中填写服务端的证书,即可正常连接。
verify_hostname
表示服务端是否校验客户端提供的SNI与服务端设置的一致性。如果服务端SNI字段留空,认证将被强制关闭。
服务端必须填入cert
和key
,对应服务器的证书和私钥文件,请注意证书是否有效/过期。如果使用权威CA签发的证书,客户端(client/nat/forward)可以不填写cert
。如果使用自签名或者自签发的证书,应当在的cert
处填入服务器证书文件,否则可能导致校验失败。
sni
指的是TLS客户端请求中的服务器名字段,一般和证书的Common Name相同。如果你使用let’sencrypt等机构签发的证书,这里填入你的域名。对于客户端,如果这一项未填,将使用remote_addr
填充。你应当指定一个有效的SNI(和远端证书CN一致),否则客户端可能无法验证远端证书有效性从而无法连接;对于服务端,若此项不填,则使用证书中Common Name作为SNI校验依据,支持通配符如*.example.com。
fingerprint
用于指定客户端TLS Client Hello指纹伪造类型,以抵抗GFW对于TLS Client Hello指纹的特征识别和阻断。trojan-go使用utls进行指纹伪造,默认伪造Firefox的指纹。合法的值有
“",不使用指纹伪造(默认)
“firefox”,伪造Firefox指纹
“chrome”,伪造Chrome指纹
“ios”,伪造iOS指纹
一旦指纹的值被设置,客户端的cipher
,curves
,alpn
,session_ticket
等有可能影响指纹的字段将使用该指纹的特定设置覆写。 alpn
为TLS的应用层协议协商指定协议。在TLS Client/Server Hello中传输,协商应用层使用的协议,仅用作指纹伪造,并无实际作用。如果使用了CDN,错误的alpn字段可能导致与CDN协商得到错误的应用层协议。
prefer_server_cipher
客户端是否偏好选择服务端在协商中提供的密码学套件。
cipher
TLS使用的密码学套件。```cipher13``字段与此字段合并。只有在你明确知道自己在做什么的情况下,才应该去填写此项以修改trojan-go使用的TLS密码学套件。正常情况下,你应该将其留空或者不填,trojan-go会根据当前硬件平台以及远端的情况,自动选择最合适的加密算法以提升性能和安全性。如果需要填写,密码学套件名用分号(":")分隔,按优先顺序排列。Go的TLS库中弃用了TLS1.2中部分不安全的密码学套件,并完全支持TLS1.3。默认情况下,trojan-go将优先使用更安全的TLS1.3。
curves
指定TLS在ECDHE中偏好使用的椭圆曲线。只有你明确知道自己在做什么的情况下,才应该填写此项。曲线名称用分号(":")分隔,按优先顺序排列。
plain_http_response
指服务端TLS握手失败时,明文发送的原始数据(原始TCP数据)。这个字段填入该文件路径。推荐使用fallback_port
而不是该字段。
fallback_addr
和fallback_port
指服务端TLS握手失败时,trojan-go将该连接重定向到该地址。这是trojan-go的特性,以便更好地隐蔽服务器,抵抗GFW的主动检测,使得服务器的443端口在遭遇非TLS协议的探测时,行为与正常服务器完全一致。当服务器接受了一个连接但无法进行TLS握手时,如果fallback_port
不为空,则流量将会被代理至fallback_addr:fallback_port。如果fallback_addr
为空,则用remote_addr
填充。例如,你可以在本地使用nginx开启一个https服务,当你的服务器443端口被非TLS协议请求时(比如http请求),trojan-go将代理至本地https服务器,nginx将使用http协议明文返回一个400 Bad Request页面。你可以通过使用浏览器访问http://your-domain-name.com:443
进行验证。
key_log
TLS密钥日志的文件路径。如果填写则开启密钥日志。记录密钥将破坏TLS的安全性,此项不应该用于除调试以外的其他任何用途。
mux
多路复用选项
mux
多路复用选项多路复用是trojan-go的特性。如果服务器和客户端都是trojan-go,可以开启mux多路复用以减少高并发情景下的延迟(只需要客户端开启此选项即可,服务端自动适配)。
注意,多路复用的意义在于降低握手延迟,而不是提升链路速度。相反,它会增加客户端和服务端的CPU和内存消耗,从而可能造成速度下降。
enabled
是否开启多路复用。
concurrency
指单个TLS隧道可以承载的最大连接数,默认为8。这个数值越大,多连接并发时TLS由于握手产生的延迟就越低,但网络吞吐量可能会有所降低,填入负数或者0表示所有连接只使用一个TLS隧道承载。
idle_timeout
空闲超时时间。指TLS隧道在空闲多长时间之后关闭,单位为秒。如果数值为负值或0,则一旦TLS隧道空闲,则立即关闭。
router
路由选项
router
路由选项路由功能是trojan-go的特性。trojan-go的路由策略有三种。
Proxy 代理。将请求通过TLS隧道进行代理,由trojan服务器和目的地址进行连接。
Bypass 绕过。直接在本地和目的地址进行连接。
Block 封锁。不代理请求,直接关闭连接。
在proxy
, bypass
, block
字段中填入对应列表geoip/geosite或路由规则,trojan-go即根据列表中的IP(CIDR)或域名执行相应路由策略。客户端(client)可以配置三种策略,服务端(server)只可配置block策略。
enabled
是否开启路由模块。
default_policy
指的是三个列表匹配均失败后,使用的默认策略,默认为"proxy”,即进行代理。合法的值有
“proxy”
“bypass”
“block”
含义同上。
domain_strategy
域名解析策略,默认"as_is"。合法的值有:
“as_is”,只在各列表中的域名规则内进行匹配。
“ip_if_non_match”,先在各列表中的域名规则内进行匹配;如果不匹配,则解析为IP后,在各列表中的IP地址规则内进行匹配。该策略可能导致DNS泄漏或遭到污染。
“ip_on_demand”,先解析为IP,在各列表中的IP地址规则内进行匹配;如果不匹配,则在各列表中的域名规则内进行匹配。该策略可能导致DNS泄漏或遭到污染。
geoip
和geosite
字段指geoip和geosite数据库文件路径,默认使用程序所在目录的geoip.dat和geosite.dat。也可以通过指定环境变量TROJAN_GO_LOCATION_ASSET指定工作目录。
websocket
选项
websocket
选项Websocket传输是trojan-go的特性。在正常的直接连接代理节点的情况下,开启这个选项不会改善你的链路速度(甚至有可能下降),也不会提升你的连接安全性。你只应该在需要利用CDN进行中转,或利用nginx等服务器根据路径分发的情况下,使用websocket。
enabled
表示是否启用Websocket承载流量,服务端开启后同时支持一般Trojan协议和基于websocket的Trojan协议,客户端开启后将只使用websocket承载所有Trojan协议流量。
path
指的是Websocket使用的URL路径,必须以斜杠("/")开头,如"/longlongwebsocketpath",并且服务器和客户端必须一致。
host
Websocket握手时,HTTP请求中使用的主机名。客户端如果留空则使用remote_addr
填充。如果使用了CDN,这个选项一般填入域名。不正确的host
可能导致CDN无法转发请求。
shadowsocks
AEAD加密选项
shadowsocks
AEAD加密选项此选项用于替代弃用的混淆加密和双重TLS。如果此选项被设置启用,Trojan协议层下将插入一层Shadowsocks AEAD加密层。也即(已经加密的)TLS隧道内,所有的Trojan协议将再使用AEAD方法进行加密。注意,此选项和Websocket是否开启无关。无论Websocket是否开启,所有Trojan流量都会被再进行一次加密。
注意,开启这个选项将有可能降低传输性能,你只应该在不信任承载Trojan协议的传输信道的情况下,启用这个选项。例如:
你使用了Websocket,经过不可信的CDN进行中转(如国内CDN)
你与服务器的连接遭到了GFW针对TLS的中间人攻击
你的证书失效,无法验证证书有效性
你使用了无法保证密码学安全的可插拔传输层
等等。
由于使用的是AEAD,trojan-go可以正确判断请求是否有效,是否遭到主动探测,并作出相应的响应。
enabled
是否启用Shadowsocks AEAD加密Trojan协议层。
method
加密方式。合法的值有:
“CHACHA20-IETF-POLY1305”
“AES-128-GCM” (默认)
“AES-256-GCM”
password
用于生成主密钥的密码。如果启用AEAD加密,必须确保客户端和服务端一致。
transport_plugin
传输层插件选项
transport_plugin
传输层插件选项enabled
是否启用传输层插件替代TLS传输。一旦启用传输层插件支持,trojan-go将会把未经TLS加密的trojan协议流量明文传输给插件,以允许用户对流量进行自定义的混淆和加密。
type
插件类型。目前支持的类型有
“shadowsocks”,支持符合SIP003标准的shadowsocks混淆插件。trojan-go将在启动时按照SIP003标准替换环境变量并修改自身配置(
remote_addr/remote_port/local_addr/local_port
),使插件与远端直接通讯,而trojan-go仅监听/连接插件。“plaintext”,使用明文传输。选择此项,trojan-go不会修改任何地址配置(
remote_addr/remote_port/local_addr/local_port
),也不会启动command
中插件,仅移除最底层的TLS传输层并使用TCP明文传输。此选项目的为支持nginx等接管TLS并进行分流,以及高级用户进行调试测试。请勿直接使用明文传输模式穿透防火墙。“other”,其他插件。选择此项,trojan-go不会修改任何地址配置(
remote_addr/remote_port/local_addr/local_port
),但会启动command
中插件并传入参数和环境变量。
command
传输层插件可执行文件的路径。trojan-go将在启动时一并执行它。
arg
传输层插件启动参数。这是一个列表,例如["-config", "test.json"]
。
env
传输层插件环境变量。这是一个列表,例如["VAR1=foo", "VAR2=bar"]
。
option
传输层插件配置(SIP003)。例如"obfs=http;obfs-host=www.baidu.com"
。
tcp
选项
tcp
选项no_delay
TCP封包是否直接发出而不等待缓冲区填满。
keep_alive
是否启用TCP心跳存活检测。
prefer_ipv4
是否优先使用IPv4地址。
mysql
数据库选项
mysql
数据库选项trojan-go兼容trojan的基于mysql的用户管理方式,但更推荐的方式是使用API。
enabled
表示是否启用mysql数据库进行用户验证。
check_rate
是trojan-go从MySQL获取用户数据并更新缓存的间隔时间,单位为秒。
其他选项可以顾名思义,不再赘述。
users表结构和trojan版本定义一致,下面是一个创建users表的例子。注意这里的password指的是密码经过SHA224散列之后的值(字符串),流量download, upload, quota的单位是字节。你可以通过修改数据库users表中的用户记录的方式,添加和删除用户,或者指定用户的流量配额。trojan-go会根据所有的用户流量配额,自动更新当前有效的用户列表。如果download+upload>quota,trojan-go服务器将拒绝该用户的连接。
forward_proxy
前置代理选项
forward_proxy
前置代理选项前置代理选项允许使用其他代理承载trojan-go的流量
enabled
是否启用前置代理(socks5)。
proxy_addr
前置代理的主机地址。
proxy_port
前置代理的端口号。
username
password
代理的用户和密码,如果留空则不使用认证。
api
选项
api
选项trojan-go基于gRPC提供了API,以支持服务端和客户端的管理和统计。可以实现客户端的流量和速度统计,服务端各用户的流量和速度统计,用户的动态增删和限速等。
enabled
是否启用API功能。
api_addr
gRPC监听的地址。
api_port
gRPC监听的端口。
ssl
TLS相关设置。
enabled
是否使用TLS传输gRPC流量。key
,cert
服务器私钥和证书。verify_client
是否认证客户端证书。client_cert
如果开启客户端认证,此处填入认证的客户端证书列表。
警告:不要将未开启TLS双向认证的API服务直接暴露在互联网上,否则可能导致各类安全问题。完整的配置文件
下面是一个完整的配置文件,其中的必填选项有
run_type
local_addr
local_port
remote_addr
remote_port
对于服务器server
,key
和cert
为必填。
对于客户端client
,反向代理隧道forward
,以及透明代理nat
,password
必填
其余未填的选项,用下面给出的值进行填充。
Trojan-Go支持对人类更友好的YAML语法,配置文件的基本结构与JSON相同,效果等价。但是为了遵守YAML的命名习惯,你需要把下划线("_")转换为横杠("-"),如remote_addr
在YAML文件中为remote-addr
最后更新于