Authentication and authorization are fundamental pillars of modern web application security. Yet, there are numerous ways they can be misconfigured or implemented incorrectly. This article discusses how to identify these security flaws and avoid vulnerabilities that can allow attackers to access sensitive data and functionality by bypassing authentication, authorization, or both at the same time.
What is the difference between authentication and authorization?
Authentication and authorization are not only similar in name and appearance, but they are also deeply interconnected. Here are their definitions:
- Authentication is the process of verifying one’s identity. This can be done by entering a username and password, using a single sign-on system, or providing a unique access key.
- Authorization is the process of checking access rights. After authentication, the application must verify that the user is authorized to access a specific resource or operation, usually based on their role.
Since the two processes are often performed together, they are often summarized by the term “auth”. Modern enterprise web applications rely heavily on properly implemented access controls to protect sensitive data. As a result, vulnerabilities and attacks related to authentication and authorization are particularly significant for web security.
Common Types of Vulnerabilities
Implementing effective access controls is a challenging task due to several factors. Security is often a secondary consideration in the software development process, and access controls are no exception. To speed up development, an application may initially be built without any access restrictions. Adding a login form only at the end introduces significant security risks.
Distributed software architectures complicate matters further, as requests typically pass through multiple services and interfaces. Enforcing consistent access control in this context is especially challenging, particularly when separate teams develop different system components. Problems with passing auth data across APIs, data formats, domains, and physical systems only increase the likelihood of errors. Here are some typical examples:
Insecure Value Comparisons
One common issue is insecure value comparison, often referred to as a “type juggling” vulnerability. For example, PHP and JavaScript are loosely typed languages. This means that they are very lenient by default about the data types they accept. Each of them also handles value comparisons differently. Without proper input validation, attackers may exploit this by providing specially crafted values that are consistently accepted within a specific context.
Example: A login form that transmits the username and password to a vulnerable PHP script using loose comparisons with the == operator. In such cases, comparing a string to TRUE or 0 with this operator can return TRUE. As a result, an attacker could craft a JSON login request that includes a boolean TRUE, effectively bypassing authentication.
Using strict comparisons with the === operator, or, even better, a dedicated comparison function, is generally enough to eliminate this type of vulnerability. However, in large software projects, even these seemingly simple mistakes can occasionally slip into production.
Pitfalls of Path-Based Auth
Another risky practice that can lead to authentication and authorization bypass is relying on directory-based access control. For instance, an application might determine if a user can access the admin panel by comparing the requested directory to the one associated with the admin section. If the input isn’t properly sanitized, an attacker could use directory traversal sequences to craft a request that appears different but ultimately resolves to the same admin panel path, thereby evading access restrictions.
Relying on directory comparisons for access control can also introduce vulnerabilities due to inconsistencies in how different servers handle URLs. For instance, a proxy server may be configured to restrict access to a particular directory by returning an error code when an unauthenticated user attempts to access it. If an attacker successfully traverses it, the proxy server could be tricked into allowing access to a directory that looks different but actually leads to the same resource.
Misplaced Trust in Authorization and Authentication Sources
In complex architectures, deployments, and data flows, auth-related decisions often take a back seat. This risk is particularly pronounced when handling requests through APIs rather than direct user interaction. In applications composed of numerous microservices, auth is often performed solely at the frontend API level, leaving backend services unaware of the requester’s identity. If the frontend contains a directory traversal vulnerability, malicious requests can slip through and be executed by the backend, potentially exposing sensitive data.
Deciding whom and what to trust in an application’s architecture can have serious consequences. A notable real-world example occurred in 2017, when Uber was vulnerable to account hijacking due to a subdomain takeover. Security researcher Arne Swinnen found that one of Uber’s subdomains was directed to an unclaimed external domain, which he successfully claimed. Since authentication relied on setting a session token valid across all subdomains, redirecting users to the compromised subdomain allowed the researcher to capture session tokens and take over accounts, demonstrating the risks of overly broad trust based on domain-level authentication.
Lack of Access Control at the Function Level
This class covers failures to verify whether a user is authorized to use a particular function. In the case of the Maian Support Helpdesk vulnerability, users could access specific API endpoints that, while hidden from the user interface, remained publicly accessible — some even allowing administrative actions. Without consistent, function-level access control, these overlooked endpoints created an easy path for attackers to perform unauthorized operations.
Implementing access control in GraphQL APIs can be particularly challenging, as the same data can often be retrieved through multiple query paths. Ideally, each request should return only the data that the user is explicitly authorized to access. However, any misconfiguration at this stage may expose sensitive information to unauthorized users. This issue becomes even more critical when a GraphQL layer is added on top of an existing REST API, increasing the risk of access control gaps.
Improper Token Management
At the HTTP request level, access control depends on securely generating the correct access tokens and sending them to the right system at the right time. Any time an attacker can obtain a valid access token (e.g., a session cookie), there is a risk of session hijacking. The risk of client-side token theft is especially high in complex single sign-on (SSO) implementations, where misconfigurations can enable attackers to intercept access tokens via redirect chains or by extracting them from server logs.
Password reset tokens are another vital security feature that is often mishandled and vulnerable to exploitation. For instance, if an application exposes an API for generating password reset tokens, any flaw that lets attackers invoke this API could enable them to reset passwords for known user accounts, resulting in account takeover. These issues often stem from misunderstandings around authorization in secondary contexts or the mistaken belief that private APIs are inherently protected from unauthorized access.
Best Practices for Implementing Authentication and Authorization
In the OWASP Top 10 for 2021, access control violations are ranked first among web application security issues. Ensuring reliable access requires careful planning, secure coding, and constant testing.
Recommendations:
- Including authorization and authentication already at the software planning and design stages.
- Enforcing access control at the application level rather than relying solely on server-side configurations.
- Adhering to secure coding practices and regular testing.
- Whenever possible, using reliable libraries for authentication and authorization instead of creating custom solutions.
- Access control should be thoroughly tested at every stage of development, including production environments.
- Monitoring third-party infrastructure that can be used to bypass authentication and authorization mechanisms.







