This article is provided by special arrangement with the
Open Web Application Security
Project (OWASP). This article is covered by the
Creative
Commons Share-Alike Attribution 2.5 license. You can find the
latest version of this article and more free and open application
security tools and documentation at
http://www.owasp.org.
Authorization
Objectives
- To ensure only authorized users can perform allowed actions
within their privilege level
- To control access to protected resources using decisions based
upon role or privilege level
- To prevent privilege escalation attacks, for example using
administration functions whilst only an anonymous user or even an
authenticated user.
Environments Affected
All applications.
Relevant COBIT Topics
DS5 – All sections should be reviewed. This section covers nearly
all COBIT detailed control objectives.
Principle of least privilege
Far too often, web applications run with excessive privileges,
either giving users far too great privilege within protected
resources, such as the database (for example, allowing table drops
or the ability to select data from any table to running privileged
stored procedures like xp_cmdshell()), all the way through to
running the web application infrastructure with high privilege
system accounts (like LOCALSYSTEM or root), to code in managed
environments running with full access outside their sandbox (ie
Java's AllPermission, or .NET's FullTrust).
If any other issue is found, the excessive privileges grant the
attacker full uncompromised scope to own the machine completely,
and often other nearby infrastructure. It cannot be stated strongly
enough that web applications require the lowest possible
privilege.
How to determine if you are vulnerable
- System level accounts (those that run the environment) should
be as low privilege as possible. Never should "Administrator",
"root", "sa", "sysman", "Supervisor", or any other all privileged
account be used to run the application or connect to the web
server, database, or middleware.
- User accounts should possess just enough privileges within the
application to do their assigned tasks
- Users should not be administrators
- Users should not be able to use any unauthorized or
administrative functions.
How to protect yourself
- Development, test and staging environments must be set up to
function with the lowest possible privilege so that production will
also work with lowest possible privileges
- Ensure that system level accounts (those that run the
environment) should be as low privilege as possible. Never should
"Administrator", "root", "sa", "sysman", "Supervisor", or any other
all privileged account be used to run the application or connect to
the web server, database, or middleware.
- User accounts should possess just enough privileges within the
application to do their assigned tasks
- Users should not be administrators and vice versa
- Users should not be able to use any unauthorized or
administrative functions. See the authorization section for more
details
- Database access should be through parameterized stored
procedures (or similar) to allow all table access to be revoked (ie
select, drop, update, insert, etc) using a low privilege database
account. This account should not hold any SQL roles above "user"
(or similar)
- Code access security should be evaluated and asserted. If you
only need the ability to look up DNS names, you only ask for code
access permissions to permit this. That way if the code tries to
read /etc/password, it can't and will be terminated
- Infrastructure accounts should be low privilege users like
LOCAL SERVICE or nobody. However, if all code runs as these
accounts, the "keys to the kingdom" problem may re-surface. If you
know what you're doing, with careful replication of the attributes
of low privilege accounts like LOCAL SERVICE or nobody is better to
create low privilege users and partition than to share LOCAL
SERVICE or "nobody".
Access Control Lists
Many access controls are out of the box insecure. For example, the
default Java 2 file system security policy is "All Permission", an
access level which is usually not required by applications.
grant codeBase "file:${{java.ext.dirs}}/*" {
permission java.security.AllPermission;
};
Applications should assert the minimum privileges they need and
create access control lists which enforce the tightest possible
privileges.
How to determine if you are vulnerable
- Determine if file, network, user, and other system level access
controls are too permissive
- Determine if users are in a minimal number of groups or
roles
- Determine if roles have minimal sets of privileges
- Determine if the application asserts reduced privileges, such
as by providing a policy file or "safe mode"
configuration
How to protect yourself
Access controls to consider:
- Always start ACL's using "deny all" and then adding only those
roles and privileges necessary
- Network access controls: firewalls and host based filters
- File system access controls: file and directory
permissions
- User access controls: user and group platform
security
Java / .NET / PHP access controls: always write a Java 2
security policy or in .NET ensure that Code Access security is
asserted either programmatically or by assembly permissions. In
PHP, consider the use of "safe mode" functionality, including
open_basedir directives to limit file system access.
Data access controls: try to use stored procedures only, so you
can drop most privilege grants to database users – prevents SQL
injection.
Exploit your platform: Most Unix variants have "trusted
computing base" extensions which include access control lists.
Windows has them out of the box. Use them!
Custom authorization controls
Most of the major application frameworks have a well developed
authorization mechanism (such as Java's JAAS or .NET's inbuilt
authorization capabilities in web.config).
However, many applications contain their own custom
authorization code. This adds complexity and bugs. Unless there's a
specific reason to override the inbuilt functionality, code should
leverage the framework support.
How to determine if you are vulnerable
- Does the code leverage the inbuilt authorization capabilities
of the framework?
- Could the application be simplified by moving to the inbuilt
authentication / authorization model?
- If custom code is used, consider positive authentication issues
and exception handling – can a user be "authorized" if an exception
occurs?
- What coverage is obtained by the use of the custom
authentication controls? Is all the code and resources protected by
the mechanism?
How to protect yourself
- Always prefer to write less code in applications, particularly
when frameworks provide high quality alternatives.
- If custom code is required, consider positive authentication
issues and exception handling – ensure that if an exception is
thrown, the user is logged out or at least prevented from accessing
the protected resource or function.
- Ensure that coverage approaches 100% by default.
Centralized authorization routines
A common mistake is to perform an authorization check by cutting
and pasting an authorization code snippet, or worse re-writing it
every time. Well written applications centralize access control
routines, particularly authorization, so if any bugs are found,
they can be fixed once and applied everywhere immediately.
How to determine if you are vulnerable
Applications that are vulnerable to this attack have authorization
code snippets all over the code.
How to protect yourself
- Code a library of authorization checks
- Standardize on calling one or more of the authorization
checks
Authorization matrix
Access controlled applications must check that users are allowed to
view a page or use an action prior to performing the rendering or
action.
How to determine if you are vulnerable
Check:
- Does each non-anonymous entry point have an access control
check?
- Is the check at or near the top of the activity?
How to protect yourself
Either use the inbuilt authorization checks of the framework, or
place the call to a centralized authorization check right at the
top of the view or action.
Client-side authorization tokens
Many web application developers are keen to not use session storage
– which is misguided when it comes to access control and secrets.
So they revert to using the client's state, either in cookies,
headers, or in hidden form fields.
How to determine if you are vulnerable
Check your application:
- Does not set any client-side authentication or authorization
tokens in headers, cookies, hidden form fields, or in URL
arguments.
- Does not trust any client-side authentication or authorization
tokens (often in old code)
If your application uses an SSO agent, such as IBM's Tivoli
Access Manager, Netegrity's SiteMinder, or RSA's ClearTrust, ensure
your application validates the agent tokens rather than simply
accepting them, and ensure these tokens are not visible to the end
user in any form (header, cookie, hidden fields, etc). If the
tokens are visible to the end user, ensure that all the properties
of a cryptographically secure session handler as per chapter 0 are
taken into account.
How to protect yourself
When your application is satisfied that a user is authenticated,
associate the session ID with the authentication tokens, flags or
state. For example, once the user is logged in, a flag with their
authorization levels is set in the session object.
Java
if ( authenticated ) {
}
.NET (C#)
if ( authenticated ) {
}
PHP
if ( authenticated ) {
$_SESSION['authlevel'] = X_USER; // X_USER is defined elsewhere as meaning, the user is authorized
}
Check your application:
- Does not set any client-side authentication or authorization
tokens in headers, cookies, hidden form fields, or in URL
arguments.
- Does not trust any client-side authentication or authorization
tokens (often in old code)
If your application uses an SSO agent, such as IBM's Tivoli
Access Manager, Netegrity's SiteMinder, or RSA's ClearTrust, ensure
your application validates the agent tokens rather than simply
accepting them, and ensure these tokens are not visible to the end
user in any form (header, cookie, hidden fields, etc). If the
tokens are visible to the end user, ensure that all the properties
of a cryptographically secure session handler as per chapter 12 are
taken into account.
Controlling access to protected resources
Many applications check to see if you are able to use a particular
action, but then do not check if the resource you have requested is
allowed. For example, forum software may check to see if you are
allowed to reply to a previous message, but then doesn't check that
the requested message is within a protected or hidden forum or
thread. Or an Internet Banking application might check that you are
allowed to transfer money, but doesn't validate that the "from
account" is one of your accounts.
How to determine if you are vulnerable
- Does the application verify all resources they've asked for are
accessible to the user?
- Code that uses resources directly, such as dynamic SQL queries,
are often more at risk than code that uses the
model-view-controller paradigm. The reason for this is that the
model is the correct place to gate access to protected resources,
whereas a dynamic SQL query often makes false assumptions about the
resource.
How to protect yourself
- Use model code instead of direct access to protected
resources
- Ensure that model code checks the logged in user has access to
the resource
- Ensure that the code asking for the resource has adequate error
checking and does not assume that access will always be
granted
Protecting access to static resources
Some applications generate static content (say a transaction report
in PDF format), and allow the underlying static web server to
service access to these files. Often this means that a confidential
report may be available to unauthorized access.
How to determine if you are vulnerable
- Does the application generate or allow access to static
content?
- Is the static content access controlled using the current
logged in user?
- If not, can an anonymous user retrieve that protected
content?
How to protect yourself
- Best -- Generate the static content on the fly and send
directly to the browser rather than saving to the web server's file
system
- If protecting static sensitive content, implement authorization
checks to prevent anonymous access
- If you have to save to disk (not recommended), use random
filenames (such as a GUID) and clean up temporary files
regularly
Further reading
ASP.Net authorization:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconaspnetauthorization.asp