使用Surge脚本& 逻辑规则建立联网防火墙 - NobyDa's Blog

文章推薦指數: 80 %
投票人數:10人

立即调用Surge内部函数, 该函数的实际用途为退出脚本执行; 使用Surge执行脚本时, 该API不可省略. 第二步: 配置捷径自动化. 打开”捷径” > 自动化 > 加号 > ... 主页归档分类标签2021-06-08发表2021-06-08更新APP高级使用技巧 / Surge36分钟读完(大约5458个字)0次浏览使用Surge脚本&逻辑规则建立联网防火墙前言 本文仅建议对Surge(iOS)APP有一定熟悉的用户阅读.如您从未使用过,则该文可能不适合您. 本文主要内容为“手机APP(iOS)隐私泄漏”问题以及解决方案. 本文将会耗费大量篇幅讲解Surge脚本或Surge逻辑规则的运用、科普、实现、以及原理,并建立手机网络防火墙. 背景有一个话题引起了我的关注,一些国内APP(iOS),如:X信,XX宝,X团. 用户安装以上APP后,手机从蜂窝网络切换至WiFi的一瞬间(包括自动连接),以上APP可能会利用iOS某个系统接口直接后台唤醒,并向服务器上传网络请求,经过抓包后发现,该类请求都隶属于以上APP(查询ASN得知),并且都经过强加密,无法得知上传内容. 以上情况不管用户是否关闭后台或关闭后台刷新,都有可能会触发.如果用户手动打开系统设置查看WiFi列表,也可能会触发以上APP的某些联网请求. 该类网络请求可能会上传: WiFi名称(SSID) 定位数据 接入或断开WiFi的时间 以上基于常识推断;由于笔者非iOS开发者,无法得知APP在该情况下具有的权限,不对的还请指正. 企业对该数据可能会: 出售或共享,建立大数据 推断出你的作息规律,几点几分离开家/到公司,并建立用户画像 基于以上两点精准推送广告 以上为背景介绍 应对 借助Surge强大的脚本和规则系统,目前有两种解决方案 方案一概括APP关闭时(后台),完全拦截手机所有APP联网请求;APP开启时(前台),放行所有APP联网请求.(只允许用户主动开启APP表示我需要用到它,否则不允许乱联网) 方案二概括手机从蜂窝网络切换至WiFi(手动/自动)的瞬间,15秒内拦截所有APP联网请求(前台/后台),15秒后恢复 该方案提供懒人Surge模块一键配置,具体可查看本文实现方案二章节 为了使读者更好的理解,本文将会极其详细的描述以上两种方案里每一步的原理以及配置,供读者参考. 实现方案一需求: 打开手机内任何一个APP时(前台),放行网络请求 关闭任何一个APP时(后台),拦截所有请求 拦截的请求可以设置白名单 有两种思路: 捷径自动化触发,当打开/关闭APP时,运行捷径,捷径内容为调用SurgeAPI(开启/关闭)模块,模块内容为:拒绝所有网络请求和白名单在内的规则 捷径自动化触发,当打开/关闭APP时,运行捷径,捷径内容为运行Surge脚本,脚本内容为:储存当前APP状态(打开/关闭),再使用Surge逻辑规则和脚本规则共同决定网络请求是否需要拦截 由于Surge模块的特殊性,开启/关闭模块时,会导致: 触发重载配置(有概率VPN断连) 丢失DNS缓存(TTL),严重影响规则匹配效率 可能会打断活动的网络连接(下载中断) 基于以上弊端,本文将跳过(开启/关闭)模块的实现方式. 第一步:配置捷径脚本 Surge内新建Cron类型脚本,Cron表达式填写0011*脚本名暂且设置为“APP防火墙”,编辑并填入以下脚本,保存后将该Cron脚本禁用(左划) APP防火墙.js123constdata=$intent.parameter;constwrite=$persistentStore.write(data,"APP_BJ");$done(); 以下为科普脚本代码的具体用途及原理,请选择性阅读. APP防火墙.js1constdata=$intent.parameter; 在JS语法中,声明一个名为data的常量,值为$intent.parameter,该API实际内容为读取Surge捷径运行后传入的字符串;如果Surge捷径的参数留空,则该API实际内容为空字符串 APP防火墙.js1constwrite=$persistentStore.write(data,"APP_BJ"); 在JS语法中,声明一个名为write的常量,值为Surge的内部函数,该函数的实际用途为持久化储存,接受2个参数,需要写入的数据(字符串类型),以及一个固定的读取键(字符串类型) 该行用途:写入(储存)上一行代码中名为data的常量的值,读取键为”APP_BJ” APP防火墙.js1$done(); 立即调用Surge内部函数,该函数的实际用途为退出脚本执行;使用Surge执行脚本时,该API不可省略. 第二步:配置捷径自动化 打开”捷径”>自动化>加号>创建个人自动化>APP>选取”已打开”>手动选取除了”设置”外的所有APP>添加操作,搜索”Surge”,选取运行脚本>展开>脚本名为前面设置的”APP防火墙”,参数留空>下一步>关闭”运行前询问”>完成 重复第1步的过程,不同的是,需要选取APP已关闭时运行捷径,并且需要把Surge动作里的参数填写1(重要) 第三步:配置规则脚本 Surge内新建Rule类型脚本,脚本名暂且设置为”RULE防火墙”,编辑并填入以下脚本并保存 RULE防火墙.js12constread=$persistentStore.read("APP_BJ");$done({matched:Boolean(read)}); 以下为科普脚本代码的具体用途及原理,请选择性阅读. RULE防火墙.js1constread=$persistentStore.read("APP_BJ"); 在JS语法中,声明一个名为read的常量,值为Surge的内部函数,该函数的实际用途为持久化读取(读取之前所写入的数据),接受1个参数:读取键(字符串类型) 该行用途:读取捷径脚本所写入”APP_BJ”键的持久化数据 RULE防火墙.js1$done({matched:Boolean(read)}); 立即调用Surge内部函数,该函数的实际用途为退出脚本执行,由于是Rule脚本(使用脚本进行规则判定),需要额外返回一个对象键值对,对象属性键为matched,值为布尔值(true/false)表示是否匹配该规则;在当前代码中,JS内部函数Boolean()用于转换布尔值 该行用途:退出脚本并判断是否匹配规则,如果常量的数据(捷径脚本所写入的数据),能够转换为true,则返回true(匹配规则),否则返回false(不匹配规则) 第四步:配置逻辑规则规则定义 逻辑规则可将多个规则相互嵌套(包含逻辑规则),用于复杂的规则判断. 1AND,((#子规则1),(#子规则2),(#子规则3)),Policy AND运算符表示:如果所有子规则都匹配,则该规则匹配 1OR,((#子规则1),(#子规则2),(#子规则3)),Policy OR运算符表示:如果子规则其中一个匹配,则该规则匹配 1NOT,((#子规则)),Policy NOT运算符表示:如果子规则不匹配,则该规则匹配 理解以上定义后,我们可以使用逻辑规则和脚本规则共同决定网络请求是否需要拦截,并设置白名单 配置规则 编辑Surge配置文件,在[Rule]段落放入以下逻辑规则: [Rule]1AND,((NOT,((OR,((USER-AGENT,Surge*),(RULE-SET,https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Apple.list))))),(SCRIPT,RULE防火墙)),REJECT 以上逻辑规则已包含Apple/Surge白名单(匹配后放行),可匹配绝大多数系统App或Surge自身发送的请求 可自行配置白名单规则: Surge内点击该AND规则>NOT>OR>新增>添加规则或规则集>完成 网络请求经过Surge规则系统时,该规则判断逻辑: 至此,已实现方案一需求: 打开手机内任何一个APP时(前台),放行网络请求 关闭任何一个APP时(后台),拦截所有请求 拦截的请求可以设置白名单 方案一:注意事项 该方案仅针对有特殊需求的用户设计,一般用户不应该使用.因为会产生各种副作用,包括但不限于: iOS14桌面/负一屏小组件无法联网 Surge后台定时脚本任务无法联网 基于主屏幕的Web,例如BoxJS、Sub-Store无法联网 低版本iOS系统或老旧机型打开APP时,可能会无法触发捷径自动化进而造成APP无法联网 前三点虽然可以抓取请求配置规则白名单,但相对来说比较麻烦. 捷径通知 当我们设定iOS捷径内的「个人自动化」功能时,虽然可以关闭“运行前询问”但是当自动化脚本开始执行时,系统会通知提醒自动化已开始执行.如果不想每次都收到这种通知,那么我们其实可以通过一个系统BUG来关闭,具体可点击此处查看具体方法;有一点需要注意,捷径通知关闭后如果运行的捷径里包含通知动作,则该捷径将直接中断. 实现方案二由于方案一过于暴力,方案二应运而生.该方案主要为本文的中心需求. 需求: 从蜂窝网络连接WiFi的瞬间,15秒内拦截所有请求,15秒后放行网络请求 拦截的请求可以设置白名单 思路: 网络环境改变时,触发运行Surge事件(Event)类型脚本,脚本内容为:如果从蜂窝网络切换至WiFi,则写入当前时间戳数据,再使用逻辑规则和脚本规则共同决定15秒内的网络请求是否需要拦截 该方案完全基于Surge,如果您“不想了解具体原理“或者“想跳过繁琐的配置“,可使用懒人Surge模块一键配置,模块地址: 1https://gist.githubusercontent.com/NobyDa/fb026a6d01fec146bd451d01b0c973d5/raw/NetworkFirewall.sgmodule 已包含Apple/Surge白名单(匹配后放行) 第一步:配置事件脚本 Surge内新建Event类型脚本,脚本名暂且设置为“WIFI防火墙”,事件名设置为“network-changed”,编辑并填入以下脚本并保存 WIFI防火墙.js1234567891011constnetwork=$network.wifi.ssid;constcurrentTime=Date.now();$httpAPI("GET","v1/traffic",null,(body)=>{if(network&&(currentTime/1000)-body.startTime>=3){consttime=JSON.stringify(currentTime);constaddTime=$persistentStore.write(time,"WiFi_Timer");$notification.post('防火墙开始拦截','',`已从蜂窝网络切换至${network}`);}$done();}) 以下为科普脚本代码的具体用途及原理,请选择性阅读. WIFI防火墙.js1constnetwork=$network.wifi.ssid; 在JS语法中,声明一个名为network的常量,值为Surge内部API,该$network实际内容为当前网络状态的总览.(加入.wifi.ssid则表示仅提取当前WIFI名称) 该行用途:事件脚本运行后读取当前网络的WIFI名称 WIFI防火墙.js1constcurrentTime=Date.now(); 在JS语法中,声明一个名为currentTime的常量,值为JS中的内部函数,该函数返回Unix时间戳 WIFI防火墙.js1$httpAPI("GET","v1/traffic",null,(body)=>{...}) 立即调用Surge内部函数并传入四个参数(method:String,path:String,body:Object,callback:Function),该$httpAPI暂时没有官方文档,但与HTTPAPI用法类似,具体可查看HTTPAPI官方文档 该行用途:由于Surge每次开启VPN时,都会触发一次network-changed事件脚本,为了避免错误触发导致的问题,以上$httpAPI回调的参数将返回开启VPN的时间,用于稍后的判断 WIFI防火墙.js1if(network&&(currentTime/1000)-body.startTime>=3){...} 在JS语法中,表示条件语句块;我们经常需要根据不同条件来执行不同的代码,以上条件语句可以实现这一点. 该行用途:脚本运行后,如果当前为WiFi环境并且”当前时间“减“开启VPN时间“大于等于3秒,则执行花括号内{…}的代码,否则跳过 WIFI防火墙.js1consttime=JSON.stringify(currentTime); 在JS语法中,声明一个名为time的常量,值为JS中的内部函数,该函数实际用途为”将对象或值转换为JSON字符串”;在当前代码中,表示转换名为currentTime的常量(Unix时间戳) 该行用途:读取声明的Unix时间戳(数字类型),并将它转换成字符串类型,便于储存 WIFI防火墙.js1constaddTime=$persistentStore.write(time,"WiFi_Timer"); 在JS语法中,声明一个名为addTime的常量,值为Surge的内部函数,该函数的实际用途为持久化储存,接受2个参数,需要写入的数据(字符串类型),以及一个固定的读取键(字符串类型) 该行用途:写入(储存)名为time常量的值(Unix时间戳),读取键为”WiFi_Timer” WIFI防火墙.js1$notification.post('防火墙开始拦截','',`已从蜂窝网络切换至${network}`); 立即调用Surge内部函数推送一个Surge通知,并传入三个参数,分别为标题,副标题,内容.三个参数仅接受字符串类型 WIFI防火墙.js1$done(); 立即调用Surge内部函数,该Surge函数的实际用途为退出脚本执行;使用Surge执行脚本时,该API不可省略. 第二步:配置规则脚本 Surge内新建Rule类型脚本,脚本名暂且设置为”TIME防火墙”,编辑并填入以下脚本并保存 TIME防火墙.js123456789101112letblock={matched:false};constreadTimer=$persistentStore.read("WiFi_Timer");if(readTimer){constcurrentTime=Date.now();constmarkTime=parseInt(readTimer);if(currentTime-markTime<=15000){block.matched=true;}else{constdelTime=$persistentStore.write("","WiFi_Timer");}}$done(block); 以下为科普脚本代码的具体用途及原理,请选择性阅读. TIME防火墙.js1letblock={matched:false}; 在JS语法中,声明一个名为block的变量,并初始化对象 该行用途:由于是Rule脚本(使用脚本进行规则判定),脚本结束时需要额外返回一个对象键值对表示是否匹配该规则;此处是为了节省代码(重复段),避免多次使用$done.初始化的对象键值对默认为false(不匹配规则),如果重新赋值(改变)为true则匹配规则 TIME防火墙.js1constreadTimer=$persistentStore.read("WiFi_Timer"); 在JS语法中,声明一个名为readTimer的常量,值为Surge的内部函数,该函数的实际用途为读取之前所写入的数据,接受1个参数:读取键(字符串类型) 该行用途:读取事件脚本所写入”WiFi_Timer”键的持久化数据(Unix时间戳) TIME防火墙.js1if(readTimer){...} 如果名为readTimer的常量可以转换成true(有Unix时间戳),则执行花括号内{…}的代码,否则跳过 TIME防火墙.js1constcurrentTime=Date.now(); 在JS语法中,声明一个名为currentTime的常量,值为JS的内部函数,该函数实际的值为当前Unix时间戳(数字类型) TIME防火墙.js1constmarkTime=parseInt(readTimer); 在JS语法中,声明一个名为markTime的常量,值为JS的内部函数,该函数在当前代码中的实际用途为将”字符串”转换成“数字”类型,(转换名为readTimer常量的值) 该行用途:读取事件脚本所写入的Unix时间戳,并将它转换成数字类型,便于判断 TIME防火墙.js1234567if(currentTime-markTime<=15000){//代码块1//重新赋值(改变)block变量中matched键的值,true表示匹配规则block.matched=true;}else{//代码块2//清除事件脚本所写入的Unix时间戳constdelTime=$persistentStore.write("","WiFi_Timer");} 如果当前Unix时间戳减事件脚本所保存的Unix时间戳小于等于15000毫秒(15秒),则执行代码块1的代码:否则则执行代码块2的代码 TIME防火墙.js1$done(block); 立即调用Surge内部函数,该函数的实际用途为退出脚本执行,并返回block变量(脚本第一行)表示是否匹配规则 第三步:配置逻辑规则规则定义在方案一中的配置逻辑规则章节里有详细描述,这里不再赘述 编辑Surge配置文件,在[Rule]段落放入以下逻辑规则: [Rule]1AND,((NOT,((OR,((USER-AGENT,Surge*),(RULE-SET,https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Apple.list))))),(SCRIPT,TIME防火墙)),REJECT 以上逻辑规则已包含Apple/Surge白名单(匹配后放行),可匹配绝大多数系统App或Surge自身发送的请求 可自行配置白名单规则: Surge内点击该AND规则>NOT>OR>新增>添加规则或规则集>完成 网络请求经过Surge规则系统时,该规则判断逻辑: 至此,已实现方案二需求: 从蜂窝网络连接WiFi的瞬间,15秒内拦截所有请求,15秒后放行网络请求 拦截的请求可以设置白名单 方案二:注意事项 该方案相对来说比较收敛,配置后对正常使用几乎没有影响,适合大多数有隐私需求的用户,但有几点需要注意: 如果您的WIFI路由器信号不稳定,则可能会错误触发事件脚本导致间歇性断网. 从WiFi切换至蜂窝可能会触发事件脚本导致断网.(小概率) 从蜂窝切换至WiFi的瞬间,可能会漏掉极少部分网络请求,导致极少部分的网络请求拦截失败. 无法阻止手动打开系统设置查看WiFi列表所触发的网络请求. 前3点是Surge自身触发事件脚本的逻辑所决定的,无法改进;如果您在意,可以选择同时配置方案一和方案二,以掌握绝对的APP联网权限. 结语本文内容相对来说比较硬核,所列出的只是极其小众的需求,非科班出身的同学可能会有理解障碍,但完全理解后你会发现非常有意思. Surge脚本规则执行效率极高,在笔者的测试环境中(iPhone12),绝大多数网络请求经过逻辑规则+脚本规则仅耗时5ms以内,某些复杂请求可能会在10ms以内,基本不必担心因使用脚本规则而带来的性能问题. 文章内的需求仅仅只是Surge高级用法的其中之一;借助Surge进行全面的网络接管并使用捷径、规则、脚本可以建立出无限可能性. 数据时代,隐私安全将会带来巨大挑战,而在中国,有这样的一种软件,不绑定手机将无法使用或受到限制;之后他们发现所有用户都绑定了手机,然后他们得出一个结论:中国人更愿意用隐私换取效率. 这种论调放在一百年前大概就是“工人愿意选择工作16个小时,放弃所有休息时间多赚钱养家糊口”.殊不知可悲的是,很多时候人们并没有别的选择. 不是我们不在乎隐私,而是没有能力去抵抗. 以上 使用Surge脚本&逻辑规则建立联网防火墙https://nobyda.github.io/2021/06/08/Surge_network_firewall/作者NobyDa发布于2021-06-08更新于2021-06-08许可协议#SurgeJavaScript喜欢这篇文章?打赏一下作者吧微信记录一次Surge&QuantumultX脚本开发过程HelloWorld评论×



請為這篇文章評分?