0% found this document useful (0 votes)
27 views

Secure Coding in Angular

This document provides an overview of a course on secure coding in Angular. The course aims to teach developers how to build secure Angular applications by avoiding common vulnerabilities. It covers topics like authentication, routing, input validation and dynamic content. The instructor is a Google developer expert who will explain security best practices and provide code examples. The course expects a basic knowledge of Angular development and will not teach Angular concepts, focusing instead on applying security principles at different stages of the development process.

Uploaded by

rahaf.hajmhd
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views

Secure Coding in Angular

This document provides an overview of a course on secure coding in Angular. The course aims to teach developers how to build secure Angular applications by avoiding common vulnerabilities. It covers topics like authentication, routing, input validation and dynamic content. The instructor is a Google developer expert who will explain security best practices and provide code examples. The course expects a basic knowledge of Angular development and will not teach Angular concepts, focusing instead on applying security principles at different stages of the development process.

Uploaded by

rahaf.hajmhd
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

Secure Coding in Angular

by Alisa Duncan

Resume Course
Bookmark Add to Channel Download Course

Table of contents Description Transcript Exercise files Discussion Related Courses

Course Overview Transcript links

Course Overview
[Autogenerated] Hi, everyone. My name is Alisa Duncan. Welcome to my course, Secure Coding in Angular. I
am a software developer and a Google developer expert who speaks and creates content about both
Angular and web security. Angular is a widely used spa framework with excellent built in security practices.
So we want to make sure we understand the ways Angular protects us and how to avoid common pitfalls that
will make our applications more vulnerable to attacks. In this course, we will learn how to stay secure while
developing applications using Angular in our day to day tasks from routing to handling inputs to creating
dynamic view content. Some of the major topics that we will cover include adding secure authentication
mechanisms, protecting authenticated sessions to avoid impersonation, validating inputs and managing
dynamic content to prevent injection related attacks, defensive strategies to employ when defining routing
to avoid accidental elevation of privilege and keeping your application secure when building and deploying.
By the end of this course, you will know how to mitigate security risks in your Angular application by looking
at examples of safe and unsafe code and knowing where to find more resources. Before beginning the
course, you should be familiar with the basics of developing Angular applications, but you do not need
security expertise. I hope you'll join me on this journey to learn about creating secure Angular applications
with the secure coding in Angular course at plural site.

Introduction to Secure Coding


About This Course
Web‑based applications are significant to our work and the organizations that employ us and have become a
foundation of our day‑to‑day lives. Web‑based applications are also under constant attack. Threat actors
recognize the importance of web apps and realize how impactful and damaging their attacks can be.
Organizations see the need to improve their security posture to defend against and preempt these attacks.
Hi, I'm Alisa Duncan. Welcome to Secure Coding with OWASP in Angular where you will learn ways to counter
threats, code defensively and securely following best practices, and avoid risky code using the Angular web
framework. First, let's make sure we get some prerequisites established. Security is foundational in Angular,
which means while the code examples in this course may apply to specific versions of the Angular framework,
the practices we cover are inclusive and widely available across most versions of Angular, including those
prior to the code example versions, but you're here for code examples, so the course's code examples are
100% applicable to the Angular version shown. While the previous slide showed which version of Angular the
course material is applicable for, the course's code examples were created using the Angular version shown
on the screen. Angular CLI has tooling requirements, so I'm using the listed versions of those tools. As with
any web development project, you'll also need a browser with good debugging capabilities, such as
watching and analyzing network requests and inspecting browser storage. If you want to follow along with
the code demos, you'll also want to have your favorite IDE handy. I want to note this course format may be
atypical of other Pluralsight courses you've watched. We're not learning concepts in this course by building
an application together. Instead, each module is independent of the previous ones. So consider this course a
cookbook and each module a recipe. Ultimately, you'll have all the recipes you need to assemble a great
meal or a secure Angular application. You can watch the modules in order or skip to a specific one. You'll just
want to ensure you watch this current module as it gives you the foundation of the security principles we will
apply throughout the course. We will focus on understanding web security best practices from theory to
concrete and apply OWASP guidelines for the different tasks you work on while developing web applications.
Web security expertise is not required. I will provide background info, explanation of concepts, and define
terminology so that anyone with web development experience in Angular will benefit. This course does not
include learning how to develop applications using Angular. I expect you already have some knowledge in
this area, so we'll jump into applying the security concepts. I'll suggest courses to learn Angular at the end of
this module. Security best practices apply across the entire software system. While securing back‑end APIs,
persistent storage, infrastructure, and more are vital, we will only focus on security patterns within the
context of Angular web applications. This course applies security practices to everyday development tasks
you encounter. For example, there are separate modules for authentication, routing, form input, or making
API calls. Each module adds an element of security awareness, including answering questions such as why
and which security principles are needed, then tying it into OWASP guidelines using Angular constructs and
capabilities. Demos are a great way to show and mitigate risks using security principles built in Angular, and
you'll see them sprinkled throughout the course. The demos are standalone and minimal, so you can focus
directly on the task we are examining without sifting through anything extra. In this introductory module, we'll
cover how we should approach secure coding and things to think about, even before we start coding.
Application security and secure coding don't start and end with implementation. Security comes before the
implementation phase and continues long after coding a feature. Everything is always a balancing act, and
secure coding is no exception. As with everything, there are trade‑offs, so we'll discuss the considerations
you have to factor in and figure out the right balance for your application. And since security goes way
beyond coding, you'll learn how to adopt a security first culture and how doing so can help improve your
approach to security for your software projects. We'll cover what the Open Web Application Security Project,
or OWASP is, its mission, resources, projects, and the documentation they have. OWASP has key projects we
should be aware of and they have specific examples of security practices to follow. One of them, the OWASP
top 10 has significant applicability to this course, and we'll cover each item in that top 10 list. We'll also cover
a few of the other OWASP projects as they are great resources to learn more about and apply to the software
development lifecycle.

Introduction to Secure Coding


You should keep some high‑level things in mind when approaching the idea of secure coding. We must move
towards a security‑first mindset and incorporate that mindset into the organization's culture. That's right, the
organization, because security isn't only applicable to the implementation phase. A security‑first mindset
starts before development starts. Before implementation, you should consider security implications and set a
strong foundation for each subsequent phase of the application‑development lifecycle to ensure they are
applying security practices within their phase. As we approach a security‑first mindset and culture, we must
recognize that security, convenience, and complexity are frequently at odds. An example of this might be
elevating authentication practices to prevent password breaches. Doing so increases security, but it might
be more complex to implement or manage, and it may be inconvenient to the users of the application who
aren't used to it. As with everything, there is a balance, and determining the balance is unique for each
system and organization. Another thing to consider is adopting and applying threat‑modeling concepts to
your application process. Threat modeling is communicating and identifying threats to your system and how
to mitigate them systematically. You first describe the system graphically through diagrams. Doing so allows
you to view the application for the next step better. Now that you have a more accurate system picture, you'll
identify possible risks, considered varied scenarios, and environment or state changes that might affect
exposure. Next, you'll define mitigation actions for those risks. Finally, you'll determine how you can validate
when the risks manifest and how to verify the success of the mitigation actions you defined. You want to
ensure that the risks are something to prepare for and have the assurance that those activities will be
successful. The Open Web Application Security Project, OWASP, is an excellent resource for helping
incorporate security best practices into the application‑development process and within the implementation
phase. They are a nonprofit foundation that works to improve the safety of software. OWASP has a lot of
different projects, and its endeavor to improve the security of software that impact the entire
software‑development lifecycle. We'll cover each of these projects in greater detail later in this module.
OWASP Top 10 is a top 10 list of the most common and impactful categories of software vulnerabilities.
Software Assurance Maturity Model, or SAMM, helps organizations create a tailored strategy for software
security based on specific risks they face. Application Security Verification Standards, ASVS, creates a basis
for testing security in software applications. Proactive Controls is another top 10 list that identifies the
highest priority security techniques to include in every software project.

OWASP Top Ten


Perhaps the Open Web Application Security Project's most well‑known project is the OWASP Top 10. This
top 10 list identifies the most critical security risks to web applications and aids standardized awareness
about their security. Through this list, we can have assured language for communicating about security and
the vulnerabilities we face. The OWASP team analyzes many applications and derives outcomes, resulting in
a ranking of categories of vulnerabilities. The OWASP Top 10 is so critical that developers globally recognize
it as the first step towards more secure coding. This OWASP project is fundamental to how we approach
secure coding. The list is updated periodically and may change with each iteration. The threat landscape
evolves, and the OWASP 10 captures this evolution. This image, which is directly from the project site, shows
the change of the list from the previous iteration. Let's look a bit more detail into each of the items of the top
10 lists. Broken Access Control is a category of vulnerabilities stemming from users acting outside the
intended permissions or viewing information they shouldn't. Ensuring we don't have broken access controls
in our Angular applications will significantly be featured in this course. Cryptographic Failures are concerns
about failing to protect data related to poor or missing cryptography. This topic's only coverage is a reminder
to always use a secure transport security layer. Injection includes injection attacks of all forms. Injection
attacks are external threats that actively try to cause damage by injecting their malicious code into yours. We
will focus on preventing injection attacks in several modules of this course. Insecure Design is the recognition
that design and architecture flaws can cause risks implementations alone can't mitigate and that security
needs to be at the forefront of those precode activities. You've already seen this category woven within this
module, and you'll see it again in later ones too. Security Misconfiguration is incorrect infrastructure or
tooling settings that inadvertently expose more information than intended or create inconsistency in the
infrastructure configuration. We'll touch on this topic when discussing ways to prevent injection attacks.
Vulnerable and Outdated Components are the dependencies we use and whether they have vulnerabilities
or are outdated. We'll talk more about this in a later module, as it does impact Angular applications.
Identification and Authentication Failures include preventing authenticated‑related attacks from being
successful, ensuring the user's identity, and session management. Angular applications house the front door
to the software system, so we will talk about authentication in more detail. Software and Data Integrity
Failures relate to vulnerable and outdated components, but focus on the supply chain of dependencies.
Considering how impactful supply‑chain attacks have become, we will cover this category in more detail
when we discuss managing dependencies. Security Logging and Monitoring Failures ensure you have
enough logging and monitoring within the software system to detect attacks and that you've captured
enough information to assess the application's health adequately. This course skips this topic as it's mostly
outside Angular scope. And lastly, Server‑Side Request Forgery is a vulnerability where an attacker
manipulates a server‑side URL to fetch resources from an unintended location. As it is solely about ensuring
systems outside of Angular prevent this attack, we won't cover the topic beyond this overview. Because we
focus on tasks you encounter as you develop your Angular application and not on each OWASP Top 10 item,
an individual module in this course may draw on principals from more than one OWASP Top 10 item, and a
top 10 category may influence security practices in multiple modules. Each module intro will also note which
OWASP Top 10 category it relates to. I always appreciate seeing and experiencing things for myself, and
you're probably the same. Let's look at the OWASP site together and see how everything fits together.

Demo: OWASP Top Ten


OWASP has a lot of resources. We've only covered the Top Ten so far, but you can already see how valuable
the information on this site must be. Let's better understand what's available on the OWASP website and
how to find resources. First, we'll take a look at the OWASP main site and see how to find the key projects and
how we can search for information. Next, we'll navigate to the OWASP Top Ten project site and take a closer
look at what's included there. Finally, we'll inspect one of the OWASP Top Ten categories to go over the
different sections it contains and how we can find critical pieces of information on the page. We'll start by
looking at the main OWASP website. This page introduces OWASP, contains news and spotlights content and
upcoming events. This is a great place to start because you can access key projects from this handy
drop‑down selector menu. For example, we have the OWASP Top Ten at the very top. You'll also see software
assurance maturity model listed here and some projects for helpful tooling. We won't get too deep into
those, but we will refer to a couple in upcoming modules. If you can't find what you're looking for in the
projects menu, you can try searching for them. We have yet to cover application security verification
standards or proactive controls in more detail, but you'll want to search for those projects. You can search for
terms such as Top Ten or authentication, and get results. Next, let's check out the OWASP Top Ten. The Top
Ten site introduces the Top Ten project. You'll see the change in the list from the previous version and the list
of Top Ten categories and information about them. If you look at the first one, Broken Access Control, it
moved up on the Top Ten list and that 94% of applications tested had some sort of broken access control.
Ouch. Ah, this category must be a slippery one. Let's look at this category more closely by navigating to it.
Each Top Ten category page starts with a table of factors. This is where we can see some metrics about this
category such as the number of CWEs, which are common weakness enumerations mapped to this category.
CWEs are community‑driven lists of software and hardware weaknesses. They serve as a common language
to describe weaknesses that have security implications. Scrolling through the rest of this factors table lists
the total number of occurrences found during testing, which is staggeringly high, and the number of CVEs,
which are common vulnerabilities and exposures related to this category. On the left and the right of the web
page, we have navigation. On the left, we can see links to other OWASP Top Ten categories, so you can hop
around to the categories you want to read more about. On the right, there's navigation links within this
category. Next, as we scroll down this page, we have an overview of the category and notable CWEs, such as
the exposure of sensitive info to an unauthorized actor and cross‑site request forgery. The description is
helpful. It provides specific examples of how access control breaks and what constitutes a problem. Many
different things are listed, including violating principles of lease privilege, bypassing access control checks,
missing access controls on API calls, the elevation of privilege, and more. Next, there is a guideline on how to
prevent this issue from occurring. This is one of my favorite sections of the OWASP Top Ten page because
examples bring it all home. You probably feel the same way. Here, we see scenarios of attacks so we can be
prepared for defensive measures. Luckily, this web page has links on where we can get information about
proactive steps to prevent broken access control from happening or on how to test this for problems and to
better understand some of the terms and concepts covered in this category. Their list of references is handy.
You can see direct links to the corresponding page about access controls on other projects, such as the
proactive controls, testing using ASVS, and more resources to understand the concepts better here. Lastly,
we get to a list of CWEs, the common weakness enumerations mapped to this category. It's an extensive list,
including path traversal, permission issues, forced browsing, improper authorization, cross‑site request
forgery, incorrect authorization, and more. This category is quite a doozy. We'll cover different aspects of
broken access control in multiple upcoming modules, so you'll see examples of the various attack
mechanisms and how to mitigate the risks.

Key OWASP Projects


