对WEB RTC在防御领域的应用

简介: 对WEB RTC在防御领域的应用

0x01 了解WEBRTC

WEBRTC架构:

webrtc主要应用于浏览器上的实时视频通讯。我们就从这一点应用上去了解。

关于cadidate:而在浏览器上实现视频通讯,首先就要保证视频编码解码能力的一致,这就应入了cadidate的概念,用于协商两个浏览器在数据处理能力方面的一致性。

而按照原本的通信过程,数据流的传输需要通过“服务器”在中间作为媒介才能实现相互访问(域名就需要走DNS服务器才能了解到对方是谁),私有IP地址也需要路由器经过NAT转换才能相互访问。这时候,webRTC就需要经过**STUN和TURN**来实现对NAT的绕过。当然,在webrtc打洞穿透NAT之前,还是需要服务端来找到双方才能建立连接。

WebSocket:是一种在单个TCP连接上进行全双工通信的协议,通常是基于HTTP协议进行握手。通过WebSocket,可以实现浏览器与服务器之间的实时、双向通信。HTTP协议是一种请求-响应协议,客户端向服务器发送请求,服务器返回响应,是单向的传输连接。而WebSocket是一种双向的传输连接,客户端和服务器可以同时发送和接收数据,实现实时、双向通信。

0x02 组成部分

按照上面的描述,可以了解到,在完整建立webrtc通信的基础上,需要三部分组成:浏览器A、中继服务端(在建立连接前使用)、浏览器B。

浏览器A的作用是:建立websocket与中继服务器建立通信,建立webrtc与浏览器B建立通信,并在浏览器端处理(压缩与解析)视频流等数据流。

浏览器B的作用与浏览器A是一样的,在服务端和控制端上与浏览器A互补。

中继服务器:在建立webrtc连接前建立浏览器A、B双方的websocket,以及turn服务的搭建,即信令服务器。这里就可以理解到,webrtc中的turn是一种服务与中继的作用。

第一步:捕获本地媒体流

<script>
        let constraints = {audio: false, video: true}; 
        let startBtn = document.getElementById('start')
        let video = document.getElementById('stream')
        startBtn.onclick = function() {
            navigator.getUserMedia(constraints, function(stream) {
                video.srcObject = stream;
                window.stream = stream;
            }, function(err) {
                console.log(err)
            })
        }
</script>

这里触发onclick就会触发WebRTC的api getUserMedia。此时第一个参数constraints只获取视频而不获取音频,第二个参数用于获取数据流,第三个参数用于返回错误,这都是显而易见的。

第二步:cadidate协调通信:信令机制

在双方传输媒介中传输的数据叫做信息,那么需要传输哪些信息?

信息的收发端点:网络信息(IP与端口)

信息加密:密钥数据

信息内容:编码解码类型和媒体元数据

信息差错:错误信息

信息起始:会话控制

这时候就需要使用JS会话建立协议(JSEP)来实现这么多信息传递的协议。引出第二个webRTC api:RTCPeerConnection

A与B之间建立一个RTCPeerConnection连接:

A使用 RTCPeerConnection.createOffer()方法产生一个offer。这个offer包括SDP协议(存储媒体元数据),也包括网络信息。

A使用offer调用setLocalDescription()生成本地会话描述(其实就是通过SDP来产生一个“输出端”),并发送给B。

B在接收到offer后调用setRemoteDescription(),生成远端会话描述(这样AB两端的视频流解析方法就一致了)

由于RTC是双工的,此时B也要调用createAnswer()生成一个answer(和offer的信息几乎一致)并发给A,并且setLocalDescription()生成(客户端)的本地会话描述。

A接收到后setRemoteDescription()将B的应答设置为远端会话描述

上面这一系列操作都是通过信令服务器完成的,接下来再次交换“查找候选项”网络信息(ICE)。

Q:为啥不直接一次性完成cadidate的信息对等交换呢

