富文本编辑器的xss问题

9,153 阅读1分钟

在使用富文本的时候是很容易出现xss问题的

如果你还不知道什么是xss攻击,那么可以先去了解一下前置知识:什么是xss?

在富文本中防止xss攻击无非是两种方法:

  • 黑名单过滤
const xssFilter = (html)=> {
    if(!html) return '';
    //将script标签过滤
    html = html.replace(/<\s*\/?script\s*>/,'');
    //过滤html标签中存在的javascript所执行的内容
    html = html.replace(/javascript:[^'"]*/g,'');
    //过滤html标签中所执行的脚本
    html = html.replace(/onerror\s*=\s*['"]?[^'"]*['"]?/g,'');
    return html;
}

但是黑名单有一个明显的弊端:在html中有很多标签和事件,要全部过滤掉风险点的确是个大问题,所以一般主流的解决办法是使用白名单

  • 白名单过滤

首先需要用到cheerio,它可以将html字符串解析成类似jquery对象,api也与jquery基本一致。

const xssFilter = (html)=>{
    if(!html) return '';
    const cheerio = require('cheerio');
    let $ = cheerio.load(html);
    
    //白名单 key为白名单标签 value为白名单标签的属性
    const whiteList = {
        'img':['src'],
        'font':['color','size'],
        'a':['href']
    }
    $('*').each((index,el)=>{
        //过滤标签
        if(!whiteList[el.name]){
            $(el).remove();
            return;
        }
        //过滤属性
        for(let attr in el.attribs){
            if(!whiteList[el.name].includes(attr)){
                //cheerio如果删除标签中的属性,就将该属性设为null;
                $(el).attr(attr,null);
            }
        }
    })
    return $.html();
}

但是其实这种需求是很常见的,这里只是列举了实现的原理,在实际开发中个人推荐使用 js-xss

我们可以使用js-xss来改进一下我们的代码

const xssFilter = ()=>{
    if(!html) return '';
    const xss = require('xss');
    const ret = xss(html,{
        whiteList:{
            img:['src'],
            a:['href'],
            font:['color','size'],
        },
        onIgnoreTag(){
            return '';
        }
    });
    return ret;
}