Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Exploit - Vulnerabilidade com cross-site scripting: innerHTML.

Cross-site scripting (XXS): innerHTML e insertAdjacentHTML

Esse texto visa dividir o meu conhecimento adquirido após ficar curioso sobre um ponto da aula.

Conforme vou acompanhando as aulas costumo checar documentações para entender melhor o que estou usando de recursos.

E encontrei um fator bem interessante acerca do innerHTML, como além de ele ser usado pela maioria dos sites também me atentei que a derivação de se qualquer texto que você colocar no input ao passar por um trecho de código que utiliza o innerHTML para colocar conteúdo no DOM, ele injetará aquele texto no HTML da página, independente do que for. Até então, qual o problema? já que o HTML 5 por padrão não executa uma tag script inserida via innerHTML.

O problema está em que rodar um código JS por um input que de alguma forma passará por um innerHTML não ocorre somente com o uso da tag script, é possível executar um script de outras formas ao colocar texto com código no input, segue os exemplos simples:

  • <img src='x' onerror='console.log("Hello World! Security are cool and vulnerability are bad :D")'>

  • <img src='x' onerror='alert("Site bastante divertido esse hein")'>

Recomendo que teste! E encontre exemplos mais complexos nesta cheat-seet de xxs.

Neste ponto pensei "okay, legal. Vão poder dar Hello World com console.log através do input", mas existem casos realmente significativos? Além dos problemas que o Orkut e o Twitter tiveram com XXS em 2010 (G1) e os problemas que o eBay teve em 2017 (portal sobre segurança na internet), por não serem recentes continuei pensando se em 2020 isso ainda é um problema e posso não ter pesquisado o bastante, mas não encontrei casos alarmantes.

Ainda sim, considero que "não possibilidade de problema de segurança" seja mais interessante que "possibilidade de problema de segurança", por isso me desafiei a dar FIX nesse problema.

O código do instrutor é algo parecido com isso: (fiz algumas alterações em nomenclaturas e difere o nosso estilo de escrita em alguns pontos, mas nada mais que isso):

cross-site scripting vunerability

Após testar vários XXS no código do instrutor, pensei "duh, basta eu utilizar outro método para inserir o HTML no DOM" e tentei a utilização do insertAdjacentHTML() de forma bastante ingênua, pois eu não havia entendido corretamente o que seria um XXS e qual fluxo ocorria para o anterior innerHTML ser um exemplo de Vulnerabilidade. Código da minha primeira tentativa de burlar um XXS que na verdade também é completamente vunerável:

cross-site scripting vunerability

Com isso que ocorreu durante uma tarde de 2 meses atrás, pausei os meus estudos de Front-end e me foquei em estudar Back-end(Foi insanamente bacana!) em paralelo com experimentações do React.Js, mas eu só queria voltar a estudar Front-end para valer quando eu vencesse esse desafio. Hoje eu venci e não demorou mais de 5 minutos para desenvolver uma solução e estou bastante contente com isso, basicamente, eu li os códigos anteriores e pensei "Ué, basta eu aninhar os nós com o .appendChild e inserir o texto com o textContent" pois mesmo se for um script colocado no input, ele interpretará como texto dentro da tag e injetará no DOM somente como um texto dentro de uma tag. Enfatizando, que, se eu li a parte da documentação que recomenda o uso do textContent, não devo ter imaginado a implementação. Código da solução:

not cross-site scripting vunerability

Sei que tudo isso não foi a coisa mais genial do mundo, provavelmente, se espera que qualquer Junior já saiba disso tudo, mas estou contente, pois demonstrá a minha evolução no entendimento da web.

Também tenho noção de que o curso visa me ajudar a familiarizar-me com o DOM e não as miúdas, tento ir além e obrigado pelo conhecimento Felipe Nascimento você está contribuindo para que algum dia eu me torne um bom Dev.

Obrigado pela atenção quem chegou até aqui!

Sapere Aude.

