走火入魔做产品

在业余时间一直开发一款小程序应用,陆陆续续也有大半年的时间。半年时间来,我的感受是产品和开发不同,开发侧重与实现与做到,产品注重是做好。

做好相对于做到没有一个明确的目标,因此需要反复迭代。半年以来设计了很多 UX/UI,过了一段时间觉得很不好用,又推翻重来。这种自虐的感觉真的很难受。

UX/UI 到组件封装复用其实每个过程都是渐进迭代,过程很曲折,但是想到也算慢慢接近目标,也就宽慰了。放上目前的阶段性成果留作纪念。

继续阅读走火入魔做产品

HTTPS 理解关键问题

Photo by stefan moertl on Unsplash

防止中间人攻击

为了防止中间人拦截攻击,对于采用证书机构来加密服务器端公钥。这样中间人假如拦截了 HTTPS 流量,并且使用自己生成公私钥对,使用自己的私钥加密数据发给客户端,那么客户端无法使用机构提供的服务器公钥对密文进行解密,从而导致协议出错。

防止中间人窥探

由于在握手阶段是协议出一个双方都可以对称密钥,客户端采用机构认证的服务器公钥对协商好的对称密钥进行加密。这样即使中间人劫持到,由于没有服务器私钥所以无法对这段密文进行解密。

证书防篡改

证书颁发机构将服务器公钥等一系列信息首先做摘要算法,然后使用 CA 机构的私钥(非服务器公钥)对服务器公钥信息进行加密,作为数字签名,在客户端需要使用机构的公钥对证书内容进行解密。

继续阅读HTTPS 理解关键问题

z-index 层叠的一些细节

最近要把一个筛选的功能做组件化,涉及到了z-index 和定位的一些细节。z-index 的最大特点是它只有作用于定位的组件之上才有效果,比如 relative,absolute 或者 fixed。

其中 relative 很特殊,它不会脱离文档流,因此一旦 relative 定位的组件被渲染,会把父结点撑开,然后不管你怎么移动 transform 那个坑都会在。

相反 absolute 和 fixed 都脱离了文档流,因此它不会把父组件撑开,也不会留一个空白坑。其中 fixed 和 fixed 的图层处于同一维度。同一维度意味着父组件的范围可以限制子组件的表示范围,假如父组件写了 overflow:hidden,那么子组件也不会显示出来。

absolute 和其最近定位的父结点处于同一维度。同一纬度在上一段落已经得到解释。

最后,微信小程序组件中使用 fixed 定位很奇怪,模拟器可以但是 IOS 端不行。

Throttle 与 Debounce 使用场景

Photo by Cristina Gottardi on Unsplash

不管什么技术概念,都要落到实际使用场景比较容易理解。Throttle 和 Debounce 也是一样,这里我分别解释一下。

单位时间只做一次使用 Throttle

单位时间只做一次使用 Throttle。PC 上有些操作在小程序真机上延迟特别明显,比如点击按钮展开菜单的动画,假如用户点击频率过高就会导致小程序显示异常。为了解决这个问题,需要在单位时间比如 500ms 之内对用户点击只响应一次,这样可以减少动画调用的频率。

等待操作不再发生使用 Debounce

等待操作不再发生使用 Debounce。比如我们搜索根据关键词从实时后台拿到商品名称,我们不知道用户什么时候结束输入。假如每监听一个关键字就去后台拿数据会导致后端压力比较大。那么再前端就可以做一个 Debounce。当用户键入一个关键字后等待 500ms,若这 500ms 之内没有新的输入,当作用户结束输入,然后再去后台请求数据,可以减轻后端压力。

IOS 视频播放黑屏问题解析

IOS 下浏览器播放本网站的视频会出现黑屏。假如在浏览器中直接访问视频文件的地址也出现黑屏,那么你就需要检查一下(通过 POSTMAN 等 HTTP 工具)后端有没有对 Range 请求头做出响应。

产生原因

IOS 下浏览器(Chrome,Safari)在请求视频流时,会默认在 HTTP 请求头中加入 Range 来向服务器请求对应的视频片段。参考这个在线视频链接,IOS 浏览器可以完美播放。使用 Fiddler 在 IOS 下抓包可以看到,在请求这个资源时(单单针对这个视频),手机发出了二次请求。

继续阅读IOS 视频播放黑屏问题解析

NGINX 反向代理百度 API

NGINX 反向代理到本机服务做过不少,但很少思考参数的意义。技术债的隐患往往会在特定时候爆发。为了解决如题的问题,我直接把配置改改拿来使用,却发现行不通。

问题

问题在于对于请求头 Host 属性的设置问题。Host 表示的是请求服务器的地址。在转发的时候,可以通过 proxy_set _header 来设置目的地址。

对于转发到本机服务,可以使用 $http_host 来指定本机作为目的地址。但是对于若想转发到非本机服务,Host 需要设置为目的服务所在的主机 IP 或者域名。

