6. DISCUSIÓN
6.2. INFLUENCIA DEL GÉNERO EN LA ENDOCARDITIS INFECCIOSA
RFC 1867 documents form-based file uploads — a way of uploading files through HTML, HTTP, and a web server. It uses an HTML form, a special form-encoding method, and an INPUT tag of type FILE:
<form
method="post"
enctype="multipart/form-data"
action="/cgi-bin/process_form.php"> <input type="text" name="photo_name"> <input type="file" name="upload"> <input type="submit" value="submit"> </form>
This is another golden opportunity for those with too much time and too little conscience. A file upload is handled by a CGI file-upload script. There is no standard script, since so many things can be done with an uploaded file.
8.4.6.1 PHP
Uploaded files are saved as temporary files in the directory specified by the PHP directive
upload_tmp_dir. The default value (/tmp) leaves them visible to anyone, so you may want to define upload_tmp_dir to some directory in a virtual host's file hierarchy. To access uploaded files, use the new autoglobal array $_FILES, which is itself an array. For the photo-uploading example, let's say you want to move an uploaded image to the photos directory of virtual host host:
<?
// $name is the original file name from the client $name = $_FILES[’photo_file’][’name’];
// $type is PHP’s guess of the MIME type $type = $_FILES[’photo_file’][’type’];
// $size is the size of the uploaded file (in bytes) $size = $_FILES[’photo_file’][’size’];
// $tmpn is the name of the temporary uploaded file on the server $tmpn = $_FILES[’photo_file’][’tmp_name’];
// If everything looks right, move the temporary file // to its desired place.
if (is_uploaded_file($tmpn))
move_uploaded_file($tmpn, "/usr/local/apache/host/photos"); You may check the file’s type, name, and size before deciding what to do with it. The PHP option
max_upload_filesize caps the size; if a larger file is uploaded, the value of $tmpn is none. When the PHP script finishes, any temporary uploaded files are deleted.
8.4.6.2 Perl
The CGI.pm module provides a file handle for each temporary file. #!/usr/bin/perl -wT
use strict;
use CGI qw(:standard);
my $handle = param("photo_file");
my $tmp_file_name = tmpFileName($handle); # Copy the file somewhere, or rename it # ...
The temporary file goes away when the CGI script completes.
8.4.7 Accessing Databases
Although relational databases have standardized on SQL as a query language, many of their APIs and interfaces, whether graphic or text based, have traditionally been proprietary. When the Web came along, it provided a standard GUI and API for static text and dynamic applications. The simplicity and broad applicability of the web model led to the quick spread of the Web as a database frontend. Although HTML does not offer the richness and performance of other graphic user interfaces, it’s good enough for many applications.
Databases often contain sensitive information, such as people’s names, addresses, and financial data. How can a porous medium like the Web be made safer for database access?
• Don’t have your database on the same machine as the web server. It’s best if your database is behind a firewall that only passes queries from your web server. For example, MySQL normally uses port 3306, so you might only permit access from ports on the web server to port 3306 on the database server.
• Check that all default database passwords have been changed. For MySQL, ensure that the default user (called root, but not related to the Unix root user) has a password. You have a problem if you can get into the database without a password by typing:
mysql -u root
• Use the SQL GRANT and REVOKE statements to control access to tables and other resources only for the desired MySQL IDs on the desired servers. An example might follow this pattern:
• GRANT SELECT ON sample_table
• TO "sample_user@sample_machine" IDENTIFIED BY "sample password"
• Do not allow access to the MySQL users table by anyone other than the MySQL root user, since it contains the permissions and encrypted passwords.
• Don’t use form variable values or names in SQL statements. If the form variable user maps directly to a user column or table, then someone will deduce the pattern and experiment. • Check user input before using it in SQL statements. This is similar to checking user input before
executing a shell command. Exploits have been called SQL injection. See SQL Injection — Are Your Web Applications Vulnerable?
(http://www.spidynamics.com/papers/SQLInjectionWhitePaper.pdf).
Any time information is exchanged, someone will be tempted to change it, block it, or steal it. We’ll quickly review these issues in PHP and Perl database CGI scripts:
• Which database APIs to use
• Protecting database account names and passwords • Defending against SQL injection
8.4.7.1 PHP
PHP has many specific and generic database APIs. There is not yet a clear leader to match Perl’s DBI. A PHP fragment to access a MySQL database might begin like this:
<?
$link = mysql_connect("db.test.com", "dbuser", "dbpassword"); if (!$link)
echo "Error: could not connect to database\n"; ?>
If this fragment is within every script that accesses the database, every instance will need to be changed if the database server, user, or password changes. More importantly, a small error in Apache’s configuration could allow anyone to see the raw PHP file, which includes seeing these connection parameters. It’s easier to write a tiny PHP library function to make the connection, put it in a file outside the document root, and include it where needed.
Here’s the include file: // my_connect.inc
// PHP database connection function.
// Put this file outside the document root! // Makes connection to database.
// Returns link id if successful, false if not. function my_connect( )
{
$database = "db.test.com"; $user = "db_user"; $password = "db_password";
$link = mysql_connect($database, $user, $password); return $link;
}
And this is a sample client: // client.php
// PHP client example.
// Include path is specified in include_path in php.ini. // You can also specify a full pathname.
include_once "my_connect.inc"; $link = my_connect( );
// Do error checking in client or library function if (!$link)
echo "Error: could not connect to database\n"; // ...
Now that the account name and password are better protected, you need to guard against malicious SQL code. This is similar to protecting against user input passing directly to a system command, for much the same reasons. Even if the input string is harmless, you still need to escape special characters.
The PHP addslashes function puts a backslash (\) before these special SQL characters: single quote (’), double quote ("), backslash (\), and NUL (ASCII 0). This will be called automatically by PHP if the option magic_quotes_gpc is on. Depending on your database, this may not quote all the characters correctly. SQL injection is an attempt to use your database server to get access to otherwise protected data (read, update, or delete) or to get to the operating system. For an example of the first case, say you have a login form with user and password fields. A PHP script would get these form values (from $_GET, $_POST, or $_REQUEST, if it’s being good), and then build a SQL string and make its query like this:
$sql = "SELECT COUNT(*) FROM users WHERE\n" . "user = ’$user’ AND\n".
"password = ’$password’"; $result = mysql_query($sql);
if ($result && $row = mysql_fetch_array($result) && $row[0] == 1) return true;
else
return false;
An exploiter could enter these into the input fields (see Table 8-9). Table 8-9. SQL exploit values
Field Value
user ’ OR ’’ = ’’
password ’ OR ’’ = ’’
The SQL string would become:
SELECT COUNT(*) FROM users WHERE user = ’’ OR ’’ = ’’ AND
password = ’’ OR ’’ = ’’
The door is now open. To guard against this, use the techniques I’ve described for accessing other external resources, such as files or programs: escape metacharacters and perform regular-expression searches for valid matches. In this example, a valid user and password might be a sequence of letters and numbers. Extract user and password from the original strings and see if they’re legal.
In this example, if the PHP option magic_quotes_gpc were enabled, this exploit would not work, since all quote characters would be preceded by a backslash. But other SQL tricks can be done without quotes. A poorly written script may run very slowly or even loop forever, tying up an Apache instance and a database connection. PHP’s set_time_limit function limits the number of seconds that a PHP script may execute. It does not count time outside the script, such as a database query, command execution, or file I/O. It also does not give you more time than Apache’s Timeout variable.
8.4.7.2 Perl
Perl has the trusty database-independent module DBI and its faithful sidekicks, the database-dependent (DBD) family. There’s a DBD for many popular databases, both open source (MySQL, PostgreSQL) and commercial (Oracle, Informix, Sybase, and others).
A MySQL connection function might resemble this: # my_connect.pl sub my_connect { my $server = "db.test.com"; my $db = "db_name"; my $user = "db_user"; my $password = "db_password"; my $dbh = DBI->connect( "DBI:mysql:$db:$server", $user $password, { PrintError => 1, RaiseError => 1 })
or die "Could not connect to database $db.\n"; return $dbh;
} 1;
As in the PHP examples, you’d rather not have this function everywhere. Perl has, characteristically, more than one way to do it. Here is a simple way:
If your connection logic is more complex, it could be written as a Perl package or a module.
Taint mode won’t protect you from entering tainted data into database queries. You’ll need to check the data yourself. Perl’s outstanding regular-expression support lets you specify patterns that input data must match before going into a SQL statement.