前言
像xss、csrf这些前端常见的安全问题,相信大家都已经比较熟悉了,这我们来看一下csv注入是个啥。
概念
- CSV注入的危害包括但不限于执行任意命令、开启应用程序、添加用户到系统或管理员组、修改注册表等
- 在Excel中,如果单元格的第一个字符是“+、-、@、=”等符号,Excel会将其作为表达式处理。特别是“=”符号,在动态数据交换(DDE)中,它可以用来执行外部应用程序
这是其中比较关键的两句话,第一句是说危害,首先就是说的,能执行任意cmd命令,可以想象,就光这一点,如果是被csv注入了的话,咱电脑就已经属于脱光光的状态了,完全没有任何隐私。第二句话是说的怎么注入csv,ok,下面细说。
csv注入
- csv注入主要发生在excel导出的时候,所以我们这从excel导出开始来
excel导出
- 使用exceljs前端导出excel exceljs中文文档
<script setup lang="ts">
import ExcelJS from "exceljs";
/**
* mock的excel表格数据
*/
const excelData = [
{
name: "张三",
age: "18",
tel: "191",
},
{
name: "李四",
age: "19",
tel: "135",
},
];
const download = async () => {
const workbook = new ExcelJS.Workbook(); // 创建工作簿
const worksheet = workbook.addWorksheet("sheet1"); // 添加工作表
worksheet.columns = [
// excel表格头部
{
header: "姓名",
key: "name",
},
{
header: "年龄",
key: "age",
},
{
header: "电话",
key: "tel",
},
];
worksheet.addRows(excelData); // 添加表格数据
/**
* buffer导出为excel
*/
const buffer = await workbook.xlsx.writeBuffer(); // 转buffer
const type =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
const blob = new Blob([buffer], { type });
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "sheet1.xlsx";
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
}, 1000);
window.URL.revokeObjectURL(url); // 释放创建的URL对象
};
</script>
<template>
<button @click="download">下载excel</button>
</template>
- ok,在页面上就可以通过点击button,导出一个excel了
csv注入
- 接下来,我们把excelData中的属性值改一下,将name,改成如下
const excelData = [
{
name: "=1+cmd|'/C calc'!A0",
age: "18",
tel: "191",
},
{
name: "李四",
age: "19",
tel: "135",
},
];
- 重新导出excel,打开excel,鼠标移入改的那个单元格,然后移除,cmd -> calc被执行,计算器弹了出来
注:免费版的office命令好像是不会被执行;收费版的office365可以复现出来,在 文件 > 选项 > 信任中心 > 外部内容 > 勾选上:开启动态数据交换服务器启动 后可以复现
csv防护
网上说的csv防护有很多,我觉得我这个是最简单实用的,我觉得就会这一个就可以了(>|<)
- csv注入的前提是,单元格的第一个字符是“+、-、@、=”等符号,所以只需要在每个单元格前面加一个再加一个特殊符号,那单元格的第一个字符是不是就不会“+、-、@、=”这些字符了,就不存在csv注入了;所以我们这只需要再每个单元格前面加个制表符'\t',完美解决
防护示例
- 再来修改 excelData,将每一个字段的属性值前方加一个'\t'
const excelData = [
{
name: "\t" + "=1+cmd|'/C calc'!A0",
age: "\t" + "18",
tel: "\t" + "191",
},
{
name: "\t" + "李四",
age: "\t" + "19",
tel: "\t" + "135",
},
];
- 再来导出excel表格,ok,首先内容是一模一样的,并且命令没在被执行了,over。