Input Validation – “All input is evil” (loops) CS1 Background Summary: Any program input– such as a user typing at a keyboard or a network connection – can potentially be the source of security vulnerabilities. All input should be treated as potentially dangerous. Description: Most software packages rely upon external input. Although information typed at a computer might be the most familiar, networks and external devices can also send data to a program. Generally, this data is of a specific type: for example, a user interface that requests a person’s name might be written to expect a series of alphabetic characters. If the correct type and form of data is provided, the program might work fine. However, if programs are not carefully written, attackers can construct inputs that can cause malicious code to be executed. Risk – How can it happen? Any data that can enter your program from an external source can be a potential source of problems. If external data is not checked to verify that it has the right type of information, the right amount of information, and the right structure of information, it can cause problems. Any program that processes data from external sources without adequate validation can be susceptible to security vulnerabilities. Example of Occurrence: A Norwegian woman mistyped her account number on an internet banking system. Instead of typing her 11-digit account number, she accidentally typed an extra digit, for a total of 12 numbers. The system discarded the extra digit, and transferred $100,000 to the (incorrect) account given by the 11 remaining numbers. A simple dialog box informing her that she had typed too many digits would have gone a long way towards avoiding this expensive error. Olsen, Kai. “The $100,000 Keying error” IEEE Computer, August 2008 How can I avoid input validation problems? The while loop is useful for input validation. The following sample loop shows input validation for a test score: cin >> testScore; while ((testScore < 0) || (testScore > 100)) { cout << "Enter valid test score between 0 and 100" << endl; cin >> testScore; } Example in Code: This program asks the user to type in an even number. It then prints all of the even numbers that are greater than or equal to zero and less than the number typed: int main(void) { int x; cout << "Please type an even number: "; cin >> x; for (int i = 0; i != x; i += 2) { cout << i << endl; } return 0; } This code has two input validation problems. The first involves the use of the cin to get an integer as typed by the user. If the user types an integer, this will work without any problems. However, if a floating point value (such as “3.2”) or a string (such as “Hello”) are typed, your program may not run correctly. Floating-point values might be truncated (3.2 becomes 3), but responses to strings may be unpredictable. A robust program would catch this error, provide a clear and appropriate error message, and ask the person to re-enter their input. The second problem involves the lack of validation of the requirement that the integer be even. If the user types an even number, this program will run perfectly well. However, if an odd number is provided, there will be trouble: as the counter i starts from zero and increases by two with each iteration, it will never be equal to an odd number, and the loop will not terminate. As a careful developer, you should use a two-part strategy to avoid this second problem. In the first part, you should verify that the number provided by the user is indeed even. If it is not, your program should return an error message and repeat the request, not proceeding until an even number is provided. The second approach involves revising the loop. The loop above will continue as long as the loop counter i is not equal to the x, the value provided. A more robust solution would be to continue the loop as long as i is less than x. Thus, even if there was a problem with your input validation, the loop would still stop. Recover Appropriately: A robust program will respond to invalid input in a manner that is appropriate, correct, and secure. When your program runs across invalid input, it should recover as much as possible, and then repeat the request, or otherwise continue on. Arbitrary decisions such as truncating or otherwise reformatting data to “make it fit” should be avoided. Laboratory/Homework Assignment: 1. 2. 3. 4. 5. Modify each problem from the previous lab to work as a loop. Write an input validation loop that asks the user to enter a body temperature. Write an input validation loop that asks the user to enter a body weight. Write an input validation loop that asks the user to enter a height, in feet and inches. Write a calculator program that displays a menu of operations and allows the user to display simple calculations 6. Complete the following checklist for each program. Add any additional input validation to your program. Security Checklist: Security Checklist Vulnerability Improper Input Validation Task – Check each line of code Course CS1 Completed 1. Mark with a V each variable that is input. For each input variable, which of the following is applicable: Yes N/A 1. Check length 2. Check range (reasonableness?) 3. Check all options 4. Check type Shaded areas indicate vulnerabilities Discussion Questions: 1. Refer back to the lab on integer errors. Can improper input validation lead to integer errors? 2. Checking for division by zero is pretty straightforward. Checking for a possible integer overflow as a result of an operation can be difficult. Why? 3. Overflow can also when the dividend is equal to the minimum (negative) value for the signed integer type and the divisor is equal to — 1. Demonstrate this with your calculator problem. 4. Filenames are particularly vulnerable to security vulnerabilities. Research to find out why. 5. Why is a while loop usually a more effective way to perform input validation than an if..else?