前端安全-JS原型链污染是怎么回事

简介: 面试题经常会提到一个问题,就是前端安全问题哪些

介绍


面试题经常会提到一个问题,就是前端安全问题哪些,我们基本上都回答上来以下几个:

  • XSS脚本攻击,利用网站漏洞,注入非法脚本
  • CSRF跨站请求伪造,攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求
  • 运营商劫持,一般是经过某些运营商DNS网关后,在外层套入iframe,然后实现页面劫持


但是在前端安全中,还有一个问题就是 :JS原型链污染, 那么是原型链污染怎么回事,请看下面详细介绍。

去年有一个很邪恶的js库叫Evil.js,名字还取得很lodash,其中主要就是利用原型prototype进行重写项目中常用的方法,如:

  • Array.map 有5%概率会丢失最后一个元素,
  • 当数组长度可以被7整除时,Array.includes 永远返回false。

所以学会如何防御项目内被攻击,了解更多JS原型安全知识很重要,起码周末不用调试半天问题,才发现项目中代码被恶意写入。


在看这篇文章,请确保自己对JS原型和原型链有一定了解,如果忘记或缺乏了解的话,可以看我之前的文案从null、undefined、NaN的区别了解JS的原型链再次复习和学习一下。

原型链污染


是什么


下面通过一段代码,我们能够快速了解原型链是如何污染的?

const foo = {
    bar: 1
};
// 如果这里将foo.__proto__改掉
foo.__proto__.bar = 2
console.log(foo.bar); // 这里正常输出 1
// 新声明一个
const zoo = {};
console.log(zoo.bar); // 这里错误输出 2

从上述代码可以概括一下,原型链攻击是:

在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。

攻击场景


其实我们主要看哪些场景会允许代码设置__proto__?主要有以下两种:

  • 对象merge
  • 对象clone
  • Node.js的construtor

merge demo案例


一般实现对象的merge代码实现如下:

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}
// 运行代码
let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)
o3 = {}
console.log(o3.b) // 发现原型链没有被污染

这是为什么呢?因为声明变量的时候,"_proto"并不是一个key,即使修改也不会改变Object的原型。


那么如何做到"_proto"成为一个key,可以将demo代码调整一下,如:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)
o3 = {}
console.log(o3.b) // 输出2

merge操作是最常见可能控制键名的操作,也最能被原型链攻击,很多常见的库都存在这个问题。如: lodash.merge

实际应用问题


Code-Breaking 2018 Thejs 分析

// ...
const lodash = require('lodash')
// ...
app.engine('ejs', function (filePath, options, callback) { 
// define the template engine
    fs.readFile(filePath, (err, content) => {
        if (err) return callback(new Error(err))
        let compiled = lodash.template(content)
        let rendered = compiled({...options})
        return callback(null, rendered)
    })
})
//...
app.all('/', (req, res) => {
    let data = req.session.data || {language: [], category: []}
    if (req.method == 'POST') {
        data = lodash.merge(data, req.body)
        req.session.data = data
    }
    res.render('index', {
        language: data.language, 
        category: data.category
    })
})

题目是利用lodash.template + lodash.merge两个方法实现部分功能:

  • 用户提交的信息,用merge方法合并到session里,session里最终保存你提交的所有信息
  • 然后利用merge方法注入原型污染
  • 最后利用template中的方法,完成整个网站污染


整个案例其实比较重要的一点就是,提交参数的时候序列化提交参数是否有做防御,如何没有的话那么很容易就中招了。

如何防御


分不同情况做防御:

引入npm包导致的


  • 项目代码扫描,主要是针对构建好的代码进行扫描,是否Evil.js修改内置原型的情况进行告警提示
  • 禁止修改原型,如:使用Object.freeze

针对node.js


  • 针对node服务端接口参数进行序列化的时候,禁止非法key值传入
  • 禁止修改原型,如:使用Object.freeze
  • 采用Object.create(null)创建对象,避免直接使用{}
  • 使用map数据类型创建
  • 不对参数做JSON.parse转换,采用封装后的反序列化方法
  • 尽量采用安全的mergeclone库方法

参考资料


目录
相关文章
|
22天前
|
前端开发 JavaScript 网络协议
前端最常见的JS面试题大全
【4月更文挑战第3天】前端最常见的JS面试题大全
45 5
|
1月前
|
JavaScript 前端开发 Java
纯前端JS实现人脸识别眨眨眼张张嘴案例
纯前端JS实现人脸识别眨眨眼张张嘴案例
52 0
|
4天前
|
缓存 安全 JavaScript
前端安全:Vue应用中防范XSS和CSRF攻击
【4月更文挑战第23天】本文探讨了在Vue应用中防范XSS和CSRF攻击的重要性。XSS攻击通过注入恶意脚本威胁用户数据,而CSRF则利用用户身份发起非授权请求。防范措施包括:对输入内容转义、使用CSP、选择安全的库;采用Anti-CSRF令牌、同源策略和POST请求对抗CSRF;并实施代码审查、更新依赖及教育团队成员。通过这些实践,可提升Vue应用的安全性,抵御潜在攻击。
|
1天前
|
JavaScript 前端开发 API
Node.js在前端的妙用:打造更出色的Web体验
Node.js在前端的妙用:打造更出色的Web体验
16 5
|
8天前
|
JavaScript
什么是js的原型链
什么是js的原型链
|
25天前
|
人工智能 前端开发 JavaScript
【前端设计】HTML+CSS+JavaScript基本特性
【前端设计】HTML+CSS+JavaScript基本特性
|
1月前
|
JavaScript 前端开发 算法
深入探讨前端框架Vue.js中的虚拟DOM机制
本文将深入探讨前端框架Vue.js中的虚拟DOM机制,分析其原理、优势以及在实际开发中的应用场景,帮助读者更好地理解Vue.js框架的核心特性。
|
1月前
|
JSON JavaScript 前端开发
Node.js:前端开发的后端利器
Node.js作为一种运行在服务器端的JavaScript环境,为前端开发者打开了后端开发的大门。它以其高效的事件驱动、非阻塞I/O模型以及强大的npm生态,使得前端开发者能够轻松构建服务器端应用,实现前后端的全栈开发。本文将探讨Node.js的核心优势、应用场景以及在前端开发中的重要性。
|
1月前
|
前端开发 JavaScript 数据可视化
JavaScript:前端开发的灵魂与动力
JavaScript(JS)作为前端开发的核心语言,赋予了网页交互性和动态性。通过JS,开发者可以实现复杂的用户交互、数据操作以及动画效果,为用户带来丰富而流畅的网页体验。本文将介绍JS的基本概念、应用场景以及在前端开发中的重要性。
|
1月前
|
JavaScript 前端开发
在JavaScript中,如何优化原型链的性能?
在JavaScript中,如何优化原型链的性能?
16 2