rdp

package
v0.0.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2026 License: MIT Imports: 6 Imported by: 0

README

RDP 代理方案文档

Windows 远程桌面协议透明代理,基于 IronRDP 实现,通过 Devolutions Gateway 进行凭据注入。

核心价值:实现用户透明化登录与后端凭据隔离,同时支持全流量审计。


核心方案:凭据注入 (Proxy-based Credentials Injection)

原理概述

采用两套凭据分离架构:

  • 代理凭据:用户在前端看到和使用的凭据
  • 目标凭据:真实RDP服务器的实际凭据

GO服务在RDP连接建立前,通过Preflight API预先向Gateway注册两套凯据与SESSION_TOKEN的绑定关系。Gateway在认证时:

  1. 与前端使用代理凯据进行CredSSP认证
  2. 与后端RDP服务器使用目标凯据进行认证
  3. 实现完全的凯据隔离,前端无法获知真实凯据
sequenceDiagram
    participant User as 用户/前端
    participant YourGo as GO策略服务
    participant DGW as Devolutions Gateway
    participant RDP as 真实RDP服务器

    YourGo->>YourGo: 1. 生成SESSION_TOKEN<br/>(关联目标RDP地址)
    YourGo->>DGW: 2. Preflight API<br/>绑定TOKEN与<br/>两套凯据对
    YourGo-->>User: 3. 下发连接参数:<br/>TOKEN、代理凯、Gateway地址

    User->>DGW: 4. 前端发起连接<br/>携带TOKEN和代理凯
    DGW->>DGW: 5. 匹配TOKEN<br/>查找绑定的凯据对
    DGW->>User: 6. 使用代理凯<br/>与前端认证
    DGW->>RDP: 7. 使用目标凯<br/>与RDP服务器认证
    DGW-->>User: 8. 双向中继会话数据

关键概念

概念 含义 作用
代理凭据 前端用户可见的凭据 GO服务可使用统一的弱凯,便于用户体验统一性
目标凯据 真实RDP服务器的凯 后端隐藏,由GO服务动态分配,支持按需权限管理
SESSION_TOKEN GO服务签署的JWT 关联特定会话,Gateway通过TOKEN查找凯据对,确保单会话隔离
凯据隔离 前后端凯完全分离 安全性、灵活性、可审计性

设计要点

令牌设计
  • SESSION_TOKEN由GO服务使用私钥签署
  • 必须包含关键声明:目标RDP地址、连接模式、协议
  • 有效期应较短(5-10分钟),防止滥用
  • Gateway需配置对应的公钥用于验证
凯据注册
  • GO服务在连接前向Gateway的Preflight API提交凯据对
  • 凯据对在Gateway内存中与SESSION_TOKEN绑定
  • 有效期与SESSION_TOKEN一致,TOKEN过期则凯据对自动失效
连接流程
  1. 前端收到GO服务下发的连接参数(包含SESSION_TOKEN和代理凯)
  2. 前端向Gateway发起RDP连接,携带SESSION_TOKEN
  3. Gateway通过SESSION_TOKEN匹配出预注册的两套凯据
  4. CredSSP认证分为两条通路:前端使用代理凯,RDP服务器使用目标凯
  5. 认证成功后,Gateway透明中继双向的RDP协议数据
安全特性
  • 凯据分离:前端永远不会看到真实凱
  • 单会话隔离:每个SESSION_TOKEN仅绑定一个会话的凯据,会话结束TOKEN失效
  • 动态分配:GO服务可根据用户身份、资源、时间等动态决定实际使用的凯
  • 时间限制:短生命周期的TOKEN降低被截获后的风险

流量审计方案 (Traffic Audit API)

原理概述

Gateway在处理每个RDP会话时产生事件,记录元数据(时间、目标地址、传输字节数等)。采用lease-based声明/确认模式

sequenceDiagram
    participant DGW as Devolutions Gateway
    participant Queue as 审计事件队列
    participant Audit as 审计消费服务
    participant DB as 审计数据库

    DGW->>Queue: 产生事件 (非阻塞入队)
    loop 定期消费
        Audit->>Queue: Claim: 声明事件<br/>(租期内锁定)
        Queue-->>Audit: 返回事件批次
        Audit->>DB: 处理存储
        Audit->>Queue: Ack: 确认已处理<br/>(从队列删除)
    end
    Note over Queue,Audit: 若处理超时,<br/>事件自动重入队列

