Secure Coding in Angular
Secure Coding in Angular
by Alisa Duncan
Resume Course
Bookmark Add to Channel Download Course
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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