OWASP Backend Security Project PHP Security Programming
Contents
Overview
Example 1
Here follows a tipical Login Forms to authenticate user. Credentials are retrieved on a backend Database by using connection parameters stored in a .inc file.
auth.php
<?php
include('./db.inc');
function sAuthenticateUser($username, $password){
$authenticatedUserName="";
if ($link = iMysqlConnect()) {
$query = "SELECT username FROM users";
$query .= " WHERE username = '".$username."'";
$query .= " AND password = md5('".$password."')";
$result = mysql_query($query);
if ($result) {
if ($row = mysql_fetch_row($result)) {
$authenticatedUserName = $row[0];
}
}
}
return $authenticatedUserName;
}
if ($sUserName = sAuthenticateUser($_POST["username"],
$_POST["password"])) {
/* successfull authentication code goes here */
...
...
} else {
/* unsuccessfull authentication code goes here */
...
...
}
?>
db.inc
<?php
define('DB_HOST', "localhost");
define('DB_USERNAME', "user");
define('DB_PASSWORD', "password");
define('DB_DATABASE', "owasp");
function iMysqlConnect(){
$link = mysql_connect(DB_HOST,
DB_USERNAME,
DB_PASSWORD);
if ($link && mysql_select_db(DB_DATABASE))
return $link;
return FALSE;
}
?>
The above example has two vulnerability:
- Authentication Bypass
- by exploiting a SQL Injection vulnerability Authentication you can authenticate as :
- username ' OR 1=1 #
- password anything
- by exploiting a SQL Injection vulnerability Authentication you can authenticate as :
- Information Disclosure
- an attacker may retrieve db.inc on unproper configured WEB Server
Example 2
The following sample code cames from a online book catalog.
getbook.php
function aGetBookEntry($id) {
$aBookEntry = NULL;
$link = iMysqlConnect();
$query = "SELECT * FROM books WHERE id = $id";
$result = mysql_query($query);
if ($result) {
if ($row = mysql_fetch_array($result)) {
$aBookEntry = $row;
}
}
return $aBookEntry;
}
....
$id = $_GET['id'];
$aBookEntry = aGetBookEntry($id);
/* Display retrieved book information */
...
...
The above example is vulnerable to Blind SQL Injection attack. An attacker exploiting this vulnerability may backup on his laptop your Database content, or even worst can spawn a remote shell into it.
Description
PHP preventing SQL Injection
Escaping Quotes
magic_quotes_gpc escapes quotes from HTTP Request by examing both GET/POST data and Cookie value. The truth is that any other data in HTTP Request isn't escaped and an evil user may attempt to exploit a SQL Injection vulnerability on other HTTP Request data such as User-Agent value. Another drawback is that while it performs well on MySQL (as example) it doesn't works with Microsoft SQL Server where single quote should be escaped with '''
magic_quotes_gpc should never be used since:
- only GET/POST/COOKIE data are escaped in served HTTP Request
- it doesn't guarantee compatibility between different DBMS
Since every application should be portable across WEB Servers we want to rollaback from magic_quotes_gpc each time a php script is running on WEB Server:
function magic_strip_slashes() {
if (get_magic_quotes()) {
// GET
if (is_array($_GET)) {
foreach ($_GET as $key => $value) {
$_GET[$key] = stripslashes($value);
}
}
// POST
if (is_array($_POST)) {
foreach ($_GET as $key => $value) {
$_POST[$key] = stripslashes($value);
}
}
// COOKIE
if (is_array($_COOKIE)) {
foreach ($_GET as $key => $value) {
$_COOKIE[$key] = stripslashes($value);
}
}
}
}
and use a DBMS related function to escape quotes such as:
- MySQL: mysql_real_escape_string
- PostgreSQL: pg_escape_string
function sEscapeString($sDatabase, $sQuery) {
$sResult=NULL;
switch ($sDatabase) {
case "mysql":
$sResult = mysql_escape_string($sQuery);
break;
case "postgresql":
$sResult = pg_escape_string($sQuery);
break;
case "mssql":
$sResult = str_replace("'", "''",$sQuery);
break;
case "oracle":
$sResult = str_replace("'", "''",$sQuery);
break;
}
return $sResult;
}
}
Both Oracle and Microsoft SQL Server connectors doesn't have a real escape_string function so you need to escape every ' with '' by using your own escapeing function or addslashes().
With properly quotes escaping we can prevent Authentication Bypass vulnerability in Example 1:
auth.php
<?php
include('./db.inc');
function sAuthenticateUser($username, $password){
$authenticatedUserName="";
if ($link = iMysqlConnect()) {
$query = "SELECT username FROM users";
$query .= " WHERE username = '".$username."'";
$query .= " AND password = md5('".$password."')";
/* escape quotes */
$result = sEscapeString("mysql", $query);
if ($result) {
if ($row = mysql_fetch_row($result)) {
$authenticatedUserName = $row[0];
}
}
}
return $authenticatedUserName;
}
/* start by rollback magic_quotes_gpc action (if any) */
magic_strip_slashes();
if ($sUserName = sAuthenticateUser($_POST["username"],
$_POST["password"])) {
/* successfull authentication code goes here */
...
...
} else {
/* unsuccessfull authentication code goes here */
...
...
}