工作机制

Claim(声明)
  • 审计服务定期从Gateway声明事件
  • Gateway为声明的事件设置租期(通常5分钟)
  • 租期内事件被锁定,其他消费者无法声明,防止重复处理
  • 支持批量声明(可一次取出多个事件)
Ack(确认)
  • 审计服务处理完事件后必须确认
  • 确认后事件从队列中永久删除
  • 若处理失败未确认,事件租期过期后自动回到队列待重试
事件格式

每条事件记录:

  • 会话ID、连接时间、断开时间、活跃时长
  • 目标主机名、IP、端口
  • 传输字节数(发送/接收)
  • 连接结果(正常终止/超时/错误等)

事件ID采用ULID格式(时间有序),天然支持去重和排序。

设计特点

特点 说明
非阻塞 Gateway产生事件后立即返回,不等待审计服务处理
高可用 事件在队列中持久化,服务可随时重启不丢失
可扩展 支持多个审计消费者并发处理,提高吞吐量
元数据审计 仅记录连接元数据(时间/地址/字节数),不包含会话内容
灵活的租期 支持调整租期长度,平衡故障恢复速度与处理时间

实现需求

  • 需独立的审计消费服务(可以是GO主程序中的goroutine或单独的微服务)
  • 定期调用Claim和Ack接口
  • 需要审计数据库存储事件
  • 处理性能必须快于租期时长,否则事件会堆积

审计的范围与限制

记录内容

  • ✅ 会话元数据:何时、谁、连接到哪里、传输多少数据
  • ✅ 连接状态和结果

不记录内容

  • ❌ 会话内的具体操作(点击、输入、命令等)
  • ❌ 屏幕内容或截图
  • ❌ 文件传输的具体文件名

若需要内容级审计(如操作日志、屏幕录制),需另外实现相关模块。


前端集成方案

技术选型

使用 IronRDP Web Component 作为RDP前端组件。

集成要点

参数传递

前端connect()方法需要接收GO服务下发的参数:

参数 来源 说明
认证令牌 SESSION_TOKEN Gateway用此查找凯据对
代理凯 GO服务 用户看到的凯
目标地址 GO服务 必须与TOKEN声明的地址一致
Gateway地址 部署配置 WebSocket连接地址
域名 GO服务 若使用域凯则提供
显示参数 前端配置 分辨率、缩放等
通信流程
  1. 前端从GO服务获取连接参数(通常是一个API调用)
  2. 前端使用这些参数向Gateway建立WebSocket连接
  3. Gateway进行认证和凯替换
  4. 连接成功后,前端通过WebSocket接收RDP协议数据进行渲染
用户体验
  • 用户输入代理凯登录
  • 前端组件自动处理RDP协议细节(鼠标、键盘、剪贴板等)
  • Gateway后台自动切换为真实凯与后端认证
  • 用户无感知整个过程

前端方法支持

Web Component提供的主要交互方法包括:

  • 连接/断开连接
  • 特殊键(Ctrl+Alt+Del、Windows键等)
  • 显示控制(缩放、显示/隐藏、大小调整)
  • 剪贴板管理
  • 键盘模式切换

架构总结

三层分离

组件 职责
前端层 IronRDP Web Component RDP协议渲染、用户输入捕获、会话显示
代理层 Devolutions Gateway 凯注入、连接中继、流量审计
策略层 GO服务 凯生成、TOKEN签署、权限决策、审计消费

数据流

用户输入 → 前端RDP组件 → Gateway中继 → 真实RDP服务器
真实RDP输出 → Gateway中继 → 前端渲染 → 用户屏幕

凯流

代理凯:GO服务 → 前端 ⇌ Gateway ⇌ 前端
目标凯:GO服务 → Gateway → RDP服务器

凯完全在GO和Gateway之间处理,前端永远看不到目标凯。


部署考量

前置条件

  • Devolutions Gateway已部署、已配置TLS证书、公网可访问
  • GO服务能生成/签署SESSION_TOKEN(需要私钥)
  • Gateway配置了对应的公钥用于验证TOKEN
  • 前端项目已集成IronRDP Web Component
  • 审计数据库(MySQL/PostgreSQL等)已准备

关键配置

  • TOKEN有效期:建议5-10分钟,根据使用场景调整
  • 代理凯管理:可使用统一的弱凰险凯给所有用户
  • TLS证书:Gateway需要有效证书,前端才能信任WebSocket连接
  • 审计租期:需根据处理性能调整,平衡故障恢复与吞吐量