A few other OWASP projects complement the top 10 list and are go‑to references as we develop software
applications. I'll go through each of these projects quickly to introduce the project and when you'd want to
refer to them. Software Assurance Maturity Model, SAMM, improves the security of your entire software
project lifecycle. Application Security Verification Standards, ASVS, ensures you test the software
consistently and adequately for your system and organization's needs. And OWASP Proactive Controls is a
developer‑specific security technique list we should use and refer to as we implement software. I'll include
links for these projects for you to reference later. Starting first with the Software Assurance Maturity Model. It
helps you create a model for improving your secure development lifecycle and outlines different measures
for each process step based off of what works for your organization. This model is organization, framework,
and technology independent. It helps you identify the strategy to use as you create software applications.
Since it's not prescriptive, it allows flexibility to tailor it to your organization's current state and where and
how it wants to grow in security maturity. This diagram, taken directly from the SAMM project, breaks down all
the steps and aspects of the software‑development process to consider. Each step identifies maturity levels
so you can determine where you are now and help your organization's software‑development process grow
in a specific arena. And because of the model's flexible structure, you can choose different maturity levels for
each area which meet your organization's interest and needs. Application Security Verification Standards,
ASVS, is another key project that provides a blueprint for security testing in web applications and creates a
consistent methodology for testing. By creating consistent methodologies for testing, it normalizes both
coverage and rigor, which makes understanding the different testing levels defined, a shared and
understandable language that also aids in communication and expectations. Each testing has three levels
you can specify in the business requirements phase. Level one is the baseline. This level is the minimum
requirement you should shoot for. Next is level two, which is more rigorous than level one, but is the sort of
defense most of us need as we work on B‑to‑B software and business‑critical applications that we work on
for our organizations. The most rigorous testing is for software requiring significant security oversight, such as
those needed for military and critical infrastructure. The last OWASP project we'll discuss in this introduction
is the Proactive Controls, an essential resource we should be aware of and refer to often, as it provides a
prioritized list of security techniques we can apply to our implementation. The Proactive Controls is the other
top 10 list for developers and architects to use as a guide for secure coding. It converts the OWASP Top 10
information into a technology‑agnostic checklist. The project recognizes that developers usually don't have
the support and resources we need to apply secure‑coding practices since formal education settings usually
overlook these topics. It cross references other OWASP projects and resources to create a compilation of
developer‑centric takeaways. Another project that closely resembles the Proactive Controls, but isn't in a
prioritized‑list format, is the OWASP Cheat Sheet Series. It provides an overview of implementation concepts,
a lot of information about factors to consider when implementing, and practical takeaways in a
technology‑agnostic format. You'll want to reference both when you get into the implementation details.
Both projects are a treasure trove of fantastic security recommendations and guides. Here are the
references I mentioned. I added a URL and a link to the projects. The SAMM project is hosted outside of the
OWASP domain, although it links from the site. An excellent starting point is navigating to the OWASP site
and then using the project menu or search. If you need to learn how to code using Angular or if you need a
refresher, check out the Angular Fundamentals course within this skill path. We covered a lot in this first
module and set the groundwork for the upcoming ones. This course is a collection of recipes, where each
recipe is a guide for adding security practices. It is not a novel that takes you on a journey from start to finish.
You can choose the task you want to focus on and get practical examples of how to approach the task
securely. Secure coding extends beyond coding. It should start way before in the requirements‑gathering
phase and extend way after to ensure the application continues to be secure. We often think of security as
secure coding. And yes, it's a big part. But remember to consider security in all aspects of software
development. Embrace a culture of security within your team and organization. We have a great resource
with an internet connection and a few taps on our keyboards. OWASP has a lot of helpful information and
resources we can use. You'll want to refer to the OWASP Top 10 regularly. It's best to understand the
landscape, the top threats, and how to mitigate them. Use the Software Application Maturity Model, or
SAMM, to get guidance on improving security through your entire software‑development lifecycle. By
allowing you to customize the different maturity levels, you can create a strategy for software development
tailored to your current stage and where you want to grow. Adopt the Application Security Verification
Standards as a guidepost for testing your application regarding security. You'll want to achieve at least a level
one, which is that your application incorporates the guidelines from the OWASP Top 10 and doesn't have
easy‑to‑find vulnerabilities. Beyond that, you'll want to incorporate the standards that make sense for your
application and organization. And finally, lean on the OWASP Proactive Controls. This other top 10 list should
be something to refer to as you start implementation phase of your application. With specific practical tips
and guidance on things to think about, it will be your new best friend, especially when you add in the OWASP
Cheat Sheet Series too. I always refer to these two projects, and you'll likely find them equally handy. This
concludes the introductory module to the Secure Coding with OWASP in Angular course. Please join me in
subsequent modules, as we apply security concepts within our Angular application.

Managi
Identityng Authentication and
Introduction
All software needs authentication, a solid front door into the application and to identify the user interacting
with it. Hello, I'm Alisa Duncan, and welcome back to Secure Coding with OWASP in Angular. In this module,
we will cover authentication and identity within the scope of an Angular application. All software systems
need authentication, and we want to ensure ours is strong to prevent attacks and for them not to be
susceptible to failures. We'll walk through scenarios that allow authentication and identity failures to occur so
you'll know how to avoid them. Applications have unique needs, so you'll identify the authentication
practices to use. We've all heard about hacks and data breaches and their impact, you may be even
watching this course because your organization is improving its security posture to guard against those sort
of attacks. Unfortunately, attackers are savvy, so old ways, such as password‑based authentication, may no
longer be good enough. You'll learn how you can elevate your authentication requirements to add better
authentication protection mechanisms. We'll cover industry recognized best practices for authentication and
learn about the importance of authentication and authorization. They go hand in hand, and you'll need both
in most Angular applications, and using industry best practices like OAuth 2.0 and OpenID Connect. Just
because you use widely accepted mechanisms, if they are poorly applied, you can still be vulnerable to
authentication related failures, which we don't want. Finally, you'll see how to incorporate authentication and
authorization into your Angular application through a code demo, so you can see the concepts in practice
and be able to integrate them into your application swiftly. We're applying security practices as identified
from the vulnerabilities in the OWASP Top Ten list. This module draws upon the OWASP Top Ten category,
Identification and Authentication Failures. Authentication grants users access to the application. Once a user
has access, they can perform actions that could impact the application. Secure authentication helps mitigate
authentication‑related attacks, and those attacks are more prevalent. The majority of data breaches stem
from an authentication‑related attack, such as using weak or stolen passwords, social engineering attacks,
phishing, or through credential‑stealing malware. We must ensure our applications use authentication best
practices to avoid this situation.

Robust Authentication Mechanisms


Having a strong authentication mechanism is essential for applications. Since getting past authentication
means having access to the application and being able to act as another user, it's crucial to ensure malicious
parties can't easily make their way in. Each application can have a different threshold of what that looks like.
Understanding the authentication requirements is a necessary first step. Some organizations may require
highly‑elevated authentication safeguards because of the very nature of their work, such as when it affects
critical infrastructure, government, or the military. Refer to the OWASP ASVS and the OWASP SAMM to
identify what authentication should look like for your application and organization. Authentication
mechanisms should protect against automated authentication attacks like bots and other brute force attack
formats. You may need to add a challenge step for entry, such as CAPTCHA. You want to ensure that there is
a real user, not an automatic process trying so tirelessly to gain access. When you have passwords as a
factor, you want to avoid anti‑patterns that may feel like you're increasing security when you aren't. Some
anti‑patterns include not supporting an adequate character length. Passwords should require at least eight
characters. Conversely, don't set the maximum too low, allow up to 64 characters. Requiring a specific variety
of characters, or curiously, not allowing a specific character, such requirements are locale‑specific and don't
incentivize users to create long passwords. You want to allow all characters, including Unicode. Not offering
password strength indicators in the UI. Password strength indicators help users understand the strength of
their passwords by checking against compromised password lists and verifying for complexity, such as
making sure the user doesn't repeatedly use the same character as a password. And you want to investigate
and embrace modern authentication patterns. This often means moving beyond username and password,
and considering multiple factors, specifically, phishing‑resistant factors. Multi‑factor authentication means
you're relying upon two or more factors of authentication. The factors include something you know, such as a
PIN number, something you have, such as a device, and something you are, such as through biometric
recognition. There are anti‑patterns you'll want to avoid when relying on multi‑factor authentication as well,
such as using security questions as a factor. Security questions can be hacked through social attacks.
Security questions are no longer recommended as a factor by security professionals, including OWASP.
Using SMS as a factor, since it is phishable and recently came under scrutiny as a cause of many high profile
breaches. Secure authentication and identity are complex. Recommendations and standards are updated
regularly due to the threat landscape, and implementing multi‑factor authentication can also be quite tricky
and time intensive.

Identity Providers
Because of the complexity of authentication, delegating this work to a reputable identity provider who
handles the intricacies of authentication and supports best practices is advised. Using an identity provider
allows you to centralize your authentication and identity model in one place, so if you have to support
multiple authentication formats, you can use an identity provider to consolidate and configure the work.
There are open‑source identity providers available. Paid models have value added features. Deciding which
way to go or which identity provider to use is entirely up to the needs of your application and organization,
but you want to avoid custom building something, as that is a sure way to invite trouble. A standard
mechanism for authentication and authorization is using OAuth 2.0 with OpenID Connect. OAuth 2.0 is a
widely used industry‑standard protocol for authorization. While this module focuses on authentication and
identity, authorization, that is ensuring access to the requested resources and performing requested actions,
is integral to most applications. OpenID Connect, or OIDC, is the identity layer on top of OAuth, which
handles authentication. OIDC is the means to identify user information in a standardized format.
Authentication and authorization work hand in hand, and most applications require both. Secure
authorization and authentication with an identity layer ensure we safely support the user's identity and
actions. Now we know who the user is and what they can do. OAuth and OIDC are big topics, but the
essence of using this authorization and authentication mechanism in Angular applications distills down to a
couple of key points. First, OAuth has different flows for the authorization process. You should use the
authorization code flow with the Proof Key for Code Exchange, or PKCE, extension for Angular applications.
While authorization code with PKCE sounds like a mouthful, this is a standard flow, so your identity provider
should support this. For your Angular application to connect to the identity provider and handle the Angular
side of the recommended OAuth flow, you should use an OIDC certified library. In addition to the SDKs your
identity provider might provide, we're fortunate to have a couple of open‑source libraries available to us in
the Angular ecosystem. We'll see how one of those OSS libraries work when we add authentication to our
Angular application. While we mostly focus on authentication as a way to enter the application, we can't
forget about when users exit the application, meaning, we must handle the revocation of access. Signing out
is as equally important as signing in. Since authentication and authorization gains access to the software
system, you must remove auth tokens and user information when the users sign out of the application.
Fortunately, most OIDC libraries handle this for us, so let's check it out.

Demo: Adding Authentication


Time for a code demo. In this demo, we will add authentication to a minimal Angular application. The user
initiates authentication using a login button. Then the home component displays identity information about
the authenticated user. We'll use an authorization server from a trusted identity provider supporting OAuth
2.0 and OIDC. I'll use a free developer account from a paid identity provider for this application, but you
could use any authorization server you want. As long as it conforms to the specifications, it will work. The
entity provider I'm using supports elevated authentication mechanisms in its developer account, so I
pre‑configured it to use a form of authentication called passkeys using biometrics. It's more secure and you
won't have to watch me type my password. The front end has work to do as part of the OAuth flow
handshake. We want to use a trusted library to handle that for us. I've added a certified OIDC client
open‑source library written for Angular applications called Angular Auth OIDC Client. The Angular Auth OIDC
Client does the heavy lifting for us, so all we need to do is add it to our application, but, there is some
configuration to handle, of course. OAuth and OIDC have specific metadata requirements. You'll need a
couple of pieces of information about your authorization server that should be readily available within your
identity provider. I'll describe the configuration requirements in more detail when we get to them. Finally, we'll
demonstrate user revocation of access, Authentication mechanisms should support users logging out, and
when that happens, any authentication tokens and user identity should no longer be available. The identity
provider handles the actual authentication or granting the consent, so you'll see how this whole thing works,
including a working demo of the code. Hey, its a demo of a demo. You can also follow along locally by using
my code project. I added the link to the GitHub repository in the slide so you can fork, clone, or download it.
Then navigate to the project directly for the demo, install the dependencies, and open it up in your favorite
IDE. Let's dive in. You can find this code project in my GitHub repository using the link I shared. I already
added the angular‑auth‑oidc‑client to this project's package manager, so we'll bring in the library into the
application and add the configuration values when initializing the Angular application. If you follow along with
the demo, you'll need an identity provider to connect to. I recommend using an identity provider that
provides a free developer account that you could use for experimentation and learning. I'll include some
options in the project's README file. You need two crucial pieces of information about your authorization
server from the identity provider. You need to set the authority of your authorization server. Your identity
provider may also call this the issuer. You also need a unique identifier for this application to connect to the
authorization server. Most identity providers generate this for you when you walk through the configuration
steps of setting up an application within the identity provider. Add this ID as the ClientID value. To maintain a
secure authentication experience and to keep authentication at a lower level of effort, let the identity
provider do the heavy lifting of dealing with the different authentication mechanisms for you. This means
we'll redirect to the sign‑in page hosted by the identity provider. You can keep the value for redirectUrl to
the Windows origin location. Same with the post logout redirect URI. The scope is where you define what you
want access to. For OpenID Connect, you'll always add the openid scope. If you used refresh tokens, you'll
use offline_access, but I won't be needing it today. Profile gets you access to the user profile endpoint, a
standard endpoint for user metadata from OIDC. Next, let's take a look at initiating the security service. The
app component hosts the router outlet, so this component displays for the duration of the application's
lifetime. This is a perfect place to initiate the OIDC library service. You can see that we're initiating the service
for the lifetime of this application and keeping it running as well, but we'll also write out to the console so we
know when everything's authenticated, just for some developer debugging. Lastly, let's take a look at the
home component. The home component displays the login and logout buttons. It also shows the user
metadata called Claims. The component code has a few more calls using the OIDC library. It supports the
code behind the login and logout buttons. It also gets some values such as those claims, pulls out the claims
for the name, and adds a boolean for whether the user is authenticated. This is all of the code for the
application. There are some things we're doing to startup services, initiate the authentication process, get
specific claims and handle the revocation of access, but that's it. The library and the authorization server do
the rest of the work. Let's see the code in action. This is the application before logging in, it's pretty plain, as
you could see. I'll first open up the debugging capabilities because you never know what you might want to
inspect. Ensure you have preserve log enabled so you can see all of the calls and redirects. Let's show some
user information. I'll press the Login button, which redirects me to the sign‑in page hosted by my identity
provider. I'll authenticate and use my biometric information to do so. The passkey is set up on my phone, so
this is where I'll be putting in my fingerprint. I'm now redirected back to the Angular application and the app
now shows information about me. I've zoomed in so you can see it more clearly. The OIDC library saves
tokens in session storage, although you can configure it to use local storage instead. You can see the ID
token, including those claims in the home component. Feel free to inspect it at your leisure. Now that we've
found where the token granting access is, we can demonstrate revocation of access. We'll press the Logout
button. This action informs the authorization server that the user revoked access. As a result, the user is no
longer authenticated, the user information no longer displays on the screen, and most importantly, the
tokens are cleared out to prevent access to the application. That's all for this demo. You can see how
straightforward adding a secure authentication and identification is when using standardized mechanisms
and OIDC certified library within Angular. Using the identity provider made setting up the authentication a
breeze, and importantly, made using elevated authentication factors very straightforward. All robust
authentication and identity processes should rely on industry standards, trustworthy services, and libraries.
Doing as little work as possible makes our Angular apps more secure than if we try to implement all this
ourselves.

