赞
踩
我们在忙着“看热闹”或者“”升级版本”的同时,静下心来想:真的有理解这个漏洞产生的原因,明白漏洞修复背后的原理了吗?
这篇短文将从原理层面分析这一事件,相信“小白”读者会有所收获。
其实漏洞很简单,举一个例子:lodash 中 defaultsDeep 方法,
_.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } })
输出:
{ 'a': { 'b': 2, 'c': 3 } }
如上例,该方法:
分配来源对象(该方法的第二个参数)的可枚举属性到目标对象(该方法的第一个参数)所有解析为 undefined 的属性上
这样的操作存在的隐患:
const payload = '{"constructor": {"prototype": {"toString": true}}}' _.defaultsDeep({}, JSON.parse(payload))
如此一来,就触发了原型污染。原型污染是指:
攻击者通过某种手段修改 JavaScript 对象的原型(prototype)
对应上例,Object.prototype.toString
就会非常不安全了。
理解原型污染,需要读者理解 JavaScript 当中的原型、原型链的知识。我们先来看一个例子:
// person 是一个简单的 JavaScript 对象 let person = {name: 'lucas'} // 输出 lucas console.log(person.name) // 修改 person 的原型 person.__proto__.name = 'messi' // 由于原型链顺序查找的原因,person.name 仍然是 lucas console.log(person.name) // 再创建一个空的 person2 对象 let person2 = {} // 查看 person2.name,输出 messi console.log(person2.name)
把危害扩大化:
let person = {name: 'lucas'} console.log(person.name) person.__proto__.toString = () => {alert('evil')} console.log(person.name) let person2 = {} console.log(person2.toString())
这段代码执行将会 alert 出 evil 文字。同时 Object.prototype.toString
这个方法会在隐式转换以及类型判断中经常被用到:
Object.prototype.toString 方法返回一个表示该对象的字符串
每个对象都有一个 toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回 [object type]
,其中 type 是对象的类型。
如果 Object 原型上的 toString 被污染,后果可想而知。以此为例,可见 lodash 这次漏洞算是比较严重了。
由上分析,我们知道原型污染并不是什么新鲜的漏洞,它“随时可见”,“随处可见”。在 Nullcon HackIM 比赛中就有一个类似的 hack 题目:
'use strict'; const express = require('express'); const bodyParser = require('body-parser') const cookieParser = require('cookie-parser'); const path = require('path'); const isObject = obj => obj && obj.constructor && obj.constructor === Object; function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a } function clone(a) {return merge({}, a); } // Constants const PORT = 8080; const HOST = '0.0.0.0'; const admin = {}; // App const app = express(); app.use(bodyParser.json()) app.use(cookieParser()); app.use('/', express.static(path.join(__dirname, 'views'))); app.post('/signup', (req, res) => {var body = JSON.parse(JSON.stringify(req.body));var copybody = clone(body)if (copybody.name) {res.cookie('name', copybody.name).json({"done": "cookie set"});} else {res.json({"error": "cookie not set"})} }); app.get('/getFlag', (req, res) => {var аdmin = JSON.parse(JSON.stringify(req.cookies))if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");} }); app.listen(PORT, HOST); console.log(`Running on http://${HOST}:${PORT}`);
这段代码的漏洞就在于 merge 函数上,我们可以这样攻击:
curl -vv --header 'Content-type: application/json' -d '{"__proto__": {"admin": 1}}' 'http://0.0.0.0:4000/signup'; curl -vv 'http://0.0.0.0:4000/getFlag'
首先请求 /signup
接口,在 NodeJS 服务中,我们调用了有漏洞的 merge
方法,并通过 __proto__
为 Object.prototype
(因为 {}.__proto__ === Object.prototype
) 添加上一个新的属性 admin
,且值为 1。
再次请求 getFlag
接口,条件语句 admin.аdmin == 1
为 true
,服务被攻击。
攻击案例出自:Prototype pollution attacks in NodeJS applications
这样的漏洞在 jQuery $.extend
中也经常见到:
对于 jQuery:如果担心安全问题,建议升级至最新版本 jQuery 3.4.0,如果还在使用 jQuery 的 1.x 和 2.x 版本,那么你的应用程序和网站仍有可能遭受攻击。
了解了漏洞潜在问题以及攻击手段,那么如何防范呢?
在 lodash “连夜”发版的修复中:
我们可以清晰的看到,在遍历 merge 时,当遇见 constructor
以及 __proto__
敏感属性,则退出程序。
那么作为业务开发者,我们需要注意些什么,防止攻击出现呢?总结一下有:
冻结 Object.prototype
,使原型不能扩充属性
我们可以采用 Object.freeze
达到目的:
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
看代码:
Object.freeze(Object.prototype); Object.prototype.toString = 'evil' consoel.log(Object.prototype.toString) ƒ toString() { [native code] }
对比:
Object.prototype.toString = 'evil' console.log(Object.prototype.toString) "evil"
建立 JSON schema 在解析用户输入内容是,通过 JSON schema 过滤敏感键名。* 规避不安全的递归性合并 这一点类似 lodash 修复手段,完善了合并操作的安全性,对敏感键名跳过处理* 使用无原型对象 在创建对象时,不采用字面量方式,而是使用 Object.create(null)
:> Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
Object.create(null)
的返回值不会链接到 Object.prototype
:
let foo = Object.create(null) console.log(foo.__proto__) // undefined
这样一来,无论如何扩充对象,都不会干扰到原型了。
采用新的 Map 数据类型,代替 Object 类型
Map 对象保存键/值对,是键/值对的集合。任何值(对象或者原始值)都可以作为一个键或一个值。使用 Map 数据结构,不会存在 Object 原型污染状况。
这里总结一下 Map 和 Object 不同点::
Object 的键只支持 String 或者 Symbols 两种类型,Map 的键可以是任意值,包括函数、对象、基本类型* Map 中的键值是有序的,而 Object 中的键则不是* 具体 API 上的差异:比如,通过 size 属性直接获取一个 Map 的键值对个数,而 Object 的键值无法获取;再比如迭代一个 Map 和 Object 差异也比较明显* Map 在频繁增删键值对的场景下会有些性能优势补充:V8,chromium 的小机灵
同样存在风险的是我们常用的 JSON.parse
方法,但是如果你运行:
JSON.parse('{ "a":1, "__proto__": { "b": 2 }}')
你会发现返回的结果如图:
复写 Object.prototype
失败了,__proto__
属性还是我们熟悉的那个有安全感的 __proto__
。这是因为:
V8 ignores keys named proto in JSON.parse
这个相关讨论 Doug Crockford,Brendan Eich,反正 chromium 和 JS 发明人讨论过很多次。相关 issue 和 PR:
相关 ES 语言设计的讨论:ES 语言设计的讨论:proto-and-json
在上面链接中,你能发现 JavaScript 发明人等一众大佬哦~
总之你可以记住,V8 默认使用 JSON.parse
时候会忽略 __proto__
,原因当然是之前分析的安全性了。
通过分析 lodash 的漏洞,以及解决方案,我们了解了原型污染的方方面面。涉及到的知识点包括但不限于:
Object 原型
原型、原型链
NodeJS 相关问题
Object.create 方法
Object.freeze 方法
Map 数据结构
深拷贝
以及其他问题
这么来看,全是基础知识。也正是基础,构成了前端知识体系的方方面面。
这篇文章灵感来源于我们的群中的相关讨论:
这是一个什么群呢?咳咳。。。到了我的广告时间了,这是我的一个课程讨论群:前端开发核心知识进阶。
感兴趣的读者可以:
移动端点击了解更多:
大纲内容:
Happy coding!
其实入门网络安全要学的东西不算多,也就是网络基础+操作系统+中间件+数据库,四个流程下来就差不多了。
其中包括操作系统Windows基础和Linux基础,标记语言HTML基础和代码JS基础,以及网络基础、数据库基础和虚拟机使用等...
别被这些看上去很多的东西给吓到了,其实都是很简单的基础知识,同学们看完基本上都能掌握。计算机专业的同学都应该接触了解过,这部分可以直接略过。没学过的同学也不要慌,可以去B站搜索相关视频,你搜关键词网络安全工程师会出现很多相关的视频教程,我粗略的看了一下,排名第一的视频就讲的很详细。 当然你也可以看下面这个视频教程仅展示部分截图: 学到http和https抓包后能读懂它在说什么就行。
web是对外开放的,自然成了的重点关照对象,有事没事就来入侵一波,你说不管能行吗! 想学好Web安全,咱首先得先弄清web是怎么搭建的,知道它的构造才能精准打击。所以web前端和web后端的知识多少要了解点,然后再学点python,起码得看懂部分代码吧。
最后网站开发知识多少也要了解点,不过别紧张,只是学习基础知识。
等你用几周的时间学完这些,基本上算是具备了入门合格渗透工程师的资格,记得上述的重点要重点关注哦! 再就是,要正式进入web安全领域,得学会web渗透,OWASP TOP 10等常见Web漏洞原理与利用方式需要掌握,像SQL注入/XSS跨站脚本攻击/Webshell木马编写/命令执行等。
这个过程并不枯燥,一边打怪刷级一边成长岂不美哉,每个攻击手段都能让你玩得不亦乐乎,而且总有更猥琐的方法等着你去实践。
学完web渗透还不算完,还得掌握相关系统层面漏洞,像ms17-010永恒之蓝等各种微软ms漏洞,所以要学习后渗透。可能到这里大家已经不知所云了,不过不要紧,等你学会了web渗透再来看会发现很简单。
其实学会了这几步,你就正式从新手小白晋升为入门学员了,真的不算难,你上你也行。
不过我们这个水平也就算个渗透测试工程师,也就只能做个基础的安全服务,而这个领域还有很多业务,像攻防演练、等保测评、风险评估等,我们的能力根本不够看。
所以想要成为一名合格的网络工程师,想要拿到安全公司的offer,还得再掌握更多的网络安全知识,能力再更上一层楼才行。即便以后进入企业,也需要学习很多新知识,不充实自己的技能就会被淘汰。
从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。
因为入门学习阶段知识点比较杂,所以我讲得比较笼统,最后联合CSDN整理了一套【282G】网络安全从入门到精通资料包,需要的小伙伴可以点击链接领取哦! 网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。