Angular
Lista de Verificação
Lista de verificação daqui.
O que é Angular
Angular é um framework poderoso e de código aberto mantido pelo Google. Ele usa TypeScript para melhorar a legibilidade e a depuração do código. Com mecanismos de segurança robustos, o Angular previne vulnerabilidades comuns do lado do cliente, como XSS e redirecionamentos abertos. Ele também pode ser usado no lado do servidor, tornando as considerações de segurança importantes de ambos os lados.
Arquitetura do Framework
Para entender melhor os conceitos essenciais do Angular, vamos revisar sua estrutura básica.
Um projeto Angular comum geralmente se parece com:
De acordo com a documentação, cada aplicação Angular tem pelo menos um componente, o componente raiz (AppComponent
) que conecta uma hierarquia de componentes com o DOM. Cada componente define uma classe que contém dados e lógica da aplicação, e está associado a um modelo HTML que define uma visualização a ser exibida em um ambiente alvo. O decorador @Component()
identifica a classe imediatamente abaixo dele como um componente e fornece o modelo e metadados específicos do componente relacionados. O AppComponent
é definido no arquivo app.component.ts
.
Os NgModules do Angular declaram um contexto de compilação para um conjunto de componentes dedicados a um domínio de aplicação, um fluxo de trabalho ou um conjunto de capacidades intimamente relacionadas. Toda aplicação Angular tem um módulo raiz, convencionalmente chamado AppModule
, que fornece o mecanismo de inicialização que inicia a aplicação. Uma aplicação geralmente contém muitos módulos funcionais. O AppModule
é definido no arquivo app.module.ts
.
O NgModule Router
do Angular fornece um serviço que permite definir um caminho de navegação entre os diferentes estados da aplicação e hierarquias de visualização na sua aplicação. O RouterModule
é definido no arquivo app-routing.module.ts
.
Para dados ou lógica que não estão associados a uma visualização específica e que você deseja compartilhar entre componentes, você cria uma classe de serviço. A definição da classe de serviço é imediatamente precedida pelo decorador @Injectable()
. O decorador fornece os metadados que permitem que outros provedores sejam injetados como dependências em sua classe. A injeção de dependência (DI) permite manter suas classes de componente enxutas e eficientes. Elas não buscam dados do servidor, validam a entrada do usuário ou registram diretamente no console; elas delegam essas tarefas para serviços.
Configuração do sourcemap
O framework Angular traduz arquivos TypeScript em código JavaScript seguindo as opções do tsconfig.json
e, em seguida, constrói um projeto com a configuração do angular.json
. Ao analisar o arquivo angular.json
, observamos uma opção para habilitar ou desabilitar um sourcemap. De acordo com a documentação do Angular, a configuração padrão tem um arquivo sourcemap habilitado para scripts e não está oculto por padrão:
Geralmente, os arquivos de sourcemap são utilizados para fins de depuração, pois mapeiam arquivos gerados para seus arquivos originais. Portanto, não é recomendado utilizá-los em um ambiente de produção. Se os sourcemaps estiverem habilitados, isso melhora a legibilidade e auxilia na análise de arquivos replicando o estado original do projeto Angular. No entanto, se estiverem desabilitados, um revisor ainda pode analisar manualmente um arquivo JavaScript compilado procurando por padrões anti-segurança.
Além disso, um arquivo JavaScript compilado com um projeto Angular pode ser encontrado nas ferramentas de desenvolvedor do navegador → Sources (ou Debugger e Sources) → [id].main.js. Dependendo das opções habilitadas, este arquivo pode conter a seguinte linha no final //# sourceMappingURL=[id].main.js.map
ou pode não conter, se a opção hidden estiver definida como true. No entanto, se o sourcemap estiver desabilitado para scripts, os testes se tornam mais complexos e não podemos obter o arquivo. Além disso, o sourcemap pode ser habilitado durante a construção do projeto, como ng build --source-map
.
Ligação de dados
A ligação refere-se ao processo de comunicação entre um componente e sua visualização correspondente. É utilizada para transferir dados para e do framework Angular. Os dados podem ser passados de várias maneiras, como através de eventos, interpolação, propriedades ou através do mecanismo de ligação bidirecional. Além disso, os dados também podem ser compartilhados entre componentes relacionados (relação pai-filho) e entre dois componentes não relacionados usando o recurso de Serviço.
Podemos classificar a ligação pelo fluxo de dados:
Fonte de dados para alvo de visualização (inclui interpolação, propriedades, atributos, classes e estilos); pode ser aplicado usando
[]
ou{{}}
no modelo;Alvo de visualização para fonte de dados (inclui eventos); pode ser aplicado usando
()
no modelo;Bidirecional; pode ser aplicado usando
[()]
no modelo.
A ligação pode ser chamada em propriedades, eventos e atributos, bem como em qualquer membro público de uma diretiva de origem:
TIPO | ALVO | EXEMPLOS |
---|---|---|
Propriedade | Propriedade do elemento, Propriedade do componente, Propriedade da diretiva | <img [alt]="hero.name" [src]="heroImageUrl"> |
Evento | Evento do elemento, Evento do componente, Evento da diretiva | <button type="button" (click)="onSave()">Save |
Bidirecional | Evento e propriedade | <input [(ngModel)]="name"> |
Atributo | Atributo (a exceção) | <button type="button" [attr.aria-label]="help">help |
Classe | Propriedade de classe | <div [class.special]="isSpecial">Special |
Estilo | Propriedade de estilo | <button type="button" [style.color]="isSpecial ? 'red' : 'green'"> |
Modelo de segurança Angular
O design do Angular inclui a codificação ou sanitização de todos os dados por padrão, tornando cada vez mais difícil descobrir e explorar vulnerabilidades de XSS em projetos Angular. Existem dois cenários distintos para o tratamento de dados:
Interpolação ou
{{user_input}}
- realiza a codificação sensível ao contexto e interpreta a entrada do usuário como texto;
Resultado: <script>alert(1)</script><h1>test</h1>
2. Ligação a propriedades, atributos, classes e estilos ou [atributo]="user_input"
- realiza a sanitização com base no contexto de segurança fornecido.
Resultado: <div><h1>test</h1></div>
Existem 6 tipos de SecurityContext
:
None
;HTML
é usado ao interpretar o valor como HTML;STYLE
é usado ao vincular CSS na propriedadestyle
;URL
é usado para propriedades de URL, como<a href>
;SCRIPT
é usado para código JavaScript;RESOURCE_URL
como uma URL que é carregada e executada como código, por exemplo, em<script src>
.
Vulnerabilidades
Métodos de Bypass de Confiança de Segurança
O Angular introduz uma lista de métodos para ignorar seu processo de sanitização padrão e indicar que um valor pode ser usado com segurança em um contexto específico, como nos seguintes cinco exemplos:
bypassSecurityTrustUrl
é usado para indicar que o valor fornecido é uma URL de estilo segura:
bypassSecurityTrustResourceUrl
é usado para indicar que o valor fornecido é uma URL de recurso segura:
bypassSecurityTrustHtml
é usado para indicar que o valor fornecido é HTML seguro. Observe que a inserção de elementosscript
na árvore DOM desta forma não os faz executar o código JavaScript contido, devido à forma como esses elementos são adicionados à árvore DOM.
bypassSecurityTrustScript
é usado para indicar que o valor fornecido é JavaScript seguro. No entanto, encontramos seu comportamento como imprevisível, pois não conseguimos executar código JS em modelos usando este método.
bypassSecurityTrustStyle
é usado para indicar que o valor fornecido é CSS seguro. O exemplo a seguir ilustra a injeção de CSS:
O Angular fornece um método sanitize
para sanitizar dados antes de exibi-los nas visualizações. Este método utiliza o contexto de segurança fornecido e limpa a entrada de acordo. No entanto, é crucial usar o contexto de segurança correto para os dados e contexto específicos. Por exemplo, aplicar um sanitizador com SecurityContext.URL
em conteúdo HTML não oferece proteção contra valores HTML perigosos. Em tais cenários, o uso incorreto do contexto de segurança pode levar a vulnerabilidades de XSS.
Injeção de HTML
Essa vulnerabilidade ocorre quando a entrada do usuário está vinculada a qualquer uma das três propriedades: innerHTML
, outerHTML
ou srcdoc
do iframe
. Enquanto a ligação a esses atributos interpreta o HTML como está, a entrada é sanitizada usando SecurityContext.HTML
. Assim, a injeção de HTML é possível, mas o cross-site scripting (XSS) não é.
Exemplo de uso de innerHTML
:
O resultado é <div><h1>teste</h1></div>
.
Injeção de Template
Renderização do Lado do Cliente (CSR)
O Angular utiliza templates para construir páginas dinamicamente. A abordagem envolve envolver expressões de template para o Angular avaliar dentro de chaves duplas ({{}}
). Dessa forma, o framework oferece funcionalidades adicionais. Por exemplo, um template como {{1+1}}
seria exibido como 2.
Normalmente, o Angular escapa a entrada do usuário que pode ser confundida com expressões de template (por exemplo, caracteres como `< > ' " ``). Isso significa que passos adicionais são necessários para contornar essa restrição, como utilizar funções que geram objetos de string JavaScript para evitar o uso de caracteres na lista negra. No entanto, para alcançar isso, devemos considerar o contexto do Angular, suas propriedades e variáveis. Portanto, um ataque de injeção de template pode parecer da seguinte forma:
Como mostrado acima: constructor
refere-se ao escopo da propriedade constructor
do Objeto, permitindo-nos invocar o construtor de String e executar um código arbitrário.
Renderização do Lado do Servidor (SSR)
Ao contrário do CSR, que ocorre no DOM do navegador, o Angular Universal é responsável pela SSR dos arquivos de modelo. Esses arquivos são então entregues ao usuário. Apesar dessa distinção, o Angular Universal aplica os mesmos mecanismos de sanitização usados no CSR para melhorar a segurança do SSR. Uma vulnerabilidade de injeção de modelo no SSR pode ser identificada da mesma forma que no CSR, pois a linguagem de modelo utilizada é a mesma.
É claro que também há a possibilidade de introduzir novas vulnerabilidades de injeção de modelo ao empregar mecanismos de template de terceiros, como Pug e Handlebars.
XSS
Interfaces DOM
Como mencionado anteriormente, podemos acessar diretamente o DOM usando a interface Document. Se a entrada do usuário não for validada antecipadamente, isso pode levar a vulnerabilidades de script entre sites (XSS).
Nós utilizamos os métodos document.write()
e document.createElement()
nos exemplos abaixo:
Classes do Angular
Existem algumas classes que podem ser usadas para trabalhar com elementos DOM no Angular: ElementRef
, Renderer2
, Location
e Document
. Uma descrição detalhada das duas últimas classes é fornecida na seção Redirecionamentos abertos. A principal diferença entre as duas primeiras é que a API Renderer2
fornece uma camada de abstração entre o elemento DOM e o código do componente, enquanto ElementRef
apenas mantém uma referência ao elemento. Portanto, de acordo com a documentação do Angular, a API ElementRef
deve ser usada apenas como último recurso quando o acesso direto ao DOM é necessário.
ElementRef
contém a propriedadenativeElement
, que pode ser usada para manipular os elementos DOM. No entanto, o uso impróprio denativeElement
pode resultar em uma vulnerabilidade de injeção de XSS, como mostrado abaixo:
Apesar do fato de que
Renderer2
fornece uma API que pode ser usada com segurança mesmo quando o acesso direto aos elementos nativos não é suportado, ainda possui algumas falhas de segurança. ComRenderer2
, é possível definir atributos em um elemento HTML usando o métodosetAttribute()
, que não possui mecanismos de prevenção de XSS.
Para definir a propriedade de um elemento DOM, você pode usar o método
Renderer2.setProperty()
e desencadear um ataque XSS:
Durante nossa pesquisa, também examinamos o comportamento de outros métodos do Renderer2
, como setStyle()
, createComment()
e setValue()
, em relação a injeções de XSS e CSS. No entanto, não conseguimos encontrar vetores de ataque válidos para esses métodos devido às suas limitações funcionais.
jQuery
jQuery é uma biblioteca JavaScript rápida, pequena e rica em recursos que pode ser usada no projeto Angular para ajudar na manipulação dos objetos DOM HTML. No entanto, como é sabido, os métodos desta biblioteca podem ser explorados para alcançar uma vulnerabilidade de XSS. Para discutir como alguns métodos vulneráveis do jQuery podem ser explorados em projetos Angular, adicionamos esta subseção.
O método
html()
obtém o conteúdo HTML do primeiro elemento no conjunto de elementos correspondentes ou define o conteúdo HTML de cada elemento correspondente. No entanto, por design, qualquer construtor ou método do jQuery que aceite uma string HTML pode potencialmente executar código. Isso pode ocorrer pela injeção de tags<script>
ou uso de atributos HTML que executam código, como mostrado no exemplo.
O método
jQuery.parseHTML()
usa métodos nativos para converter a string em um conjunto de nós DOM, que podem então ser inseridos no documento.
Como mencionado anteriormente, a maioria das APIs do jQuery que aceitam strings HTML executará scripts incluídos no HTML. O método jQuery.parseHTML()
não executa scripts no HTML analisado, a menos que keepScripts
seja explicitamente true
. No entanto, ainda é possível na maioria dos ambientes executar scripts indiretamente; por exemplo, via o atributo <img onerror>
.
Last updated