docs(security): proofread prose, app now shows good and bad

- App now shows how Angular handles untrusted URLs and resources
- E2e test covered new functionality
- Copyedits to prose
- Updated provider expressions to use latest syntax

The original security feature tracker:
https://github.com/angular/angular/issues/8511
This commit is contained in:
Patrice Chalin 2016-06-30 07:21:55 -07:00 committed by Naomi Black
parent 909f230cc7
commit 705d8c50fd
7 changed files with 58 additions and 35 deletions

View File

@ -1,7 +1,8 @@
/// <reference path="../_protractor/e2e.d.ts" />
'use strict';
describe('Security E2E Tests', () => {
beforeAll(function() { browser.get(''); });
beforeAll(() => browser.get(''));
it('sanitizes innerHTML', () => {
let interpolated = element(By.className('e2e-inner-html-interpolated'));
@ -13,13 +14,23 @@ describe('Security E2E Tests', () => {
expect(bold.getText()).toContain('Syntax');
});
it('escapes untrusted URLs', () => {
let untrustedUrl = element(By.className('e2e-dangerous-url'));
expect(untrustedUrl.getAttribute('href')).toMatch(/^unsafe:javascript/);
});
it('binds trusted URLs', () => {
let dangerousUrl = element(By.className('e2e-dangerous-url'));
expect(dangerousUrl.getAttribute('href')).toMatch(/^javascript:alert/);
let trustedUrl = element(By.className('e2e-trusted-url'));
expect(trustedUrl.getAttribute('href')).toMatch(/^javascript:alert/);
});
it('escapes untrusted resource URLs', () => {
let iframe = element(By.className('e2e-iframe-untrusted-src'));
expect(iframe.getAttribute('src')).toBe('');
});
it('binds trusted resource URLs', () => {
let iframe = element(By.className('e2e-iframe'));
let iframe = element(By.className('e2e-iframe-trusted-src'));
expect(iframe.getAttribute('src')).toMatch(/^https:\/\/www.youtube.com\//);
});
});

View File

@ -5,7 +5,7 @@ import { BypassSecurityComponent } from './bypass-security.component';
import { InnerHtmlBindingComponent } from './inner-html-binding.component';
@Component({
selector: 'app-root',
selector: 'my-app',
template: `
<h1>Security</h1>
<inner-html-binding></inner-html-binding>
@ -14,7 +14,7 @@ import { InnerHtmlBindingComponent } from './inner-html-binding.component';
directives: [
BypassSecurityComponent,
InnerHtmlBindingComponent,
],
]
})
export class AppComponent {
}

View File

@ -2,14 +2,19 @@
<h3>Bypass Security Component</h3>
<!--#docregion dangerous-url -->
<h4>A dangerous URL:</h4>
<p><a class="e2e-dangerous-url" [href]="dangerousUrl">Click me.</a></p>
<h4>A untrusted URL:</h4>
<p><a class="e2e-dangerous-url" [href]="dangerousUrl">Click me</a></p>
<h4>A trusted URL:</h4>
<p><a class="e2e-trusted-url" [href]="trustedUrl">Click me</a></p>
<!--#enddocregion dangerous-url -->
<!--#docregion iframe-videoid -->
<h4>Resource URL:</h4>
<p><label>Showing: <input (input)="updateVideoUrl($event.target.value)"></label></p>
<iframe class="e2e-iframe" width="640" height="390" [src]="videoUrl"></iframe>
<p>Trusted:</p>
<iframe class="e2e-iframe-trusted-src" width="640" height="390" [src]="videoUrl"></iframe>
<p>Untrusted:</p>
<iframe class="e2e-iframe-untrusted-src" width="640" height="390" [src]="dangerousVideoUrl"></iframe>
<!--#enddocregion iframe-videoid -->
<!--#enddocregion -->

View File

@ -8,14 +8,18 @@ import { DomSanitizationService, SafeResourceUrl, SafeUrl } from '@angular/platf
templateUrl: 'app/bypass-security.component.html',
})
export class BypassSecurityComponent {
dangerousUrl: SafeUrl;
dangerousUrl: string;
trustedUrl: SafeUrl;
dangerousVideoUrl: string;
videoUrl: SafeResourceUrl;
// #docregion trust-url
constructor(private sanitizer: DomSanitizationService) {
// javascript: URLs are dangerous if attacker controlled. Angular sanitizes them in data
// binding, but we can explicitly tell Angular to trust this value:
this.dangerousUrl = sanitizer.bypassSecurityTrustUrl('javascript:alert("Hi there")');
// javascript: URLs are dangerous if attacker controlled.
// Angular sanitizes them in data binding, but we can
// explicitly tell Angular to trust this value:
this.dangerousUrl = 'javascript:alert("Hi there")';
this.trustedUrl = sanitizer.bypassSecurityTrustUrl(this.dangerousUrl);
// #enddocregion trust-url
this.updateVideoUrl('PUBnlbjZFAI');
}
@ -23,11 +27,12 @@ export class BypassSecurityComponent {
// #docregion trust-video-url
updateVideoUrl(id: string) {
// Appending an ID to a YouTube URL is safe.
// Always make sure to construct SafeValue objects as close as possible to the input data, so
// Always make sure to construct SafeValue objects as
// close as possible to the input data, so
// that it's easier to check if the value is safe.
this.dangerousVideoUrl = 'https://www.youtube.com/embed/' + id;
this.videoUrl =
this.sanitizer.bypassSecurityTrustResourceUrl('https://www.youtube.com/embed/' + id);
this.sanitizer.bypassSecurityTrustResourceUrl(this.dangerousVideoUrl);
}
// #enddocregion trust-video-url
}
// #enddocregion

View File

@ -11,4 +11,3 @@ export class InnerHtmlBindingComponent {
// E.g. a user/attacker controlled value from a URL.
htmlSnippet = 'Template <script>alert("0wned")</script> <b>Syntax</b>';
}
// #enddocregion inner-html-controller

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<title>Angular Content Security</title>
@ -21,6 +21,6 @@
</head>
<body>
<app-root>Loading...</app-root>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -1,7 +1,7 @@
block includes
include ../_util-fns
:marked
Web application security has many aspects. This documentation describes Angular's built in
Web application security has many aspects. This chapter describes Angular's built in
protections against common web application vulnerabilities and attacks, such as Cross Site
Scripting Attacks. It does not cover application level security, such as authentication (_Who is
this user?_) or authorization (_What can this user do?_).
@ -50,7 +50,7 @@ h2#best-practices Best Practices
h2#xss Preventing Cross-Site Scripting (XSS)
:marked
[Cross-Site Scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) enables attackers
to inject malicious code into web pages. Such code can then for example steal user's data (in
to inject malicious code into web pages. Such code can then, for example, steal user's data (in
particular their login data), or perform actions impersonating the user. This is one of the most
common attacks on the web.
@ -81,10 +81,10 @@ h2#xss Preventing Cross-Site Scripting (XSS)
Angular defines four security contexts: HTML, style, URL, and resource URL.
* HTML is used when interpreting a value as HTML, e.g. when binding to `innerHtml`
* HTML is used when interpreting a value as HTML, e.g., when binding to `innerHtml`
* Style is used when binding CSS into the `style` property
* URL is used for URL properties such as `<a href>`
* Resource URLs are URLs that will be loaded and executed as code, e.g. in `<script src>`
* Resource URLs are URLs that will be loaded and executed as code, e.g., in `<script src>`
Angular sanitizes untrusted values for the first three items; sanitizing resource URLs is not
possible as they contain arbitrary code. In development mode, Angular prints a console warning
@ -95,7 +95,8 @@ h2#xss Preventing Cross-Site Scripting (XSS)
The template below binds the value of `htmlSnippet`, once by interpolating it into an element's
content, and once by binding it to the `innerHTML` property of an element.
+makeExample('security/ts/app/inner-html-binding.component.html')(format=".")
+makeExcerpt('app/inner-html-binding.component.html')
:marked
Interpolated content is always escaped - the HTML is not interpreted, and the browser displays
angle brackets in the elements text content.
@ -121,8 +122,7 @@ figure.image-display
### Content Security Policy
A [Content Security Policy (CSP)]
(http://www.html5rocks.com/en/tutorials/security/content-security-policy/) is a defense-in-depth
A [Content Security Policy (CSP)](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) is a defense-in-depth
technique to prevent XSS. To enable CSP, configure your web server to return an appropriate
`Content-Security-Policy` HTTP header.
@ -139,7 +139,7 @@ figure.image-display
### Server side XSS protection
HTML constructed on the server is vulnerable to injection attacks. Injecting template code into an
Angular application is the same as injecting executable code (e.g. JavaScript) into the
Angular application is the same as injecting executable code (e.g., JavaScript) into the
application; it gives the attacker full control over the application. To prevent this, make sure
to use a templating language that automatically escapes values to prevent XSS vulnerabilities on
the server. Do not generate Angular templates on the server side using a templating language, this
@ -181,7 +181,7 @@ figure.image-display
If we need to convert user input into a trusted value, it can be convenient to do so in a
controller method. The template below allows users to enter a YouTube video ID, and load the
corresponding video in an `<iframe>`. The `<iframe src>` attribute is a resource URL security
context, because an untrusted source can e.g. smuggle in file downloads that unsuspecting users
context, because an untrusted source can, e.g., smuggle in file downloads that unsuspecting users
would execute. So we call a method on the controller to construct a trusted video URL, which
Angular then allows binding into `<iframe src>`.
@ -198,12 +198,12 @@ h2#http HTTP-level Vulnerabilities
h3#xsrf Cross-site Request Forgery (XSRF)
:marked
In a Cross-site Request Forgery (XSRF or CSRF), an attacker tricks the user into visiting a
_different_ page, and has them e.g. submit a form that sends a request to your application's
_different_ page, and has them, e.g., submit a form that sends a request to your application's
web server. If the user is logged into your application, the browser will send authentication
cookies, and the attacker could - for example - cause a bank transfer in the user's name with
cookies, and the attacker could &mdash; for example &mdash; cause a bank transfer in the user's name with
the right request.
To prevent this, your application must make sure that user requests originate in your own
To prevent this, your application must ensure that user requests originate in your own
application, not on a different site. A common technique is that the server sends a randomly
generated authentication token in a cookie, often with the name `XSRF-TOKEN`. Cookies can only
be read by the website on which they are set, so only your own application can read this token. On
@ -220,14 +220,17 @@ h3#xsrf Cross-site Request Forgery (XSRF)
Angular applications can customize cookie and header names by binding their own
`CookieXSRFStrategy` value, or implement an entirely custom `XSRFStrategy` by providing a custom
binding for that type, by adding
`provide(XSRFStrategy, {useValue: new CookieXSRFStrategy('myCookieName', 'My-Header-Name')})` or
`provide(XSRFStrategy, {useClass: MyXSRFStrategy})` to your providers list.
binding for that type, by adding either of the following to your providers list:
code-example(language="typescript").
{ provide: XSRFStrategy, useValue: new CookieXSRFStrategy('myCookieName', 'My-Header-Name')}
{ provide: XSRFStrategy, useClass: MyXSRFStrategy}
:marked
Learn about Cross Site Request Forgery (XSRF) at the Open Web Application Security Project (OWASP)
[here](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29) and
[here](https://www.owasp.org/index.php/CSRF_Prevention_Cheat_Sheet). This [Stanford University
paper](https://seclab.stanford.edu/websec/csrf/csrf.pdf) is a rich source of detail.
paper](https://seclab.stanford.edu/websec/csrf/csrf.pdf) is also a rich source of detail.
h3#xssi Cross-site Script Inclusion (XSSI)
:marked