excel导出之csv注入与防护,不得不了解的前端安全

887 阅读3分钟

前言

像xss、csrf这些前端常见的安全问题,相信大家都已经比较熟悉了,这我们来看一下csv注入是个啥。

概念

image.png

  • CSV注入的危害包括但不限于执行任意命令、开启应用程序、添加用户到系统或管理员组、修改注册表等
  • 在Excel中,如果单元格的第一个字符是“+、-、@、=”等符号,Excel会将其作为表达式处理。特别是“=”符号,在动态数据交换(DDE)中,它可以用来执行外部应用程序

这是其中比较关键的两句话,第一句是说危害,首先就是说的,能执行任意cmd命令,可以想象,就光这一点,如果是被csv注入了的话,咱电脑就已经属于脱光光的状态了,完全没有任何隐私。第二句话是说的怎么注入csv,ok,下面细说。

csv注入

  • csv注入主要发生在excel导出的时候,所以我们这从excel导出开始来

excel导出

<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了

image.png

csv注入

  • 接下来,我们把excelData中的属性值改一下,将name,改成如下
const excelData = [
  {
    name: "=1+cmd|'/C calc'!A0",
    age: "18",
    tel: "191",
  },
  {
    name: "李四",
    age: "19",
    tel: "135",
  },
];
  • 重新导出excel,打开excel,鼠标移入改的那个单元格,然后移除,cmd -> calc被执行,计算器弹了出来

image.png

注:免费版的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。