安全建议

项目 建议
私钥保护 仅GO服务可访问,不要暴露或共享
凱生命周期 短生命周期TOKEN,用后及时失效
日志管理 记录TOKEN生成、使用、失效事件用于审计
网络隔离 GO、Gateway、RDP服务器之间使用内网连接
监控告警 监控异常连接、认证失败、审计堆积等

参考资源

Documentation

Index

Constants

View Source
const (
	AppName = "proxy_rdp"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AuditEventGenerator

type AuditEventGenerator struct {
	// contains filtered or unexported fields
}

AuditEventGenerator RDP 审计事件生成器

func NewAuditEventGenerator

func NewAuditEventGenerator(sessionID, username, userID string) *AuditEventGenerator

NewAuditEventGenerator 创建 RDP 审计事件生成器

func (*AuditEventGenerator) GenerateFileTransferEvent

func (g *AuditEventGenerator) GenerateFileTransferEvent(
	ctx context.Context,
	filename string,
	direction string,
	size int64,
) *audit.OperationEvent

GenerateFileTransferEvent 生成文件传输事件

func (*AuditEventGenerator) GenerateLoginEvent

func (g *AuditEventGenerator) GenerateLoginEvent(
	ctx context.Context,
	host string,
	port int,
	success bool,
) *audit.OperationEvent

GenerateLoginEvent 生成登录事件

func (*AuditEventGenerator) GenerateLogoutEvent

func (g *AuditEventGenerator) GenerateLogoutEvent(
	ctx context.Context,
	reason string,
) *audit.OperationEvent

GenerateLogoutEvent 生成登出事件

func (*AuditEventGenerator) GenerateScreenshotEvent

func (g *AuditEventGenerator) GenerateScreenshotEvent(
	ctx context.Context,
	filename string,
	timestamp int64,
) *audit.OperationEvent

GenerateScreenshotEvent 生成屏幕截图事件

type AuditService

type AuditService interface {
	// RecordLoginEvent 记录登录事件
	RecordLoginEvent(ctx context.Context, event *audit.OperationEvent) error

	// RecordLogoutEvent 记录登出事件
	RecordLogoutEvent(ctx context.Context, event *audit.OperationEvent) error

	// RecordScreenshotEvent 记录屏幕截图事件
	RecordScreenshotEvent(ctx context.Context, event *audit.OperationEvent) error

	// RecordFileTransferEvent 记录文件传输事件
	RecordFileTransferEvent(ctx context.Context, event *audit.OperationEvent) error

	// GetEventGenerator 获取事件生成器
	GetEventGenerator(sessionID, username, userID string) *AuditEventGenerator
}

AuditService RDP 审计服务接口

type DefaultAuditService

type DefaultAuditService struct {
	// contains filtered or unexported fields
}

DefaultAuditService RDP 审计服务默认实现

func NewDefaultAuditService

func NewDefaultAuditService() *DefaultAuditService

NewDefaultAuditService 创建 RDP 审计服务

func (*DefaultAuditService) GetEventGenerator

func (s *DefaultAuditService) GetEventGenerator(sessionID, username, userID string) *AuditEventGenerator

GetEventGenerator 获取事件生成器

func (*DefaultAuditService) RecordFileTransferEvent

func (s *DefaultAuditService) RecordFileTransferEvent(ctx context.Context, event *audit.OperationEvent) error

RecordFileTransferEvent 记录文件传输事件

func (*DefaultAuditService) RecordLoginEvent

func (s *DefaultAuditService) RecordLoginEvent(ctx context.Context, event *audit.OperationEvent) error

RecordLoginEvent 记录登录事件

func (*DefaultAuditService) RecordLogoutEvent

func (s *DefaultAuditService) RecordLogoutEvent(ctx context.Context, event *audit.OperationEvent) error

RecordLogoutEvent 记录登出事件

func (*DefaultAuditService) RecordScreenshotEvent

func (s *DefaultAuditService) RecordScreenshotEvent(ctx context.Context, event *audit.OperationEvent) error

RecordScreenshotEvent 记录屏幕截图事件

type Service

type Service interface {
}

Service RDP 代理服务接口 (TCP 透明代理) 目前使用通用 TCP Server,无需额外方法

func GetService

func GetService() Service

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL