Valine 是一款款式精美,部署简略的评论零碎,第一次接触便被它精美的款式,无服务端的个性给吸引了。它最大的特色是基于 LeanCloud 间接在前端进行数据库操作而无需服务端,极大的缩减了部署流程,仅须要在动态页引入 Valine SDK 即可。
???????? 初识 Valine
以下是 Valine 官网提供的疾速部署脚本,其中 appId
和 appKey
是你在 LeanCloud 上创立利用后对应的利用密钥。也正是基于这对密钥,Valine 在外部调用了 LeanCloud SDK 进行数据的获取,最终将数据渲染在 #vcomments
这个 DOM 上。这便是 Valine 的大略原理。
<head>
..
<script src='//unpkg.com/valine/dist/Valine.min.js'></script>
...
</head>
<body>
...
<div id="vcomments"></div>
<script>
new Valine({
el: '#vcomments',
appId: 'Your appId',
appKey: 'Your appKey'
})
</script>
</body>
有同学可能会有疑难了,appId
和 appKey
都间接写在前端了,那岂不是谁都能够批改数据了?这就须要牵扯到 LeanCloud 的数据安全问题了,官网专门写了篇文档《数据和平安》来阐明这个问题。简略的了解就是针对数据设置用户的读写权限,确保正确的人对数据有且仅有正确的权限来保证数据的平安。
乍听一下,保障用户数据只读的话,感觉还是挺平安的。可事实真的如此么,让咱们持续来看看。
????♂️ Valine 的问题
???? 浏览统计篡改
Valien 1.2.0 减少了文章浏览统计的性能,用户拜访页面就会在后盾 Counter 表中依据 url 记录拜访次数。因为每次拜访页面都须要更新数据,所以在权限上必须设置成可写,能力进行后续的字段更新。这样就造成了一个问题,实际上该条数据是能够被更新成任意值的。感兴趣的同学能够关上 https://valine.js.org/visitor… 官网页面后进入控制台输出以下代码试试。试完了记得把数改回去哈~
const counter = new AV.Query('Counter');
const resp = await counter.equalTo('url', '/visitor.html').find();
resp[0].set('time', -100001).save();
location.reload();
能够看到该页面的拜访统计被设置成了 -100000
了。这个问题惟一值得庆幸的是 time
字段的值是 Number 类型的,其它的值都无奈插入。如果是字符串类型的话就是一个 XSS 破绽了。
该问题有一个解决办法,就是不应用次数累加的存储形式。更改为每次拜访都存储一条只读的拜访记录,读取的时候应用 count()
办法进行统计。这样所有数据都是只读的,就不存在篡改的问题了。这种解决方案惟一的问题就是数据量会比拟大,对查问会造成肯定压力。当然如果是在基于原数据不变的状况下,只能是减少一层服务端来做批改权限的隔离了。
???? XSS 平安
从很早的版本开始就有用户报告了 Valine 的 XSS 问题,社区也在应用各种办法在修复这些问题。包含减少验证码,前端 XSS 过滤等形式。不过起初作者才明确,前端的所有验证都只能防小人,所以把验证码之类的限度去除了。
现有的逻辑里,前端公布评论的时候会将 Markdown 转换成 HTML 而后走一下前端的一个 XSS 过滤办法最初提交到 LeanCloud 中。从 LeanCloud 中拿到数据之后因为是 HTML 直接插入进行显示即可。很显著,这个流程是存在问题的。只有间接提交的是 HTML 而且拿到 HTML 之后间接进行展现的话,XSS 从根本上是无奈铲除的。
那有没有基本的解决办法?其实是有的。针对存储型的 XSS 攻打,咱们能够应用本义编码进行解决。只有效仿早前 BBCode 的做法,提交到数据库的是 Markdown 内容。前端读取到内容对所有 HTML 进行编码后再进行 Markdown 转换后展现。
function encodeForHTML(str){return ('' + str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g,'"')
.replace(/'/g,''')
.replace(/\//g, '/');
};
因为 Serverless 攻击者是能够中转存储阶段,所以数据存储之前的所有防备是有效的,只能在读取展现过程解决。因为所有的 HTML 本义后无奈解析,Markdown 相当于咱们依据自定义的语法解析成 HTML,保障转换后的 HTML 没有被插入的机会。
不过这个办法存在一个问题,那就是对老数据存在不兼容。因为这相当于批改了存储和展现的规定,而之前始终存储的都是 HTML 内容,修复后之前的数据将无奈展现 HTML 款式。而为了能在存储的还是 HTML 状况下躲避 XSS 平安问题,惟一的方法就是减少服务端中间层。存储阶段减少一道阀门,将本义阶段提前至存储阶段,保障新老数据的通用。
???? 隐衷泄露
说完了存储的问题,咱们再来看看读取的问题。攻击者除了能够中转存储,也能够中转读取,当一个数据库的字段凋谢了读取权限后,相当于该字段的内容对攻击者是通明的。
在评论数据中,有两个字段是用户比拟敏感的数据,别离是 IP 和邮箱。灯大甚至专门写了一篇文章来批评该问题《请马上停止使用 Valine.js 评论零碎,除非它修复了用户隐衷泄露问题》。甚至掘金社区在晚期应用 LeanCloud 的时候也暴出过泄露用户手机号的平安问题。
<p>
<img src=”https://p1.ssl.qhimg.com/t0133ebd7694320f80f.png” width=”50%”/>
</p>
为了躲避这个问题,Valine 作者减少了 recordIP
配置用来设置是否容许记录用户 IP。因为是 Serverless,目前能想到的也只是不存储的形式解决了。不过该配置项会存在一个问题,就是该配置项的配置权在网站,隐衷的问题是评论者遇到的,也就是说评论者是无权治理本人的隐衷的。
除了这个矛盾点之外,还有就是邮箱的问题。邮箱实质上只须要返回 md5 用来获取 Gravatar 头像即可。然而因为无服务端的限度,只能返回原始内容由前端计算。而邮箱咱们又须要获取到原始值,不便做评论回复邮件告诉性能。所以咱们也不能不存储,或者存储 md5 后的值。
该问题的解决方案只能是减少一层服务端,通过服务端过滤敏感信息解决这个问题。
???? Waline!
基于以上起因,咱们发现只有减少一层服务端中间层能力很好的解决 Valine 的平安问题,所以 Waline 横空出世了!Waline 与 Valine 最大的不同就是减少了服务端中间层,解决 Valine 裸露进去的平安问题。同时基于服务端的个性,提供了 邮件告诉 、 微信告诉 、 评论后盾治理 、LeanCloud, MySQL, MongoDB, SQLite, PostgreSQL 多存储服务反对 等诸多个性。不仅如此,Waline 默认应用 Vercel 部署,实现完全免费部署!
Waline 最后的指标仅仅是为 Valine 减少上服务端中间层。然而因为作者不知为何从 1.4.0
版本开始只推送编译后的文件到 Github 仓库中,源文件进行更新。导致我只能连带前端也实现一遍。当然前端的很多代码和逻辑为了和 Valine 的配置保持一致都有参考 Valine,甚至在名字上,我也是从 Valine 上衍生的,让大家能明确这个我的项目是 Valine 的衍生版。
???? 后记
Serverless 的概念火了十分多年,但技术没有银弹,咱们在看到它的长处的同时,也要正视它所带来的问题。而 Serverless 本人可能也意识到了这个问题,从晚期的 无服务端 缓缓转向了 无服务器,更偏差 BaaS 了。不过因为 Valine 没有凋谢源代码,所以下面说的一些问题和解决办法只能期待作者本人发现这件事了。