前端安全-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库方法

参考资料


目录
相关文章
|
6天前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
102 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
4月前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
前端开发
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
40 1
【2025优雅草开源计划进行中01】-针对web前端开发初学者使用-优雅草科技官网-纯静态页面html+css+JavaScript可直接下载使用-开源-首页为优雅草吴银满工程师原创-优雅草卓伊凡发布
|
4月前
|
JavaScript 前端开发
JavaScript 原型链的实现原理是什么?
JavaScript 原型链的实现原理是通过构造函数的`prototype`属性、对象的`__proto__`属性以及属性查找机制等相互配合,构建了一个从对象到`Object.prototype`的链式结构,实现了对象之间的继承、属性共享和动态扩展等功能,为 JavaScript 的面向对象编程提供了强大的支持。
|
2月前
|
监控 安全 中间件
Next.js 实战 (十):中间件的魅力,打造更快更安全的应用
这篇文章介绍了什么是Next.js中的中间件以及其应用场景。中间件可以用于处理每个传入请求,比如实现日志记录、身份验证、重定向、CORS配置等功能。文章还提供了一个身份验证中间件的示例代码,以及如何使用限流中间件来限制同一IP地址的请求次数。中间件相当于一个构建模块,能够简化HTTP请求的预处理和后处理,提高代码的可维护性,有助于创建快速、安全和用户友好的Web体验。
|
4月前
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
springboot解决js前端跨域问题,javascript跨域问题解决
|
4月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
103 5
|
4月前
|
缓存 前端开发 JavaScript
JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式
本文深入解析了JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式(Hash路由和History路由)、优点及挑战,并通过实际案例分析,帮助开发者更好地理解和应用这一关键技术,提升用户体验。
146 1
|
4月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
87 4
|
5月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
372 14

热门文章

最新文章