大概在去年《WebRTC,P2P技术,IPv6》一文中探讨了互联网p2p技术的基本原理,从资源守恒和分形结构的角度揭示了NAT技术的2个本质:

  • 物质守恒:利用端口号资源扩充稀缺的IPv4资源。

  • 分形拓扑:网络嵌套的虚拟化技术。

WebRTC简介

WebRTC是一个重量级的API家族,抛开底层原理,光API接口就非常复杂。WebRTC的底层原理可以分成若干部分,最主要的3大块分别是ICE、压缩算法、p2p协议。

WebRTC 作用 涉及的学科
p2p连接 通过ICE agent完成网络层的点到点UDP连接,以及信令通道 图论
音视频压缩 音视频压缩算法,包括H.264/5和VP8/9 信息论
即时通讯协议 在传输层之上的流媒体通信协议RTP(RTCP) 博弈论、控制论

即时通讯技术要求最低的延迟,比如网络游戏和聊天室应用,通讯数据都是临时生成,没有缓冲的机会,需要在最短的时间内完成通讯同时还要保证安全性,所以即时通讯app的难度大于普通的app。即时通讯应用场景中,流量最大,性能要求最苛刻的场景是即时音视频通讯。目前最成熟的技术是WebRTC,从功能、性能、安全性考虑,WebRTC主要为我们做了很多事情:

  • 功能:开源、回声消除/降噪、支持媒体流和普通数据

  • 空间性能:音视频压缩、流量控制

  • 时间性能:UDP传输、p2p通讯

  • 安全性:数据加密、外设用户授权

虽然WebRTC最核心的地方是音视频的压缩算法,后者也是10G源代码的主体,p2p技术仍然是WebRTC跨技术栈中最好玩的地方。今天继续探讨WebRTC中的p2p技术。


私有IP地址

Web平台是这样一个特殊的平台:和桌面/移动app不同,Web应用总是需要临时下载JS脚本来渲染网页、处理逻辑。开发者的视角:浏览器可以执行我的任何代码,我可以“为所欲为”。当然事实上不可能这样,因为浏览器是一个沙盒环境,没有用户授权,JS无法进行高危操作,而更多的私密操作压根就没有相应的接口,比如JS是没法读取主机的网卡IP地址的。

除非用IP地址作为URL,否则你无法通过JS嗅探DNS的解析过程,也不知道本机的网络IP。通过这种机制,网站只知道你的公网IP,却不知道你的私有IP,也就是NAT内网中你的网卡IP。同时你也不可能知道反向代理的网站背后的真实IP。通过这种对等的私有网络/虚拟化技术,浏览器/服务器架构和平共处了几十年。

但是WebRTC的出现打破了这一局面。ICE打洞技术必须得到IP地址才能跑得起来,上图红字的3种地址代表3种ICE候选者(ICE candidate):

  • 内网内p2p:需要获取你的私有IP

  • 互联网p2p:一般是通过STUN反射出你的公网IP

  • 中转服务器:一般需要TURN中转站的IP(强烈不推荐)

其中内网p2p技术暴露了host candidate这样一个能够获取网卡IP的api。于是我们可以这样玩:

/** * Get the private IP address through webRTC * 通过WebRTC获取主机的网卡IP地址 * @resolve IP */async function getNetworkIP() {  let found = false;  let resolve;  const promise = new Promise((res) => {    resolve = res;  });    const pc = new RTCPeerConnection({ iceServers: [] });  pc.addEventListener("icecandidate", (e) => {    if (!e.candidate || found) return;    resolve(e.candidate.address);    found = true;  });  pc.createDataChannel("");  pc.createOffer().then((desc) => pc.setLocalDescription(desc));  return promise;}

代码赏析:

  1. 拟造一个RTCPeerConnection对象

  2. 指定iceServers为空,这样排除掉代理IP

  3. 创建DataChannel和offer激活ICE候选者

  4. 监听icecandidate事件,拿到本机IP

使用:


私有IP泄露的影响

个人认为私有IP泄露没啥影响,漂亮国人民对隐私的敏感达到癫狂的程度,以为别人可以利用你的私有ip地址窥探内网拓扑,甚至锁定你的地理位置(⊙﹏⊙)。其实都是无知惹得,稍微了解一下计算机网络的基本原理,就能知道,私有ip地址并没有强制的分配原则,泄露私有IP就相当于泄露你的员工工号一样,外面人拿到手没有任何意义。

然而,作为被写入前额叶神经网络ROM区的固件,收集用户数据已经是各大厂商不得不去执行的思想钢印,chrome就统计了所有网站RTCPeerConnection构造函数的调用次数,得出了惊人的结果:

https://www.chromestatus.com/metrics/feature/timeline/popularity/1042

数据来源

平均8%的网页都用到了WebRTC,隐私收集证据确凿了。为此,在许多人心里,WebRTC甚至成了隐私泄露的代名词,chrome商店里居然出现了保护私有IP的插件,插件的原理非常简单:禁用WebRTC。

没必要,真的没必要。


mDNS to the rescue

mDNS指Multicast-DNS,是一种去中心化的多播DNS,所谓的中心化就是传统的DNS服务器,但是如果局域网的规模比较小,let's say 只有2~20台主机,没必要专门开一台新机器来搞DNS服务,万一机房没有多余的机器可用怎么办?当然你也可以将DNS服务部署到某一台终端上,但mDNS是一种更好的方案,它避免了DNS服务器繁琐的安装和配置,开箱即用,因为它是分布式的DNS。

mDNS适用于这样的情境:几台机器想要快速地组建一个局域网,并且可以呼叫对方的主机名(如何设置主机名看这篇文章),由于大家都相互信任,又赶时间,每人把自己的主机名广播给其余所有人,同时把接收到的域名和ip写入本地的DNS缓存,这样不出几秒钟,每台机器都知道所有人的域名了。

