13. Improving Security

What We Will Cover


Elucidations

Questions from last class?

Questions about your project?

13.1: Security Threats and Solutions

Learner Outcomes

At the end of the lesson the student will be able to:

  • Describe the need for security
  • Describe cross-site scripting and its defenses
  • Describe path (directory) traversal and its defenses
  • Describe SQL injection and its defenses

13.1.1: Why We Need Website Security

  • Website security is important for anyone who controls a Web presence
  • Using the Web can be a wonderful experience
  • But lack of Web security leads to many things that make the Web unpleasant or harmful, like spam, viruses and identity theft
  • When we run a database-driven website, we also need to assess the value of our data
  • Most database-driven websites have some important data
  • Important data needs protection

Common Website Attack Techniques

  • Cross-site scripting: injecting client-side script into Web pages viewed by others
  • Path (Directory) Traversal: accessing file and directories stored outside the web root folder
  • SQL Injection: including parts of SQL statements into fields of web forms

13.1.2: URIs: the Main Way to Attack a Website

  • The address of a file on the Internet is its Uniform Resource Identifier
  • For example, my website address is: http://edparrish.com
  • The page you see when you open the URI in a browser is: http://edparrish.com/index.html
  • The server automatically redirects the URI to the page index.html
  • The page includes an image at: http://www.edparrish.com/images/ed.jpg
  • All these URIs are public and okay to access
  • However, some URIs contain information that should not be accessible to the outside world
  • For example, the /etc/password file contains passwords and other information that should not leak to the Internet
  • Every URI can contain parameters in the form of query strings
  • For example, if you want to search for pirates on Google, you can use the URI: http://www.google.com/search?q=pirates
  • You can send a parameter to a script with a URI using form fields, links or any HTML tag with an href or src attribute
  • If an attacker can override any of your URIs, they can point to their own URIs and send their own parameters
  • In the following sections we look at some of the main types of attack and understand what they are and what they mean

13.1.3: Cross-Site Scripting (XSS)

  • Cross-site scripting (XSS) injects client-side script into Web pages viewed by others
  • With XSS, an attacker injects JavaScript code into your document by adding it to the end of the URI as a query string or in a form field
  • To understand XSS, lets watch the movie: XSS Movie 1

Example XSS Script

  • As an example, we can use the following page to allow users to enter information about a car
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<title>Car Info</title>
<style type="text/css">
  input { position: absolute; left:6em; }
</style>
</head>
<body>
<h3>Enter car info</h3>
<form action="xsstest.php" method="post">
<p>Make: <input type="text" name="make"></p>
<p>Model: <input type="text" name="model"></p>
<p><input type="submit" value="Click To display listing"></p>
</form>
</body>
</html>
  • Name this file xssform.html and save in a phptest folder
  • To access the file on your localhost server, use a URI like:
    http://localhost/phptest/xssform.html
  • We can enter information about a car into the form
  • The second page displays a listing of the information from the form
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// Get form input
$make = $_REQUEST['make'];
$model = $_REQUEST['model'];

?>
<html>
<head>
<title>Public Car Listing</title>
<?php
// Remove slashes for easier XSS
$model = stripslashes($model);
?>
</head>
<body>
<h3>Public Car Listing</h3>
<p>Make: <?php echo $make; ?></p>
<p>Model: <?php echo $model; ?></p>
</body>
</html>
  • An attacker could enter the following into the second form field:

    <input type="button" onmouseover="JavaScript: alert('XSS' )" value="Click to see color!">

  • While this script is harmless, we could do anything that JavaScript is allowed to do
  • For instance, you could:
    • Read cookies
    • Open forms that ask the user to enter their passwords or credit cards
    • Try to execute known viruses or worms

Solutions

  • The solution to XSS is to whitelist or verify any input from the URI or forms
  • As an example of whitelisting, we could rewrite our script to allow only certain color names
  • Another option is to write your own validator function

Check Yourself

  1. ________, or XSS, injects client-side script into Web pages viewed by others.
  2. Of the following, XSS is ________.
    1. easy to spot
    2. easy to exploit
    3. potentially harmful
    4. all of these
  3. True or false: it is important to validate all user input.

More Information

13.1.4: Path (Directory) Traversal

  • Path (or directory) traversal exploits the ability to traverse directories (folders) on a web server
  • A simple example is to find a directory without an index page
  • For example, we can search Google for something like: "index of /ebooks"
  • From a directory listing, we can explore all the available files and subdirectories
  • Another exploit is when we use code like the following:
    1
    2
    3
    4
    5
    6
    7
    
    <?php
    $page = 'home.php';
    if (isset($_COOKIE['PAGE'])) {
        $template = $_COOKIE['PAGE'];
    }
    include ("/home/users/phpguru/pages/".$page);
    ?>
    
  • An attack against this system would be to set a cookie like:
    PAGE=../../../../../../../../../etc/passwd
    
  • This could generate a server response such as:

    root:fi3sED95ibqR6:0:1:System Operator:/:/bin/ksh
    daemon:*:1:1::/tmp:
    phpguru:f8fk3j1OIf31.:182:100:Developer:/home/users/phpguru/:/bin/csh

  • The repeated ../ characters caused the includes() file to traverse to the root directory and then include the UNIX password file /etc/passwd
  • The UNIX /etc/passwd is commonly used to demonstrate path traversal
  • However, in more recent UNIX system, the passwd file does not contain hashed passwords
  • Instead, the passwords are located in a file that cannot be read by unprivileged users
  • Even so, you can still see usernames and other data
  • Note that on Windows, the directory traversal uses: ..\

