- 开发者工具预览和真机调试无法访问网络 1.02.1907300?
更新版本之后,无法预览以及真机调试,打开手机调试日志显示,fail request connect error 环境: 本地服务端:http://127.0.0.1;调试基础库:2.8.1 小程序后端域名已配置,开发者工具取消了域名校验; 问题描述: 1、开发者工具模拟器可以正常请求本地服务端; 2、点击预览,手机打开预览,网络请求失败,本地服务端收不到请求; 3、点击真机调试,手机扫码打开,本地服务端收不到网络请求; 尝试解决办法: 1、手机和服务端在同一个网段,尝试过,无法解决; 2、本地电脑防火墙关闭,尝试过,无法解决; 3、重启开发者工具、重启服务端、重启电脑,尝试过,无法解决; 4、重启手机,尝试过,无法解决 5、删除本地手机小程序使用记录,清楚缓存,重新打开,尝试过,无法解决; [图片]
2019-09-02 - 关于小程序恶意对抗平台规则的违规行为公告
小程序平台对开发者提交的小程序服务会进行名称、类目、代码等方面的审核,并在开发者发布小程序后,对其提供的在线服务进行持续性的监管,全流程保障用户的使用体验和权益。 平台在审核及监管过程中,如果发现小程序有违规,会反馈引导开发者进行修改,内容合规后即可正常提审及申诉解封。但近期,我们发现有部分开发者为了能够通过审核以及躲避监管,在代码审核、类目审核、线上监管等过程中通过一些方式进行了恶意对抗,包括但不限于以下行为: 1、代码审核内容绕过 小程序提交审核的版本应与小程序实际发布、上线运营的版本一致。部分开发者在代码提审环节,通过技术手段将不符合当前类目规则或违规的内容进行隐藏,使得审核侧看到的内容与小程序实际发布后的运营内容无关,以期通过代码审核。如下是代码审核内容绕过的一个例子,该小程序不具备外卖平台资质,在版本提审时展示了无关内容,但实际运营过程中提供了外卖平台服务: [图片] [图片] 提审时展示的内容 实际运营内容 2、类目审核资质造假 开发者应根据小程序的实际经营业务内容选择合适的类目并提交对应的资质许可进行类目申请。部分开发者通过伪造资质,如伪造金融资质、ICP证、食品经营许可证等,以期通过类目审核。如下是伪造ICP证的例子,经公开渠道查询确认,该公司并没有申请ICP证: [图片] 伪造ICP证 3、线上监管绕过 小程序官方投诉入口是平台用以收集用户对小程序违规内容反馈的一个途径。部分开发者在小程序上线后,通过采用虚假、仿冒官方投诉入口或在截屏时闪退等方式拦截用户投诉来躲避平台的线上监管,或在申诉解封时通过技术手段隐藏违规内容,在申诉审核通过后继续违规。如下是仿冒官方投诉页面躲避监管的例子: [图片] [图片] 虚假投诉页面 官方投诉页面 上述对抗行为属于严重违反《微信小程序平台运营规范》的恶意行为,在开发者与平台之间形成了对抗关系,并且对用户体验造成了严重的损害。平台视此类对抗行为为最恶意的失信行为,开发者一旦存在此类对抗欺骗平台及用户的行为,将对其(同主体或关联的开发者)后续的代码提审、申诉解封、帐号注册等流程带来持续的影响。请开发者及时了解和学习平台的规则,避免做出错误的判断和选择。 部分服务商为小程序开发者提供服务时,会选择低成本的开发方式(如上述恶意对抗行为),一经发现,平台会限制该等服务商的小程序注册、提审等能力,并对该等服务商已提交上线的小程序进行能力限制或下架等处罚。与此同时,我们发现有外部开发者发布小程序审核包过、加速审核等宣传广告,这其中可能存在以故意隐藏代码或内容、或伪造资质文书等方式绕过或规避平台审核监管,请开发者不要上当受骗,以免自己的小程序受到牵连处罚。最后,平台对恶意对抗行为保留法律追究权利,请各位开发者对自身的行为负责,避免触犯法律底线。 相关信息:近期,平台对存在上述对抗行为的开发者进行了起诉,经调查取证,杭州互联网法院宣判被告的行为构成不正当竞争,应承担停止侵权、消除影响、赔偿损失65万元的民事责任,具体细节可参看《判赔65万 | 首例恶意公众号/小程序不正当竞争案宣判》。
2019-08-27 - 微信开发者工具稳定版 1.02.1907300 更新说明
下载地址 Windows 64 、 Windows 32 、 macOS1. 小程序支持自动化测试小程序自动化 SDK 为开发者提供了一套通过外部脚本操控小程序的方案,从而实现小程序自动化测试的目的。 如果你之前使用过 Selenium WebDriver 或者 Puppeteer,那你可以很容易快速上手。小程序自动化 SDK 与它们的工作原理是类似的,主要区别在于控制对象由浏览器换成了小程序。 特性 通过该 SDK,你可以做到以下事情: 控制小程序跳转到指定页面 获取小程序页面数据 获取小程序页面元素状态 触发小程序元素绑定事件 往 AppService 注入代码片段 调用 wx 对象上任意接口 了解更多详情,点击查看小程序自动化快速开始。 2. 云开发控制台支持黑色主题云开发控制台增加支持黑色主题的展示,具体效果可参看下面的特性。 3. 云开发控制台监控图表增加数据总和显示为方便用户了解一段时间内资源的总体使用情况,这边在云开发控制台中的监控图表增加数据总和的显示。 [图片] 4. 云开发控制台支持购买和变更套餐在云开发控制台增加支持购买和调整套餐配额方案的能力。 配额调整方式如需调整配额,可按照以下方式操作: 登录 微信开发者工具 并打开 云控制台。 点击 设置 页面,选择需调整到的配额版本。 核对调整信息并确认已阅读并同意《小程序·云开发资源配额调整规则》。 在购买页选择相应的购买时长,确认无误后点击 提交订单。 [图片] 查看订单详情提交订单,用户可以在 历史配额 页面的订单记录列表中,查看订单号、创建时间和订单状态等,并可通过点击订单记录查看详细的订单信息。 更多详情请参考相关文档 5. setTabBarItem 支持临时文件和网络路径开发者工具 setTabBarItem 支持传入临时文件和网路文件路径 6. 公众号网址栏下拉菜单点击URL自动跳转[图片] 7. 通用设置——使用GPU加速模式(默认关闭)在工具通用设置增加 “使用GPU加速模式”,开启 GPU 加速可以提高项目中动画相关的绘制渲染效果。 注:部分低端显卡可能无法支持 GPU 加速,因此工具默认不开启,开发者根据自身情况选择使用 [图片] GPU 加速效果(左边为未开启 GPU 加速,右边为开启了 GPU 加速) [图片][图片] 8. 版本管理支持直接 checkout 远程分支工具的版本管理将直接支持 checkout(检出)远程分支 [图片] 9. 优化文件监听模块过去的文件监听模块,存在着如下问题: 在 Windows 下,可能会导致文件夹无法删除的问题 可能无法监听到某些文件夹的修改 没有使用 macOS 的原生 fsevents,性能不是最好的。 如果文件过多、文件的变更频繁时,可能会导致工具变卡 针对上述的问题,这边优化了工具的文件监听模块。 优化效果 测试机器:win10(4G 内存)文件fileUtils耗时3.55 GB,共 78217 文件[代码]新[代码]文件监听模块1.5s-2.8s3.55 GB,共 78217 文件旧文件监听模块45s-60s提升约是 25-35 倍左右 测试机器:MacBookPro i7 (16 GB) 文件fileUtils耗时3.55 GB,共 78217 文件[代码]新[代码]文件监听模块6s-7s3.55 GB,共 78217 文件旧文件监听模块12s-14s提升约是 2 倍左右 10. 优化体验评分 UI 开发者工具提供了体验评分的功能,但之前功能比较简单,都是以文字的方式展示具体的评分结果,这边对其相应的展示优化。目前优化后的展示如下: [图片] 更多体验评分详情可查看相关文档11. 优化非 miniprogramRoot/pluginRoot 目录下文件的修改不会触发编译过去工具将监听整个项目文件的修改,本次优化成只对于 miniprogramRoot / pluginRoot 目录(源码目录)下的文件进行监听变更。从而避免不必要的文件监听和性能浪费。 12. 支持预览当前页为解决用户调试某个页面时无法快速预览该页面(需要手动创建自定义编译模式)的问题,工具提供预览当前页面的功能。用户在工具模拟器下方点击预览的文字链后,将显示预览当前页的二维码(预览界面显示信息和正常预览相同)。 注:之前模拟器下的“打开”的文字链入口和功能将迁移到项目页面路径上,项目页面路径变为可点击的文字链,点击文件链后在编辑器代开该页面的js文件。 [图片]
2019-08-13 - 「激励式视频广告」向非游戏类小程序流量主开放
[图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片] [图片]
2019-04-16 - 微信开放社区线下沙龙(北京站)现正报名
[图片] 点击此处立即报名
2019-08-23 - 小程序地图学习之获取位置 获取经纬度 获取地名 获取地址
我们在做小程序开发时,难免会遇到地图相关的开发,而小程序已经为我们提供的比较完善的地图组件。我们只需要调用相关的api就可以实现大致的功能。如:获取经纬度,获取位置,获取地址,获取地名。结下来就具体给大家讲解。 老规矩先看效果图 [图片] 接下来我们就来看看具体实现步骤 一,定义一个按钮来调用位置获取的api [代码]<!--index.wxml--> <button bindtap='getLocation'>获取位置信息</button> <text>{{jingwei}}</text> <text>{{address}}</text> <text>{{name}}</text> [代码] 二,调用获取地理位置的方法 [代码]//index.js Page({ getLocation() { let that = this; wx.chooseLocation({ success: function(res) { console.log(res) var latitude = res.latitude var longitude = res.longitude; that.setData({ jingwei: "经纬度:" + longitude + ", " + latitude, address: " 地址:" + res.address, name: " 地名:" + res.name }) } }); } }) [代码] 其实到这里我们就可以实现获取经纬度,获取位置信息的功能了。 但是呢??现在小程序调用用户位置信息时,需要用户授权,如下图,如果用户点击了拒绝,我们就没有办法调用地图获取位置信息了。 [图片] 所以呢,我们要想实现一个完整的获取用户位置信息的功能,就要在监测到用户拒绝的位置权限时,引导用户去重新授权。这样才是一个友好的健壮的程序。下面就来教大家如何引导用户去打开授权。 三,在app.json里注册位置权限 [图片] 上图红色框里就是我们的位置权限的注册代码,app.json的完整代码如下。 [代码]{ "pages": [ "pages/index/index", "pages/setting/setting" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } }, "sitemapLocation": "sitemap.json" } [代码] 四,定义检查位置权限是否打开的方法 [代码] //校验位置权限是否打开 checkLocation() { let that = this; //选择位置,需要用户授权 wx.getSetting({ success(res) { if (!res.authSetting['scope.userLocation']) { wx.authorize({ scope: 'scope.userLocation', success() { wx.showToast({ //这里提示失败原因 title: '授权成功!', duration: 1500 }) }, fail() { that.showSettingToast('需要授权位置信息'); } }) } } }) }, [代码] 这个方法就是来检查用户的位置权限是否授权,如果没有授权,就弹窗提示用户去授权页授权。弹窗代码如下: [代码] // 打开权限设置页提示框 showSettingToast: function(e) { wx.showModal({ title: '提示!', confirmText: '去设置', showCancel: false, content: e, success: function(res) { if (res.confirm) { wx.navigateTo({ url: '../setting/setting', }) } } }) }, [代码] 至此就可以实现一个完整的获取用户位置信息的小程序了,index.js完整代码如下 [代码]//index.js Page({ getLocation() { this.checkLocation(); let that = this; wx.chooseLocation({ success: function(res) { console.log(res) var latitude = res.latitude var longitude = res.longitude; that.setData({ jingwei: "经纬度:" + longitude + ", " + latitude, address: " 地址:" + res.address, name: " 地名:" + res.name }) } }); }, //校验位置权限是否打开 checkLocation() { let that = this; //选择位置,需要用户授权 wx.getSetting({ success(res) { if (!res.authSetting['scope.userLocation']) { wx.authorize({ scope: 'scope.userLocation', success() { wx.showToast({ //这里提示失败原因 title: '授权成功!', duration: 1500 }) }, fail() { that.showSettingToast('需要授权位置信息'); } }) } } }) }, // 打开权限设置页提示框 showSettingToast: function(e) { wx.showModal({ title: '提示!', confirmText: '去设置', showCancel: false, content: e, success: function(res) { if (res.confirm) { wx.navigateTo({ url: '../setting/setting', }) } } }) }, }) [代码] 从代码中可以看到,我们在用户拒绝授权时的提示框,点击会跳转到setting页,setting也是我们自己的页面,但是这个页面特别简单。就定义一个button。 [代码]<!--pages/setting/setting.wxml--> <button class="button" open-type="openSetting" type='primary'> 打开授权设置页 </button> [代码] 为什么要这么做呢,因为微信不允许我们直接打开权限设置页,必须通过button组件提供的开发能力去到设置页,这里的开放能力就是open-type=“openSetting” 中的openSetting。我们点击按钮后就到了权限设置页。 [图片] 这样就可以引导用户再次授权了。 有任何关于编程的问题都可以加我微信2501902696(备注编程开发) 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 完整的源码可以加老师微信获取,也可以关注下面老师公号,回复“地图源码” 获取。 [图片]
2019-05-08 - 巧用云调用,实现【共享名片夹】小程序
原创: 锋少 一、前言 从一个较早的小程序开发者到第一批使用小程序·云开发的开发者,这期间一直在关注关于小程序各方面的更新,同时也用小程序·云开发做了几款产品,其中包括上次分享的随手记Lite小程序,比较上次,这次分享的技术点相对更加全面和实用一些。 涉及的技术点有: 数据上传、数据更新、分页读取、数据删除,AI智能名片识别读取。 单图上传、多图上传,图片URL获取,带参小成码生成。 下发模板消息,云调用使用。 二、主要功能 创建电子名片:信息存储,图片上传,名片读取(AI智能名片识别) 转发电子名片:专属名片海报(带参小程序码生成) 电子名片被访问:下发模板消息(云调用) 三、功能实现 3.1、准备工作 1、注册微信小程序账号: 方式一:直接注册(https://mp.weixin.qq.com/wxopen/waregister?action=step1) 方式二:已经有微信公众号(已认证)朋友可以直接【登录公众号】 -> 【小程序管理】 -> 【添加】->【快速注册并认证小程序】,注册完成后,找到小程序的 AppID和 AppSecret [图片] 2、下载微信开发者工具、创建项目 ,打开开发者工具,键入项目目录、项目名称、刚才的 AppID,此时项目创建成功,然后点击开发者工具上方的【云开发】开通云开发。 3.2功能实现一:【创建电子名片】 信息存储,图片上传,名片读取(AI智能名片识别) 1.功能简要描述 对于一个名片的小程序,第一步肯定是创建电子名片,除此之外,可以用传统信息录入的方式创建名片,同时也支持纸质名片的识别读取,快速创建名片,这里本地需要导入 [代码]mapping.js[代码]框架,接下来以纸质名片识别为例。 2.核心代码 [代码] // 上传名片后获取零时链接 getTempFileURL() { wx.cloud.getTempFileURL({ fileList: [{ fileID: this.data.fileID, }], }).then(res => { console.log('获取成功', res); if (res.fileList.length) { this.setData({ coverImage: res.fileList[0].tempFileURL }, () => { this.parseNameCard(); }); } else { Toast('获取图片地址失败'); } }).catch(err => { Toast('获取图片地址失败'); }); }, // 读取名片 parseNameCard() { wx.cloud.callFunction({ name: 'parseCard', data: { url: this.data.coverImage } }).then(res => { if (res.result.data.length == 0) { Toast('解析失败,请上传【纸质名片】或【手动创建】'); return; } let data = this.transformMapping(res.result.data); wx.setStorageSync("parseCardData", data) Toast('解析成功'); }).catch(err => { console.error('解析失败,请上传【纸质名片】或【手动创建】', err); Toast('解析失败,请上传【纸质名片】或【手动创建】'); }); }, // 名片数据解析 transformMapping(data) { let record = {}; let returnData = []; data.map((item) => { let name = null; if (mapping.hasOwnProperty(item.item)) { name = mapping[item.item]; // 写入英文名 item.name = name; } return item; }); // 过滤重复的字段 data.forEach((item) => { if (!record.hasOwnProperty(item.item)) { returnData.push(item); record[item.item] = true; } }); return returnData; }, [代码] 3.3功能实现二:【转发电子名片】 专属名片海报(带参小程序码生成) 1.功能简要描述:转发电子名片有两种方式。 1.以小程序的形式直接转发给好友或微信群。 2.生成专属名片海报分享到朋友圈长按进入对应的电子名片页面。名片海报上除了有对应用户的姓名之外,还有专属的名片小程序码,效果如下: [图片] 2.核心代码 [代码]const cloud = require('wx-server-sdk') const axios = require('axios') var rp = require('request-promise'); cloud.init() // 云函数入口函数,小程序端传过来页面和名片id exports.main = async (event, context) => { console.log(event) try { const resultValue = await rp('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret') const token = JSON.parse(resultValue).access_token; const response = await axios({ method: 'post', url: 'https://api.weixin.qq.com/wxa/getwxacodeunlimit', responseType: 'stream', params: { access_token: token, }, data: { page: event.page, width: 300, scene: event.id, }, }); return await cloud.uploadFile({ cloudPath: 'xcxcodeimages/' + Date.now() + '.png', fileContent: response.data, }); } catch (err) { console.log('>>>>>> ERROR:', err) } } [代码] 3.4功能实现三:【电子名片被访问】 下发模板消息(云调用) 1.功能简要描述 用户名片被访问的时候,用户者会收到【客户来访提醒】的模板消息,同时提醒用户完善名片信息。 2.核心代码 [代码]const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { try { const result = await cloud.openapi.templateMessage.send({ touser: event.toUser, page: "pages/index/index", data: { keyword1: { value: event.visitDate }, keyword2: { value: "刚刚有人深度访问了您的名片,经常完善名片信息,更容易被查找和访问。" }, }, templateId: 'templateId', formId: event.formId, }) return result } catch (err) { throw err } } [代码] 四、总结 和传统的小程序 + WEB后台开发模式比起来,云开发在精力和人力上真的是节省了很多,这能使开发者将大部分精力和时间放到功能的开发上。 云开发上线时间不算太长,但逐步有新的功能开放出来,比如云控制台数据的导入导出、云调用等,希望小程序·云开发开放出更多的接口和功能… 五、项目预览 [图片]
2019-05-05 - 跨界 - Omi 发布多端统一框架 Omip 打通小程序与 Web
Omip 今天,Omi 不仅仅可以开发桌面 Web、移动 H5,还可以直接开发小程序!直接开发小程序!直接开发小程序! → omijs.org → Github 地址 Omi 简介 Omi 框架是腾讯研发的下一代前端框架, 基于 Web Components 规范设计的组件化框架,可以开发 PC Web、移动端 H5,也可以直接使用 Omi 开发小程序。Omi 服务于腾讯的 H5 页面, PC 网站以及腾讯内部的一些管理系统和小程序等。自去年年底开源以来,该项目共获得 Star 数 7000+,贡献者 40+。Omi 借助京东 O2Team 优秀的 taro 多端统一框架,以及 Omi 开发团队和社区贡献者近期的共同努力,使 Omi 打通了小程序与 Web。细心的用户会发现,Omi 的 slogan 从 下一代 Web 框架 变更为 下一代前端框架, 因为 Omip 的加入,Omi 生于 Web 却能脱离 Web。 [图片] 同样的语法,同样的书写格式,运行在不同的平台、不同的环境,除了一些平台特有的API,几乎不用任何改动! 老的 Omi 项目做一些极其微小的改动(平台特性相关)就能跑在安卓/IOS的小程序里。 Learn Once, Write Anywhere Write Once, Run Anywhere [图片] Omip 特性 一次学习,多处开发,一次开发,多处运行 使用 JSX,表达能力和编程体验大于模板 支持使用 npm/yarn 安装管理第三方依赖 支持使用 ES6+ 支持使用 CSS 预编译器 小程序 API 优化,异步 API Promise 化 超轻量的依赖包,顺从小程序标签和组件的设计 快速开始 [代码]npm i omi-cli -g omi init-p my-app cd my-app npm start //开发小程序 npm run dev:h5 //开发 h5 npm run build:h5 //发布 h5 [代码] 把小程序目录设置到 dist 目录就可以愉快地调试了! node 版本要求 >= 8 也支持一条命令 [代码]npx omi-cli init-p my-app[代码] (npm v5.2.0+) 当然也支持 TypeScript: [代码]omi init-p-ts my-app [代码] TypeScript 的其他命令和上面一样,也支持小程序和 h5 SPA 开发。 Omip 多端示例 [图片] [图片] Omi 其他 [图片] [图片] 社区化发展,欢迎加入并贡献社区 目前 Omi 的贡献者遍布国内外各大公司(中国、韩国、美国、土耳其),Omi 共接受了快 40 位贡献者的文档和代码提交,核心贡献者共 11 名。欢迎有想法有能力有激情的开发者加入贡献者行列并最终能够进入 Omi Team。 你可以从这几个方面贡献: 1.翻译文档,目前有中文、英文和韩文,欢迎其他语言版本的翻译加入 2.提交补丁代码优化 Omi 3.积极参与 Issue 的讨论,如答疑解惑、提供想法或报告无法解决的错误 4.贡献案例,可以是管理后台、PC 网站、移动端 H5等等 5.完善文档,可以反复修正文档,让其更易懂,上手更快 6.扩展 Omi 生态,编写 Omi 自定义组件 7.分享与 Omi 的故事 8.写 Omi 相关的 blog 我们非常欢迎开发者们为腾讯开源贡献一份力量,相应也将给予贡献者激励以表认可与感谢。参见腾讯贡献者激励计划 Omi 交流群 欢迎加入Omi交流群,群聊号码:256426170,也可扫码加入: [图片] 感谢 感谢京东 O2Team taro 项目 感谢京东 O2Team taro 团队 Github https://github.com/Tencent/omi
2019-03-20 - 微信开发者工具 1.02.1904090 更新说明
下载地址 https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html 企业微信模拟器插件 通过 菜单 -> 工具 -> 插件 打开插件管理面板 [图片] [图片] 可以添加企业微信小程序模拟器,添加成功后重启开发者工具 [图片] 选择企业微信小程序模式即可调试企业微信小程序。 查看更多 云函数本地调试 在云函数目录右键可以打开云函数本地调试功能 [图片] 查看更多 背景音频交互变更 背景音频播放器不再以弹出窗口的交互方式展示 [图片] [图片] 通过 CLI/HTTP 调用关闭工具 需要先在设置中打开服务端口 [图片] CLI/HTTP 调用关闭开发者工具时,开发者工具会有个交互反馈 [图片] 查看更多 分包新增 page 配置会自动生成页面 [图片]
2019-04-17 - Cross-Origin Read Blocking (CORB)
本文的开始源于落地页项目中遇到的 Chrome 控制台 warn 提示,担心影响页面渲染,特此弄个究竟。提示如下, [代码]Cross-Origin Read Blocking (CORB) blocked cross-origin response https://www.example.com/example.html with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details. [代码] 除非特殊说明,否则本文中的浏览器均指 Chrome Browser。 前言 本文将从以下几个方面对 CORB 进行探讨, 什么是 CORB 为什么会产生 CORB 什么情况下会出现 CORB 出现 CORB 时,我们可以如何看待 CORB 发生时浏览器表现 CORB 是一种判断是否要在跨站资源数据到达页面之前阻断其到达当前站点进程中的算法,降低了敏感数据暴露的风险。 - Chrome 浏览器提示 当请求发生 CORB 时,浏览器控制台会打印如下警告内容, [图片] [代码]Cross-Origin Read Blocking (CORB) blocked cross-origin response https://www.example.com/example.html with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details [代码] 在 [代码]chrome 66[代码]或这个版本之前,提示信息有细微不同, [代码]Blocked current origin from receiving cross-site document at https://www.example.com/example.html with MIME type text/html [代码] <p style=“color: #2c74bd”>当请求的响应结果本身就出错或为空时,早期版本 Chrome 依旧会出现上述提示,但 Chrome 69 之后的版本不再出现上述提示。下文<b>实验一和实验二</b>验证了该描述。</p> - Chrome 浏览器行为 [代码]The response body is replaced with an empty body. // 响应数据置为空 The response headers are removed. // 移除响应请求头 [代码] <p style=“color: #2c74bd”> CORB 启动时,虽然响应结果会被置空,但是请求的服务仍然成功,[代码]status: 200[代码]。比如:使用 [代码]img[代码] 标签上报页面监控数据,尽管响应结果为空,但请求依旧发送成功,服务器亦正常响应。下文<b>实验一</b>已验证。 </p> 为什么会有 CORB 的出现? 简单来说,就是出现了一些网络安全漏洞,为防止漏洞肆虐,便出现了站点隔离(Site Isolation),CORB 则是其中的一种实现策略。 Spectre 和 Meltdown 漏洞 当恶意代码和正常站点存在于同一个进程时,恶意代码便可以访问进程内的内存,进行一系列访问攻击,此时,恶意代码窃取数据的唯一难点在于不知道敏感数据的具体存储位置,但通过 CPU 预执行 和 SCA 可以一步步 试探 出来。详细了解可参看: https://zhuanlan.zhihu.com/p/32784852 什么是 CPU 预执行? [代码]if(condition) do_sth(); [代码] CPU 执行速度大于内存读取速度,为了提升 CPU 使用率,在从内存中读取 [代码]condition[代码] 完成之前,CPU 就已经开始执行下文内容。即不管 [代码]if[代码] 条件是否返回 [代码]true[代码],CPU 都会提前执行里面的语句[代码]do_sth()[代码]。 CPU 预执行是芯片制造者决定的,为了提升 CPU 使用速度和效率而建的,预执行红利不是轻易就能放弃的,因此,目前或短期来看基本没可能改变。 普通浏览器中,不同的站点可能共享同一个进程 在某些情况下,没有实现 Site Isolution 的普通浏览器会出现一个进程里面同时运行多个站点的代码,这就让恶意站点有机可乘。比如恶意站点 [代码]a.dd.com[代码] 在自己的代码中嵌入 [代码]<iframe src="https://v.qq.com" frameborder="0"></iframe>[代码],这时,普通浏览器就会把带有恶意站点 [代码]a.dd.com[代码] 的恶意代码 和 [代码]v.qq.com[代码] 放在同一个内存中运行。 [图片] SCA(Side-Channel Attacks) 旁道攻击 简单来说,就是利用程序运行时,系统产生的一些物理特征(如:时延,能耗,电磁,错误消息,频率等)进行推测型攻击。看起来有点不可思议,但早在 1956 年,英国已经利用 SCA 获取了埃及驻伦敦的加密机。 缓冲时延(Cache Timing)旁路是通过内存访问时间的不同来产生的旁路。假设访问一个变量,这个变量在内存中,这需要上百个时钟周期才能完成,但如果变量访问过一次,这个变量被加载到缓冲(Cache)中了,下次再访问,可能几个时钟周期就可以完成了,可根据这种访问速度窃取特定数据。Spectre 和 Meltdown 漏洞便是利用了这种特性。 如何预防 Spectre 和 Meltdown 漏洞呢? 漏洞三大关键点是 CPU 预执行、SCA 和 共享进程。预防就得从这三个方面着手。先看 SCA,算法运行时间的变化本质就是源于数据处理,根据时间变化推测运算操作和数据存储位置,因此 SCA 可预防性极低。再看 CPU 预执行,性能至少提高 10%,一片可观的红利,芯片厂商如何舍得放弃。如此,只能针对共享进程下手了,Site Isolation 便是剥离共享进程的一项技术,采用独立站点独立进程的方式实现,降低漏洞的威胁。 Site Isolation 站点隔离保证了不同站点页面始终被放入不同的进程,每个进程运行在一个有限制的沙箱环境中,在该环境中可能会阻止进程接收其它站点返回的某些特殊类型敏感信息,恶意站点不再和正常站点共享进程,这就让恶意站点窃取其它站点的信息变得更加困难。从 Chrome 67 开始,已默认启用 Site Isolation。 [图片] 经验证,[代码]Site Isolation[代码] 关于进程独立的原则是 只要一级域名一样,站点实例就共享一个进程,无论子域名是否一样。如果使用 iframe 嵌入了一级域名不一样的跨域站点,则会生成一个新的进程维护该跨域站点运行,这一点同前文介绍的普通浏览器共享进程不同。更详细的内容参看 http://www.yaoyanhuo.com/blog/site_isolate_process 这是 Site Isolation 的进程设计,那么其中的 CORB 扮演了什么角色呢? 在同源策略下,Site Isolation 已经很好地隔离了站点,只是还有跨域标签这样的东西存在,敏感数据依旧会暴露,依旧会进驻恶意站点内存空间。 有这样一个场景,用户登录某站点 [代码]some.qq.com[代码]后,又访问了 [代码]bad.dd.com[代码] 恶意站点,恶意站点有如下代码,[代码]<script src="some.qq.com/login">[代码],跨域请求了原站点的登录请求,此时,普通浏览器会正常返回登录后的敏感信息,且敏感信息会进驻 [代码]bad.dd.com[代码] 内存空间。好不容易站点隔离把各个站点信息分开了,这因为跨域又在一起了。咋整?CORB 来了。CORB 会在敏感信息到达 web apge 之前,将其拦截掉,如此,敏感信息既不会暴露于浏览器,也不会进驻内存空间,得到了很好的保护。 CORB 发生时机 当跨域请求回来的数据 MIME type 同跨域标签应有的 MIME 类型不匹配时,浏览器会启动 CORB 保护数据不被泄漏,被保护的数据类型只有 [代码]html[代码] [代码]xml[代码] 和 [代码]json[代码]。很明显 [代码]<script>[代码] 和 [代码]<img>[代码] 等跨域标签应有的 MIME type 和 [代码]html[代码]、[代码]xml[代码]、[代码]json[代码] 不一样。 MIME type (Multipurpose Internet Mail Extensions) MIME type 同 CORB 有着相当紧密的关系,可以说 CORB 的产生直接依附 MIME 类型。因此,阅读本文前,有必要先理解一下什么是 MIME type。 MIME 是一个互联网标准,扩展了电子邮件标准,使其可以支持更多的消息类型。常见 [代码]MIME[代码] 类型如:[代码]text/html[代码] [代码]text/plain[代码] [代码]image/png[代码] [代码]application/javascript[代码] ,用于标识返回消息属于哪一种文档类型。写法为 [代码]type/subtype[代码]。 在 HTTP 请求的响应头中,以 [代码]Content-Type: application/javascript; charset=UTF-8[代码] 的形式出现,[代码]MIME type[代码] 是 [代码]Content-Type[代码] 值的一部分。如下图, [图片] 内容嗅探技术(MIME sniffing) 内容嗅探技术是指 当响应头没有指明 [代码]MIME type[代码] 或 浏览器认为指定类型有误时,浏览器会对内容资源进行检查并执行,来猜测内容的正确[代码]MIME[代码]类型。嗅探技术的实现细节,不同的浏览器在不同的场景下有不同的方式,本文不做详述。详细内容参见:https://www.keycdn.com/support/what-is-mime-sniffing 如何禁用 [代码]MIME sniffing[代码] 呢? 服务器在响应首部添加 [代码]X-Content-Type-Options: nosniff[代码],用来告诉浏览器一定要相信 [代码]Content-Type[代码] 中指定的 [代码]MIME[代码] 类型,不要再使用内容嗅探技术探测响应内容类型。该方法仅对 [代码]<script>[代码] 和 [代码]<style>[代码] 有效。 官方解释:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#MIME_sniffing 浏览器如何判断响应内容是否需要 CORB 保护? 这可能是本文最需要关心的内容了,到底什么情况下会出现 CORB 。在满足跨域标签(如:[代码]<script>[代码],[代码]<img>[代码])请求的响应内容的 [代码]MIME type[代码] 是 [代码]HTML MIME type[代码] 、 [代码]XML MIME type[代码]、[代码]JSON MIME type[代码] 和 [代码]text/plain[代码] 时,以下三个条件任何一个满足,就享受 CORB 保护。([代码]image/svg+xml[代码] 不在内,属图片类型) 响应头包含 [代码]X-Content-Type-Options: nosniff[代码] 响应结果状态码是 [代码]206 Partial Content[代码] (https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/206) 浏览器嗅探响应内容的 MIME 类型结果就是 json/xml/html 这种嗅探用于防止某些内容因被错误标记 MIME 类型 而被 CORB 阻断不能正常响应返回,且该嗅探基于 [代码]Content-Type[代码] 进行,比如类型是 [代码]text/json[代码],便只会对内容进行 json 类型检查,而不会进行 xml 或 html 的检查。 [代码]HTML MIME type[代码] 、 [代码]XML MIME type[代码]、[代码]JSON MIME type[代码] 的出现能理解,为什么 [代码]text/plain[代码] 类型也会在保护范围内? 因为 当 [代码]Content-Type[代码] 缺失的时候,响应内容 [代码]MIME type[代码] 有可能就是 [代码]text/plain[代码];且据可靠数据显示, HTML, JSON, or XML 有时候也会被标记为 [代码]text/palin[代码]。如, data.txt [代码]{ "ret_code": 0, "msg": "请求成功!", "data": [1, 2, 3, 4, 5] } [代码] server.js [代码]app.get('/file', function getState(req,res,next){ // res.type('json') res.sendfile(`${__dirname}/public/data.txt`) }) [代码] 如上代码,启动 server.js ,Chrome 浏览器访问 [代码]/file[代码] 时服务返回 [代码]data.txt[代码] 内容,尽管响应头是 [代码]Content-Type: text/plain; charset=UTF-8[代码],响应内容依旧能被识别为 [代码]json[代码]。由此, [代码]text/plain[代码] 会作为 [代码]json[代码] 的标记也是一种常见现象。如果跨域访问 [代码]/file[代码] 就会出现 CORB,验证结果如下图, [图片] 如果使用 script 跨域请求本就是 js 资源,但该资源却被打上了错误的 Content-Type,还添加了 nosiniff,会发生什么? 很多时候 [代码]script[代码] 文件被会打上 [代码]html[代码] [代码]xml[代码] [代码]json[代码] 这些 MIME 类型,如果 Chrome 浏览器直接 block,将相应内容置空,当前域下的网站便会 因为缺少 js 执行内容而不能正常运行。为避免这种情况出现,Chrome 浏览器在决定是否保护响应内容前,会先判断 script 的响应内容是否是受保护的 MIME 类型([代码]html[代码] [代码]xml[代码] [代码]json[代码] )。如果检测结果是,则启动 CORB,如果无法检测会直接返回,不启用 CORB。 对于跨域请求 js 资源,如果已经存在 nosniff 的情况下,还把 js 资源设置成了其它类型(如:json),那么必定触发 CORB 保护机制,无法返回 js 资源内容,如果此时本域站点刚好需要这个 js 资源,就 GG 了。相当于 错误的 MIME type 加上 [代码]X-Content-Type-Options: nosniff[代码] 会触发 CORB ,即使资源真正的类型同跨域标签一致。 为了最佳安全策略,建议开发者 为响应内容标记正确的 [代码]Content-Type[代码]; 使用 [代码]X-Content-Type-Options: nosniff[代码] 禁止 [代码]MIME sniffing[代码],如此,可以让浏览器不进行内容 MIME 类型嗅探,从而更简单快速地保护资源或响应返回。 控制台出现 CORB 提示时,不用担心,一般不会对页面产生本质性的影响,可以直接忽略。 Chrome 发生 CORB 保护时的提示和行为验证 虽然该部分内容属于验证类,但想了解一项知识点,仅仅简单地阅读是不够的,实际操作试验后才能获得更深的印象和理解。 环境准备 Chrome 版本: Chrome 73。 Node 服务代码 [代码]index.js[代码], [代码]const express = require('express') const path = require('path') const app = express() const port = process.argv[2] || 3002 app.get('/', function (req, res) { res.send('<p>hello world!</p>') }) app.get('/data', function (req, res) { console.log('请求正常,只是浏览器将响应数据置空') res.json({greeting: 'hello chrome!'}) }) app.listen(port, () => console.log(`app is listening at localhost:${port}`)) [代码] 配置 host [代码]127.0.0.1 a.dd.com 127.0.0.1 c.dd.com 127.0.0.1 test.pp.com [代码] 实验一:在[代码]test.pp.com[代码]中使用 [代码]img[代码] 标签跨域请求 [代码]c.dd.com[代码] 的数据,数据 MIME 类型为 json 执行 [代码]npm init[代码] 和 [代码]npm install[代码] 安装服务依赖包 执行 [代码]node index.js[代码] 启动服务 浏览器中访问 [代码]test.pp.com:3002[代码] 并打开 开发者工具 开发者工具 [代码]Elements[代码] 中插入 [代码]<img src="http://c.dd.com:3002/data"/>[代码] (选中 body 元素,再按 F2 即可进入 html 编辑模式) [图片] 查看控制台 [代码]console[代码] 即可见,CORB 提示。 [图片] 删掉 [代码]app.get('/data')[代码] 方法返回的数据 [代码]{greeting: 'hello chrome!'}[代码],即 将服务本身返回的数据本身置空,CORB 提示消失,但依旧看不到请求头 和 响应结果。 <p style=“color: red”> 实验结果:1. 使用 [代码]img[代码] 跨域请求 json 类型的数据确实会出现 CORB;2. 当服务本身返回数据为空时,CORB 提示会消失,但其行为依然保持。 </p> 实验二:在[代码]test.pp.com[代码] 中使用 [代码]script[代码] 跨域请求 [代码]c.dd.com[代码] 的数据,数据 MIME 类型为 json 补回实验一删掉的代码 [代码]{greeting: 'hello chrome!'}[代码],浏览器中访问 test.pp.com 并 打开开发者工具。 在开发者工具 [代码]console[代码] 栏中执行下方代码,即可插入 js 标签并发送跨域请求。 [代码]s = document.createElement('script') s.src = 'http://c.dd.com:3002/data' document.head.appendChild(s) [代码] 效果如图, [图片] 同 [代码]img[代码] 表现一致,出现了 CORB 提示。清除[代码]{greeting: 'hello chrome!'}[代码],将服务返回数据置空,效果同 [代码]img[代码] 方式表现一致,CROB 提示消失。其它行为也同 [代码]img[代码] 。 <p style=“color: red”> 实验结果:同 [代码]img[代码] 行为效果一模一样。 </p> 看了浏览器中 请求的响应 情况,现在看看,两次实验的 请求执行 情况, [图片] <p style=“color: red”> 可以看到尽管产生了 CORB 保护,让响应结果变为空,也隐藏了请求头,但服务请求本身始终正常接收请求并进行处理。由此,看到 CORB 后,一般可以直接忽略该提示。 </p> 如果跨域请求 [代码]http://a.dd.com:3002/data[代码] 本身发生错误,则完全无需 CORB 的保护,本身就已经不能正常返回了。因此,更不需要 CORB 的提示和行为。 实验三:在 [代码]test.pp.com[代码] 中跨域请求 [代码]c.dd.com[代码] 服务的 server.js 文件 本实验旨在验证 在某站点跨域请求 js 文件,而该 js 文件被设置了不同的 MIME 类型 和 [代码]nosniff[代码] 时,Chrome 是否会出现 CORB 。 第一步,server.js 文件 MIME 类型为默认,不设置 [代码]nosniff[代码]。[代码]c.dd.com[代码]服务代码 index.js 中添加如下代码, 代码片段一, [代码]app.get('/file', function getState(req,res,next){ res.sendfile(`${__dirname}/public/js/server.js`) }) [代码] 打开 Chrome [代码]test.pp.com[代码] 的开发者工具,并在开发者工具中执行如下代码,跨域请求 server.js 代码片段二, [代码]s = document.createElement('script') s.src = 'http://c.dd.com:3002/file' document.head.appendChild(s) [代码] 运行结果如下图, [图片] [图片] 如图所示:真实请求头被隐藏,[代码]Provisional headers are shown[代码];响应头可见;响应结果可见。 第二步,设置 MIME 类型为 [代码]json[代码],即 [代码]Content-Type: application/json; charset=utf-8[代码],不设置 [代码]nosniff[代码]。修改 index.js [代码]/file[代码] 部分代码如下, 代码片段三, [代码]app.get('/file', function getState(req,res,next){ res.type('json') res.sendfile(`${__dirname}/public/js/server.js`) }) [代码] 再次执行本实验 代码片段二,发现运行结果同第一步(即默认 MIME 类型)完全一样:真实请求头被隐藏,Provisional headers are shown;响应头可见;响应结果可见。 第三步,设置 MIME 类型为 json,即 [代码]Content-Type: application/json; charset=utf-8[代码],并添加 [代码]'X-Content-Type-Options': 'nosniff'[代码] 响应头。(如果不理解该响应头的含义,请再次阅读文顶内容嗅探相关描述) 两个响应头加在一起的意思是,明明自己是 js ,却告诉浏览器 MIME 类型是 json,还非不让浏览器使用嗅探技术修正 MIME 类型。 修改 index.js [代码]/file[代码]部分代码如下。 代码片段四, [代码]app.get('/file', function getState(req,res,next){ res.type('json') res.set({ 'X-Content-Type-Options': 'nosniff' }) res.sendfile(`${__dirname}/public/js/server.js`) }) [代码] 再次执行本实验 代码片段二,运行结果如下图, [图片] [图片] [图片] 如图所示: 跨域请求 js 文件时,如果没有设置 nosniff,甭管 MIME 类型设置了什么,都只是请求头不显示,响应头和响应结果正常显示。如果设置了 nosniff 且 MIME 类型不是 js,则会触发 CORB 保护,跨域 js 无法正常加载。 因此,如果作为跨域站点 [代码]c.dd.com[代码] 和 本域站点 [代码]test.pp.com[代码] 合作时,如果为了 减少 MIME 类型嗅探时间 加上了 [代码]nosniff[代码] 请求头,同时,需务必保证设置的 MIME 类型同 js 文件一致!否则 本域站点 无法拿到 跨域站点 的 js 资源数据! ----------------- 关于 CORB , Chrome 表现和行为验证结束 ------------------- 原文地址:http://www.yaoyanhuo.com/blog/corb 参考内容 CORB 行为官方说明:https://www.chromium.org/Home/chromium-security/corb-for-developers CORB Explainer:https://chromium.googlesource.com/chromium/src/+/master/services/network/cross_origin_read_blocking_explainer.md speculative side-channel attack techniques: https://security.googleblog.com/2018/01/todays-cpu-vulnerability-what-you-need.html Chrome浏览器安全新功能 网站隔离:https://www.trustauth.cn/wiki/26052.html 30 分钟理解 CORB 是什么:https://www.cnblogs.com/oneasdf/p/9525490.html X-Content-Type-Options:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Content-Type-Options 浏览器 MIME 类型嗅探:https://www.keycdn.com/support/what-is-mime-sniffing 延伸阅读,曾经 IE 的一个内容嗅探技术漏洞:http://www.safebase.cn/article-131906-1.html 浏览器工作原理:https://www.infoq.cn/article/CS9-WZQlNR5h05HHDo1b 给程序员解释 Spectre 和 Meltdown 漏洞:https://zhuanlan.zhihu.com/p/32784852 旁道攻击:https://zh.wikipedia.org/wiki/旁路攻击 V8 引擎:https://zhuanlan.zhihu.com/p/27628685 一些还在讨论中的 CORB 行为:https://github.com/whatwg/fetch/issues?utf8=✓&q=is%3Aissue+CORB+ fetch API:https://developers.google.com/web/updates/2015/03/introduction-to-fetch
2019-04-29