A:因为WebRTC在建立点对点连接时需要交换的信息比较多,所以将其拆分成两步进行发送。第一步是交换SDP信息,通过SDP来协商媒体流的类型、编码格式、传输协议等信息,确定双方数据传输的方式。第二步是交换候选项信息,用于在不同网络环境中建立点对点连接。

继续看下去,A使用onicecandidate创建一个RTCPeerConnection对象,注册一个处理器函数(处理器函数的作用是将ICE发送给远端),处理器将候选数据发送到B。

B获得候选消息时,调用addIceCandidate(),添加到远端对等描述(注意:这个远端对等描述远端会话描述不是一个东西)

补充解释一下候选数据就是 STUN 和 TURN 服务器返回的 IP 地址和端口信息,用于进行 NAT 穿越和中继转发。

上面就是描述了两个任务的实现过程:

获取和分享网络信息:可能的连接端点,也就是ICE候选获取和分享本地和远端的描述:SDP格式的本地媒体的元信息

demo分析

这里是通过websocket实现ICE传输的,和上述的onicecandidate不太一样,但是实现原理是一样的,websocket本身就完成了ICE的交换,自行理解一下。

信令服务器

// 创建 WebSocket 连接,客户端连接到信令服务器的地址
const wsServer = new WebSocket.Server({ port: 8080 });
// 用于存储连接信息的对象
let connections = {};
// 当有新的WebSocket连接时,将其存储在connections对象中
wsServer.on('connection', socket => {
  socket.id = Math.random().toString(36).substr(2, 9);
  connections[socket.id] = socket;
  socket.on('message', message => {
    const data = JSON.parse(message);
    if (data.type === 'offer') {
      // 如果是offer,就将offer存储在connections对象中
      connections[data.to].send(JSON.stringify({
        type: 'offer',
        offer: data.offer,
        from: socket.id
      }));
    } else if (data.type === 'answer') {
      // 如果是answer,就将answer存储在connections对象中
      connections[data.to].send(JSON.stringify({
        type: 'answer',
        answer: data.answer,
        from: socket.id
      }));
    } else if (data.type === 'candidate') {
      // 如果是candidate,就将candidate存储在connections对象中
      connections[data.to].send(JSON.stringify({
        type: 'candidate',
        candidate: data.candidate,
        from: socket.id
      }));
    }
  });
  socket.on('close', () => {
    // 当WebSocket连接关闭时,将其从connections对象中删除
    delete connections[socket.id];
  });
})

浏览器端

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebRTC基础教程</title>
  </head>
  <body>
    <video id="remote-video" autoplay></video>
    <script>
      // 创建WebSocket连接
      const socket = new WebSocket("ws://<WEBSOCKET_SERVER>:8080");
      // 创建RTCPeerConnection对象
      const pc = new RTCPeerConnection();
      // 获取本地媒体流
      navigator.mediaDevices
        .getUserMedia({ video: true, audio: false })
        .then((stream) => {
          // 将本地媒体流添加到RTCPeerConnection中
          pc.addStream(stream);
          // 当获取到远端的媒体流时,将其添加到video元素中
          pc.onaddstream = (event) => {
            const video = document.getElementById("remote-video");
            video.srcObject = event.stream;
          };
          // 当收到远端的offer时,向其发送answer
          socket.onmessage = (message) => {
            const data = JSON.parse(message.data);
            if (data.type === "offer") {
              pc.setRemoteDescription(data.offer)
                .then(() => pc.createAnswer())
                .then((answer) => pc.setLocalDescription(answer))
                .then(() =>
                  socket.send(
                    JSON.stringify({
                      type: "answer",
                      answer: pc.localDescription,
                      to: data.from,
                    })
                  )
                );
            } else if (data.type === "answer") {
              pc.setRemoteDescription(data.answer);
            } else if (data.type === "candidate") {
              pc.addIceCandidate(new RTCIceCandidate(data.candidate));
            }
          };
          // 创建并发送offer
          pc.createOffer()
            .then((offer) => pc.setLocalDescription(offer))
            .then(() =>
              socket.send(
                JSON.stringify({
                  type: "offer",
                  offer: pc.localDescription,
                  to: "remote",
                })
              )
            );
        });
