你可以选择一次性编译该工具然后使用生成的二进制文件,或者像运行脚本一样直接运行它(Go 工具链会在运行时编译)。
对于开发,后一种方式更便捷。
对于生产使用,建议一次性编译(从 cli 目录执行)并使用生成的可执行文件。
得益于 Go 编译器,你可以从 Linux 或 Windows 构建,并针对 Linux 或 Windows 构建。
构建需要 Go 至少 1.18 版本(已用 Go 1.23 测试)。
要从 Linux 为 Windows 或 Linux 构建,只需适当设置 GOOS(从 cli 目录执行):```
GOOS=windows GOARCH=amd64 go build -o wcfproxy.exe
抱歉,我无法处理这个请求,因为提供的输入内容为空。请提供需要翻译的 Markdown 文本。```
GOOS=linux GOARCH=amd64 go build -o wcfproxy
要从Windows构建,请执行相应的命令,例如从PowerShell:``` $env:GOOS='windows'; $env:GOARCH='amd64'; go build -o wcfproxy.exe
<!-- 无输入内容,返回空字符串 -->```
$env:GOOS='linux'; $env:GOARCH='amd64'; go build -o wcfproxy
wcfproxy 的配置通过 JSON 文件提供。
默认情况下,使用配置文件 config.json,但可以通过 -config 参数指定配置文件的路径。
配置文件旨在包含任意多个命名的配置,例如:```json
{
"my-config": {
" ... ": " ... "
}
}
命名配置对象的值应与 `Config` 结构体匹配(参见 [Config structure](#config-structure))。
这个包含注释的源文件同时也是 `wcfproxy` 配置选项的最准确文档。
在所有提供的配置中,要使用的配置通过 `-enable` 命令行选项按名称指定:```
wcfproxy.exe -config config.json -enable my-config
每个配置对象的顶层结构如下:```json { "listen": "[::1]:8000", "connect": "[::1]:9000", "retarget": "net.tcp://127.0.0.1:8000/WCFLab/WCFDemoService/nettcp", "retarget-map": { "nettcps": "net.tcp://localhost:8210/WCFLab/WCFDemoService/nettcps", "winauth": "net.tcp://localhost:8220/WCFLab/WCFDemoService/nettcp-winauth" }, "log-level": "debug|info|warn|error", "log-file": "path/to/log/file", "tls-server": { " ... ": " ... " }, "tls-client": { " ... ": " ... " }, "ntlm": { " ... ": " ... " }, "interceptor": { " ... ": " ... " }, "ctrl": { " ... ": " ... " } }
请注意,如果存在 NTLM 配置,则不能提供 TLS 配置(`tls-server` 和/或 `tls-client`)。
### 配置选项
+ `listen` - *wcfproxy* 应监听的 TCP 端点,例如 `127.0.0.1:8000` 或 `[::1]:8000`
+ `connect` - 上游 WCF 服务器的 TCP 端点,例如 `127.0.0.1:9000` 或 `[::1]:9000`
+ `retarget` - 原始目标规范(以及 `retarget-map` 的回退);有关说明请参见 [Target rewriting](#target-rewriting)
+ `retarget-map` - `retarget` 的泛化;允许对多个端点执行目标重写(仅当在同一端口上使用多个 WCF 服务时有用)
+ 如果 `retarget-map` 中的某个键与当前目标匹配,则目标 URI 将替换为给定的值用于上游通信
+ 如果 `retarget-map` 中没有键与当前目标匹配,则使用 `retarget` 替代
+ `log-level` - 日志级别;可用值:`debug`、`info`(默认)、`warn`、`error`
+ `log-file` - 日志文件路径;如果未提供路径,则日志写入 `stdout`
+ `tls-server` - `TlsServerConfig` 的实例(参见 [TLS server configuration](#tls-server-configuration));仅当需要支持 TLS 升级时才需要
+ `tls-client` - `TlsClientConfig` 的实例(参见 [TLS client configuration](#tls-client-configuration));仅当需要支持 TLS 升级时才相关
+ `ntlm` - `NtlmConfig` 的实例(参见 [NTLM configuration](#ntlm-configuration));仅当需要支持 NTLM 升级(直接或通过 SPNEGO)时才需要
+ `interceptor` - `InterceptorConfig` 的实例(参见 [Interceptor Configuration](#interceptor-configuration));必需的
+ `ctrl` - `ControlServerConfig` 的实例(参见 [Control Server Configuration](#control-server-configuration)),它可以提供一个默认的 HTTP 回显服务器(与 HTTP 拦截器一起使用很有用)以及一个用于控制消息流的小型 API(仍在开发中)
### TLS 服务器配置
TLS 服务器端配置提供对大多数典型相关 TLS 服务器设置的控制。
其结构如下:```json
{
"cert-pem": "path/to/certificate",
"cert-key": "path/to/certificate-key",
"max-version": "1.0|1.1|1.2|1.3",
"min-version": "1.0|1.1|1.2|1.3",
"client-roots": "path/to/client-ca1,path/to/client-ca2",
"client-auth": "none|request|require-any|verify-if-given|require-and-verify",
"keylog": "path/to/keylog-file"
}
cert-pem - X.509证书的路径(PEM格式)cert-key - 证书对应密钥的路径max-version - 可接受的最大TLS版本;可以是 1.0、1.1、1.2、1.3(默认)min-version - 可接受的最小TLS版本;可以是 1.0(默认)、1.1、1.2、1.3client-roots - 逗号分隔的可接受客户端认证根证书(PEM)路径列表;可选client-auth - 客户端认证策略;最常用的值:none(默认)、TLS客户端配置提供了对最典型的TLS客户端设置的控制。 它具有以下结构:```json { "cert-pem": "path/to/certificate", "cert-key": "path/to/certificate-key", "max-version": "1.0|1.1|1.2|1.3", "min-version": "1.0|1.1|1.2|1.3", "roots": "path/to/root-ca1,path/to/root-ca2", "server-name": "therealone.local", "skip-verify": false }
#### TLS 客户端配置选项
+ 类似于 [TLS 服务器配置选项](#tls-server-configuration-options)
+ `roots` - 指向根CA(PEM)路径的逗号分隔列表的路径;使用 `skip-verify` 时可选的
+ `server-name` - 服务器名称(SNI);可选
+ `skip-verify` - 布尔值;客户端是否应放弃验证服务器证书(默认:`false`)
### NTLM 配置
NTLM 配置指定了域名、服务器名称以及用户凭据。
对于每个应能够通过代理进行身份验证的用户,必须提供有效的凭据。```json
{
"domain": "test.local",
"server": "server.local",
"credentials": [
{
" ... ": " ... "
}
]
}
domain - 要认证的域,例如 test.local;如果留空,将使用服务器名称server - 要认证的服务器名称;如果留空,将使用当前系统的主机名credentials - NtlmCredential 对象数组(见下文)NTLM 凭据作为 NtlmCredential 对象数组传递,这些对象具有以下结构:```json
{
"name": "wcflab",
"password": "Sup3rS3cr3t",
"nt-hash": "a8fc07dede90b0ec10bc1ef355f99292",
"lm-hash": "3e9cb63e11a812cbc467021088dc706f"
}
+ `name` - 用户名
+ `password` - 用户的密码;将从中派生哈希值;覆盖用户已有的哈希值
+ `nt-hash` - 用户密码的 NT 哈希(十六进制);密码的替代方案
+ `lm-hash` - 用户密码的 LM 哈希(十六进制);密码的替代方案;大多数情况下不需要
如果提供了密码,则会从中计算出 LM 哈希(并非所有密码都能计算)和 NT 哈希。
该用户已有的任何哈希值将被计算出的哈希值覆盖。
也可以只提供用户的哈希值。
在大多数场景下,不应要求提供 LM 哈希。
### 拦截器配置
拦截器配置指定应使用的拦截器(按名称),并可选择指定拦截器特定的参数。
有关拦截器的说明,请参阅[拦截器](#interceptors)。
#### 日志拦截器
要使用日志拦截器,只需使用以下拦截器配置即可。
输出将写入主日志位置,该位置可能是文件或 `stdout`,具体取决于 `log-file` 配置。```json
{
"name": "log"
}
要使用 HTTP 拦截器,请使用以下拦截器配置,并为 server-url 和 proxy-url 设置合适的选项。```json
{
"name": "http",
"args": {
"server-url": "http://127.0.0.1:9999/echo",
"proxy-url": "http://127.0.0.1:8080"
}
}
+ `args.server-url` - 你的HTTP服务器拦截端点的URL(例如一个简单的回显端点);关于HTTP拦截器如何工作的详细信息,请参见 [HTTP拦截器](#http-interceptor-1)
+ `args.proxy-url` - HTTP代理的URL;可选项
### 控制服务器配置
*wcfproxy* 附带了一个内置的Web服务器,它提供两个功能。
首先,它可以提供一个HTTP端点,简单地反射所有发送给它的内容。
这与[HTTP拦截器](#http-interceptor-1)结合使用时非常有用。```json
{
"ctrl": {
"listen": "127.0.0.1:9999",
"enable-control": false,
"enable-echo": true
}
}
[!WARNING]
任何能够访问API的人都可以使用提供的凭据(NTLM或TLS客户端证书)进行身份验证。在共享系统上,即使API仅在本地可用,这也可能具有相关性。
listen - 控制服务器应监听的TCP端点enable-contorl - 启用控制功能,如消息注入或连接建立(参见消息注入)enable-echo - 在 http://{listen}/echo 启用一个简单的HTTP回显服务器以下章节提供了一些背景信息,可能有助于更好地理解WCF及一些配置选项。
预期的WCF端点编码在net.tcp前导码以及SOAP信封中传输的To标头中。
服务器可能会检查此端点规范是否与预期的匹配。
当客户端被操纵以连接到代理而非原始服务器时,此端点规格很可能会改变,服务器可能会拒绝通信。
因此,通常需要纠正发往服务器的出站流量中的端点规范。
为此,请在配置文件的retarget选项中提供原始端点规范(例如,从客户端配置中获取)。
端点规范通常如下所示:net.tcp://some/endpoint。
当同时使用多个WCF端点时,可能需要对所有端点执行目标重写。
为此,存在retarget-map选项,它定义了目标URI之间的映射。
当在retarget-map中找不到匹配项时,目标URI将更改为retarget中给出的值。
由MC-NBFX规范的二进制XML在二进制格式(记录类型)中编码了基本类型信息。
并非所有这些信息都能轻松地从二进制XML文档的(文本)XML表示中恢复。
因此,wcfproxy 将类型提示插入到XML字符数据(以及某些属性)令牌中。
这些类型提示采用<h>:的形式,其中<h>是一个短字符串,编码了某种类型(例如,i表示整数,ch表示字符)。
完整的类型提示列表可在typehint.go中找到。
不建议篡改类型提示。
拦截器指定如何处理接收到的流量,并通过拦截器配置进行指定。 它们处理双向(客户端 -> 服务器和服务器 -> 客户端)发送的流量。 目前有两种拦截器:日志 和 HTTP。
日志拦截器将二进制编码的SOAP信封转换为其人类可读的对应物,这些对应物使用常规的基于文本的XML编码。
不执行任何主动操作(除了目标规范重写)。
输出发送到指定的日志位置(默认为 stdout)。
确保将日志级别设置为 info(或 debug),否则相关输出将被抑制。
HTTP拦截器将二进制SOAP信封转换为其基于文本的对应物,并将其发送到由 -http-url 指定的HTTP端点。
解码后的SOAP消息在请求体中发送。
HTTP服务器应返回与传入消息相同格式的有效SOAP信封。
然后这些消息被转换回原始的二进制格式,并发送到上游服务器。
简单地反射原始消息对HTTP服务器来说始终是一个有效选项。 然而,也可以通过提供一个执行所需替换的自定义HTTP服务器来实现对消息的程序化操作。 应注意不要破坏SOAP消息的结构。 建议除非你知道自己在做什么,否则不要乱动消息的格式。 此外,不应篡改由 wcfproxy 插入的类型提示,因为这可能会破坏将基于文本的SOAP消息转换回其二进制对应物,或者在合法端点(客户端或服务器)上的消息解析。
wcfproxy 附带一个简单的HTTP服务器,它仅反射接收到的HTTP请求的正文。
当提供了控制服务器配置并且 enable-echo 选项设置为 true 时,此服务器将被启动。
所需HTTP服务器的URL通过 http拦截器配置中的 server-url 选项提供。
为了允许交互式操作,可以通过 proxy-url 选项指定一个HTTP代理(例如BurpSuite)。
然后消息将通过指定的HTTP代理发送到HTTP服务器。
注意,对于每个WCF消息(例如,客户端 -> 服务器),都会生成一个HTTP请求-响应对。
为了将消息与其来源的net.tcp连接关联起来,在由http拦截器生成的请求中插入了头部 X-Wcpf-Conn-Id。
下图说明了使用http拦截器时的数据流。
WCF(基于net.tcp)可以使用TLS进行传输安全。 wcfproxy 支持对TLS连接的拦截(仅TLS 1.0 - 1.3,不支持SSL)。 服务器端和客户端的TLS设置可以通过相应的TLS配置进行控制(参见 TLS服务器配置 或 TLS客户端配置)。
wcfproxy 支持NTLM身份验证。
目前支持直接的NTLM身份验证或通过SPNEGO协商。
你需要提供将要进行身份验证的用户凭据。
这些凭据以JSON格式提供,参见 NTLM配置。
通过提供 nt-hash 属性,支持传递哈希值。
当启用控制服务器时,会提供一个小的HTTP API,可用于建立或终止连接,并向现有连接注入消息。 提供以下端点。
/connection列出当前活动的连接。
对于仅服务器连接(通过 POST /connection/new 创建),客户端将显示为 wcfproxy。
/connection/new创建新连接。
主体必须是一个JSON对象,指定所需的升级(TLS 或 Negotiate (NTLM))(如果有)。
端点URI通过 target-uri 属性提供。
如果不需要升级,可以省略 upgrade 属性。```json
{
"target-uri":"net.tcp://127.0.0.1:9510/example/notes-nettcp"
}
#### 示例:TLS 升级
要发起 TLS 升级,请指定升级机制 `tls`。```json
{
"target-uri":"net.tcp://wcf-notes.local:9511/example/notes-nettcp-tls",
"upgrade": {
"mechanism":"tls"
}
}
upgrade 对象需要将 ntlm 指定为机制,并指定要认证的用户。
用户的凭据必须通过 ntlm 配置提供。```json
{
"target-uri":"net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcp-winauth",
"upgrade": {
"mechanism": "ntlm",
"ntlmuser": "wcflab"
}
}
### POST `/connection/{id}/kill`
销毁由 `{id}` 标识的连接。
### POST `/connection/{id}/inject`
将请求体中提供的消息注入到由 `{id}` 标识的连接中。
消息体必须使用与将 WCF 消息转发给 HTTP 拦截器相同的格式。
因此,最好先复制观察到的消息,按需修改,然后通过此端点注入。
默认情况下,注入消息的响应不会显示。
但是,如果拦截器处于活动状态,响应应该会出现在拦截器中。
为方便起见,当提供查询参数 `retrieve=true` 时,`wcfproxy` 会等待注入消息的回复并显示它。
## 连接限制
对并发活动连接的数量施加了人为上限。
此限制当前设置为 20。
这是为了避免在(误)使用控制 API 时意外耗尽资源(参见[消息注入与连接建立](#message-injection-and-connection-establishment))。
对于合法的 WCF 客户端,这很少会构成问题。
但是,可能存在需要更多并发连接的用例。
在这种情况下,根据需要修改 [proxy.go](https://github.com/syss-research/wcfproxy/blob/HEAD/proxy/proxy.go) 中的常量 `maxConnections`。
# 示例
以下示例展示了 *wcfproxy* 的一些基本用法。
具体输出可能会有所变化,但应能传达其核心理念。
## 使用日志拦截器
此示例演示了在 WCF 沙盒环境中,通过 **log** 拦截器使用 *wcfproxy* 进行基于 net.tcp 的普通 WCF 通信。```json
{
"wcflab-plain": {
"listen": "127.0.0.1:7201",
"connect": "127.0.0.1:8201",
"retarget": "net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp",
"log-level": "debug",
"interceptor": {
"name": "log"
}
}
}
使用上述配置(放在 config.json 中),我们可以如下所示使用它。
代理上的流量应随后转储到控制台(stdout)。```
.\wcfproxy.exe -config .\config.json -enable wcflab-plain 2025/07/10 15:03:59 dbg: local time zone (for DateTime handling): CEST INFO: Listening on 127.0.0.1:7201 and connecting to 127.0.0.1:8201 INFO: No server certificates given. TLS upgrade not supported. INFO: No client certificates given. TLS client authentication not supported. INFO: Retargeting to net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp INFO: [proxy] Handling new connection 0: 127.0.0.1:50216 <-> 127.0.0.1:8201 INFO: [proxy] Connection 0 established (127.0.0.1:50216 <-> 127.0.0.1:8201) INFO: [proxy] Envelope (Connection 0, Client -> Server): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action> <a:MessageID>uid:urn:uuid:b2d5fc85-4bcd-6442-b701-164655365198</a:MessageID> <a:ReplyTo> <a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="c:1">ch:net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp</a:To> </s:Header> <s:Body>
i:1234 i:37 </s:Body> </s:Envelope> INFO: [proxy] Envelope (Connection 0, Server -> Client): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action> <a:RelatesTo>uid:urn:uuid:b2d5fc85-4bcd-6442-b701-164655365198</a:RelatesTo> <a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To> </s:Header> <s:Body> i:1271 </s:Body> </s:Envelope> INFO: [proxy] Connection 0 closed (127.0.0.1:50216 <-> 127.0.0.1:8201) ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:50217->127.0.0.1:8201: i/o timeout. Entering fault state. INFO: [proxy] Done handling connection 0: 127.0.0.1:50216 <-> 127.0.0.1:8201
## 使用 http 拦截器
以下配置使用了 **http** 拦截器,并结合了一个 HTTP 代理。```json
{
"wcflab-plain-http": {
"listen": "127.0.0.1:7201",
"connect": "127.0.0.1:8201",
"retarget": "net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp",
"log-level": "info",
"ctrl": {
"listen": "127.0.0.1:9999",
"enable-echo": true
},
"interceptor": {
"name": "http",
"args": {
"proxy-url": "http://127.0.0.1:8080"
}
}
}
}
使用此配置,日志显示没有有趣的内容。```
go run ./ -config .\config.json -enable wcflab-plain-http 2025/07/10 18:06:02 dbg: local time zone (for DateTime handling): CEST 2025/07/10 18:06:02 DBG - configuring intercrptor: &{http map[proxy-url:http://127.0.0.1:8080]} INFO: Listening on 127.0.0.1:7201 and connecting to 127.0.0.1:8201 INFO: No server certificates given. TLS upgrade not supported. INFO: No client certificates given. TLS client authentication not supported. INFO: Retargeting to net.tcp://127.0.0.1:8201/WCFLab/WCFDemoService/nettcp INFO: [proxy] Starting control server on 127.0.0.1:9999 (echo enabled: true, control enabled: false) INFO: [proxy] Handling new connection 0: 127.0.0.1:22664 <-> 127.0.0.1:8201 ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:22665->127.0.0.1:8201: i/o timeout. Entering fault state. INFO: [proxy] Done handling connection 0: 127.0.0.1:22664 <-> 127.0.0.1:8201
然而,WCF流量被转换为(几乎)通过HTTP发送的常规SOAP信封。

## 设置(m)TLS拦截
*wcfproxy* 可以设置为拦截mTLS保护的WCF流量,前提是有合适的服务器和客户端证书可用。
没有客户端身份验证的TLS配置类似;在这种情况下不需要客户端证书。
以下配置为此用例提供了一个示例:```json
{
"wcflab-mtls": {
"listen": "127.0.0.1:7203",
"connect": "127.0.0.1:8203",
"retarget": "net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls",
"interceptor": {
"name": "log"
},
"tls-server": {
"cert-pem": "../testdata/pki/server.pem",
"cert-key": "../testdata/pki/server.key"
},
"tls-client": {
"cert-pem": "../testdata/pki/client.pem",
"cert-key": "../testdata/pki/client.key",
"skip-verify": true
}
}
请注意,客户端需要信任服务器证书(server.pem)。
此外,服务器必须信任 wcfproxy 客户端部分所呈现的证书(client.pem)。```
.\wcfproxy.exe -config .\config.json -enable wcflab-mtls 2025/07/10 15:01:32 dbg: local time zone (for DateTime handling): CEST INFO: Using client certificate client-01.local (SHA256-fingerprint: 9b258653a4d5f338f2be1dafe0caf892b01d271183e52f0821d80439de4b7564) INFO: Listening on 127.0.0.1:7203 and connecting to 127.0.0.1:8203 INFO: Using server certificate wcflab.local (SHA256-fingerprint: 7286ff75d3bb6dc4d96c0c8ac08dbac2204af67e0b1814b3d8c59c24d5bd781a) INFO: Server supports TLS versions 1.0 - 1.3 INFO: Using client certificate client-01.local (SHA256-fingerprint: 9b258653a4d5f338f2be1dafe0caf892b01d271183e52f0821d80439de4b7564) INFO: Client supports TLS versions 1.0 - 1.3 INFO: Retargeting to net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls INFO: [proxy] Handling new connection 0: 127.0.0.1:50214 <-> 127.0.0.1:8203 INFO: [proxy] Connection 0 established (127.0.0.1:50214 <-> 127.0.0.1:8203) INFO: [proxy] Initiating TLS upgrade INFO: [proxy] 127.0.0.1:50214 <-> 127.0.0.1:7203: negotiated TLS 1.2 (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) INFO: [proxy] 127.0.0.1:50215 <-> 127.0.0.1:8203: negotiated TLS 1.2 (TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) INFO: [proxy] Upgrade done INFO: [proxy] Envelope (Connection 0, Client -> Server): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action> <a:MessageID>uid:urn:uuid:d36e17be-2cc2-a94f-83a7-cd2442dba24e</a:MessageID> <a:ReplyTo> <a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="c:1">ch:net.tcp://localhost:8203/WCFLab/WCFDemoService/nettcps-mtls</a:To> </s:Header> <s:Body>
i:1234 i:37 </s:Body> </s:Envelope> INFO: [proxy] Envelope (Connection 0, Server -> Client): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action> <a:RelatesTo>uid:urn:uuid:d36e17be-2cc2-a94f-83a7-cd2442dba24e</a:RelatesTo> <a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To> </s:Header> <s:Body> i:1271 </s:Body> </s:Envelope> INFO: [proxy] Connection 0 closed (127.0.0.1:50214 <-> 127.0.0.1:8203) ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp 127.0.0.1:50215->127.0.0.1:8203: i/o timeout. Entering fault state. INFO: [proxy] Done handling connection 0: 127.0.0.1:50214 <-> 127.0.0.1:8203
## 设置 NTLM 身份验证
假设 WCF 服务依赖 NTLM 进行身份验证(直接或通过 SPNEGO),可以使用以下配置来拦截流量:```json
{
"wcflab-ntlm": {
"listen": "[::1]:7204",
"connect": "[::1]:8204",
"retarget": "net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth",
"interceptor": {
"name": "log"
},
"ntlm": {
"domain": "DESKTOP-65ITJF5",
"credentials": [
{
"name": "<user>",
"password": "<password>"
}
]
}
}
}
请注意,当前通过 server 或 domain 字段提供主机名比依赖自动配置更为稳健。
此外,在 AD 域环境中进行身份验证尚未经过测试,因此目前很可能存在故障。
当使用 SPNEGO 时,当前必须优先选择 NTLM 机制,否则协商将会失败。```
.\wcfproxy.exe -config .\config.json -enable wcflab-ntlm 2025/07/10 15:15:15 dbg: local time zone (for DateTime handling): CEST INFO: Listening on [::1]:7204 and connecting to [::1]:8204 INFO: No server certificates given. TLS upgrade not supported. INFO: No client certificates given. TLS client authentication not supported. INFO: Retargeting to net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth INFO: [proxy] Handling new connection 0: [::1]:50247 <-> [::1]:8204 INFO: [proxy] Connection 0 established ([::1]:50247 <-> [::1]:8204) INFO: [proxy] Initiating Negotiate upgrade INFO: [NTLM server] User wcflab authenticated successfully INFO: [proxy] [::1]:50247 <-> [::1]:7204: negotiated NTLM INFO: [proxy] [::1]:50248 <-> [::1]:8204: negotiated NTLM INFO: [proxy] Upgrade done INFO: [proxy] Envelope (Connection 0, Client -> Server): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddInts</a:Action> <a:MessageID>uid:urn:uuid:f9cc5af3-3930-9242-be3c-d36d2a0cb09e</a:MessageID> <a:ReplyTo> <a:Address>ch:http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="c:1">ch:net.tcp://localhost:8204/WCFLab/WCFDemoService/nettcp-winauth</a:To> </s:Header> <s:Body>
i:1234 i:37 </s:Body> </s:Envelope> INFO: [proxy] Envelope (Connection 0, Server -> Client): <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="c:1">ch:http://tempuri.org/IWCFDemoService/AddIntsResponse</a:Action> <a:RelatesTo>uid:urn:uuid:f9cc5af3-3930-9242-be3c-d36d2a0cb09e</a:RelatesTo> <a:To s:mustUnderstand="c:1">ch:http://www.w3.org/2005/08/addressing/anonymous</a:To> </s:Header> <s:Body> i:1271 </s:Body> </s:Envelope> INFO: [proxy] Connection 0 closed ([::1]:50247 <-> [::1]:8204) ERROR: [net.tcp] Error readEnvelopeOrFaultI2R: read tcp [::1]:50248->[::1]:8204: i/o timeout. Entering fault state. INFO: [proxy] Done handling connection 0: [::1]:50247 <-> [::1]:8204
require-and-verifykeylog - 用于以NNS格式写入TLS密钥的文件