Referências:

3 respostas

Observação: Não estou usando o jQuery, apenas senti vontade de usar o cifrão/dólar para document.querySelector(), então coloquei-o dentro do dólar.

``` $ = document.querySelector.bind(document); ```
solução!

Olá João, tudo bem?

Realmente essa parte de segurança é essencial estarmos sempre aprendendo, principalmente pela web ser tão livre, e ataques XSS muitas vezes acabam sendo esquecidos, principalmente com a facilidade que é montar toda uma template string com nosso código

Um ponto que achei interessante foi se espera que qualquer Junior já saiba disso tudo

Ao mesmo tempo que é fundamental saber disso, por outro lado você mesmo trouxe exemplo de empresas gigantes que sofreram com essa vulnerabilidade, então até mesmo pessoas mais experientes as vezes não conhecem

E esse ano mesmo eu vi exemplos recentes, como esse daqui:

E o mesmo atacante fez no Bank of America no ano passado dessa vez com o jogo Doom =)

Agora uma outra alternativa, que é bem utilizada até, é permitir a template string mas fazer a sanitização do input do usuário, um exemplo bem simples seria algo assim:

    let valor = input.value

    const pattern = /<.+?>/g;

    const result = input.value.match(pattern);

    result.forEach( match => {
        valor = valor.replace(match, "")
    })

Obviamente da para melhorar bastante, mas eu fiz uma regex que encontra todas as tags presente no input do usuário, e armazena dentro de `result, então o input

<image src="aaaa">Texto Aleatorio </image>

resulta em:

[
  "<image src=\"aaaa\">",
  "</image>"
]

E na linha posterior eu faço que para cada match, eu troque o valor da tag por uma string vazia

Essa também foi uma maneira didática, poderíamos encurtar pela função replaceAll e trocar todo esse código por:

    const pattern = /<.+?>/g;
    const valor = input.value.replaceAll(pattern, "")

Desta maneira temos certeza que o valor que será utilizado dentro da template string está "limpo" e pode ser inserido no html normalmente :)

Se quiser aprender um pouco mais de Regex, eu particularmente acho esse curso fantástico

Abraços e Bons Estudos!

Opa Geovani beleza!

Realmente, obrigado por me lembrar que mesmo sendo algo fundamental é de valor ter esse conhecimento.

Wowww, sobre esse exemplo de XXS com o TSF e Minecraft, achei insano demais, eu até cheguei a ler alguma coisa sobre, mas não fazia ideia que havia sido um XXS e além do exemplo nacional você agregou bastante pra mim com o outro caso do Doom no Bank of America. Obrigado pelas ótimas referências!

Sobre a aplicação da solução com Regex, isso com certeza ampliou demais a minha visão da aplicação de expressões regulares e repertório, eu já havia feito o curso ministrado pelo Nico Steppat (sem dúvidas é um dos melhores cursos da plataforma), mas nem havia passado pela minha cabeça em usar Regex.

O principal motivo de eu ter gostado da sua solução é que em componentes/templates mais complexos (em tamanho) geraria tantos .createElement e .appendChild que tornaria mais trabalhosa a leitura do código, portanto vejo essa solução como escalável de templates simples à complexos, obrigado pelo insight!

Embora eu tenha feito o curso de Regex, eu não conhecia o .replaceAll(), fiquei surpreso ao tentar implementar a solução que o utiliza e o navegador me retornar “replaceAll is not a function”, li o meu código e não identifiquei erros, então fui ler a documentação e vi que o suporte a esse método começou em Agosto pelo Firefox e no Chrome a a partir da versão 85, já no Opera GX (navegador que eu utilizo) na versão 71 e eu estava com a 68; isso me lembrou de atualizar o navegador kkkk e ainda aprendi um método novinho em folha, obrigado por isso também!!!

Definitivamente até hoje essa foi a resposta mais produtiva que já obtive num fórum, obrigado pela ajuda e muito sucesso à ti!