</script>
  </body>
</html>

RTCPeerConnection 本身只支持音视频流通道,但是你可以在音视频流的基础上,通过 RTCDataChannel 实现任意数据的传输。

这样以来,就能很容易看懂webRTC的原理和实现了

接下来,进入正题,如何进行反制?为什么能进行反制?

反制原理

我们借用下面这个3.4K star的项目进行分析


https://github.com/diafygi/webrtc-ips

补丁

原项目以及不生效了,因为(issues #51)RTCPeerConnection的createDataChannel其中一个参数出现了问题


https://developer.mozilla.org/zh-CN/docs/Web/API/RTCPeerConnection/createDataChannel

简单来说,你必须在createDataChannel()中输入一个参数(通道名)。

而在diafygi的项目中,并没有实现这一点;

    80:   //create a bogus data channel
    81:  pc.createDataChannel("");

    只要把任意字符(比如”blueteam“)填进去,就是一个补丁了()

    代码分析

    在getIPs函数中首先检测WebRtc支持(支持不同浏览器)

    var RTCPeerConnection = window.RTCPeerConnection
                        || window.mozRTCPeerConnection
                        || window.webkitRTCPeerConnection;
    var useWebKit = !!window.webkitRTCPeerConnection;

    通过iframe标签独立浏览器进程来绕过webrtc的禁用

    var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};

    在建立RTCPeerConnection时,第一个参数使用server定义公用的ICE server(防止空参数的时候出现奇怪的错误),第二个参数用于拓展RtpDataChannels,原本数据包是使用RTCdatachannels数据包传输。

    这是因为原本的RTC通道是只支持音频数据流传输的,为了获取其他(恶意者的信息)数据,(也许你可以试试RTC直接去调用摄像头看看攻击方的正脸照)。

    var mediaConstraints = {
                        optional: [{RtpDataChannels: true}]
                    };
                    var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
                    //construct a new RTCPeerConnection
                    var pc = new RTCPeerConnection(servers, mediaConstraints);

    在往下正常的创建offer、answer流程之前,注意到在此之前处理onicecandidate的时候(对应一下demo中websocket的处理),出现了一些变化

    pc.onicecandidate = function(ice){
    //skip non-candidate events
    if(ice.candidate)
        handleCandidate(ice.candidate.candidate);
    };

    pc.onicecandidate 是一个监听器,并在当 RTCPeerConnection 发现新的可用的网络候选项(ICE)时,就会触发 onicecandidate 事件(获取IP的函数handCandidate)。

    https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/localDescription

    peerConnection.localDescription 返回RTCPeerConnection.pendingLocalDescription 或者RTCPeerConnection.currentLocalDescription 的值,其都是返回一个SDP。

    根据SDP格式,附加属性a=* 格式a=candidate:第一个字段表示候选项ID

    最终返回IP给回调函数进行正则判断,得到目标IP

    (如果你仔细看了SDP格式,你会发现,candidate其实是走的UDP协议,也就是说,即使对方挂了socks代理,仍然可以获取到目标IP)

    FIX version


    https://github.com/matoujin/webrtc-ips
    相关实践学习
    每个IT人都想学的“Web应用上云经典架构”实战
    本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
    目录
    相关文章
    |
    7月前
    |
    前端开发 算法 API
    构建高性能图像处理Web应用:Next.js与TailwindCSS实践
    本文分享了构建在线图像黑白转换工具的技术实践,涵盖技术栈选择、架构设计与性能优化。项目采用Next.js提供优秀的SSR性能和SEO支持,TailwindCSS加速UI开发,WebAssembly实现高性能图像处理算法。通过渐进式处理、WebWorker隔离及内存管理等策略,解决大图像处理性能瓶颈,并确保跨浏览器兼容性和移动设备优化。实际应用案例展示了其即时处理、高质量输出和客户端隐私保护等特点。未来计划引入WebGPU加速、AI增强等功能,进一步提升用户体验。此技术栈为Web图像处理应用提供了高效可行的解决方案。
    |
    存储 监控 安全
    如何在Python Web开发中确保应用的安全性?
    如何在Python Web开发中确保应用的安全性?
    |
    6月前
    |
    缓存 前端开发 应用服务中间件
    Web端实时通信技术SSE在携程机票业务中的实践应用
    本文介绍了携程机票前端基于Server-Sent Events(SSE)实现服务端推送的企业级全链路通用技术解决方案。文章深入探讨了 SSE 技术在应用过程中包括方案对比、技术选型、链路层优化以及实际效果等多维度的技术细节,为类似使用场景提供普适性参考和借鉴。该方案设计目标是实现通用性,适用于各种网络架构和业务场景。
    193 1
    |
    7月前
    |
    缓存 前端开发 应用服务中间件
    Web端实时通信技术SSE在携程机票业务中的实践应用
    本文介绍了携程机票前端基于Server-Sent Events(SSE)实现服务端推送的企业级全链路通用技术解决方案。文章深入探讨了 SSE 技术在应用过程中包括方案对比、技术选型、链路层优化以及实际效果等多维度的技术细节,为类似使用场景提供普适性参考和借鉴。
    258 7
    |
    前端开发 JavaScript 安全
    前端性能调优:HTTP/2与HTTPS在Web加速中的应用
    【10月更文挑战第27天】本文介绍了HTTP/2和HTTPS在前端性能调优中的应用。通过多路复用、服务器推送和头部压缩等特性,HTTP/2显著提升了Web性能。同时,HTTPS确保了数据传输的安全性。文章提供了示例代码,展示了如何使用Node.js创建一个HTTP/2服务器。
    352 3
    |
    前端开发 JavaScript
    探索现代Web应用的微前端架构
    【10月更文挑战第40天】在数字时代的浪潮中,Web应用的发展日益复杂多变。微前端架构作为一种新兴的设计理念,正逐步改变着传统的单一前端开发模式。本文将深入探讨微前端的核心概念、实现原理及其在实际项目中的应用,同时通过一个简单的代码示例,揭示如何将一个庞大的前端工程拆分成小而美的模块,进而提升项目的可维护性、可扩展性和开发效率。
    |
    10月前
    |
    中间件 关系型数据库 数据库
    docker快速部署OS web中间件 数据库 编程应用
    通过Docker,可以轻松地部署操作系统、Web中间件、数据库和编程应用。本文详细介绍了使用Docker部署这些组件的基本步骤和命令,展示了如何通过Docker Compose编排多容器应用。希望本文能帮助开发者更高效地使用Docker进行应用部署和管理。
    307 19
    |
    11月前
    |
    Web App开发 编解码 vr&ar
    使用Web浏览器访问UE应用的最佳实践
    在3D/XR应用开发中,尤其是基于UE(虚幻引擎)开发的高精度场景,传统终端因硬件局限难以流畅运行高帧率、复杂效果的三维应用。实时云渲染技术,将渲染任务转移至云端服务器,降低终端硬件要求,确保用户获得流畅体验。具备弹性扩展、优化传输协议、跨平台支持和安全性等优势,适用于多种终端和场景,特别集成像素流送技术,帮助UE开发者实现低代码上云操作,简化部署流程,保留UE引擎的强大开发能力,确保画面精美且终端轻量化。
    485 17
    使用Web浏览器访问UE应用的最佳实践
    |
    监控 安全 测试技术
    如何在实际项目中应用Python Web开发的安全测试知识?
    如何在实际项目中应用Python Web开发的安全测试知识?
    213 61
    |
    Kubernetes 安全 Devops
    有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
    有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
    288 10
    有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙

    热门文章

    最新文章