Summary
As you saw in this module about managing authentication and identity, authentication failures stem from
various sources. We must play a proactive role in following best practices to mitigate attacks. Understanding
your authentication requirements is key. Depending on your application and organization, you may need a
super high level of authentication security, or, enough to prevent the common attack vectors. It's key to
understanding your authentication needs and ensuring you meet them. Attackers target passwords in
various ways, such as credential stuffing and brute force. Relying on your users to follow best practices is not
the best idea. Users are motivated by the ease of authenticating, and many of them love using the same
passwords repeatedly, which is rife with security concerns. You may need to elevate your authentication
factors to prevent authentication failures, such as considering multi‑factor authentication or using
non‑phishable factors. Industry best standards means security professionals have vetted and tested the
authentication mechanism. Vetting and testing at that level are beyond what we can or should do as part of
implementing authentication. If you don't remember anything else about this module, please remember this,
use proven standards like OAuth 2.0 and OpenID Connect. Proven standards are vitally important, but using
libraries that meet those standards is just as important. Use certified libraries. This means using a reputable
identity provider with those standards built in and certified OSS libraries within your application too. Avoid
falling into the trap of writing your own authentication mechanism, it is far too risky.

Managing Sessions
Introduction
We use sessions to add additional metadata for each action a user takes to tie all related requests from the
user. Since the additional session metadata can include secret information for accessing resources or
validating the user's identity, we must follow best practices and guard critical session information. Welcome
back to Secure Coding with OWASP in Angular. Hi, I'm Alisa Duncan, and I'm delighted to have you join me.
We will discuss ways to securely manage sessions across their entire lifecycle, including what sessions are
and why they are used, the things you want to consider to start a session, and handling expired sessions and
having the application reflect the state in a seamless and security‑minded way. Once we have an active
session, there's work we must do, as protecting the active session is important for security. Active sessions
are targets of attack, so we'll cover the common session‑related ones. Then we'll apply this practice to
mitigating a common web attack in Angular. We're applying security practices as defined from the
vulnerabilities in the OWASP Top Ten list. This module draws upon three OWASP Top Ten categories, Broken
Access Control, Security Misconfiguration, and Identification and Authentication Failures. Sessions in web
applications fulfill two concepts, organization and holding information. Sessions organize related requests
from a user. Usually related means those requests are within a time period. Ideally, the session begins before
authentication so that it can accurately capture all the requests from the user, including the authentication
process. Once authenticated, the session reflects that state and the authenticated session may be valid for
some time or until the user revokes access. Sessions can be either a cookie or a token, both are usually
supplied and managed by the back end. The Angular application needs to react to any session state
changes and help protect session information from leaking.

Session Considerations
Session management is a big topic for software systems and extends beyond the scope of user‑facing
applications. Furthermore, depending on the application and your organization's business requirements, you
may require unique session handling needs, so it's crucial to refer to the fantastic resources OWASP has on
this topic during the software planning phase and implementation. It may help to think of a session flow in a
diagram like this, directly from the OWASP cheatsheet series. There are different stages of sessions from the
point of view of the user interaction with the software application. We're focusing on sessions only in this
module, as we cover authentication and access control in other modules within this course. This session
discussion emphasizes the security aspects of session management and session finalization. There's much to
consider regarding sessions. For example, you may want to consider factors such as when do sessions start?
Should you start capturing and recording session information before authentication, or wait? How do you
convert pre‑authenticated sessions into authenticated sessions? How do you manage storing
session‑related metadata? What sort of information will you keep? How do you want to structure the
information? Should the format use tokens or cookies? It may depend on how your system is set up. Where
will you store the token within the client if you use tokens? Once you have an authenticated session, should
you have time constraints on a session and require them to end at a specific time, or do you support
extending session length as long as the session continues to be used, also known as sliding sessions? How
this is handled and implemented may be a server‑side specific concern and the front end only worries about
whether the session is expired. Still, a long‑running session may impact the Angular application depending
on how you identify the session use. Does session use require a back‑end call? Or can there be user
interaction with the front end only? Does the front end have processes or services running tied to the
session that may impact performance if the session runs too long? Plus, you may need to consider
server‑side best practices, not just for implementation, which is outside this course's scope, but precisely
how those best practices implementation may affect the front end. Sessions have to start somehow. We'll
skim the surface about the how‑tos of starting a session because it is system specific, and the back end may
handle it entirely. If the session starts before authentication, the front end may need to make extra calls to
the back end to initiate session on application load. Or, there may need to be a different way to handle it as
part of the authentication process. Now that there's a session, you'll have security practices you'll need to
incorporate when managing it. You'll learn more about that coming up soon. Lastly, sessions end in some way.
Sessions can ultimately expire, or a user can revoke them intentionally. Let's dig deeper into ending sessions
and learning best practices around handling it. Handling user revocation of access when a user intentionally
signs out of an application and when sessions expire are essential to the user‑facing application. When a user
intentionally signs out, the application should react accordingly, ensuring that the user no longer has access
to protected resources and views and clearing any tokens granting access. The same behavior applies to
expired sessions as well. Let's take a look at how you might handle this within your application.

Demo: Session Expiration


When a session expires or a user revokes access, users shouldn't access protected resources. You'll start by
mocking authentication to the application to simulate an active session. Then watch for session exploration,
which prompts the application to redirect the user to a public view without any protected resources. You'll
also see this behavior if the user logs out of the application. You can follow along locally by using my code
project. I added the link to the GitHub repository in the slide so you can fork, clone, or download it. Then
navigate to the project directory for the demo, install dependencies, and open it up in an IDE. In this demo,
we'll show a way to handle session expiration. You should no longer allow access to protected resources
when a session expires. A session can end due to tokens expiring and because the user revoked access, so
just by logging out of the application. Let's look first at the user‑revoked access. This application is a very
minimal Angular application with two routes. The home route is the default and displays the home
component. Everyone has access to see the home component view. There is a protected path to a protected
component that only authenticated users should see. Please note if you're following along locally with the
project, I've removed some code to allow you to better focus on the pertinent part of this demo. I added a
very basic auth service to mimic authenticated state. It emits an auth state upon changes. It also supports
login and logout in the simplest way possible for demonstration purposes. The login method simulates
expiration by setting a timeout, which will change the authenticated state. Ideally, your authentication library
supports event changes for session exploration. Most of the libraries I've seen do. How we react to this event
is the pertinent part of the discussion. The home component has text welcoming everyone. This is all that will
display by default. The protected component has text informing us that only authenticated users should see
this view. The central smarts for this application reside in the app component. Here, we have the view which
shows navigation to the home of protected views and a friendly greeting based on the authenticated user's
name. There's also logic to display a login and logout button. The component has a reference to the auth
service. The auth service emits authenticated state so we can use the information to determine whether to
show certain UI elements. The authenticated state also includes the user's name so that we can display that
as well. The app component watches for authenticated state changes. The application navigates back to the
home view if the user's state changes from authenticated to not authenticated. This is one way to handle
session ending, whether by user revocation or session expiration. Forcing navigation away from a protected
view immediately makes sense when the user initiates cancellation of an access. Still, there might be extra
steps your application should take if the session expires, such as saving the user's in‑flight work first or
adding some mechanism to allow the user to extend the session, depending on whether your software
system supports it. We'll demonstrate this most straightforward case. Let's start the application and view how
this works. First, you see the home view. If you press this Login button, we simulate authentication. This is a
huge skip in application security, so I recommend checking out the Managing Authentication and Identity
module to securely fill this gap. Now that you're authenticated, you see the route link to the protected view.
Let's check it out. The protected view displays information warning us that only authenticated users can see
it. First, we'll manually revoke access by pressing Logout. Now that we're no longer authenticated, we're
immediately taken back to the home view since we shouldn't have access to the protected view anymore.
Let's try this one more time and simulate session exploration. We'll log in again, then navigate to the
protected view. This time we want the session to end. The auth service simulated session expiration after a
short time. The application logs to the console when the session expires, so we'll open up debugging
capabilities to view the console logs. And now we wait for the session to expire. Now we see the console log,
and we're navigated back to the home view when the session expires. We're treating session exploration the
same as revocation of access. You may have a more nuanced need in your application than this approach,
but the outcome should be the same. The user should no longer be able to access protected resources and
views or perform actions when their session expires.

Protecting Sessions
When you have an authenticated session, it's vitally important to protect it. The session, a token or cookie,
holds user variables, some of which may include sensitive personal information and permit access to
resources and actions. You want to avoid letting a session fall into the wrong hands. A malicious party can
use it, causing significant damage. Protecting the active session is essential to application security. There are
ways to keep sessions secure and avoid session hijacking. For both tokens and cookies, you must ensure all
communication between your user‑facing application and the back end is secure using appropriate
transport layer security and encryption. Secure communication between systems is necessary to mitigate
meddler‑in‑the‑middle attacks. The back end should limit third‑party requests to avoid malicious actions with
stolen sessions. If you use session cookies, the back end needs to add adequate security. There are built‑in
modern browser capabilities for cookies to help keep them out of unsafe hands, such as the same‑site
attribute to limit the cookie from being shared with third parties. The category of session attack I'm referring
to is Cross‑site Request Forgery, or CSRF. This attack forces an end user to execute actions they did not
intend to, and can only work when they have an authenticated session with that application. You'll see both
acronyms for this attack, CSRF and XSRF, but both mean the same thing, Cross‑site Request Forgery. An
example XSRF attack might look like this. The attacker sends you a malicious link embedded within an email.
The email spoofs your bank and urgently wants you to sign in, prompting you to do so. You sign in at your
bank. Your bank manages sessions using cookies, but doesn't have appropriate protection mechanisms, and
now you have an unprotected authenticated session cookie. The email is alarming, so you click the malicious
link navigating you to a malicious website. Your browser automatically forwards the unprotected session
cookie to the malicious site since the cookie allows a browser to do so. The malicious website makes a
request to your bank asking for a money transfer. The session cookie automatically forwards back to the
bank. Since you have the active authenticated session as part of the request and because your bank doesn't
verify the authenticity of the request, the bank processes the transfer request. The transfer proceeds,
allowing the attacker to steal hard‑earned money from your bank account. Using the built‑in modern browser
capabilities, such as limiting where the session cookie forwards to and restricting cross‑origin requests by
defining strict policies helps. Your back end has a hand in managing this. The next step is to verify the
authenticity of requests using an enhanced mitigation scheme. For stateless session management
architecture, commonly used for client‑side front‑end applications like Angular, it is to use something called
the double submit cookie pattern. This strategy adds a new cookie specifically for XSRF mitigation that holds
a secret random value. The back end generates this XSRF token cookie and provides it to the front end. The
front‑end application automatically sends the cookie back to the back‑end request, but it also adds a secret
value in a secondary vehicle for the back end to validate. The back end has work to do in this pattern to
ensure validity by verifying the cookie and the secret value.

XSRF Protection in Angular


Angular has built‑in support for the double submit cookie pattern. The default behavior for an XSRF
mitigation strategy is to send the value as a header in HTTP requests. Add the code mechanism appropriate
for your Angular application as shown to get the behavior of automatically including the cookie value as an
HTTP header. Remember, the back end needs to validate the request or else you will not have the protection
mechanisms this pattern affords. Let's take a look at the code to add the XSRF protection in greater detail.
Here are the steps to add the double submit cookie pattern to your Angular application. These steps add
XSRF mitigation protection using the default cookie and HTTP header names, which are XSRF‑TOKEN and
X‑XSRF‑TOKEN, respectively. These defaults are configurable. You can change the cookie and header name
to names that the back end expects by configuring it when you add the mitigation pattern to your
application. Here, I am showing the default cookie and HTTP header names in the configuration option, but
you'll want to override them. You can configure and change each property separately to have the flexibility
your system requires. Let's see what XSRF protection looks like in action.

Demo: XSRF Protection


This is going to be a big demo. We saw how XSRF works, so let's get into mitigating the attack using the
double submit cookie pattern. We'll need a back end to show how this works end to end. We'll start by
reviewing a minimal express API used in the demo. The last thing we want to do is enable CORS in a way that
makes us less secure, so we'll configure Angular to run on the same port as the API using a proxy. The
Angular front end will get an XSRF token cookie from the API so we can see the mitigation working, and then
we'll inspect network requests to verify the exchange of the XSRF token. You can follow along locally by
using my code project. I added the link to the GitHub repository in the slide so you can fork, clone, or
download it. Then navigate to the project directory for the demo, install dependencies, and open it up in an
IDE. Let's dive in. This application has two parts, the Angular front end and an express API back end. The API
code has only the bare requirements to demonstrate the back‑end handling for the XSRF mitigation strategy.
The server handles generating the XSRF token cookie, so the express app needs a few libraries, such as
cookieParser. Since we'll want to demonstrate the XSRF token added to the API communication, the
application spoofs a messaging app. As a result of handling POST requests, we'll need to parse the POST
body. The server must generate a cookie and get that to the front end. Here, we have an XSRF endpoint for
the front end to call. There may be better mechanisms for your application, but we'll take the most
straightforward path. Please do not use this demonstration code as an example of creating secure express
APIs, we're focusing on Angular only. The XSRF endpoints creates a cookie with the token value of top secret
and sets the value in the cookie called the XSRF‑TOKEN. Exposing an endpoint to get the XSRF token is risky,
so we'll limit attacks by adding the sameSite strict attribute. This means the cookie can only pass in a
first‑party context. Notice CORS is not enabled. We need the Angular front end to make the API calls in a
first‑party context. Now we'll move on to the Angular application. What we'll do in Angular is use a proxy
when running the application so that all outgoing API calls use the same port as the express API. You can set
up the proxy in a separate file and add the configuration to use the same port. You want to use the proxy
settings when serving the application, so add the proxy configuration location to the serve options within
Angular JSON. With this, the API calls use the proxy location. The application adds an XSRF protection built
into Angular. Even though I'm using the default cookie and header names, I edit the configuration to use the
default names so you can see where you would do that. I want to get the XSRF token cookie immediately
upon app initialization, prior to authentication, so I'm using the APP_INITIALIZER injection token to call a
factory method that will call the XSRF token endpoint on the API. The factory method is very minimal, it calls
the XSRF endpoint of the API using the HTTP client. The message service has two API calls, one to get
messages, which won't include the XSRF token, and one to add a message. The POST request will include
the XSRF token. The protected component allows you to add messages and communicate with the API, but
it's spoofed, so there's not a lot of communication going on. But with this, we can post to the message's
endpoint, which will allow us to see the XSRF token exchange in action. The protected component calls the
message service and adds your username. That was a bit of setup required to see this code in action, let's
start it up. First, we need to start the express API. Now we can start up the Angular application. Now you see
the Angular application, it's pretty minimal. Before we get too far, let's open debugging capabilities. We'll
want to see the cookie and the network requests. Let's reload the application to see the initial call. We see
the first call to the XSRF endpoint. If we look at the network requests, we see we got a cookie. Let's check
this out. We see we got a cookie named XSRF‑TOKEN, and that value is top secret. Cool. You can log in and
navigate to the protected view, where you see a message from Mabel. The XSRF protection works by adding
the XSRF token to outgoing calls that require it. Let's take a look at that message's network request. We can
click on the cookie tab to see that there is a cookie sent, but if we look at the request headers, we see that
there are no request headers for the XSRF token. The XSRF token protection works by adding the XSRF
token to outgoing calls that require it. We need to make a different HTTP request, like POST. Let's send a
message back to Mabel, such as Hello. Now, let's take a look at the network request. We see that cookie is still
being sent, and then if we look at the request header for the POST call, we now see the top secret value in
the X‑XSRF‑TOKEN header. The back end should verify the authenticity of this request by checking the
cookie and the token value.
Summary
There's a lot to think about when managing sessions, and we covered a couple of aspects of session
management by focusing on the parts that affect Angular applications. Please take the opportunity to read
more about sessions and OWASP resources. The key takeaway is to ensure you handle session exploration
and access revocation. When we add authentication to applications, it's easy to forget about this, but it's
important to do. You don't want to be a back door to gaining access to protected resources. Protecting the
active session is paramount, as this is a way attackers can impersonate you. Always use secure transport
security layer. While this isn't something you set up with an Angular, it is a foundational requirement for your
software system. If you use tokens to manage sessions, ensure you don't leak the tokens. If you use cookies,
ensure the cookies have secure built‑in cookie protection mechanisms. Robust foundational protection
mechanisms such as cookie protection and strict CORS policies will get you a good way towards preventing
XSRF attacks. Use the double submit cookie pattern mitigation strategy to add an extra protection layer.

Handling Inputs and Outputs


Introduction
Supporting user input and displaying the output is a requirement for nearly all web applications. We want to
ensure we're safely handling user input and displaying any output from it. Hi, I'm Alisa Duncan, welcome back
to Secure Coding with OWASP in Angular. Forms are widely used in software applications, and we want to
avoid causing vulnerabilities when handling forms, user input, and displaying values in Angular. This module is
all about precisely this. You will first start by understanding the attack vectors associated with handling
inputs. User input requires data hygiene, which you will apply to values and learn how Angular automatically
supports data hygiene when displaying values using interpolation. Data hygiene is not enough. You will learn
why input validation is important for security and what to validate for, the different ways you can validate, and
how to leverage Angular form's API for custom validation. We're applying the security practices as identified
from the vulnerabilities in the OWASP Top Ten list. This module draws upon the OWASP Top Ten categories,
Broken Access Control, and Injection. Broken Access Control means someone can act outside of their
intended access level. It might mean someone can view data they shouldn't or perform unauthorized actions.
Injection attacks mean an attacker tries to insert malicious code into the application. The attack can occur in
different areas of your software system. The most common ones include SQL injection and client‑side attacks
such as cross‑site scripting, also known by the acronym XSS. We'll focus on cross‑site scripting. Cross‑site
scripting has various forms and attack techniques, and covering the specific mechanisms of this attack
category is outside of this course's scope. They all stem from the same concept, though, your software
displays values within it and the values can be data from the server or user input. The value can be the
source of danger. The value from the server or the user input can be from an attacker who inserted malicious
code into your application. The malicious code can try to steal sensitive data such as gathering content from
cookies, redirecting the user to a malicious site, or impacting back‑end systems, and so on. If you are
interested, please read more about cross‑site scripting on OWASP's site. We will demonstrate one of the
forms of the attack in this module, but there are many, and the attack mechanisms can be sneaky and
inventive. At a high level, the root of XSS attacks is the pollution of values you intend to display with malicious
code. Browsers can't distinguish between the two and run that malicious code.

Escaping Displayed Values


Escaping values allows us to defend against injection attacks because it can neutralize malicious code
before the browser runs them. So escaping values is a good data hygiene practice. Escaping transforms
markup characters into plain text, meaning the browser no longer treats the value as code, it's just text.
Escaping values means the browser has no code to interpret and run. Angular takes a security‑minded
approach to values by treating them all as untrusted, which means Angular always applies data hygiene
techniques to the values you display. Angular automatically escapes all values displayed within the
application when you use interpolation. Since everything transforms to plain text, the application does not
run the malicious script in the value. Let's see some code so we can turn this into something more concrete.
If we look at a minimal component, we see a title in the component template. Notice the title has markup, it
has a span element. Interpolation escapes code within values so the output will include the markup. Suppose
we run the application with this component and view the browser output. The title includes the span
element as text within the header element. Inspecting the DOM confirms the value as text within the header
element. The element inspection tool renders the display value, but we can see a complete picture.
Attempting to edit the element shows the complete picture. We see the entire escape transformation of the
value, which Angular's interpolation handles for us. Any time you can use interpolation to display values
within the Angular application, you should do so. Let Angular handle data hygiene for you. It's a built‑in safety
mechanism to guard against cross‑site scripting attacks.

Demo: Escaping Displayed Values


Interpolation is the default way we display values in Angular. You may think that's all it does, just displays
values, but it's got a secret superpower, it also protects your application. Let's see how interpolation escapes
values. And, we'll put this superpower to work by demonstrating an example attack that tries to sneak its way
into the application using route data. You can follow along yourself using my project, which is hosted in a
GitHub repository. I added the link to the slide so you can fork, clone, or download it. Then navigate to the
project directory for the demo, install dependencies, and open it up in an IDE. Let's go. This application has a
searching capability. The idea is you search for something you're looking for, then you're navigated to the
results view. So we have two routes, the home route and the results route. We're also using forms in this
application. You may notice some differences if you're following along locally as we continue looking at this
project code together. This is because I removed some code to allow you to focus on the sections directly
applicable to this specific demo, while the application code is applicable to the entire module which you will
see in an upcoming demo. The app component view houses the router outlet. It also displays a greeting,
which includes the title of this application. The title of the application includes HTML, a span element. You
saw this in the slides, but now you have an opportunity to see what this looks like in the application when we
run it. The search component has an input element so you can type in your search criteria. Then it adds the
search criteria to the URL to pass over to the result route. Ah, this app allows you to search, but has no
results to show you, how tricky, it's an illusion of a search, but that's okay. We can still understand how this
app is supposed to work and see the example attack even without the search results. The result component
takes a search criteria parameter from the URL and displays it back within the application. It is using
component input binding with that ID property. One day, it may even show the results of that search, but not
today. Let's see how interpolation works with that span element and how a sample attack might work by
starting up the application. We now have the answer to the question about the span element in the title.
When we use interpolation, the values transform to plain text, and any code elements, even a span element,
displays as plain text. Let's try searching for something. How about searching for something like book, and
then let's find the results. We're navigated to the results component and see book in the URL and in the view.
The results component took book parameter from the URL and then reflected it back into the view. Since
we're adding user input back into the DOM for display without proper handling, this is a possible attack
vector. Let's try attacking our application with something sneaky, such as injecting something in a script tag,
something like a very in‑your‑face greeting using the JavaScript alert. We'll say hello. We're being very nice in
our attack by displaying a friendly greeting even if it is by surprising the user with a JavaScript alert, but
imagine if the attack did something more dangerous here and we injected the script into the application.
Let's see what happens when we find the results. We displayed the exact content of our attack back to the
user in plain text. Attack rejected. Nothing happened in this attack because Angular escaped the code we
displayed, so there was no code to inject because it is plain text. This type of attack where we're taking a
value from a URL and trying to inject it within the application is a form of cross‑site scripting called reflected
cross‑site scripting. We managed to get out of trouble here.

Input Validation
We showed how Angular escapes code for us when we use interpolation and how it can help mitigate XSS
attacks, but there's a flip side to ensuring values don't cause other injection‑related attacks in your software,
that is to validate untrusted values before using them. You want to ensure any user input matches your
expected type and format. If you expect a phone number, validate the input as numeric only and format it as
you expect with a minimum and maximum length. Don't allow all characters in the input, you need to limit
them to what you expect. Not only is input validation better for data shaping within your application, it is also
vital to preventing attackers from trying to add malicious code to your application. The flip side I mentioned
to guard against injection related attacks outside of escaping displayed values is also to treat the values as
untrusted within business logic. You don't want to propagate malicious scripts throughout your application,
and even worse, accidentally run it. Remember to validate values before using them within HTTP requests.
Your back end should also guard against malicious values, but each part of the application should have
protection mechanisms built in. For example, you want to avoid accidentally sending a SQL injection script as
a query parameter. When you use Angular forms as the user input mechanism, you may need to use the
forms API validator and not rely on HTML element attributes alone. This is where you should add validation of
type and format beyond what the built‑in HTML attributes can offer, with the bonus of improving user
experience by providing error feedback. We might see the following if we look at an example form input
asking for the user's favorite pizza. The input element notes the required input and the type is text. Having
the required attribute is helpful, but more is needed. The text input allows all characters, but we should
validate the input to remove any suspicious elements. Only alphabetic characters should be good enough. I
didn't add in min and max length attributes, but I'm sure you'll do better than my example. When we use the
form API, we have access to validators, such as adding a required validator which helps add that feedback to
the user, but it isn't strictly a security best practice. We see the application of security best practices in this
pattern validation. We only want to allow alpha characters, so we create a regex allow list for this validation.
The forms API allows us to create custom validators too, so we aren't limited to only adding a regex pattern to
the form validator's array, and the validator can be as complex as we need it to be. Creating a separate
custom validator also allows for better reuse and testability, so I encourage you to explore this path. You want
to think about what the input should allow, not deny. Creating denial lists is difficult. You can only anticipate
some of the input user's imagine, it's all of the user's imagination against yours. You'll need help to predict all
of that. Instead, think of what the input allows. This way, you'll adequately protect your application.

Demos: Custom Validators


User input can be an attack vector. Some bad actors will try sending injection attacks targeting your
database or back‑end systems through the front‑end user input. Even though the back‑end system should
always be watching for malicious activities, it doesn't mean the Angular application should allow it. We should
prevent such input from the application in the first place. We can do this in Angular using form validators.
There are built‑in validators, and we can also create custom ones. We'll demonstrate creating a custom
validator, then adding the custom validator to the form. This way we can limit the type of input that the
application accepts, which mitigates this attack vector. You can follow along in your own IDE with my project.
I added the link to the GitHub repo in the slide so you can fork, clone, or download it. Then navigate to the
project directory for the demo, install dependencies, and open it up in IDE. This is the same application we
looked at earlier in the interpolation demo, but supercharged a little bit. We had the same routes as before,
and the overall flow remains. The SearchComponent hosts an input for the user to search for items, and the
application routes the user to the results view. The ResultsComponent has some changes. We now take the
search value and send the call to the productsService to getProducts. Let's take a peek at that
ProductsService. The ProductsService calls a product' API. It adds the search query as a query parameter to
the URL. Pretty straightforward. But how can this be an attack? If we allow malicious code to make its way
into the application, while that code may not be harmful to the Angular application, if the back end doesn't
have proper validation measures and just runs the code as is, it can be an attack. This could be a vector for
SQL injection as an example. Imagine if the query included a DB statement, such as dropping a table,
updating records, or getting all users' personal information from a user table. The back end definitely needs
to have validation measures, but we should also not let that sort of attack through the UI as well. Let's see
what we can do. In the SearchComponent, we can add validation. We can limit the sort of input the user is
allowed to enter. The form API allows us to add validators to form controls. We can add a built‑in one, such as
required. This is more helpful to the Angular application and user experience than preventing injection
attacks, but it demonstrates the example. You can also add minimum and maximum length validators here
too. But what we want to use in our case is a custom validator that limits the user input to match the format
we expect. The custom validator ensures the user enters a valid search format, which is in the form of a
product ID. The format is three alpha characters and three numeric characters, so we can write a custom
validator that tests for it using a regular expression. Your validators may be more complex than this example,
but the nice part about using custom validators is just that it can be as complex as you need it to be. The
goal here is to make sure you are limiting the input to valid entries. So think about allow lists, not deny lists
here as you write your validator. We could add the validator to the form control. Add the custom validator to
the Validators array, and check for validity of the form prior to processing the form submit. You can also add
helpful text to improve the user experience if the input isn't in a valid format. Now that we limit the validity of
the input, it's not a problem for us to pass the value to the product's API. We know that the URL formed by
the Angular app will be secure. Shall we see this in action? We can try searching for something that doesn't
match the format, such as a SQL injection. Luckily, the validator caught that the format isn't valid and
prevented the SQL injection from trying to return personal user information in the results. Now let's try
something valid like abc123. This is a valid format for the product ID searches, so the validation and form
submit is successful, and we navigate to the results view.

Summary
Untrusted values can cause a lot of problems. It's vitally important to always validate data before using it,
especially within business logic. Fortunately, Angular helps us in views by escaping values before displaying
them when we use interpolation, but we must prepare for handling malicious values prior to using them
within the application. One way to validate user input is to use the Form API validators. You'll want to explore
built‑in validators such as min, max, and email. Think about what your application allows, not denies. If it can
be represented in a regex pattern, you can also use a built‑in validator and add the regex to the pattern
validator. If you need more customized validation, writing a custom validator is the way to go. Angular has
support for synchronous and asynchronous validators, so it can be as complex as you need it to be. Once
again, make sure you follow the pattern of what your application allows, not what it should deny, in order to
have robust validation.

Creating Dynamic Views


Introduction
Reacting to server responses or other input mechanisms to create dynamic views might encompass most of
our work as web developers. Whether we're embedding the user's avatar within their profile page, displaying
all of the products a storefront has for sale, or showing the activity of transactions within an individual
account, we have to respond to some form of data to display it within the application on the fly. And, of
course, we need to do this securely so that we aren't opening ourselves up to attacks. Welcome back to
Secure Coding with OWASP in Angular. Hi, I'm Alisa Duncan, and I'm happy to have you join me. You want to
ensure you're creating dynamic content securely, so we'll cover sanitizing values. We'll cover when you need
to bypass sanitization and how to do so safely. We'll also talk about pitfalls when creating dynamic content
and how to explicitly sanitize to minimize attack vectors. We're applying the security practices as identified
from the vulnerabilities in the OWASP Top Ten list. This module draws upon the OWASP Top Ten categories,
Injection, and Security Misconfiguration. Injection means an attacker tries to insert malicious code into the
application. The attack can occur in different areas of your software system. The most common ones include
SQL injection and client‑side attacks, such as cross‑site scripting, also known by the acronym XSS. We'll
focus on cross‑site scripting. Security misconfigurations is caused by incorrect settings that causes the
application to inadvertently expose more information than intended. Cross‑site scripting has various attack
techniques. Covering the specific mechanisms of the attack category is outside of this course's scope, but
they all stem from the same concept. In this case, your software incorporates values through dynamic view
content. The values can be data from the server or user input. The value can be dangerous. The value from
the server or user input can be from an attacker who inserted malicious code into your application. The
malicious code can try things like gathering content from cookies, stealing sensitive data, or impersonating
you. Please read more about cross‑site scripting, if you're interested, on OWASP's site. We will demonstrate
one of the forms of the attack in this module, but there are many, and the attack mechanisms can be sneaky
and inventive. At a high level, the root of XSS attacks is the pollution of values you incorporate within your
application with malicious code. Browsers can't distinguish between the two and will run that malicious code.

Sanitizing Displayed Values


Sanitizing values protects us against injection attacks by removing a malicious code before the browser runs
them. Sanitizing values is a good data hygiene practice. Sanitizing values removes unsafe elements and
unsafe attributes from safe elements. Sanitization is contextual on the value, meaning the value's usage
affects the sanitization process. Sanitization changes if the value is HTML, or a URL, for example. Angular
takes a security‑minded approach to values by treating them all as untrusted, which means Angular always
applies data hygiene techniques to the values you incorporate within your application. Angular automatically
sanitizes all values when you use property binding to bind values to attributes of an HTML element. Angular
removes unsafe portions of values. We could add values to dangerous contexts when we incorporate values
in our applications using property binding. Dangerous contexts are the act of using values and injection
syncs. Injection syncs are web API functions that can be vectors for cross‑site scripting attacks. Injection
syncs includes ways to insert HTML into the document, passing values into the functions that execute code
such as global objects or running eval, and adding values to element attributes that accept URLs, such as
links. Let's see an example of property binding a value to an injection sync. In this example, we have a source
URL. The source URL is bound to the SRC attribute, allowing us to view this image when the component
renders. When we property bind values in Angular, Angular sanitizes them by evaluating them before
rendering. Angular removes any unsafe code and leaves safe code. Angular's sanitization process removes
unsafe code from values. Angular has allowlists of safe values that differ based on the context of the value,
that is, where the value is bound. Anything outside of that allowlist is removed. But not all code is dangerous,
safe code within values remain, which is handy in cases such as rich text editors. We want to allow safe
text‑based markup to display in the application, and Angular supports doing so. We can compare unsafe
versus safe code. On the left, we have an unsafe component. The unsafe component property binds a URL
source to the href attribute of an anchor element. Unfortunately, the URL source contains a script that pops
up a JavaScript alert. Even though the script is more surprising than dangerous, running any script you didn't
intend to means the application is vulnerable to attack. Using JavaScript alerts is a common approach for
testing cross‑site scripting vulnerabilities. On the other hand, we have safe markup in this safe component on
the right. We want to show a friendly welcome message wrapped in an h1 element within a div. Property
binding to the innerHtml attribute of the div allows us to do this because the h1 element is safe. There's one
more way Angular developers can help prevent cross‑site scripting attacks. That is to use AOT compilation,
especially when building the product application. AOT compilation, short for ahead‑of‑time compilation, adds
Angular sanitization code into the application at compile time, so it helps make sure you are always sanitized.
Without AOT compilation, that is when you use JIT, or just‑in‑time compilation, the code generates on the fly
and you don't always get that assurance of sanitization. AOT compilation is the default compilation process
starting in Angular version 8. If you aren't using AOT compilation, please look into making the switch for the
safety of your application. Regarding strategies to prevent cross‑site scripting attacks in product
applications, there's one other topic to highlight, that is to use content security policies for CSPs to harden
the security of your product application. First, you should apply fetch directives to control the locations
where your application loads resources from. You can ensure your application is only loading resources from
trusted sources. Angular has a recommended minimum fetch directive to apply. Next is the trusted type CSP.
Trusted types show a lot of promise as a safeguard against cross‑site scripting attacks. Since this is a
relatively new CSP, you will want to verify it's available on the browsers you need to support. Angular has
built‑in support for trusted types and has predefined policies for Angular applications based on the features
the application has, such as whether the application uses lazy‑loaded modules, uses JIT compilation, or
bypassed sanitization, which we'll talk about next. Add the predefined policy that your application requires to
the trusted type CSP to gain the benefits.

Demo: Property Binding and Safe Markup


This demo is all about understanding property binding and how it works under the covers. We'll show an
example of property binding using a value that includes markup to demonstrate sanitization. Then we'll show
an example of property binding using a value that includes safe markup, so you can see the difference. You
can follow along the code project in your own IDE. I added a link to the GitHub repo in the slide, so you can
fork, clone, or download it. Then navigate to the project directory for the demo, install dependencies, and
open it up in an IDE. First, a quick overview of the application. There's very little going on in the app setup.
The application has a form and a few routes, but we only focus on the search route for this demo. The app
component view has a router outlet and some navigation links; otherwise, not much going on here. The part
we're interested in is search. The search component tricks you into thinking it has searching capability, but
really it's just an input element so you can type in your search criteria. The view then shows you what you
searched on, not the most helpful component, but displaying user input back in the view is fairly common, so
we can spoof it with a fake search component. Notice that in this component, the user input value is added
as property binding to the innerHtml attribute of the paragraph element, so a user can put in whatever they
want, and the application displays it back at them. Hm, I wonder how that'll work. Let's check it out and try a
few things by starting the application. The search route is the default route. Let's try searching for something.
How about searching for something like book? And notice there's no submit button, the application shows
you exactly what you typed. Unusual, but it doesn't matter in our case. We see book, which is what we typed
in. What if you tried something a bit more dangerous? By adding user input directly into the DOM, we're
opening ourselves up for attack. Let's try attacking ourselves by typing in something like an
attention‑grabbing greeting using a JavaScript alert. We'll say hello. The application ignored our input. That's
because script is dangerous and immediately removed. We're trying to take advantage of cross‑site scripting
to display an alert. This type of attack where we're taking a value and trying to manipulate the DOM with it is
a form of cross‑site scripting called DOM‑based cross‑site scripting, but so far it's not working. How about
something less dangerous? How about some markup, such as an image? Yes, that worked. Now let's try to be
sneaky again and add the alert message saying hello. Back to cross‑site scripting. This time, we'll change the
image source to something intentionally broken and add our friendly greeting to the on error handler. We see
the broken image, but no JavaScript alert. What's going on? For this, we can inspect the DOM. What's this?
The image element is there, but the error handler was removed? Foiled again. Angular is too good at
sanitizing values. But how about if we search for something we feel strongly about and want our feelings to
display in the application? For example, what if we emphatically searched for pizza? Hey, our search term is
emphatic. If we inspect the element, we see the M element is in the DOM. The M element is an example of
safe markup, so the element retains in the value and is added to the DOM. Pretty neat. Angular handles safe
markup versus unsafe markup, including unsafe attributes, to help prevent DOM‑based cross‑site scripting
for us. What a relief.

Bypassing Automatic Sanitization


There may be times when you need to bypass Angular's automatic sanitization. Although the times may be
rare, they can occur. Before diving deeper into this concept, I must caution you about the dangers. Angular's
built‑in sanitization for property binding is a security mechanism, and by circumventing it, we are opening
ourselves up to danger and the possibility of attacks. With this warning, let's better understand why we might
need to do this and how we can do this more safely. The first step in bypassing automatic sanitization is to
evaluate whether the need is legitimate. You should always avoid bypassing if you can. A legitimate need is if
there's no option other than to embed an iframe in your application, such as embedding a video player from
the video hosting site, as an example. In this case, you must bypass automatic sanitization because the
source for the embedded iframe contains code. Then, if you identify there is no way to avoid bypassing
automatic sanitization, then limiting the attack vector is essential. You must validate any user‑entered values
and identify any other steps you can take to minimize the risk. Any time you bypass sanitization, strongly
consider conducting a security audit on your application. Since you are circumventing Angular's built‑in
security mechanisms, verifying you haven't opened yourself up to attacks is crucial. To bypass automatic
sanitization, use the DomSanitizer class. The DomSanitizer class has methods to bypass security trust for the
type of value you are trusting, in this case, a URL. Calling the bypassSecurityTrust method returns a safe type
of that value, which signals Angular to skip sanitization. In this example, we've caused an injection attack
because the URL source that we property bound to the href attribute of the anchor element is unsafe. The
rendered application will show the link with the unsafe link label. Clicking on the link will cause the JavaScript
alert to appear.

Demo: Bypassing Automatic Sanitization


It's essential to limit attack vectors when you legitimately have to bypass Angler's built‑in sanitization. This
demo bypasses sanitization to embed a video. So you'll see how to construct a safe link for the video source
to mitigate risks before property binding the video link within the template. Video embeds make your site
interactive and engaging, so you'll see what you need to consider to do this safely. I added the link to the
GitHub repo in the slide so you can fork, clone, or download the project to run it locally and follow along with
the demo. Then navigate to the project directory for the demo, install dependencies, and then open it up in
your IDE. Let's dive in. This is the same application we looked at earlier in the previous demo, but this time
we'll focus on a new route and component. This time we'll look at the bypass component. The bypass
component displays a video using an embed from YouTube inside an iframe. The iframe property binds the
iframe source, which is a video link. This is so we can form the link dynamically based off a video ID, which is
the functionality required. However, before we get too far, let's see what happens if you don't bypass
sanitization. We'll try for the most straightforward case, where the video link isn't dynamic. So we'll define the
entire link directly in the component. To make it clear this is a test, I'll append the word test here. Now,
update the iframe source property binding to bind to the new videoLinkTest property. Now we're ready to
see what this looks like in the application. First, open debugging capabilities to see the console, then
navigate to the bypass route. You'll see console errors. This is Angular informing us that bypassing is required
because we're using an unsafe value for the URL. Since you're binding A URL to the iframe, the value is
untrusted. Even though we know it's safe, since Angular can't determine this, we have one of two options.
One, don't bind a URL at all. If the URL is a static value, you can define it directly in the template. Then you'll
see the video, no problem, but then you're not property binding to the source, which means the video
cannot be dynamic. This isn't the feature requested, so this option doesn't work for our needs here. Two,
bypass sanitization on the source link. Bypassing will mark the URL value as trusted, so Angular will display it,
but doing so means we'll risk exposing our application to risks, so next, you'll step through how to do this
safely. Back in the IDE, let's first undo the test URL link. It looks like we must bypass sanitization. The bypass
component injects the DomSanitizer, which is the class you work with when you need to explicitly bypass
sanitization. Next up, the video host. The video host in this case is YouTube, where the videos are sourced
from. Notice the video host property only defines the host. You want to specify the hosting location and
define as much of the URL as possible so that you can maintain safety assurances. In other words, since this
video link is dynamic, which means other sources such as the server or user input can provide the URL of
which video to display, you want to decrease attack vectors by limiting how much control those other
sources have. This way, other sources can't pull from any old video source, including potentially unsafe or
unvetted ones. Then, you have a property for the bypassed video link. This is the link you've marked as safe,
as a SafeResourceUrl, so that Angular will bind to the iframe source. In the component initialization, the video
ID is hard coded. Let's talk about that for a moment. In this example, it's hard coded for a quick
demonstration, but if you want to dynamically change the video for display, this may be a component input
property, or something you pulled in from a URL, or something you retrieved from an API call. In any case, this
video ID is not something you defined; therefore, it is untrusted and may be unsafe. You want to ensure you
limit the variables outside of your control so you can ensure safety. So while there is the element of untrusted
data, you've limited the scope of the untrusted data by only allowing the ID to vary. Additionally, you want to
ensure the format of this property is valid and matches what you expect. You'll want to watch the module on
handling inputs and outputs, if you haven't done so already, to ensure that you validate that the ID value is
secure. With those precautions in place, you can move onto forming the video source. Then finally, bypassing
security for the resource URL. Let's check out the application. Yes, a video. Now you can watch this video
introducing the OWASP Top Ten. You've limited exposure by tightening the control external sources have to
your application. But bypassing security is inherently dangerous. Don't forget to consult with security experts
and get a security audit when you do this in your application.

Explicit Sanitization
In addition to methods that bypass automatic sanitization, the DomSanitizer class has methods for explicitly
sanitizing values. This is useful if you work outside property binding and want to sanitize values. Previously, I
mentioned sanitization is contextual, meaning the mechanism for sanitization depends on where you're using
the value, and when we looked at the example of how to bypass automatic sanitization using the
DomSanitizer's bypass security trust methods, you had to specify the type of value you're bypassing. Once
again, sanitization differs by how you intend to use the value. Angular supports the following context for
explicit sanitization, HTML, Script, Style, URL, and ResourceUrl. The DomSanitizer's explicit sanitize method
takes the context as a parameter so that it knows how to do the sanitization. The contexts are available
through the security context enumeration. Let's see what this looks like. Once again, we are using the
DomSanitizer class. The DomSanitizer has a method, sanitize, that takes a security context and value to
sanitize as parameters. Because we are property binding this value to the innerHtml property, we specify the
security context as HTML. The DomSanitizer will remove the dangerous onclick event handler from the
markup, so the rendered application displays an Add to Favorites button that doesn't do anything. Explicit
sanitization is helpful, but you should always prefer to use the built‑in security mechanisms that Angular has
for automatic sanitization for property binding. Creating templates server‑side using templating languages to
inject within your application is tempting, but doing so leaves you at grave risk of injection‑related attacks
and should be avoided. You may be tempted to manually manipulate the DOM if your back end drives your
UI elements, but this is very dangerous, as you're adding untrusted values to the application's DOM without
proper data hygiene. Always prefer Angular templates, including when your back‑end systems drive the UI.
Take a look at Angular dynamic forms as a pattern of how you can do so using form elements, and then you
can extrapolate that pattern to other UI needs. Also, you want to avoid using DOM APIs and manipulating the
DOM elements manually. Just because you can access DOM elements using the ElementRef doesn't mean
you should. Any time you use DOM APIs, you are circumventing Angular safety mechanisms. Be wary of
libraries that do this as well. Using built‑in Angular constructs is the best protection mechanism against
cross‑site scripting. Any time you operate outside of Angular's built‑in sanitization mechanisms, you are
putting your application at risk for attacks.