真实情况下的mDNS还要考虑重名问题域名更新的情况,由于和本文主题无关,还是谈谈mDNS和WebRTC的安全问题。前面说了,想要在局域网内搞p2p,又不想让JS代码有机会收集私有IP,那把私有IP换成域名不就行了?

于是,在chrome认为安全系数高的网站上使用前面定义的getNetworkIP(),会得到一串.local结尾的域名:

乍一看还以为是IPv6地址,其实它是UUIDv4,没错,就是URL.createObjectURL()得到的域名。在getNetworkIP()的背后,WebRTC悄悄地向操作系统注册了mDNS的域名,所以我可以通过它访问localhost:

我的建议

mDNS是个轻巧的好东西,主流的操作系统和路由器都应该默认开启,但是WebRTC没必要使用mDNS作为host candidate,真的,因为有损性能,每次都需要注册和解析,直接用IP地址是最快的。所以理想情况下,当需要获取私有IP的时候,浏览器应该提示用户是否授权,这样才是兼顾性能与安全性的解决方案。

js获取内网ip_WebRTC安全问题:私有IP与mDNS相关推荐

  1. js获取内网/局域网ip地址,操作系统,浏览器版本等信息

    这次呢,说一下使用js获取用户电脑的ip信息,刚开始只是想获取用户ip,后来就顺带着获取了操作系统和浏览器信息. 先说下获取用户ip地址,包括像ipv4,ipv6,掩码等内容,但是大部分都要根据浏览器 ...

  2. js获取内网ip地址,操作系统,浏览器版本等信息

    这次呢,说一下使用js获取用户电脑的ip信息,刚开始只是想获取用户ip,后来就顺带着获取了操作系统和浏览器信息. 先说下获取用户ip地址,包括像ipv4,ipv6,掩码等内容,但是大部分都要根据浏览器 ...

  3. 前端Js获取本网IP和外网IP方法总汇

    我们应该知道一台电脑需要两个ip才可以上网,一个是本地的内网ip(本地ip),另一个就是外网ip(公网ip).值得说明的是:外网ip具有世界范围的唯一性,而内网ip只在局域网内部具有唯一性.并且一个局 ...

  4. python脚本获取内网,公网ip

    2019独角兽企业重金招聘Python工程师标准>>> 获取内网ip: get_inner_ipaddr.py #!/usr/bin/env python import socket ...

  5. python --获取内网IP地址

    方法一 import socketdef get_local_ip_address():ip_address = ''try:# 获取本机主机名hostname = socket.gethostnam ...

  6. python获取内网IP和外网IP的方法

    1.获取内网IP 示例代码: import socket# 获取内网IP s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect( ...

  7. Flask 获取内网和外网 IP

    from flask import requestrequest.remote_addr # 获取内网IP request.environ.get('HTTP_X_REAL_IP', request. ...

  8. 全球 IP(外网)和私有 IP(内网)

    全球 IP(外网)和私有 IP(内网) 文章目录 全球 IP(外网)和私有 IP(内网) 全球 IP(外网)和私有 IP(内网)概念 几点需要注意的地方 转载于: 谈谈NAT:什么?全球IP和私有IP ...

  9. linux下获取本机的获取内网和外网地址

    1.获取内网地址(私有地址) ifconfig -a 2.获取外网地址(公网地址) curl members.3322.org/dyndns/getip 转载于:https://www.cnblogs ...

  10. Cisco pix或asa如何防止内网用户乱改ip配置案例

    在pix或asa如何防止内网用户乱改ip配置案例 防止内网用户乱该ip地址,用户 只能用给定的ip,如果改ip地址,则无法访问网络资源. 例如:做了下述配置后(arp inside 10.64.64. ...

最新文章

  1. 网络口协商_以太网端口协商解析
  2. 【408预推免复习】操作系统引论
  3. String,StringBuffer和StringBuilder的区别
  4. linux nodejs 采集器,Linux记录-jstack采集namenode gc信息
  5. Java构造方法以及重载
  6. 信息学奥赛一本通(1157:哥德巴赫猜想)
  7. 我的nginx+php是如何配置的?
  8. myeclipse的电商系统模板_电商市场分析怎么做?3分钟了解程序员必备分析软件...
  9. tomcat https 启用8443加证书
  10. Java用for语法找素数,求1-100的质数,用FOR循环。求救。。
  11. 毕设题目:Matlab图像融合
  12. 用最简单的方法解决:linux系统重启网络delaying initialization错误
  13. 多智时代,人工智能发展历史的时间表
  14. GitQ 导读: 为什么 GitHub ?
  15. yolov5 训练结果解析
  16. python爬虫教程:实例讲解Python爬取网页数据
  17. 数字金额大写转换Java工具类
  18. 「GoTeam 招聘时间」腾讯教育 后端高级工程师
  19. 利用Aria2和旧电脑打造一台下载机
  20. 股票市场中有哪些是一般散户想不到但实际却很重要的知识?

热门文章

  1. 阶段3 1.Mybatis_03.自定义Mybatis框架_5.自定义Mybatis的编码-创建两个默认实现类并分析类之间的关系...
  2. 关于select标签曾经踩过的几个坑!
  3. Spring Boot详情
  4. JavaScript闭包 懂不懂由你反正我是懂了
  5. ABAP术语-Implementation
  6. GoogleCpp风格指南 8)格式 _part1
  7. sql语句中【模糊查询like的使用】
  8. 15年3月CCF真题2-数字排序
  9. 数据结构与算法之递推算法 C++与PHP实现
  10. 怎么去掉word标题前的黑点