• 首页
  • 归档
  • 关于
  • 微博
  • GITHUB
  • Urlencode踩坑日记

    Mar 31, 2020

    Urlencode又称百分号编码,是一种很常用的编码方式,作为前端工程师,少不了与它要打交道。不管是GET请求发送参数,还是POST请求发送body,都少不了要使用Urlencode来编码。

    而Urlencode的编码规则又特别简单:取出字符的ASCII码,转成16进制,然后前面加上百分号即可。如果是多字节的字符,则取出每一字节,按照同样的规则进行转换即可。例如问号?的ASCII码为63,转换为16进制为3F,所以%3F即为?进行Urlencode编码的结果。

    背景

    项目需要对外提供HTTP API接口,因此接口鉴权成为一个很重要的内容。为了确保安全,防止中间人篡改数据或进行重放攻击,双方约定的私钥不可以直接出现在请求中,因此采用请求签名的方式来鉴权。

    双方约定appKey和appSecret,其中appKey用于识别请求对象,appSecret用于请求签名。具体的方案如下:

    1. 客户端按照当前时间生成时间戳timestamp和随机数nonce
    2. 客户端按照指定的规则将HTTP请求的queryString和POST的body进行编码,得到一个字符串data
    3. 将timestamp、nonce和data按规则拼接,然后使用appSecret计算签名
    4. 将appKey、timestamp、nonce和签名一起随请求发出

    服务端在接到请求后将使用获得的数据和appSecret重新计算签名,然后判断与客户端给出的签名值是否一致,如果不一致则鉴权不通过。

    这一套鉴权机制可以有效防御一些攻击手段:

    • 使用了时间戳,可以避免过期请求被重发
    • 使用了随机数,可以避免请求被短时间重复发送
    • 签名数据包含了完整的时间戳、随机数和请求数据,保证服务端收到的确实是客户端发送的数据,避免被拦截修改
    • 签名的密钥是双方协商好的,避免请求伪造

    踩坑

    在上面的鉴权过程中,一个非常重要的点就是第2点,即将请求的queryString和POST的body进行编码,得到一个字符串。

    因为GET和POST请求中,数据都会被Urlencode编码,因此很容易想到,我们也使用Urlencode来进行这个鉴权前的编码过程。

    于是坑就这么不期而遇了。

    ...more
  • 使用Rebase操作抹去Git仓库中的敏感信息

    Nov 29, 2019

    使用Git的时候,有时候会碰到需要从Git仓库中永久“抹除”某些敏感信息的情况。例如不小心提交了密码之类的信息到仓库,此时只抹掉这些信息重新提交是没有用的,因为其他人仍然可以通过Git历史看到这些敏感信息。因此需要一种方法将这些信息彻底从仓库中抹去。

    如果去网上搜索的话,能很容易找到使用branch-filter来处理的方法,例如

    1
    git filter-branch --tree-filter "find . -name '*.*' -exec sed -i '' -e 's/OLDSTRING/NEWSTRING/g' {} \;" -f

    写法有很多种,但是思路都差不多,就是遍历一遍所有的提交,对这些提交执行指定的命令(例如用sed替换指定的内容,或者移除相关文件),然后重新生成新的提交和分支。

    不过这种思路对于我来说却不太受用,原因有几个:

    1. 命令行掌握不太好,看到这种命令都不太认识,完全不敢直接放在项目中去跑
    2. 直接进行字符串级别的替换,在某些情况下不够用,例如想通过更复杂的编辑手段(新增文本、修改文本、删除文本同时操作)抹除敏感信息
    3. 直接对整个仓库/整个文件进行字符串级别的替换还是有些不放心,毕竟要修改的部分是明确的,却无法明确地指定这个命令只修改这一部分信息

    那怎么办呢?其实在这种场景下,也可以尝试使用git rebase来解决问题。

    rebase是干什么的

    rebase顾名思义,就是重新确定一个提交(一个分支)的“基”,这个“基”就是指它的祖先元素。具体的做法是,首先将提交退回到“基”所在的点,然后将之前做过的提交在这个“基”的基础上重复做一遍。相当于修改了当前分支衍生出来的基础,因此中文也被译为“变基”。

    ...more
  • Sequelize的一些小技巧

    Nov 10, 2019

    Sequelize.js是一个用于Node.js的数据库ORM库,支持Postgres、MySQL/MariaDB、SQLite、SQL Server等引擎。

    本文记录一些团队在使用Sequelize过程中积累的经验教训。

    介绍

    ORM即Object Relational Mapping,中文叫“对象关系映射”。简单地说就是可以将数据库的各种对象(表、字段)及关系映射为程序语言的对象和关系,从而使开发者不需要直接操作数据库,转而操作对象即可。

    例如,将表user映射为模型User后,从数据库中查询id为1的用户就可以直接调用findOne()方法:

    1
    2
    3
    4
    5
    const user = await User.findOne({
    where: {
    id: 1
    }
    });

    这样做会带来几个明显的好处:

    1. 降低开发难度:ORM都有完善的文档,几乎所有的操作只需要按文档调用指定方法即可,不需要自己拼接SQL
    2. 提升安全性:ORM会处理好SQL注入问题,不需要开发者关注
    3. 降低封装复杂度:公共逻辑可以基于ORM封装,非常方便

    下文不区分“模型”和“Model”,均指Sequelize中与数据表对应的数据模型。

    ...more
  • 轻松迁移博客到AMP

    Aug 29, 2017

    AMP 全称 Accelerated Mobile Pages ,是由 Google 提出的一种移动端页面的规范。相比普通 HTML 而言,最大的特点是对页面中可用元素进行了严格的限制,以确保高性能。此外,Google 还对 AMP 页面提供了高速缓存,如果从 Google 搜索中打开 AMP 页面,速度非常快,几乎是秒开。

    前几天将我的博客完全迁移到了 AMP,在此也做一个记录。

    作为单独页面存在的 AMP

    在很长一段时间内,我都以为 AMP 只适用于移动端某些特殊场景,至少文章页应该是适用的,于是自然而然就想到了博客应该是非常适合 AMP 的场景。因为我的博客使用的是著名的静态博客程序 Hexo,所以也就很自然地想到了,会不会有人已经写好了 Hexo 的 AMP 插件?搜了一下,果然没有失望,找到了一个名为 hexo-generator-amp的插件。

    这个插件不会修改已有的文章页面,而是会为文章页面再生成一个合法的 AMP 页面。这两个页面可以互相引用,表示一个是普通页面,一个是 AMP 页面。这种方式也是 Google 搜索等平台认可的 AMP 生成方式。

    按照插件的文档,使用起来还是比较简单的,具体的方式就不写了,直接参考文档即可。有几个值得注意的点:

    1. 一定要修改文章页的模板,添加link[rel=amphtml]链接,要不然搜索无法找到 AMP 页面
    2. AMP 页面会自动在head中添加canonical链接回原有的文章页

    这个插件支持自己修改模板。鉴于我对它的样式并不是很满意,没有修改的欲望,于是也就没有去改它。如果你需要修改 AMP 模板的话,可以在网址中添加#development=1,然后在控制台中查看 AMP 验证结果。

    ...more
  • 一些比较新的前端安全相关的技术点

    May 18, 2017

    本文为《Web前后端漏洞分析与防御》课程的配套文章。早年在慕课社区发布,现补发在博客上。

    一说到安全,大家总会特别敏感,尤其是有相当部分的前端开发者并不了解安全相关的知识,颇有谈虎色变的感觉。具体到前端安全这个话题呢,又有些说不清道不明,因为大部分的防御方案,总少不了后端的参与,也有开发者慢慢觉得好像安全都应该由后端来关注了。

    其实不然,起码 XSS CSRF 这一类的安全问题前端是一定要了解它们的原理和防御方法的。从防御方法上来说,XSS 和 CSRF 的防御在业界都有比较成熟的方案了。本文将记录一些比较新的防御方案,可能有一些比较老的书籍或者文章中不会提及这些方法。

    ...more
  • 【译】nginx是如何处理请求的

    May 5, 2017

    本文首发于富途web开发团队博客 https://futu.im/posts/2017-05-05-how-nginx-processes-a-request/

    Nginx首先需要确定由哪个server来处理请求。我们看一个简单的配置文件,在*:80端口上包含了三个虚拟主机(server):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    server {
    listen 80;
    server_name example.org www.example.org;
    ...
    }

    server {
    listen 80;
    server_name example.net www.example.net;
    ...
    }

    server {
    listen 80;
    server_name example.com www.example.com;
    ...
    }

    在这个配置下,Nginx只通过请求的Host头来决定路由到哪个server。如果Host头的值跟所有的server的server_name都不匹配,或者请求中没有包含这个阔大,Nginx会使用这个端口上的默认server。在这个配置文件中,默认server是指第一个,这正是Nginx标准的默认行为。默认server也可以通过配置显示指定,只需要在listen指令值中加上default_server参数即可。

    ...more
  • ES2015 WeakMap的学习和使用

    Feb 27, 2017

    ES2015(ES6)中新增了几种数据类型,包括Map WeakMap Set WeakSet等。其中Map可以与我们熟悉的对象Object进行对照,他们的功能都是提供一个键值对集合,主要的区别在于Object的key只能是字符串,而Map的key可以是任意类型。关于Map的大致用法可以参考MDN,我在前一篇文章《也谈JavaScript数组去重》中也有提及。

    今天要讨论的主角是WeakMap。

    按照MDN上的说明

    WeakMap 对象是键/值对的集合,且其中的键是弱引用的。其键只能是对象,而值则可以是任意的。

    从这段描述来看,我们可以大致推断出,WeakMap与Map的主要区别在于两点:

    1. WeakMap对key的引用是弱引用
    2. WeakMap的key只能是对象

    这两点意味着什么呢?反正我第一眼看到的时候不是拉格良日懵就是三元二次懵的状态。于是围绕WeakMap去查阅了一些资料,渐渐地有了一些更深入的认识,记录成本文。

    ...more
  • 也谈JavaScript数组去重

    Jan 5, 2017

    JavaScript的数组去重是一个老生常谈的话题了。随便搜一搜就能找到非常多不同版本的解法。

    昨天在微博上看到一篇文章,也写数组去重,主要推崇的方法是将利用数组元素当作对象key来去重。我在微博转发了“用对象key去重不是个好办法…”然后作者问什么才是推荐的方法。

    细想一下,这样一个看似简单的需求,如果要做到完备,涉及的知识和需要注意的地方着实不少,于是诞生此文。

    定义重复(相等)

    要去重,首先得定义,什么叫作“重复”,即具体到代码而言,两个数据在什么情况下可以算是相等的。这并不是一个很容易的问题。

    对于原始值而言,我们很容易想到1和1是相等的,'1'和'1'也是相等的。那么,1和'1'是相等的么?

    如果这个问题还好说,只要回答“是”或者“不是”即可。那么下面这些情况就没那么容易了。

    ...more
  • 如何使用web录制视频

    Sep 25, 2016

    本文首发于富途web开发团队博客,原文链接https://futu.im/posts/capture-video-on-web/。

    最近在某个需求的评审会上,产品同学脑洞大开,提出了使用web录制视频的想法。并兴致勃勃地说“看,XXX网站可以调用摄像头,还能聊天呢!”本着负(Zhuang)责(Bi)的原则,我们也对该方案做了认真的预研。大致结论:

    1. 非实时录制时(文件上传框),兼容性相对较好,且API和性能稳定
    2. 实时录制视频在Chrome for Android中可行,其它机型和浏览器均不可使用。考虑到相关标准仍处于不稳定状态,不建议在产品中使用
    3. 微信有非公开接口可以调用实时视频录制(微证券使用)

    详细方案如下:

    ...more
  • Node.js中低成本实现错误告警

    Jan 27, 2016

    相比其他语言(特指PHP)而言,Node.js应用更需要关注出错信息,因为一旦处理不慎,就会导致应用crash。

    一种偷懒的方法是使用PM2之类的进程管理软件来启动Node.js进程,从而达到出错crash后自动重新启动应用的目的。

    当然更好的办法则是手工捕获错误,然后进行适当的处理,防止应用产生未被接住的错误导致crash。

    在捕获到Node.js产生的错误后,下一步自然是记录到错误日志中,以便日后可以进行分析,并针对性地排查修改。本文要说的,即是对错误日志的处理方式之一——告警。

    告警是运维工作中非常重要的一个环节,它能让开发者(维护者)及时获知应用出错状态和详情,及早介入处理,将线上故障的影响降低到最低。而要实现告警功能,则需要从两方面入手,一方面是对错误信息进行集中处理(分类、分级、合并、限流等),另一方面需要将这些错误信息及时推送出去。

    ...more
NEXT

© 2012 - 2021 TooBug, powered by Hexo and hexo-theme-apollo.

粤ICP备15078043号-3