在如题所描述的场景中,我需要把请求转发到 vop.baidu.com 这个域名下的 server_api 接口。该接口属于非服务器本机服务,故需要替换 $http_host 为域名 vop.baidu.com。(场景描述 localhost/server_api => vop.baidu.com/server_api)

继续阅读NGINX 反向代理百度 API

使用 Babel Webpack 打造库

Photo by Lê Tân on Unsplash

本人工作后一直采用自顶向下的方法自学编程知识。初期的学习曲线就是直接上手框架加第三方类库,加之这些工具都比较成熟,自带转译(Babel)和打包工具(Webpack),故这两类工具的使用较少。今天在编写自己的类库后发现,使用这两种工具还是有很多问题,故记录分享如下。

工具链逻辑

转译(transpile)。Babel 转译工具的作用是将可在最新的 JavaScript 语法转化为可被旧浏览器运行的兼容代码。转译工具不会处理模块之间的依赖关系。Babel 默认会把 import export 等转译为 require 和 module.exports。

打包。在撰写本文的 2020 年,浏览器对 JavaScript 模块化的支持还是很糟糕,因此需要单独的打包工具来将各个模块聚合在一个文件中。而聚合的线索就是转译工具生成的 require 或者 import 语法。

继续阅读使用 Babel Webpack 打造库

Web 安全之浅见

Photo by Ozzie Stern on Unsplash

CSRF(跨域请求攻击) 与 CORS

一旦允许站点跨域请求,就会有 CSRF 问题的出现。CSRF 是指攻击者通过伪造页面的方式,诱导用户点击被伪造的页面,然后在页面中注入目标页面的 URL。一旦用户点击 URL,用户的 Cookie 就会被带上在服务端进行验证。若服务端没有防范非法跨域请求的能力,那么就会导致后台数据在用户不知情的情况下被恶意修改。

庆幸的是,现代浏览器都对非同源请求做了限制,若要启动非同源请求需要,后端服务程序会根据 CORS 对发起的请求进行过滤。只有后端程序允许,才能对跨域请求予以“放行”。

但是值得注意的是,即使服务程序中使用 CORS 来控制 ORIGION 和 REFERER,也无法规避 CSRF 的发生。因为 CORS 不能对表单请求进行预检,同时预检的信息其实也是一种请求,若在预检请求中带上恶意代码也容易造成攻击。

当然防范 CSRF 的方法还有很多,比如后端渲染的页面可以直接在表单上注入随机的 CSRF TOKEN 来校验每一次提交的请求是否合法等。

XSS(跨站脚本攻击)

XSS 主要是指黑客把恶意脚本注入到 URL中,并由后端程序把恶意代码当做参数渲染在页面上返回给浏览器进行执行的一种攻击方式。细分下来主要包含三种不同的形式。

反射型 XSS 。黑客通过电子邮件或者其他社工形式把一个包含恶意代码的 URL 发送给受害者,诱使其点击。后端程序把 URL 上携带的恶意代码当做参数取出并且渲染在页面上。这样一旦用户点击这个 URL 时,浏览器就会执行包含恶意代码的页面。

DOM 型 XSS。和发射型 XSS 一样,黑客通过电子邮件或者其他社工形式把一个包含恶意代码的 URL 发送给受害者,诱使其点击。不同的是,后端程序把 URL 上携带的恶意代码当做参数取出,并赋值给某个脚本变量,返回给受害者,在浏览器端用脚本将恶意代码渲染在页面上并执行。可以看到和发射型 XSS 不同的地方在于恶意代码渲染的时机。

存储型 XSS 。是指黑客精心构造一个包含恶意代码的 URL发送给服务器。后端服务器没有验证 URL 传参中的恶意脚本部分,而是直接把这部分代码存储在数据库中。一旦当其他用户浏览该网站的功能页面,后端程序会把恶意代码从后端数据库中取出并渲染在页面上,从而导致攻击发生。

XSS 与 CSRF

XSS 与 CSRF 的最大区别在于, XSS 是由受害者直接访问目标站点,没有涉及到跨域的问题。漏洞的产生在于服务端没有对URL 中的参数进行校验,从而页面包含恶意代码。而 CSRF 是由受害者无意间向目标服务器发起跨域请求,并使用浏览器存储的 Cookie 饶过验证。漏洞的产生在于后端程序未对跨域的请求进行限制。

参考链接

Using CORS policies to implement CSRF protection

Cross-site scripting

DOM-based XSS 与存储性 XSS、反射型 XSS 有什么区别?

Base64 编码与 JSON 交换

JSON 是常用的数据交换格式。但是由于 JSON 本身并不支持文件图片等形式的附加数据,想要直接借助 JSON 来实现文件的传输非常困难。一般的做法是,首先需要使用 Base64 编码将这些数据从二进制流编码成为字符形式,再封装成 JSON 格式进行传输。

本文首先讨论 Base64 编码大致原理,然后引入 MIME 类型的简单介绍,最后通过 Web API 来实现文件的自动编码实现文件图片等内容的 JSON 传输。

继续阅读Base64 编码与 JSON 交换