Demo: Explicit Sanitization


When you must manipulate the DOM, you weaken the security defenses of your application. DOM
manipulation requires special consideration and explicit sanitization. You'll see how DOM manipulation can
cause a vulnerability and lead to a potential for attacks. And how to limit exposure by explicitly sanitizing
values when you cannot avoid manipulating the DOM. You may find following along in your own IDE as
equally helpful as I do. I added the link to the GitHub repo in the slide so you can fork, clone, or download it.
Then navigate to the project directory for the demo. Install the dependencies and open it up in an IDE. Let's
jump in. This is the same application we looked at earlier in previous demos, but now we'll focus on a different
route and component. We'll work out of the build‑dom component. The build‑dom component demonstrates
exactly that, building out the DOM and appending HTML elements manually. It has two developments, each
with their own template reference variables. One is called dangerEl, which sounds ominous, and the other is
called sanitizedEl. Each template reference variable has a corresponding ViewChild property decorator, so
we can access an element reference and manipulate the template from within the component. The
component also injects the renderer and DomSanitizer. Moving on to where it constructs the DOM, first,
there is a string for a bit of HTML to append to the DOM. Imagine you got this string from some external
source, perhaps from an API or somewhere else. This string is an anchor element with an href that runs a
script. The script displays an alert saying danger. Yikes! Imagine if the script was more malicious. Now comes
the dangerous part. You set the string to the div. You have a couple of ways you might approach doing so.
You can access the HTML element directly by accessing the native elements in our HTML property, or you
might use the renderer instead and set the innerHTML property. Since both do the same thing, let's
comment out one of the methods to avoid confusion. The problem with building the DOM like this is that
there is no security. The values aren't sanitized before apppending to the DOM, which means we'll see that
dangerous alert. Unlike in earlier demonstrations where there was built‑in sanitization. If building the DOM is
unavoidable, then you'll want to handle doing so as securely as possible. This means you'll need to explicitly
sanitize values. The DomSanitizer sanitize method, a requires the security context. Since we are adding to the
innerHTML, our security context is HTML. Remember that sanitization is context dependent. So if you're
using the DOM APIs to do other things like set styles or links, you'll need to use the appropriate security
context. If the sanitized method successfully sanitizes the value, then we can append the sanitized value to
the DOM. Let's take a look at the application. Navigate to the build‑dom route. Both links display as links and
both seem fairly threatening. Click on the first link. This is the link where you did not sanitize before
appending to the DOM. Oh no, we're in danger! A dangerous script could have run and caused all sorts of
problems. That's no good. Let's try the second link. This time, the value was sanitized first. Nothing happened.
That's more promising. We can see what's going on by looking at the console. We see a warning. There's a
warning that unsafe URL value with the script was sanitized. That's why nothing happened when clicking the
link. Sanitization to the rescue.

Summary
Dynamic views and content are what make websites into web applications. So dynamic views are a
requirement for most applications we work on. Cross‑site scripting attacks are very sneaky, and their attack
vectors can be very subtle. When working with dynamic views, which is a way cross‑site scraping attacks
sneak in, there are some things you'll want to keep in mind. You will need to use property binding to
dynamically change HTML elements or HTML element attributes. When you use property binding, Angular
automatically sanitizes the values for you. To take full advantage of Angular's built‑in security mechanisms,
make sure you use ahead‑of‑time compilation in your application. Add further protection by defining fetch
directives in your content security policy. Then elevate protection against cross‑site scripting by using
Trusted Type CSP. Just because you can, doesn't mean you should. Even though Angular has a mechanism
to bypass security checks on property binding values, you shouldn't use this capability lightly. Avoid this
practice if you can. If you cannot, then ensure you limit your application from attack vectors and get a
security audit. This is dangerous and requires extra scrutiny. If you use a Trusted Type CSP, there's a special
predefined policy Angular provides for this scenario. Always prefer using Angular templates to construct the
DOM. If you cannot use Angular templates and have to manipulate the DOM using DOM APIs, then
remember you don't get the automatic sanitization benefits from Angular and you must explicitly sanitize
values before appending them to the DOM.

Managing
Elements Condit ional Vi ew
Introduction
Most applications require conditional UI elements. We can display a different view if the user has something
in their shopping cart, is authenticated, or has a special privilege. Angular's built‑in capability to show or hide
UI elements conditionally is something we rely on to handle these scenarios for us. Hello, I'm Alisa Duncan,
and welcome back to Secure Coding with OWASP in Angular. In this module, we'll cover preventing views
and actions when the user doesn't have access levels by covering access controls at a high level and
applying access control measures to conditional view elements in the template using Angular's built‑in
structural directives. Then enhancing access control measures by utilizing the full capabilities of creating a
structural directive in Angular. We'll cover when it makes sense to do so, and how you can scale that custom
structural directive as your access control measure needs grow. We're applying the security practices as
identified from the vulnerabilities in the OWASP top 10 list. This module draws upon broken access control
and insecure design OWASP top 10 categories. Broken access control is when someone acts outside of their
privilege level. Insecure design is the recognition that fundamental design flaws create vulnerabilities that
implementation alone can't overcome. We'll discuss access control measures and apply specific access
control checks in this module. Some access control measures that you may commonly see are verifying
authentication status and ensuring only authenticated users can access the view. Role‑based access control
uses a predefined set of roles to determine access. The roles may include categories such as user and admin.
This access control measure can be a bit too broad at times and not handle the complexity of access control
measures in more complicated applications. You'll also hear the acronym RBAC, for role‑based access
control. Attribute‑based access control uses attributes about the user, action, object being operated upon,
and environmental information to determine access. Those attributes can include attributes about the
subject such as department, job level, or an action such as view, delete, approve operations, and more. It's a
fine‑grained access control measure that can model more complex scenarios. You'll also hear the acronym
ABAC, for attribute‑based access control. Defining how you handle access controls within your system is
foundational, and I encourage you to refer to OWASP resources to ensure you carefully consider access
control design.

Structural Directives
There may be items only certain users should see within the application based on their access levels. When
these items are within Angular templates, we must render them conditionally. Angular has structural
directives as the building blocks of the application. We can use out‑of‑the‑box structural directives, such as
ngIf, to handle the conditional logic of determining whether to render the view. Unlike using CSS classes to
show or hide elements, structural directives will remove or add DOM elements, which means someone can't
inspect the DOM to have more visibility into a feature that they shouldn't. The ngIf structural directive is a
helpful first step in protecting simple conditional view access, such as for binary logic verifying authenticated
status. An example using ngIf structural directive looks like this. Here, we want to provide a friendly greeting
to authenticated users. This example is a quick and minimal check on the user's authenticated status to
display a warm greeting, and the ngIf directive works well for that. However, managing conditional elements
can become much more complicated as you start trying to control views for more complex access control
measures beyond binary values. Adding an ngIf to check rules or attributes can be a lot to manage and
become a source of human error, inadvertently allowing access to resources that break access control
measures. Another built‑in structural directive, ngSwitch, is an option, but it can be cumbersome depending
on the complexity and usage of your system. A more elegant, reusable, and testable solution is to create your
own custom structural directive for any complex access control‑based visibility of elements. Angular
supports creating custom structural directives, so you have the flexibility to tailor it for your system's needs.
Creating a custom directive may also be more secure long term, as it will be more straightforward to maintain
any application growth related to access control measures. A custom structural directive option for
role‑based access control checks might look like this. In this code example, we have a custom structural
directive for a specific role, such as admin. Any conditional elements that should display for admins have this
structural directive where you pass in the user's role as a parameter. The structural directive can determine
whether to render the view or not. Another option is to create a more generic custom structural directive
that handles any role, and you'd pass in two parameters, one for the role that should have access and
another for the user's role. In this example, you would only need to create a single directive, but the
downside is that the structural directive is more generic, so you'll want to ensure you have plenty of tests. In
any case of using structural directives to control view access, you'll want to verify you've applied the
directive to all elements that should be protected, otherwise, you'll still have broken access controls within
your application.

Demo: Limit Access to Views


Not everything on a template is meant to be visible to everyone. You can limit access to components and
views using the built‑in ngIf structural directive. This option works great when you have straightforward
binary logic to test against, such as when the user is authenticated, which we'll see first in this demo. For
more complex needs, creating a custom directive simplifies the logic. We'll walk through how to check for a
specific role, such as admin. Lastly, creating a separate custom directive for each role or each attribute if
using attribute‑based access controls can become unmanageable, so we'll talk about enhancements to
make the custom structural directive that can scale with your application needs. You can follow along locally
in your own ID with this project. I added the link to the GitHub repo in the slide, so you can fork, clone, or
download it, then navigate to the project directory for the demo. Install dependencies and open it up in your
IDE. Let's jump in. This app is very minimal. It only has one component with just the default route. The entire
view is inside this app component. This app allows you to choose which role you want to operate as, so
there's two buttons to facilitate this, a button that allows you to act as an end user and a button that allows
you to act as an admin. To help make sure you know what role you're operating as, you'll see which role you
are in the display. Next, there are a few conditional elements. We'll just display text greeting stating the
condition. So there's ngIf. If the user is an end user, Message for endusers using ngIf displays. The user's role
needs to be managed somewhere to maintain the application state. This happens in the userService. The
userService has one property, the role. You can either be an end user or an admin. Very basic, but it'll serve
our needs. Let's see what this looks like. We see that we start off as an end user and we see the message
from the ngIf. If we switch roles, we see that our role changes and the message goes away. This is the most
straightforward example of using ngIf for access control checks. We had to add the conditional logic of
checking the userService role to the role we wanted to show the view for. This can get complicated
depending on the complexity of the logic and the access control measures that you need to take, but it's an
easy way to show hide elements when your needs are simple. Next, let's write a structural directive
specifically for a single role. This admin directive is a directive specifically for admins. It takes the user's role
as a parameter, and if the user is an admin, it adds the view, or it removes the view if not. This is a
straightforward way to create structural directives. The naming of the directive is clear on what the directive
is for, and it can help decrease developer error by removing some of the conditional logic out of the
template. And it's also really clear on what factors to test for. The name of the input property is a little bit
more unusual, but it matches the selector for the directive. Let's see how you'd add this to the application.
You'll add a new message for admins using the admin directive and then pass in the user role. No more
conditional logic in the template here. Let's see what this looks like in action. First, we'll start off as an end
user and see that message using ngIf, and then now, as we switch from end user to admin, we'll see a
different message. The admin message displays the message protected by the custom structural directive.
The custom structural directive has a lot of advantages, but a disadvantage is that it's too specialized and
may not scale well if you have a lot of roles. Let's make the structural directive a little bit more generic so it
can scale. One way you can do this is to put more control back in the hands of the developers, by having
them pass in both the user role as well as the role it should check for. So this directive, the HasRole directive,
has two input properties, one for the role to check and the other is for the user's role. The naming convention
for this is a little funky because the name of the directive is the default property, and then it has to prepend
the second property. You'll see how the developers will set the values here in a bit. We want to make sure
we're handling the changes between users, so we watch for changes and appropriately add or remove the
view. This directive does assume the role associated with an element doesn't change. If you have a need to
handle dynamically set roles on elements, you'll need to build in a check for that. Let's see how to use this
directive. You now see a couple more messages added to the app component, this time, using the most
recent structural directive. There's a message for end users and a message for admins. Notice how the
structural directive is applied. The role for the element is passed in first, then the user role parameter is set
using the user service. Let's see how this works in the app. Now we see two messages for end users. One is
from the ngIf and a message for the end users using the latest custom structural directive. No message for
admins only. If we switch roles, we see two different messages, one using the admin directive, and one using
the HasRole structural directive, and no message for the end users. We were able to protect views within the
application using structural directives based on a user's access level. Success.

Summary
Showing views conditionally is a great built‑in Angular feature, and it's something most applications utilize
frequently. You want to evaluate the access control measures you're using. Refer to the OWASP resources to
help make the determination of access control systems that your application and organization requires.
Ensure your access control is consistent and streamlined. Having too many conditional elements can
become unmanageable quickly. Structural directives are secure. Angular removes elements from the DOM
when they shouldn't be there, which is much more secure than hiding it using styles. When you do need to
conditionally show elements, structural directives is the preferred option. The built in ngIf structural directive
can get you by in most basic cases. When complexity increases, it's time to evaluate building a custom
structural directive. Creating a structural directive to handle your specific use case can help eliminate the
human error aspect of complicated logic that you might end up with if only using ngIf. Creating a custom
structural directive allows you to customize a directive to your needs, plus it's testable, so you can ensure
you've covered different use cases. Always be sure to test your work and automate testing. You don't want to
break access control and accidentally elevate someone's privileges. Since this is an area where the
developer may have to customize parameters for access control checking, there can be human errors. Make
sure you test your final views across all privilege levels.

Protecting Routes
Introduction
As our application grows, we need to add routes to define the site's various sections. As a user navigates
through the application, there may be certain areas they shouldn't access based on their privilege level.
Since Angular routes are permissive by default, protecting routes by access level is a requirement for many
applications. Welcome back to Secure Coding with OWASP in Angular. Hi, I'm Alisa Duncan, and I'm excited to
have you join me. We'll discuss route organization considerations. The way we structure our routes impacts
how we think about protecting them. You want to design routes in a way that makes protecting features
within your application more straightforward and less prone to human errors. And preventing route
navigation when users don't have the access levels necessary for that route. There's different ways Angular
supports us in preventing unauthorized route access, so we'll cover the options and practice applying some.
We're applying security practices from the vulnerabilities in the OWASP Top Ten. This module covers the
practical application of Broken Access Control, and Insecure Design OWASP Top Ten categories. Broken
Access Control occurs when someone acts outside their privilege level. This includes accidentally elevating a
user's privilege level so they can view routes that they shouldn't. Insecure design happens when
fundamental design flaws create vulnerabilities that implementation alone can't overcome. We'll discuss
access control measures and apply specific access control checks in this module. Some access control
measures that you may commonly see are verifying authenticated status and ensuring only authenticated
users can access the route. Role‑based access control uses a pre‑defined set of roles to determine access.
The roles may include categories such as user and admin. This is a common access control measure you may
see in existing Angular applications, but this access control measure can become too broad and not
fine‑grained enough for complex use cases. You'll also hear the acronym RBAC for role‑based access
control. Attribute‑based access control uses attributes about the user, action, object operated on, and
environmental information to determine access. Those attributes can include attributes about the subject,
such as the users department. Attributes can also describe an action, such as an operation on a resource,
plus more. It's a fine‑grained access control measure that can model more complex scenarios. You'll also hear
the acronym ABAC for attribute‑based access control. Defining how you handle access controls within your
system is foundational, and I encourage you to refer to OWASP resources to ensure you carefully consider
access control design.