Solutions

  • An obvious solution to the first problem is to turn off folder listings
  • We can ensure this by adding an index.html or index.php file to every directory
  • In addition, we must whitelist or verify any input from the URI, forms or cookies
  • For example, you could limit the page template example to certain files by:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    <?php
    $sites = array(
      'about'=>'about-us.php',
      'contact'=>'contact.php',
      'clients'=>'clients.php',
      'portfolio'=>'portfolio.php',
      'home'=>'index.php',
      'partners'=>'partners.php'
    );
    $page = 'home';
    
    if (isset($_COOKIE['PAGE']))
            && isset($sites[$_COOKIE['PAGE']])
            && file_exists($sites[$_COOKIE['PAGE']])) {
        $template = $_COOKIE['PAGE'];
    }
    include ("/home/users/phpguru/templates/".$page);
    ?>
    
  • Another option is to write your own validator function
  • However, you cannot simply check for character strings like:
    • ..
    • ../
    • ..\
  • The reason is that the attacker can use percent encoded strings like:
    • %2e%2e%2f which translates to ../
    • %2e%2e/ which translates to ../
    • ..%2f which translates to ../
    • %2e%2e%5c which translates to ..\

Check Yourself

  1. Path (or directory) traversal exploits the ability to traverse ________ on a web server.
  2. True or false: all web folders should have a default index.html or index.php page.
  3. True or false: it is important to validate all data received from the browser.

More Information

13.1.5: SQL Injection

  • One widespread problem in database-driven Web sites is SQL injection

    SQL Injection: passing SQL code into an application in a way that was not intended by the developer

  • An attacker tries to create or alter existing SQL commands from scripts
  • The following XKCD comic shows the problem

Exploits Of A Mom

  • Let us use the following code for an example:
    $user = $_POST['user'];
    $pwd = $_POST['pwd'];
    $sql = "SELECT * FROM users
      WHERE UserName='$user'
      AND Userpwd='$pwd'";
    $result = mysql_query($sql);
    
  • Consider what would happen if $_POST['user'] was: 'OR 1 OR UserName = '
  • When concatenated into the original expression, you have a query which looks like:

    SELECT * FROM users
    WHERE UserName = '' OR 1 OR UserName = ''
    AND Userpwd='whatever'";

  • This statement selects all rows from the users table

SQL Injection Defenses

  • Limit database permissions and segregate users:
    • If you are only reading the database, connect to the database as a user who only has read permissions
    • Never connect as a database administrator in your web application
  • Be careful when reporting error messages:
    • Default errors give away information valuable to attackers like table and column names
    • We discussed how to control error messages in lesson 12.1: Encapsulating the Database
  • Verify and sanitize user input:
    • Validation of user input is critical in all Web applications
    • You need to make sure the data meets database constraints
    • Failure to build in error checking can cause wrong results or worse
  • Use mysql_real_escape_string() as discussed below
  • We will explore the issue in the following exercise

