编写安全 PHP应用程序的七个习惯深入分析(2)


<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text"
    value="<?php echo(isset($_POST['account_number']) ?
        $_POST['account_number'] : ''); ?>" />
<select>
<option value="account_number">Account Number</option>
<option value="name">Name</option>
<option value="address">Address</option>
</select>
<input type="submit" value="Save" /></div>
</form>
<?php
if ($_POST['submit'] == 'Save') {
    /* do the form processing */
    $link = mysql_connect('hostname', 'user', 'password') or
        die ('Could not connect' . mysql_error());
    mysql_select_db('test', $link);

  $col = $_POST['col'];
    $select = "SELECT " . $col . " FROM account_data WHERE account_number = "
        . $_POST['account_number'] . ";" ;
    echo '<p>' . $select . '</p>';
    $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');
    echo '<table>';
    while ($row = mysql_fetch_assoc($result)) {
        echo '<tr>';
        echo '<td>' . $row[$col] . '</td>';
        echo '</tr>';
    }
    echo '</table>';
    mysql_close($link);
}
?>
</body>
</html>


因此,要形成保护数据库的习惯,请尽可能避免使用动态 SQL 代码。如果无法避免动态 SQL 代码,请不要对列直接使用输入。清单 4 显示了除使用静态列外,还可以向帐户编号字段添加简单验证例程以确保输入值不是非数字值。
清单 4. 通过验证和 mysql_real_escape_string() 提供保护

复制代码 代码如下:


<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
<div><input type="text"
    value="<?php echo(isset($_POST['account_number']) ?
        $_POST['account_number'] : ''); ?>" /> <input type="submit"
    value="Save" /></div>
</form>
<?php
function isValidAccountNumber($number)
{
    return is_numeric($number);
}
if ($_POST['submit'] == 'Save') {
    /* Remember habit #1--validate your data! */
    if (isset($_POST['account_number']) &&
    isValidAccountNumber($_POST['account_number'])) {
        /* do the form processing */
        $link = mysql_connect('hostname', 'user', 'password') or
        die ('Could not connect' . mysql_error());
        mysql_select_db('test', $link);
        $select = sprintf("SELECT account_number, name, address " .
  " FROM account_data WHERE account_number = %s;",
        mysql_real_escape_string($_POST['account_number']));
        echo '<p>' . $select . '</p>';
        $result = mysql_query($select) or die('<p>' . mysql_error() . '</p>');
        echo '<table>';
        while ($row = mysql_fetch_assoc($result)) {
            echo '<tr>';
            echo '<td>' . $row['account_number'] . '</td>';
            echo '<td>' . $row['name'] . '</td>';
            echo '<td>' . $row['address'] . '</td>';
            echo '</tr>';
        }
        echo '</table>';
        mysql_close($link);
    } else {
        echo "<span style=\"font-color:red\">" .
    "Please supply a valid account number!</span>";
    }
}
?>
</body>
</html>


本例还展示了 mysql_real_escape_string() 函数的用法。此函数将正确地过滤您的输入,因此它不包括无效字符。如果您一直依赖于 magic_quotes_gpc,那么需要注意它已被弃用并且将在 PHP V6 中删除。从现在开始应避免使用它并在此情况下编写安全的 PHP 应用程序。此外,如果使用的是 ISP,则有可能您的 ISP 没有启用 magic_quotes_gpc。
最后,在改进的示例中,您可以看到该 SQL 语句和输出没有包括动态列选项。使用这种方法,如果把列添加到稍后含有不同信息的表中,则可以输出这些列。如果要使用框架以与数据库结合使用,则您的框架可能已经为您执行了 SQL 验证。确保查阅文档以保证框架的安全性;如果仍然不确定,请进行验证以确保稳妥。即使使用框架进行数据库交互,仍然需要执行其他验证。

保护会话
默认情况下,PHP 中的会话信息将被写入临时目录。考虑清单 5 中的表单,该表单将显示如何存储会话中的用户 ID 和帐户编号。
清单 5. 存储会话中的数据

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4d932b1638724203594054ffc9c0fa03.html