Route Architecture
You should think about how you structure and organize features within the application, as it can affect how
you handle access control checks. A recommendation is to identify all of the application's features, especially
if they require specific access. Identifying these up front and thinking about the organization will help guide
how to set up routes and even file structure organization of your application. It never hurts to review OWASP
resources as you think through this process too. Let's think about how to organize a software application that
handles flight reservations. Some key features might include all users can view flight options and prices. You
want this public view to draw users in and have them book on your system. Support personnel help ensure
everything runs smoothly and fix any errors that might occur, so support personnel can modify reservations
when users make a mistake. Pricing specialists help negotiate prices and can override flight prices if needed.
Maybe you want to set up a special promotion to visit a fun city. Admins onboard more support personnel
and pricing specialists into the system. They are also the ones to configure the application settings too, so
they need access to configuration options. Although this app probably has more features, we'll limit our
discussion to the features and roles listed here, just to keep things straightforward. Now, let's think about
organizing the routes. Since the ability to view flight options is front and center of the value of the
application, it probably needs to be the first thing people see. Now, onto the application's roles and
capabilities, modify, override, and manage, those are all back‑office functions, and while each function ties to
a specific position, all the features are distinct, yet related. Accessing those functions might be best
organized by a parent route, admin, followed by the function they perform. Another way to envision it is in a
tree structure. If we look at each part of the route, we have home and admin as siblings, then, each capability
related to a back‑office operation as a child of admin. We can see how the features of this application might
grow and how this routing organization supports growth. Now that we created a diagram for our routes, let's
think about the access control levels that should have access to those routes. All back‑office operators
should have access to the admin route, and then each back‑office function ties to a specific position. We
now better understand where to add route protection and who has access. Taking the time to think through
the organization, where to add the route protections, and how to protect the route is essential to ensuring
the application has proper access control measures.

Routing and Route Guards


Angular has built‑in route protection mechanisms called route guards. When you define a route guard, you
can conditionally determine whether the user can navigate to the route or if the application recognizes the
validity of the route. In addition to route protection, the advantages of defining guards are reusability,
maintainability, and testability. Those route guards include the following types. You can define whether a user
can navigate to a route when you use the canActivate guard. The canActivateChild guard mediates
navigation to child routes. The canMatch guard conditionally determines the validity of the route. Even if the
path matches a defined URL segment, this guard can prevent the route from completing the match. Let's
take an example guard. In this example, we define the routes for the application, a home route, navigates to
the HomeComponent, and the admin route loads routes for the admin route definition. The admin route has
a guard checking whether the user is an admin in the canMatch guard. If the user is not an admin, the admin
route doesn't complete route matching, so the application acts like the admin route doesn't exist. If we look
at the roleIsAdmin function implementation, we see it's a function that has expected parameters for the
canMatch guard, plus we're injecting the AuthService. We only need the AuthService for this guard, as we're
verifying authenticated state for the user and that they have the specific role, admin. The path definition is
where you apply the diagram you created identifying routes and the required access control measures. You
want to implement the route guard for the type of access control required. Remember to apply principles of
least privilege. Since Angular routes are permissive by default, you want to set up routes in your application
accordingly, and then use your system's specific access control checks to the routes. We are skimming the
surface of routing and route guards and only talking about applying secure coding principles to routes, but
there's a lot more to routes, so you may want to check out the course, Angular Routing, to learn more.

Demo: Route Guards


All right, let's see some code. We'll take a look at using route guards to protect routes that require elevated
privilege levels to access. First, a quick overview of the application and understanding the existing routes.
Then you apply a route guard to the route definition. You'll implement a route guard to protect for
authenticated state, followed by implementing and adding a guard to protect by access level. You may find
following along in your own IDE as equally helpful as I do. I added the link to the GitHub repo in the slide, so
you can fork, clone, or download it. Then navigate to the project directory for the demo, install dependencies,
and open it up in your IDE. Let's go. This app has three routes, a home route that contains the public view,
which everyone can see, the profile route, which should only be accessible to authenticated users, and the
admin route, which is only accessible to users with the admin role. The app component has buttons to
simulate authentication. For demonstration purposes, you'll be able to log in as a non‑admin user or as an
admin user, so we could see the route guards at work. This example should not be used for secure
authentication. Please refer to Managing Authentication and Identity module. This component also displays
whether you are acting in context of an authenticated user and what your role is, so you can keep track of
things. The AuthService exposes the secrets of the fake authentication going on in this application. It defines
the roles available for this demo. One can be either an end user or an admin. It's very minimal, but it's enough
to showcase access controls. The service also manages and tracks the state of the user that we're operating
in and also handles changing the state of the user operation context. We'll take a peek at the profile
component so you know what to expect. There's not much here, though, just a message displaying that this
is the profile component. The admin component is lazy‑loaded, there's not much here either, just a message
displaying that this is the admin component. Let's see how this application works without any guards. The
app has user information about your authenticated state and role. You also see a message saying that the
view is public. This is the home route, which is open for everyone. You can press Login to authenticate and
press Login as Admin to authenticate and act as an admin role. Right now, without any guards, you can
navigate to any route. Let's add some access control measures to the routes. What we want want is to guard
the profile route and admin route, starting first with the profile route. Only authenticated users should have
access to this route. This route shouldn't load when the user isn't authenticated, which means using the
canActivate guard. The canActivate guard checks for a boolean condition to identify whether it should load,
so you could use the AuthService to verify if the user is authenticated as the condition and add the guard to
the route declaration. This guards the profile route to ensure that the user is authenticated before loading
the route. Now to protect the admin route, the admin route is lazy‑loaded. A good option to guard this route
is the canMatch guard. The canMatch guard prevents the route from matching. You can inject the
AuthService into the roleIsAdmin function and verify that the user is both authenticated and has the role of
admin. I think checking both authenticated and role makes sense in this case, but another option as your
application grows in both features and complexity is to split access control checks into different guards, like
having an isAuthenticatedCanMatchFn. That way, if you need to check for authentication only on some
routes, you can also define role specific guards to add on. You can define multiple guards for a route,
including multiple of the same type of guard, and add the canMatch guard to the admin route. Since route
guard declarations are an array, you can define as many guards as you need. Keep your guards small, it's
more testable and maintainable, and favor adding multiple guards instead of writing a really complex single
route guard. Let's see this in action. Now we have guards for the routes. If we try navigating to profile without
logging in, we can't. Let's first log in, then navigate to Profile. Okay, this works, so we are properly guarding,
and navigating to Admin does not work. Now, let's operate as an admin and navigate to the admin route, just
to make sure everything works. I enabled router debug tracing so you can trace the routing calls. And now,
when you navigate to profile, you'll see the router ActivationStart, the guards are checked, and then the
navigation is canceled. When you try navigating to admin, you can see the NavigationStart, and then errors
because the route does not match. Depending on the access level you want your users to have and the
existence of the routes your users should have visibility to, you may want to use a combination of both the
canActivate and canMatch routes.

Summary
When applying access control measures, it's important to consider how it affects your application's routes.
Access control measures can vary, so make sure you understand the access control requirements for the
application. From the broad strokes of authentication only to fine‑grained access control measures that
come with attribute‑based access control, you'll want to make sure you understand requirements so you can
design the software appropriately. Route organization goes hand‑in‑hand with understanding the access
control requirements for your application. Think about route hierarchy and add more granularity to the
access control needs within that hierarchy. It will help you maintain new routes and features better. Once
you've identified business requirements and designed the route organization, then implement guards to
manage access. Tailor the route guard appropriately for the type of control you need. You can prevent routes
from loading or matching, and you'll want to think about how the application should behave and what the
application should disclose about a route when applying guards. You can use multiple guards, so layer
protection mechanisms as needed.

Calling APIs
Introduction
Full‑featured web applications aren't static. We have to call our back‑end systems or external resources to
gather information for display. Secure back‑end systems and external APIs should have access control
checks, and it's the Angular application's responsibility to add metadata those systems need to validate the
request. We want to make sure we're handling adding the authorization controls securely. Welcome back to
Secure Coding with OWASP in Angular. Hi, I'm Alisa Duncan, and I'm happy to have you join me. We'll cover
managing token credentials. You need to be able to make authorized API calls, so you'll most likely have to
have some sort of authorization token to your API calls, which means you'll have to handle secret information
within your application. And how you handle credentials is part of keeping your application secure. With
proper credentials, you can make authorized API calls by intercepting outgoing calls and adding tokens to
them. But you want to prevent authorization tokens from leaking. You don't want bad actors to gain access to
your authorization tokens. We're applying security practices as identified from the vulnerabilities in the
OWASP Top Ten list. This module draws upon three OWASP Top Ten categories, Broken Access Control,
Identification and Authentication Failures, and Insecure Design. Broken Access Control is when someone
acts outside of their privilege level. Identification and Authentication Failures are failures that stem from
authentication weaknesses. Insecure Design happens when fundamental design flaws create vulnerabilities
that implementation alone can't overcome. When calling APIs, you usually need to include information that
provides access to that API. This is called authorization metadata. You'll need to provide authorization
metadata for each API call you make. The format of the authorization depends on the type of API you're
calling. The common formats are API tokens, a key that provides full access to that API and its resources, the
key is the same for all callers; and OAuth, which allows for more granular resource access limited by the
user's scope. We'll cover making calls over HTTP using REST. In REST, systems use HTTP headers to add
metadata about the request and the response. There may be many headers to add additional context about
the call. A specific header called Authorization is the header for the authorization data. This is the header
where you'll add the authorization token. The Authorization header supports schemes such as basic, digest,
or a custom scheme. In OAuth 2.0, you'll use the Bearer scheme when adding the token. API tokens may use
the Authorization header, or it may have a different mechanism to pass the token in, such as adding it as a
URL parameter. Since API tokens aren't a standard format, the use case varies.
Managing Credentials
It's essential to remember that JavaScript‑based web applications, like Angular, can't maintain secrets,
everything is public. A user can view page source, network requests and their payloads, and look at browser
storage, nothing is secret to the user. So with that understanding, it's important to consider what your
system's expectation of confidentiality is when calling an API. Your user will see everything, so you need to be
prepared for that. Refer to OWASP resources for considerations on design and testing. When you work with
API tokens, you have a few approaches to how to handle getting the value into your application. The first
option is to hard code the token in code. While this is very straightforward, now you're committing secrets to
your source code, which is bad practice. Even if the API token really isn't a secret, it's still not a good idea.
Another approach is to inject API tokens into your application during the build process, usually by means of
environment variables. While better than committing secrets to source code, there are still downsides. This
approach is not recommended by OWASP proactive controls, as it still exposes the secret, which we should
have no expectation of. The problem with this method is that if you have different environments for
development and production, each with a unique API token, you'll have to generate a new build for each
environment instead of using CI/CD practices like release promotion. The last option is to load your API
tokens at runtime from a separate system. Once again, you don't have confidentiality, but you can change
the API tokens at runtime, so you won't have to generate a new build for each environment. We can load
resources at runtime using the APP_INITIALIZER injection token. This allows us to have a dependency or a
factory method to run when the application initializes so that we can have our API token call at runtime and
have it available for use within the application. The factory method can call out to the location to retrieve the
token. You will need to store the token somewhere accessible in your application for your API calls to use
later. If you require confidentiality of the token, then you must proxy the calls. You will need to create some
sort of system around the API requiring the API token. Your Angular application calls the proxy instead. The
proxy handles the request, adds the API token, and returns the response without exposing the token to the
user. OAuth solves this problem because when you use OAuth's access token for authorization, it is already
created with the user's scope and context. If you can use OAuth to handle resource authorization, you
should do so.

API Access and Interceptors


Interceptors allow you to inspect and transform HTTP requests and responses. Angular has the concept of
interceptors built in, so we can perform HTTP manipulation as our system requires. When we use
interceptors, they intercept incoming and outgoing HTTP calls. They automatically run based on your
implementation. You can define multiple interceptors in your application. Let's see how this might work. Let's
say you're making an outbound call to an API to get products. You can have an interceptor that adds
headers, such as the Accept header and the Authorization header. You should implement a separate
interceptor for each action to perform to make your interceptors more manageable and testable.
Interceptors are a fantastic way to centralize routine HTTP‑related tasks, such as adding logging for requests
or to responses, adding MIME type headers, such as the accept or content type header, or adding the
Authorization header to outbound calls. Conversely, you may want to intercept responses, such as those
indicating a 401 unauthorized status, so you can redirect the user to reauthenticate. There's a lot more ways
interceptors are helpful, this is just the tip of the iceberg in terms of ideas. Let's see what an interceptor
implementation looks like. You get the request, transform it, such as adding the Accept header in this
example, then pass it down the chain. Since there may be many interceptors, you're chaining operations one
after the other. With our interceptor implementation, we need to add it to the application so that the app can
use it. You can add multiple interceptors. The order in which you declare the interceptors to your application
is the order the interceptors run. We looked at an example interceptor adding the Accept header, but we're
talking about security, and specifically, an interceptor to add the authorization header. Authorization uses the
token returned from the OAuth flows, and it's the access token. You'll add the token as is, using the Bearer
scheme to the header value. However, you only want to add the access token to some outgoing calls. You
want to ensure the call location should include the Authorization header. You want to verify you're making
the call to an allowed origin to prevent leaking your token. The same guidance holds true for API tokens as
well. It is vitally important to guard the access token. This is secret information, and in the wrong hands, it can
be dangerous. The access token grants access, so anyone with the token can impersonate you to request
resources or perform actions. Only add the token to allowed origins. There are some considerations for the
back end when using the Authorization header too. Even though this is outside of Angular's scope, they are
essential safeguarding notes. The back‑end API should verify the token is valid. In the case of OAuth, the
token contains metadata it should validate, such as the issuing authorization server, expiration time, the client
ID, etc. There's no reason to entertain processing the request if a token isn't valid. The back end should also
verify access controls. The token may contain scopes the user can access, but it also may not have enough
metadata to verify whether the request should proceed. The back end should perform the same checks that
we run on the front end. Double checking isn't wasteful, it's necessary.

Demo: Authorization Header Interceptor


