Implmeentação da Solução Técnica
Este guia aborda a integração do plugin UEditor em um sistema CMS para permitir a colagem segura de conteúdo do Word, com foco na prevenção de ataques como XSS e na preservação de estilos.
Configuração do Frontend (Vue.js com UEditor Modificado)
// Arquivo: ueditor.config.js
window.UEDITOR_CONFIG = {
pasteFilterStyle: false, // Desativa filtragem padrão para manter estilos
toolbars: [
['codigo-fonte', 'desfazer', 'refazer', 'imagem-word', 'colagem-simples',
'|', 'colagem-word-customizada', 'anti-xss'] // Botões personalizados
]
};
// Registrar botão de colagem personalizada no UEditor
UE.registerUI('colagem-word-customizada', function(editor, nomeUI) {
const botao = new UE.ui.Button({
name: 'colagem-word-customizada',
title: 'Colagem de Word com Estilo Preservado',
cssRules: 'background-position: -726px -77px;',
onclick: function() {
editor.execCommand('colagemDeWordSegura');
}
});
return botao;
}, 10);
// Registrar botão de filtragem XSS no frontend
UE.registerUI('anti-xss', function(editor) {
return new UE.ui.Button({
name: 'anti-xss',
title: 'Modo de Segurança Ativado',
onclick: () => {
const conteudo = editor.getContent();
const conteudoSeguro = conteudo.replace(/<script>.*?<\/script>/gi, '');
editor.setContent(conteudoSeguro);
}
});
});
// Comando principal para colagem segura com suporte a backend
UE.commands['colagemDeWordSegura'] = {
execCommand: function() {
document.addEventListener('colar', async (evento) => {
const itens = (evento.clipboardData || window.clipboardData).items;
for (let item of itens) {
if (item.type.includes('office')) {
const arquivo = item.getAsFile();
const dadosFormulario = new FormData();
dadosFormulario.append('documento-word', arquivo);
// Chamada ao backend para análise segura
const resposta = await fetch('/api/analise-word-segura', {
method: 'POST',
body: dadosFormulario,
headers: { 'X-Token-Anti-CSRF': 'token-seguro' }
});
const { htmlGerado, linksOss } = await resposta.json();
// Substituir caminhos de imagens por URLs do OSS
let htmlFinal = htmlGerado.replace(/src="temp\//g, `src="${linksOss.join(',')}"`);
this.execCommand('inserirHtml', htmlFinal);
}
}
});
}
};
Implementação do Backend (ASP.NET com Segurança Reforçada)
// Arquivo: AnaliseWordSegura.ashx
public class AnaliseWordSegura : IHttpHandler {
public void ProcessRequest(HttpContext contexto) {
// Validação de arquivo para evitar vulnerabilidades
if (contexto.Request.Files.Count == 0 || !contexto.Request.Files[0].FileName.EndsWith(".docx")) {
contexto.Response.Write("{\"erro\":\"Arquivo inválido\"}");
return;
}
var arquivo = contexto.Request.Files[0];
using (var documento = new XWPFDocument(arquivo.InputStream)) {
// Sanitização para prevenir XSS
var htmlConstruido = new StringBuilder();
foreach (var paragrafo in documento.Paragraphs) {
var textoSanitizado = HttpUtility.HtmlEncode(paragrafo.Text);
htmlConstruido.AppendFormat("<p style="\"{0}\"">{1}</p>", paragrafo.Style, textoSanitizado);
}
// Upload de imagens para OSS com nomes aleatórios
var urlsOss = new List<string>();
foreach (var imagem in documento.AllPictures) {
var nomeSeguro = Guid.NewGuid() + Path.GetExtension(imagem.SuggestFileExtension());
var urlImagem = ServicoOSS.Enviar(imagem.Content, "imagens-word/" + nomeSeguro);
urlsOss.Add(urlImagem);
}
// Retorno em formato JSON
contexto.Response.ContentType = "application/json";
contexto.Response.Write(JsonConvert.SerializeObject(new {
html = htmlConstruido.ToString(),
urlsOss = urlsOss
}));
}
}
}
// Classe utilitária para operações no OSS
public static class ServicoOSS {
private static readonly string endpoint = "seu-endpoint-oss";
private static readonly string chaveAcesso = "sua-chave-acesso";
private static readonly string chaveSecreta = "sua-chave-secreta";
public static string Enviar(byte[] dados, string caminho) {
// Validação de caminho para evitar ataques de path traversal
if (caminho.Contains("..") || caminho.Contains("//"))
throw new ArgumentException("Caminho inválido");
var cliente = new OssClient(endpoint, chaveAcesso, chaveSecreta);
using (var fluxo = new MemoryStream(dados)) {
var resultado = cliente.PutObject("seu-bucket", caminho, fluxo);
return resultado.Uri.ToString();
}
}
}
</string>