Testing for business logic

[Up]

Introduction
Business logic comprises:
 * business rules that express business policy (such as channels, location, logistics, prices, and products); and
 * workflows that are the ordered tasks of passing documents or data from one participant (a person or a software system) to another.

The attacks on the business logic of an application are dangerous, difficult to detect and specific to that application.

Description of the Issue
Business logic can have security flaws that allow a user to do something that isn't allowed by the business. For example, if there is a limit on reimbursement of $1000, could an attacker misuse the system to request more money than is allowed? Or perhaps you are supposed to do operations in a particular order, but an attacker could invoke them in a different order. Or can a user make a purchase for a negative amount of money? Frequently these business logic security checks simply are not there in the application.

Automated tools find it hard to understand context and hence its up to a person to perform these kind of tests.

Business Limits and Restriction
Consider the rules for the business function being provided by the application. Are there any limits or restrictions on people's behavior? Then consider whether the application enforces those rules. It's generally pretty easy to identify the test and analysis cases to verify the application if you're familiar with the business. If you are a third-party tester, then you're going to have to use your common sense and ask the business if different operations should be allowed by the application.

Example: Setting the quantity of a product on an ecommerce site as a negative number. which may result in funds being credited to the attacker. The countermeasure to this problem is to implement stronger data validation, as the application permits negative numbers to be entered in the quantity field of the shopping cart.

Black Box Testing and Examples
Although uncovering logical vulnerabilities will probably always remain an art, one can attempt to go about it systematically to a great extent. Here is a suggested approach that consists of:
 * Understanding the application
 * Creating raw data for designing logical tests
 * Designing the logical tests
 * Standard prerequisites
 * Execution of logical tests

Understanding the application
Understanding the application thoroughly is a prerequisite for designing logical tests. To start with
 * Get any document describing the application's functionality. Examples of this include:
 * Application manuals
 * Requirements documents
 * Functional specifications
 * Explore the application manually and try to understand all the different ways in which the application can be used, the acceptable usage scenarios and the authorization limits imposed on various users

Creating raw data for designing logical tests
In this phase, one should ideally come up with the following data:
 * All application business scenarios. For example for an e-commerce application this might look like,
 * Product ordering
 * Checkout
 * Browse
 * Search for a product
 * Workflows. This is different from business scenarios since it involves a number of different users. Examples include:
 * Order creation and approval
 * Bulletin board (one user posts an article that is reviewed by moderator and ultimately seen by all users)
 * Different user roles
 * Administrator
 * Manager
 * Staff
 * CEO
 * Different groups or departments (note that there could be a tree (e.g. the Sales group of the heavy engineering division) or tagged view (e.g. someone could be a member of Sales as well as marketing) associated with this.
 * Purchasing
 * Marketing
 * Engineering
 * Access rights of various user roles and groups - The application allows various users the privilege on some resource (or asset) and we need to specify the constraints of these privileges. One simple way to know these business rules/ constraints is to make use of the application documentation effectively.  For example look for clauses like "If the administrator allows individual user access..", "If configured by the administrator.." and you know the restriction imposed by the application.
 * Privilege Table – After learning about the various privileges on the resources along with the constraints, you are all set to create a Privilege Table. Get answers to - What can each user role do on which resource with what constraint?  This will help you in deducing who cannot do what on which resource.  What are the policies across groups? Consider the following privileges, "Approve expense report" or "Book a conference room" or "Transfer money from own account to another user's account". A privilege could be thought of as a combination of a verb (e.g. Approve, Book, Withdraw) and one or more nouns (Expense report, conference room, account). The output of this activity is a grid with the various privileges forming the leftmost column while all user roles and groups would form the column headings of other columns. There would also be a “Comments” column that qualifies data in this grid.



This data is a key input for designing logical tests.

Developing logical tests
Here is a guideline to design logical tests from the raw data gathered.


 * Privilege Table - Make use of the privilege table as a reference while creating application specific logical threats. In general, develop a test for each admin privilege to check if it could be executed illegally by a user role with minimum privileges or no privilege. For example:
 * Privilege: Operations Manager cannot approver a customer order
 * Logical Test: Operations Manager approves a customer order


 * Improper handling of special user action sequences - By navigating through an application in a certain way or revisiting pages out of synch can cause logical errors which may cause the application to do something its not meant to. For example:
 * A wizard application where one fills in forms and proceeds to the next step. One can not in any normal way (according to the developers) enter the wizard in the middle of the process. If one bookmarks a middle step (say step 4 of 7) and then continues with the other steps until completion or form submission, then revisits the middle step which was bookmarked this may "upset" the backend logic as it was developed with a weak state model.


 * Cover all business transaction paths - While designing tests, check for all alternative ways to perform the same business transaction. For example, create tests for both cash and credit payment modes.


 * Client-side validation - Look at all client side validations and see how they could be basis for designing logical tests. For example, in case funds transfer transcation the amount field has a validation for negative values.  This information can used to design a logical test such as "A user transfers negative amount of money".

Standard prerequisites
Typically some initial activities useful as setup are follows:
 * Create test users with different permissions
 * Browse all the important business scenarios/ workflows in application

Execution of logical tests
Pick up each logical test and do the following:
 * Analyze the HTTP/S requests underlying the acceptable usage scenario corresponding to the logical test
 * Check the order HTTP/S requests
 * Understand the purpose of hidden fields, form fields, query string parameters being passed
 * Try and subvert it by exploiting the known vulnerabilities
 * Verify that the application fails for the test

Tool Ideas
The automated tools are incapable of detecting logical vulnerabilities. For example, the tools have no means of detecting if a bank’s "fund transfer" page allows a user to transfer a negative amount to another user (in other words, it allows a user to transfer a positive amount into his own account) nor do they have any mechanism to help the human testers to suspect this state of affairs.

Preventing transfer of a negative amount: Tools could be enhanced so that they can report client side validations to the tester. For example, the tool may have as feature whereby it fills a form with strange values and attempts to submit it using a full-fledged browser implementation. It should check to see whether the browser actually submitted the request. Detecting that the browser has not submitted the request would signal to the tool that submitted values are not being accepted due to client-side validation. This would be reported to the tester, who would then understand the need for designing appropriate logical tests that bypass client-side validation. In our "negative amount transfer" example, the tester would learn that the transfer of negative amounts may be an interesting test. He could then design a test wherein the tool bypasses the client-side validation code and checks to see if the resulting response contains the string "funds transfer successful". The point we are making here is not that the tool will be able to detect this or other vulnerabilities of this nature – rather we are saying that with some thought, it would be possible to add many such features that will enlist the tools in guiding and aiding the human testers to home in on such logical vulnerabilities.