Using mysql_real_escape_string()

  • PHP provides a function for escaping special characters in a string: mysql_real_escape_string()
  • This function adds a backslash ('\') in front of all potentially dangerous characters
  • For example:
    $user = mysql_real_escape_string($_POST['user']);
    $pwd = mysql_real_escape_string($_POST['pwd']);
    $sql = "SELECT * FROM users
      WHERE UserName='$user'
      AND Userpwd='$pwd'";
    $result = mysql_query($sql);
    
  • Now if an attacker entered OR 1 OR user = " you get:

    SELECT * FROM users
    WHERE UserName='\\\' OR 1 OR UserName = \\\''
    AND Userpwd='whatever'";

  • This would cause an error and prevent access
  • You should always use this function before sending data to a database

More Information

Exercise 13.1

In this exercise, we explore how SQL injection works. We will discuss the questions after you complete the exercises.

Specifications

  1. Open the XAMPP Control Panel by double-clicking the icon on the desktop or by using the Apache Friends entry in the start menu.

    XAMPP icon

  2. Start the Apache and MySQL modules, if they are not already running.

    XAMPP control panel

  3. Verify that the Artzy database is installed as described in lesson 2.1.5: Importing and Exporting Data.

  4. In addition, verify the following files are installed in a subdirectory named includes of the htdocs/phptest directory:

    If needed, copy the files and paste them into a text editor such as TextPad. After saving, verify you saved the page without turning angle brackets and other special characters into HTML entities such as &lt; and &gt;. Also if needed, change the dbconvars.php values assigned to $dbuser and $dbpwd to match your MySQL installation. For more information see lesson 6.3.1: Connecting to a MySQL Database.

  5. Copy the following HTML page into a text editor, save the file in your htdocs/phptest directory as loginexer.html, and then view the file as a Web page in your browser using the address: http://localhost/phptest/loginexer.html
    <html>
    <head>
    <title>Login Form</title>
    <style type="text/css">
      input { position: absolute; left:6em; }
    </style>
    </head>
    <body>
    <h1>Please Login</h1>
    <form action="loginexer.php" method="post">
    <p>Username: <input type="text" name="login"></p>
    <p>Password: <input type="password" name="pwd"></p>
    <p><input type="submit" value="Click To Login"></p>
    </form>
    </body>
    </html>
    

    The page is a simple login form.

  6. Copy the following PHP script into a text editor, save the file in your htdocs/phptest directory as loginexer.php
    <?php
    require("includes/db.php");
    
    //Retrieve form data
    $login = $_POST['login'];
    $pwd = $_POST['pwd'];
    if (get_magic_quotes_gpc()) {
        $login = stripslashes($login);
        $pwd = stripslashes($pwd);
    }
    
    // Make the query
    $db = new DB();
    $sql = "SELECT * FROM users
      WHERE UserName='$login'
      AND Userpwd=OLD_PASSWORD('$pwd')";
    $result = $db->query($sql);
    
    // Check results of query
    if (mysql_num_rows($result) > 0) {
        echo "<h1>You have logged in successfully</h1>\n";
    } else {
        echo "<h1>Loggin failed</h1>\n";
    }
    
    // Display the data
    echo "<h4>Your SQL query was:</h4>";
    echo "<pre>$sql</pre>\n";
    echo "<h4>The results of the SQL query were:</h4>";
    $db->showQuery();
    ?>
    

    Read through the script and make sure you understand how it verifies the username and password. For more information on the MySQL function OLD_PASSWORD() see: OLD_PASSWORD(str).

  7. Try entering a random username and password into the form to see if you can login. After trying to login with an invalid username and password, then login with the following:
    • Username: jbond
    • Password: bond007

    You should be able to login successfully with the above username and password. If you cannot, then ask another student or the instructor for help.

  8. Try using other usernames and passwords chosen at random.

    Only move to the next step when you are convinced that you cannot login without a valid username and password.

  9. Now enter the following code in its entirety into the Username field and then enter any password you like in the Password field. Make sure to use the entire line in the Username field including the single-quote marks (').
    jbond' or 1=1 or '1

    Try entering other usernames instead of jbond but keeping the SQL code after the username: ' or 1=1 or '1. Observe the SQL code displayed by the loginexer.php page and be prepared to discuss how the SQL injection attack works. We will discuss how to avoid these attacks in the following parts of the lesson.

As time permits, be prepared to answer the Check Yourself questions in the following section.

13.1.6: Summary

  • We must consider website security whenever we are in control of a Web presence
  • Otherwise we enable many things that make the Web unpleasant or harmful
  • The main way to attack a website is through the URI
  • Accessing many URIs is fine, but some should not be accessible to the Internet
  • Every URI can contain parameters in the form of query strings
  • You can send a parameter to a script with a URI using form fields, links or any HTML tag with an href or src attribute
  • If an attacker can override any of your URIs, they can point to their own URIs and send their own parameters
  • We looked at some of the most common website vulnerabilities including:
    • Cross-site scripting (XSS)
    • Path (Directory) Traversal
    • SQL Injection
  • With XSS, an attacker injects JavaScript code into your document by adding it to the end of the URI as a query string or in a form field
  • Path (or directory) traversal exploits the ability to traverse directories on a web server
  • With SQL injection, an attacker tries to create or alter existing SQL command from scripts
  • We looked at solutions to all these problems

More Information

Check Yourself

  1. Why do web developers need to worry about security? (13.1.1)
  2. What is the main way to attack a website? (13.1.2)
  3. What is cross-site scripting? (13.1.3)
  4. What are the solutions to cross-site scripting? (13.1.3)
  5. What is path (or directory) traversal? (13.1.4)
  6. What are the solutions to path traversal? (13.1.4)
  7. What is SQL injection? (13.1.5)
  8. What is the defenses against SQL injection? (13.1.5)

13.2: Safeguarding Against User Input

Learner Outcomes

At the end of the lesson the student will be able to:

  • Describe PHP functions to use in protecting database data
  • Protect applications from embedded HTML and Javascript

13.2.1: Introduction

  • Data verification is an important safeguard for applications that rely on user input
  • Failure to build in error checking can cause wrong results or worse
  • We discussed how to design validation into our applications using the FormLib class
  • Many times choosing which validation techniques to use are obvious
    • Sometimes they are not so obvious
  • In this section we will focus primarily on how to protect your database from user input

Verifying User Input

  • Verify data types where possible
  • Restrict the length of the input
  • Escape database string quotes and other special characters
  • Scan user input for correct format

13.2.2: Validating Database Column Types

  • It is important to make sure user data meets database constraints
  • If data does not meet constraints, MySQL will usually fail to update and issue an error
  • You then need to trap these errors to ensure data is not lost
  • Trapping the errors is difficult with lots of overhead for both PHP and MySQL
  • Presenting these errors to the user in a meaningful way is hard
  • A better approach is to validate the data and not rely on the database
  • We covered how to solve this problem with the FormLib class
  • Most database constraints involve type checking user input
  • PHP provides a number of functions for type checking

Commonly Used Variable Handling Functions for Type Checking

Function Description
floatval($var) Returns the float value of $var.
intval($var) Returns the integer value of $var.
is_float($var) Returns TRUE if $var is a floating-point number.
is_int($var) Returns TRUE if $var is an integer number.
is_numeric($var) Returns TRUE if $var is a number.
is_string($var) Returns TRUE if $var is a string.

Checking for Integers

  • Checking if a form variable is an integer is more difficult than it seems at first glance
  • A form variable is always a string, so using is_int() alone will fail
  • To check if something is an integer value, you need to:
    1. Check if the value is_numeric()
    2. If so, convert the value to an integer using intval() and then
    3. Check if the converted value is equivalent to the original value.

Checking for Floating-Point Values

  • Checking for a floating-point value is similar, but complicated by questions of precision
    • Many decimal numbers (e.g. 0.1) cannot be represented exactly
    • Thus, testing for equality for such numbers may fail
  • To compare two floating-point values, you compare if they are "close enough":
    abs($valueOne - $valueTwo) < .000001

13.2.3: Checking Database Column Size

  • If a user enters more data into a text field than your database can hold, MySQL truncates the entry
  • For text fields, you should validate user input to the column size
    • Prevents losing user data
    • Adds security by restricting the size of the input data
    • Many attacks depend on long user input
  • Note that PHP has a function that returns the length of a field: mysql_field_len()
  • You could use this function rather than hard coding the length
  • Then if you ever change the column size, your code still works
  • While it does add overhead to PHP and MySQL, robust code is usually a worthwhile tradeoff
  • You can see how to use this function in the following example

Example Using mysql_fetch_lengths()

<?php
require("includes/db.php");

// Test with fake form data (remove in real use)
$_POST["user"] = "aUserNameFarTooLong";
$_POST["pwd"] = "Supercalifragilisticexpialidocious";

// Retrieve form data
$user $_POST["user"];
$pwd $_POST["pwd"];

// Make the query
$db = new DB();
$sql "
SELECT UserName, Userpwd FROM users
WHERE UserName= '$user'
AND Userpwd = '$pwd'
"
;
$result $db->query($sql);

// Check for length errors
if (strlen($user) > mysql_field_len($result0)) {
    echo 
"<p>User name too long.</p>";
    
// Add error message
}
if (
strlen($pwd) > mysql_field_len($result1)) {
    echo 
"<p>Password too long.</p>";
    
// Add error message
}
?>

Try it!

13.2.4: PHP Magic Quotes

  • Even valid data may pose problems for database data
  • For example, text that contains single or double quotes
    • Like the name: O'Reilly
  • PHP has a feature known as "magic quotes" that works on external variables:
    • All GET, POST, and Cookie variables
  • Magic quotes automatically insert a backslash (\) before the following characters:
    • single-quote (')
    • double quote (")
    • backslash (\)
    • ASCII NULL (\0)
  • For example: "foo's bar and\or baz" becomes "foo\'s bar and\\or baz"
  • The purpose of magic quotes is to prevent the quoted characters from being inserted directly into a database
    • Similar to the MySQL QUOTE() function
  • Quoting prevents problems in database queries where these characters may be used
  • However, magic quotes may unexpectedly cause backslash characters to appear in your data
  • You can remove the backslashes with the stripslashes() function
  • For more information see the PHP Manual: Magic Quotes
  • Note that Magic Quotes has been deprecated as of PHP 5.3.0 and removed from PHP 6

Using Magic Quotes

  • Some hosts have magic quotes turned off and some have them turned on
  • You can use the get_magic_quotes_gpc() function so your code works under either condition:
    if (!get_magic_quotes_gpc()) {
        $myVar = mysql_real_escape_string($myVar);
    }
    
  • The approach you should use is to store data with magic quotes (slashes)
  • When retrieving data from the database, remove the slashes before use:
    if (!get_magic_quotes_gpc()) {
        $myVar = stripslashes($myVar);
    }
    

Commonly Used Magic Quote Functions

Function Description
addslashes() Returns a string with backslashes before characters that need to be quoted in database queries.
stripslashes() Returns a string with backslashes stripped off.
get_magic_quotes_gpc() Returns TRUE if magic quotes is enabled in the system.
get_magic_quotes_runtime() Returns TRUE if magic quotes is enabled for external data such as databases.
set_magic_quotes_runtime() Set the current active configuration setting external data such as databases.
mysql_real_escape_string() Escapes special characters taking into account the current character set of the connection.

More Information

13.2.5: Dealing With Embedded HTML Tags

  • You may want to develop a script that allows users to save textual information
  • Later, on another page, you display that information
  • Unless you are careful, users can enter malicious code
  • For example, consider the following form:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head><title>Message Form</title></head>
<body>
<h1>Your Message Is Heard!</h1>
<form action="msgexer.php" method="post" >
<p>Name:<br>
<input type="text" size="30" name="user">
<p>Comments:<br>
<textarea rows="4" cols="50" name="comment">
Your comments here
</textarea></p>
<br> <input type="submit" value="Click To Post">
<input type="reset" value="Erase and Restart">
</form>
</body>
</html>
  • You save the messages in your database, carefully using addslashes()
    • Database code not shown
  • Later you retrieve the messages from the database for others to read
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// Code to retrieve from database here...

// Remove slashes for display
$user = stripslashes($_POST['user']);
$comment = stripslashes($_POST['comment']);

// Display the data
include("includes/header.php");
echo "<h1>We Heard You!</h1>";
echo "<h4>From: $user</h4>\n";
echo "<p>Comment: $comment</p>\n";
echo "</body>\n</html>";
?>

Using strip_tags()

  • Function strip_tags() tries to remove all SGML tags from a string
    $comment = strip_tags($comment);
  • This includes HTML and PHP tags
  • This function prevents users from planting malicious scripts in user data that you might echo back to the browser
  • You can include a list of tags you do NOT want removed as well
  • For example:
    <?php
    $text = "<p style=\"color:red\"><b>Line one</b><br>
    <font size='+5'>Line two</font></p>";
    echo "<h4>Original Text:</h4>\n";
    echo $text;
    echo "<h4>Stripped Text:</h4>\n";
    echo strip_tags($text, "<p>");
    ?>
    

    Try it and view the source.

  • Produces the output:

    Original Text:

    Line one
    Line two

    Stripped Text:

    Line one Line two

  • Note that attributes of tags you allow are not removed
  • You would normally use strip_tags() before saving data in a database

Translating to HTML Entities

  • Some characters have special meaning in HTML:
    • Like the less than sign (<)
    • Defines the start of an HTML tag
  • To display the character, we need to translate it to an HTML entity
  • An HTML entity is a special HTML code for a character:
    • For instance, the code for the less than sign (<) is: &lt;
  • Function htmlentities() translates many characters into HTML entities
    • Useful for displaying HTML code in a Web page.
  • html_entity_decode() performs the reverse operation of htmlentities():
    • Converts entities into HTML characters
  • Function htmlspecialchars() works like htmlentities but only translates a smaller set:
    • Characters that have special significance in HTML
    • Useful in preventing user-supplied text from containing HTML markup
  • For example, the code:
    <?php
    $new = htmlspecialchars("<a href='test'>Test</a>");
    echo $new; // &lt;a href='test'&gt;Test&lt;/a&gt;
    ?>
    
  • Produces the output: <a href='test'>Test</a>

Commonly Used Functions for Working With HTML Tags

Function Description
strip_tags() Tries to remove all SGML tags from a string. Prevents users from planting malicious scripts in user data that you might echo back to the browser.
htmlentities() Translates certain characters into HTML entities. This is useful for displaying HTML code in a Web page.
html_entity_decode() Converts HTML entities into HTML characters.
htmlspecialchars() Translates HTML characters with special meaning. Useful in preventing user-supplied text from containing HTML markup.

Exercise 13.2

In this exercise we consider how to protect our scripts from SQL injection like we saw in the previous exercise. We will discuss the solution after about 5 minutes.

Specifications

  1. Verify your web server is started and all the support files are installed as specified in the first 4 steps of exercise 13.1.

    We will modify the loginexer.php script from exercise 13.1.

  2. Verify you can still attack the login script by entering the following for the Username in the form:
    jbond' or 1=1 or '1
  3. In the loginexer.php script from exercise 13.1, change the following code from:
    if (get_magic_quotes_gpc()) {
        $login = stripslashes($login);
        $pwd = stripslashes($pwd);
    }
    
    to:
    if (!get_magic_quotes_gpc()) {
        $login = mysql_real_escape_string($login);
        $pwd = mysql_real_escape_string($pwd);
    }
    

    Rather than removing quotes, we are adding quotes. For more information see section 13.3.4: PHP Magic Quotes.

  4. Try attacking the login script again and notice that you can no longer bypass the login. Also notice the difference in the SQL query:
    SELECT * FROM users
      WHERE UserName='jbond\' or 1=1 or \'1'
      AND Userpwd=OLD_PASSWORD('password')
    

    The quotes that were entered are now escaped with a leading backslash (\).

    Note that escaping quotes is only part of the solution. We still need to verify the length of the input and the format of the input. These checks are done easier within the framework of FormVerifier.

As time permits, be prepared to answer the Check Yourself questions in the following section.

13.2.6: Summary

  • Data verification is an important safeguard for applications that rely on user input
  • In this section, we discussed techniques to safeguard your data from user input
  • One important safeguard is to verify that the data is the correct type for a database column
  • This can be trickier than you might expect for integer and floating-point types
  • Another important safeguard is to verify that textual data does not exceed the allowed length
  • Even valid data may pose problems for database data
  • For example, text that contains single or double quotes:
    • Such as a name like O'Reilly
  • PHP provides "magic quotes" and various quoting functions to handle this problem
  • Some hosts have magic quotes turned off and some have them turned on
  • To allow your code to work under either condition, you can test for the condition
    if (!get_magic_quotes_gpc()) {
        $myVar = addslashes($myVar);
    }
    
  • You should store your data quoted and remove the quotes before display
  • User input that you redisplay can pose additional problems
    • It is easy to insert malicious HTML or script
  • To preclude this possibility, you should use strip_tags() or htmlspecialchars()

Check Yourself

As time permits, be prepared to answer these questions. You can find more information by following the links after the question.

  1. Why is user input validation so important? (13.3.1)
  2. What is the algorithm for determining if the input field of a form is an integer value? (13.3.2)
  3. What PHP function can you use to determine the size of a database column? (13.3.3)
  4. What characters are quoted by PHP's Magic Quotes? (13.3.4)
  5. True or false? Magic quotes will protect your application from all malicious data entered by a user. (13.3.5)

13.3: Reducing Security Exposures

Learner Outcomes

At the end of the lesson the student will be able to:

  • Describe the cost and tradeoffs of security
  • Identify security responsibilities of the programmer
  • Describe what the programmer should do to reduce security risks

13.3.1: Protecting our Database-Driven Websites

  • Security does not come free
    • Cost of security devices, services and software
    • Reduced web-site usability
  • Security must be balanced with usability
    • Web sites that allow access to nobody are secure but useless
  • As the developer, you need to find the right balance
  • Note that not all data may need the same level of protection
  • For instance, how important is each of the following data? (scale 1-10)
    • Customer credit-card transactions
    • User logins and passwords
    • User e-mail addresses
    • Product descriptions displayed in a catalog
    • A Web sites HTML code

Security Practices for Database-Driven Websites

  • Much of a web site's protection comes from the web server's configuration
    • Beyond the scope of this course
    • See CIS-164: Intro. to Managing and Securing a Web Server
  • However, you can audit your Web sites PHP security using PHPSecInfo
    • Download and extract to a folder
    • FTP the folder to your hosting service
    • Open the folder in a browser and view the information
    • Remember to remove the folder after the audit
    • Otherwise, you give away too much information for exploiters
  • As the Web site developer you have responsibility for many aspects of security including:
    • Designing to reduce security exposures
    • Encrypting confidential data
    • Authenticating users when required
    • Securing transmission of confidential data
    • Testing for security
    • Validating user input
  • We already discussed validating user input
  • We consider the other aspects in the sections that follow

13.3.2: Designing to Reduce Security Exposures

  • In this section we consider how the overall web-site design affects security

Deciding What Data to Store

  • Make certain you only keep confidential data that you really need
  • Do you really need to keep a customers credit card data?
  • If you do not keep the data, they cannot be stolen

Deciding On Services and Features

  • Remove unused or unnecessary features to reduce potential weaknesses
  • The more features you add, the more complicated your site
  • A common developer phenomena is adding features that are not used
    • But you may need them some day
  • As your code becomes more complicated, you tend to overlook things
  • The solution is to keep your code as simple as possible, but no simpler
  • Implement all the features you need now, but no others

Limiting Access

  • Be careful where you store confidential data
  • For example, do not store anything with Web server access that you do not want seen
    • It is very unlikely that your Web server will send PHP pages as plain text
    • If you are concerned, you can keep login and password information where the Web server cannot access them
    • Then use include files to access the data kept outside the Web document directories
    • However, please do not use this approach for your project
    • It makes it too difficult for the instructor to install and test your code
  • Limit access to database information from the Web server
    • Our most important data tends to be kept in our databases
    • Use a database account with restricted access for your PHP scripts
    • This is usually a concern only if you run your own server
    • Most ISPs do not allow you to have root database-user access
  • Use the file permissions of the operating system to restrict access
    • Make certain your scripts cannot be written to by anyone but the owner
    • Also make certain that directories cannot be written to by anonymous users
    • If someone can install a script, they can perform many malicious acts to your Web site
    • If you use external files in your program, set permissions appropriately

Check Yourself

  1. True or false: you should always store your customer's credit card data in your database to make sure it is safe.
  2. True or false: to improve security and to make your site attractive, include as many services as possible.
  3. True or false: storing data in the web application folder is safe.

13.3.3: Encrypting Confidential Data

  • The foundation of many security techniques is the encryption of data
  • Encryption transforms data into a seemingly unreadable string
  • Plaintext is the information before encryption and after decryption
  • Ciphertext is a term for encrypted data
  • For example, if we encode the plaintext "password" using PHP's md5() function:

    <? echo md5("password"?>

  • The resulting ciphertext looks like:

    5f4dcc3b5aa765d61d8327deb882cf99

  • As you can see, the ciphertext looks nothing like the plaintext
  • Note that encrypting the same plaintext always produces the same ciphertext

Reversing Encryption

  • You can reverse many, but not all, encryption processes

    Why is non-reversible encryption useful?

  • The reverse process of encryption is called decryption
  • For reversible encryption algorithms, you must have a value known as a key
    • If you do not know the key value, you cannot reverse the process
  • Some encryption schemes use the same key to encrypt and decrypt a message
    • Called a secret (or private) key because you must keep it secret

    What is the problem with a secret key when you want to transmit encrypted data?

  • Some algorithms allow you to use one key to encrypt data and another to decrypt data
  • This two-key system is known as public key encryption
    • Allows you to keep one key private
    • You publish the other key to allow people to send you encrypted data
    • Only you can decrypt the data using your private key

PHP's Encryption Functions

  • PHP offers a wrapper to C's crypt() function
  • Also provides implementations of md5 and sha1
  • All the above are for one-way encryption of string data
  • PHP also provides one set of easy to use encryption and decryption functions:
  • For stronger reversible encryption, PHP has an extension for the mcrypt library:
    • To use mcrypt at home, you may need to install additional DLLs
    • Also, you may want to check if your ISP has mcrypt installed
  • Also, PHP has a library for OpenSSL

What to Encrypt

  • Encrypting confidential data may seem like a good idea
  • Encryption hides data from someone who has control of your database
  • However, encryption may have little value if you need to decrypt it automatically:
    • Decryption requires storing keys and using decryption functions or programs
    • Anyone cracking your site would have access to your passwords, functions and programs if they can read your data
  • However, encryption can protect data if you do not need to decrypt it automatically
  • For instance, you should store passwords using one-way (non-reversible) encryption
    • Prevents anyone but the user from knowing their passwords
    • Even someone who cracks your site cannot get the passwords
  • Password verification with encryption is straightforward:
    • User enters a password
    • Password gets encrypted
    • Encrypted version of the entered password is compared against the stored version of encrypted password
  • You may be able to use a similar approach for storing other confidential data such as credit card numbers
  • Cookie data usually should be encrypted with a reversible algorithm
    • Prevents the user from modifying their cookie data
    • Prevents hackers from discerning the structure of your cookie data
  • For some cookies you can use base64_encode() and base64_decode():

    <?php
    ob_start
    ();

    $name "cartID";
    $value "8122c5b69a5721cc95263b10540c9720";
    echo 
    "<h4>Original values</h4>\n";
    echo 
    "<p>name=$name</p>\n";
    echo 
    "<p>value=$value</p>\n";

    $name base64_encode($name);
    $value base64_encode($value);
    //setcookie($name, $value, time() + 14400);
    echo "<h4>Encrypted values</h4>\n";
    echo 
    "<p>name=$name</p>\n";
    echo 
    "<p>value=$value</p>\n";

    $name base64_decode($name);
    $value base64_decode($value);
    echo 
    "<h4>Decrypted values</h4>\n";
    echo 
    "<p>name=$name</p>\n";
    echo 
    "<p>value=$value</p>\n";
    ?>

    Try it!

  • Base64 is well known and easy to reverse without knowing a key value
  • For sensitive data, you should use a stronger encryption function

Check Yourself

  1. Plain text that has been encryted is known as ________.
  2. True or false: encrypted data can be worth storing in a database even if you cannot decrypt it.
  3. True or false: the problem with secret key data transmission is that you need to transmit the key to the receiver.
  4. True or false: some encryption systems allow you to publish a key that can decode a message.

Further Information

13.3.4: Authenticating Users When Required

  • There is a difference between authorization and authentication
  • Authorization establishes your authority to perform some act
  • Authentication establishes that you are not false or an imitation
  • One common method of authentication is a login name and password
  • Logins and passwords are relatively simple to implement and use
    • We explored how to do this previously

When to Authenticate

  • Use authentication when you need surety of whom you are dealing with
    • For example, when making a financial transaction such as with a credit card
    • Without authentication, the credit card holder may deny having authorized the purchase
  • Another example is when you provide special privileges or higher authorization levels
    • Even if already authenticated, you should relogin when accessing more privileged data
    • For instance, when accessing administrative pages or accessing account information
  • Yet another time to use authentication is when providing confidential data
    • For example, when allowing users to change passwords or view their personal information

Digital Signatures (Optional)

  • A stronger form of authentication is the digital signature using public and private keys
  • A digital signature is the electronic version of a physical signature
  • With paper and pen, a person signs a document with a physical signature
  • In the digital world, users and machines sign documents or data using a digital signature
  • Digital signatures are most often based on public-key cryptography
  • As was mentioned earlier, public and private keys come in pairs
  • Only the owner of the public and private key pair knows the private key
  • Encrypting using one key requires the other key for decryption
  • Any message encrypted by the private key can be decrypted by the public key
  • Thus any message encrypted by the private key can use the public key to verify it came from the owner
  • This allows authentication that a message in fact originated from the identity it appears to have originated from

Digital Signature Example

To send an authenticatable secret message from Alice to Bob:

  1. Alice encrypts her message with her private key
  2. Alice encrypts her message with Bob's public key
  3. Alice transmit the message and Bob receives the message
  4. Bob decrypts the message with his private key
  5. Bob decrypts the message with Alice's public key

    secret message

13.3.5: Securing Transmission of Confidential Data

  • Data is at risk while traversing a network
  • Network data often passes through 10 to 20 machines to reach a destination
  • You can examine how a packet moves over the Internet
  • On UNIX, run the traceroute program
  • On Windows, run the tracert program:
    • From the Start menu, select Run
    • Type in command for Win9X/ME or cmd for WinNT/2000/XP
    • At the command prompt, type tracert and a destination
  • From the Internet, use a traceroute utility
  • For example:

    C:\> tracert php.net

    Tracing route to php.net [64.246.30.37]
    over a maximum of 30 hops:

    1 <10 ms 1 ms <10 ms rocky.cabrillo.cc.ca.us [172.16.1.1]
    2 1 ms 1 ms 2 ms seahawk.cabrillo.cc.ca.us [207.62.185.33]
    3 2 ms 2 ms 2 ms 207.62.184.1
    ...
    18 56 ms 55 ms 55 ms rs1.php.net [64.246.30.37]

    Trace complete.

  • This shows it took 18 "hops" for packets to travel from my PC to php.net
  • Oftentimes a firewall will block ping requests

Protecting Data Transmission

  • The most common way to secure transmissions is using Secure Sockets Layer (SSL)
  • SSL provides data encryption and other services for TCP/IP (Internet) transmissions:
  • SSL comes in two key strengths: 40-bit and 128-bit
    • Longer keys makes breaking encryption more difficult
  • To implement, you must arrange with your hosting service to install a certificate
  • You can obtain certificates from Verisign, Thawte (owned by Verisign) and others
  • Many hosting services have their own certificate your can use
  • You can also create your own certificate (self-signed)

Using SSL

  • You should use https for transmitting all confidential data
  • To invoke a secure channel, use the https protocol in your URLs
    <form action="https://some url/page.php" method="post">
    
  • Notice that using my ISP's certificate requires me to use their domain name
  • Depending on your application, this may be good enough
  • Some ISPs require you to use HTML when using SSL for security reasons

Further Information

13.3.6: Testing for Security

  • As a developer, you are responsible for testing your code
  • Programs that successfully complete their intended task still may not be correct
  • Sometimes developers use poor programming practices that have potential security risks
  • When you test your scripts, try entering extreme or even ridiculous values
  • Such values will often cause the program to crash or have unintended side effects
  • Crackers often exploit these types of bugs

Testing Your Web Forms

Following are adapted from the MySQL Documentation: General Security Guidelines on how to test your Web forms:

  • Try to enter (') and (") in all your web forms. If you get any kind of database error, the Web application is not checking user input properly.
  • Try to modify dynamic URLs by adding %22 ("), %23 (#), and %27 (') in the URL.
  • Try to modify data types in dynamic URLs from numeric ones to character ones containing characters from previous examples. Web applications should check for these types of insertions.
  • Try to enter characters, spaces, and special symbols instead of numbers in numeric fields. Your application should remove them before passing them to a database or your application should generate an error.
  • Check data sizes before passing them to the database.
  • Have the application connect to the database using a user name with the absolute minimum privileges needed.
  • Do not give your applications any more access privileges than they need.

Further Information

13.3.7: Summary

  • Much of a web site's protection comes from the web server's configuration
  • However, the web-site programmer is responsible for some aspects of security including:
    • Designing to reduce security exposures
    • Encrypting confidential data
    • Authenticating users when required
    • Securing transmission of confidential data
    • Testing for security
    • Preventing SQL Injection
  • We discussed how to meet these responsibilities in the previous sections

Check Yourself

  1. Why do web developers need to worry about security? (13.3.1)
  2. What is the best way to avoid losing credit card data? (13.3.2)
  3. What is the problem with adding features to you web site that you do not end up using? (13.3.2)
  4. Why is non-reversible encryption useful? (13.3.3)
  5. What is the problem with secret key encryption when you want to transmit encrypted data? (13.3.3)
  6. How does public key encryption solve the problem with secret keys? (13.3.3)
  7. What is a digital signature? (13.3.4)
  8. When should you authenticate users? (13.3.4)
  9. On the web, how do you transmit confidential data? (13.3.5)
  10. How do you test a form for security problems? (13.3.6)

Wrap Up

Due Next:
Final Project Report and Presentation (5/29/12)

When class is over, please shut down your computer if it is on
Work on your project!
Home | Blackboard | Syllabus | Expectations | Schedule
Project | Help | FAQ's | HowTo's | Links
Last Updated: May 21 2012 @23:25:49