Most API calls require authorization, so this is something you'll want to happen behind the scenes in a clean,
maintainable way. To support making authorized API calls, you'll create an interceptor that handles adding
the Authorization header securely. Credentials are not something you want leaked. Since inspecting network
requests is always fun, you'll see the interceptor in action and find the Authorization header yourself.
Speaking of fun, following along with code demos at home definitely goes on the fun list. You can clone, fork,
or download this project from my GitHub repository. Then navigate to the directory for this module, install
your dependencies, and open it up in your favorite IDE. Time to code. The name of the game here are API
calls, and for that, you need to have an API. So this project has an Angular front end, which we'll tour next,
and an API back end. The API back end is a very minimal express API that returns a list of the OWASP Top
Ten. The Angular application calls this endpoint to get the list of OWASP Top Ten items for display. Now, onto
the Angular application. As promised in the intro module, this demo app is very minimal, it only has one
component with just the default route. The entire view is inside this app component. The app has a button
that kicks off making the HTTP request to the express API. This is the API call that we'll inspect and look for
the Authorization header. The application has a fake auth service that holds a fake access token. To learn
more about real auth services and getting real access tokens, check out the Managing Authentication and
Identity module. For this module, we're faking it and avoiding the overhead of adding the mechanisms that
handle this process, and I've hard coded an access token to use. Please note that using secure
authentication mechanisms and OAuth should be used. Now, to add the Authorization header to the
outgoing calls, you'll define an interceptor. The interceptor has a parameter to the request so you can
manipulate it. You'll inject the AuthService in order to get a hold of the access token. The interceptor sets the
Authorization header using the Bearer scheme and the access token from the AuthService and passes the
request to the next thing handling the request, whether it's another interceptor or the actual HTTP back end.
It's crucial to not leak your access token. The access token allows consumers using the token, access and
actions in the context of the user for whom the token was created, which means if Penelope authenticated
and received the token as part of authentication and authorization, if she shares the token with Maria, then
Maria accesses data and performs actions as Penelope. You don't want to leak tokens. Luckily, Penelope and
Maria are best friends, so while it's not good that they shared the token, Maria wouldn't do anything
malicious. However, not everyone is that friendly or well intentioned. You must prevent tokens from leaking by
limiting who has access to the token. Only allow trusted parties access to tokens by defining an allowlist of
those trusted parties or origins. Then only add the token if the request is made for an allowed origin. Now
that you have a secure auth interceptor, you'll need to register this interceptor in the application. Here, I
added the AuthInterceptor to the application. You can have multiple interceptors. The order in which you
register interceptors will determine the interceptor handling order. Let's take a look at the application and
inspect some network calls. You'll have to start the server in the Angular application to see the interceptor
from end to end. The application is pretty bare bones, but that's good so you can focus on the network
request. Let's inspect the network request. So open that debugger up, press the make API call button to
make the network request. You'll see the Authorization header with the Bearer scheme and the hard coded
access token is added. You can try changing the allowed origins if you'd like. Now you no longer need to
remember to add the Authorization header to the individual HTTP request code in your application.

Summary
Secrets can be hard to keep, and handling secret information in web applications can be challenging. Most
API calls require authorization metadata, which require special handling. You need to make sure you manage
the tokens in a way it doesn't expose your API to the public. Working in context of OAuth is more secure than
API tokens because OAuth operates in the context of the authenticated user, but that's not the case with API
tokens. If you have an option, choose OAuth to protect your APIs, but if you have to use API tokens, you'll
want to protect that secret value. One way you can get an API token without committing it to source or
having it part of the build output is to use the APP_INITIALIZER injection token to retrieve it dynamically upon
application initialization via a network call from another location you host. But keep in mind that this solution
will still expose the value to the user if they inspect network requests. If you need to keep the token a secret
from the user, you'll have to proxy calls to the API in question so that the token is completely opaque to the
user. Once you have the authorization metadata, you can start making authorized API calls. Interceptors are
what you should use for this. You can add logic to your interceptors to add the authorization header, and to
do so conditionally. The authorization metadata gains access to the system, and leaking it can allow bad
actors to impersonate the user. Make sure you don't leak tokens to untrusted originsse allowlists for origins
that should have the Authorization header.

Managing Dependencies
Introduction
All Angular applications have dependencies. If it's not dependencies on the Angular framework itself, most
applications have additional dependencies on libraries we rely on to augment Angular capabilities. Those
dependencies can be a source of security concerns, so we want to ensure we're limiting risks associated with
relying on them. Hi, I'm Alisa Duncan, and welcome back to Secure Coding with OWASP in Angular. This
module is all about dependencies in your application, from considerations you have when selecting a library
to managing those dependencies, including maintaining dependencies to the Angular framework and
libraries in the Angular ecosystem, and the dependencies outside of the Angular ecosystem as well. You then
use these dependencies within the build process, and there's more considerations and secure approaches
to take there as well, such as making sure you are intentional about the version of the dependencies you use
and have assurances about the integrity of the dependency in the software supply chain. We're applying
security practices from the vulnerabilities in the OWASP Top Ten. This module covers Vulnerable and
Outdated Components, and Software and Data Integrity Failures. Vulnerable and Outdated Components
occur when a dependency is vulnerable to attacks, or when it's out of date and doesn't contain updated
security features. Software and Data Integrity Failures occur when we make poor assumptions about a
software dependency and don't verify the integrity of the dependency before consuming it.

Vulnerable and Outdated Components


Dependency management can encompass much, but our focus remains on security. We must ensure the
dependencies we use are maintained, updated, and don't contain known vulnerabilities. There's one rule of
thumb when selecting dependencies for your application, it's essential to use common, well‑maintained
libraries. When they're common, it means many people use and consume it. As a result, there's much more of
a chance of finding vulnerabilities before a release, and if any do make it into a published version, they will be
identified quickly. Well‑maintained libraries are needed because if a problem arises, the chance of it getting
swiftly fixed is greater. Angular is just that, common and well‑maintained. While Angular is a safety‑minded
framework and is pretty secure, it doesn't mean the framework can't evolve over time to incorporate safety
updates and better security practices. One such example is making ahead‑of‑time compilation, or AOT,
default in Angular version 8, because it improves security over just‑in‑time, or JIT, compilation. So you want
to ensure you keep up with Angular updates, especially if they contain security updates. We are fortunate to
have fantastic tooling available in the Angular ecosystem. The Angular CLI can make updating our
application much easier. You could use the ng update CLI I command to update Angular versions. The ng
update CLI command works outside of Angular core libraries too. As long as the library publishes update
schematics that Angular CLI can run, you could use the same mg update command to update that
dependency as well. Angular applications rarely only rely on core libraries or only libraries within the Angular
ecosystem with published update schematics. We have dependencies to other libraries too. Angular itself
has dependencies such as TypeScript and RxJS. In those cases, we need to ensure we keep those libraries
updated as well. Those updates may require a more manual update process, and don't forget that even when
we use Angular core libraries, we have dev dependencies, non‑production dependencies that impact
development processes, such as building, testing, and linting. We'll need to ensure those libraries are also
updated, as vulnerabilities there can also impact the application. An example of a vulnerability affecting
dependencies is the Log4Shell vulnerability that affected Java applications using Log4j. It was a highly
impactful vulnerability with the potential of causing great damage to Java applications. Fortunately, this
library is both common and well‑maintained, so the maintaining team swiftly added a fix and published a
more secure version. Kudos to this OSS team. This vulnerability captured a lot of attention and press
coverage, so consumers of Log4j knew there was a problem, when to fix it, and how to do so. However, not all
vulnerabilities will hit the newscycle like this one did, so how do we know what we need to do for the libraries
we use? We can watch for vulnerabilities in our dependencies a few ways. First, we can use OSS tooling.
There are several options. If you use GitHub for your project repository, you'll have access to Dependabot. If
you need extra bells and whistles that OSS tooling doesn't have, then you also have paid options to explore.
You want to find a tool that alerts you when a new version of a dependency becomes available and whether
any of the versions of the dependencies you're using has any security vulnerabilities. You could also use
tooling built into package managers. If you use npm, you can run npm audit, as an example. Npm audit shows
any outdated versions of dependencies, as well as any security risks. And, there's great tooling available from
the OWASP team. They have tools to run dependency scans, such as Retire.js. You can find more information
about Retire.js from the OWASP project site.

Demo: Running a Dependency Scan


All right, time for a demo. While there are great OSS tools out there that can scan your application
dependencies for vulnerable components, you can also use the built‑in checker in your repository manager.
In this demo, you'll scaffold an Angular application and check vulnerabilities by using npm audit. This demo
doesn't really look at code, it's a demonstration of the command line, so feel free to follow along locally. What
we're going to do is use the Angular CLI to spin up a recent Angular application, then check for audit. Then
you'll do it again with an older version of Angular. Let's go. You can specify the version using an npx
command, use the command shown. You'll get prompts for routing and which stylesheet format to use. I said
yes to routing and to use SCSS. When successful, navigate into the project directory. Then, to check for
outdated and vulnerable dependencies, run npm audit. Thankfully, there's no vulnerabilities when it's a
recent version of Angular, all good. Angular makes sure the base framework is secure, which is nice. Let's try
an older version. We'll use Angular v8 because according to NPM stats, it's still widely downloaded, although
it is outside of Angular's maintenance range. I'll scaffold it using Angular v8 using npx and make the same
selections at the prompt to use routing and to use SCSS stylesheet format. When you create the app, you'll
see the vulnerability scan, but we can also run it manually. Let's see the damage. Navigate into the project
directory and run npm audit. Eek! As expected, there's definitely vulnerabilities, 50 of them, including 20 high
and 10 critical vulnerabilities. We see a lot of dev dependencies in this list, which is still not good, but let's see
if any vulnerabilities make it into production code. You can pass in a flag to check only production
dependencies using the ‑‑production shorthand flag. Now, you see there's only one production dependency.
Unfortunately, it's Angular's core library, and it's a cross‑site scripting issue that's present in all Angular
versions less than 11.0.5. If you haven't updated your Angular application, please do so. We only looked at
Angular core libraries here. Imagine the vulnerabilities that could exist on larger Angular applications that
have dependencies in non‑Angular libraries.

Software and Data Integrity Failures


We must ensure the dependencies we rely on are safe to use. That means verifying the dependency hasn't
been tampered with, and it's the code we've tested and approved for use within our application. We want to
make sure the dependency we rely on and the process in which we incorporate the dependency into our
application are reliable. A newsworthy change in software integrity that led to problems are the colors and
faker packages. The maintainer published a malicious change as a patch change in order to protest current
events. The change was highly impactful and affected well‑known JavaScript projects. It's extremely
important to pin your dependencies, by which I mean you need to use lock files for your dependencies,
which ensures that your application's dependencies are reproducible. And you want to use a narrow
semantic versioning range to avoid accidentally consuming a dependency you shouldn't. In your CI/CD
pipeline, you want the build process to use exactly the same version you've tested on. You don't want to
accidentally consume a different untested version of a dependency right before releasing the application to
production. You should use the lock file specific versions of the dependency by running npm ci or yarn install
‑‑frozen‑lockfile in the build process. Remember, npm install will automatically update a library version to the
highest version allowed in your semantic version range. This is how the colors and fakers dependencies
caused such an impact. Personally, I always use npm ci or yarn install ‑‑frozen‑lockfile. I want to use the
version in the lock file. To ensure the library hasn't been tampered with, you can and should verify the
integrity of the library. Package managers have built‑in tooling to do this, such as npm audit signatures. This
command audits your dependencies to verify they have package signatures. There's recently been a lot of
attacks of library registries themselves. There's been reported cases of attackers flooding npm with
thousands of fake packages containing phishing links. You need to ensure the dependencies you pull in are
legitimate. To keep malicious packages out of your system, you may want to use a repository manager and
point dependency installation to use the repository manager instead of npm directly. This way, you can
manage which libraries and which versions of those libraries your organization has access to.

Demo: Verify Package Signatures


This demo is about verifying the integrity of the dependency by checking the package signatures. Npm audit
has a flag you can pass in to verify the integrity of packages to ensure they haven't been tampered with. Let's
see how that works. Using one of the Angular applications you scaffolded in the last demo, you can verify the
integrity of the dependencies, but just in case you didn't watch the last demo, or if you deleted the project
directory, you can scaffold a new application. I'll use a recent version of Angular and scaffold a new
application using npx. You'll get prompts for using routing and which stylesheet format to use. I said yes to
routing and to use SCSS. When successful, navigate into the project directory. You can verify the integrity of
the packages. The integrity of the package means that this package hasn't been tampered with and is signed
when published. You can test the packages by running npm audit signatures. All dependencies have been
signed, and we have assurances that they haven't been modified. If you get an error message, then the
package may not have been signed properly, or integrity cannot be established. Npm also verifies integrity
when installing dependencies by adding an integrity checksum to the package lock file. Let's check this out.
Yep, we'll use the command line, but feel free to open up the package lock file in an editor of your choice
instead. You see all the dependencies here, and the dependencies have an integrity property with the
checksum, so npm can run the comparison check and ensure your dependencies are good to go. If in doubt,
use a registry proxy to ensure you only have access to vetted and safe versions of that dependency.

Summary
Web applications rely on dependencies. It's pretty much necessary to have a dependency on some library.
You want to ensure you're managing those dependencies well and securely. It all starts at the beginning
when selecting the library to consume within your application. Always use common, well‑maintained libraries.
You shouldn't rely on obscure or poorly‑maintained libraries, as you cannot ensure vulnerabilities will be
addressed. Look at package download stats, repository star ratings, and commit history when selecting OSS
libraries. Or, if you have concerns, look into paid libraries that offer support and maintenance to ensure the
library remains secure. It's not enough to choose your dependencies wisely, it's also important to keep them
up to date, especially if there are vulnerabilities or CVEs that are posted. You can employ tools including OSS
tools and tools from OWASP to help check the dependencies for any vulnerabilities. You should use these
tools regularly, and as early and as often as possible, add it to your builds or a regular action that runs in your
repository. Add npm audit scans as part of your app's startup or initialization step, and look into IDE plugins
that can run it in the background. Once you select a trustworthy library, you want to ensure the specific
version you use is vetted and tested appropriately. Avoid accidentally consuming new versions of the
dependency without thoroughly testing it. So the last thing you want is to add it as part of the production
build step and ship it out the door without realizing which specific version of a dependency you're using.
Keep your version ranges tight, and make sure you get your dependencies from a trusted source. Thank you
for joining me in this course about creating secure Angular applications. I hope you feel more confident in
creating secure applications and better understand the security implications in implementation tasks we
encounter while building web apps. I'd love to hear from you, so please leave a comment in the discussion.
Don't forget to click the Follow button on my profile to stay updated on this course and future courses. If you
want more on this topic, feel free to find me on Twitter, @AlisaDuncan, to hear about my latest Angular and
web security content.

Course author
Alisa Duncan
Alisa Duncan is a full-stack developer, content creator, conference speaker, and community builder who
loves the thrill of learning new things. She is a Google Developer Expert in Angular, a Women...

Course info
Level Intermediate
Rating  (11)
My rating 

Duration 2h 56m
Updated 24 May 2023

Share course
  

You might also like