Page 1 of 1

Security Review - PHP/MySQL Control Panel Installer

Posted: Mon Jul 21, 2008 12:33 pm
by JAB Creations
Knowing the forums and the fact that I'm not nearly finished with this I decided not to post this script in the critique forum as I feel there is still a lot of work to polish code. However I did spend the past week working on this project which was inspired in part by the vBulletin installer. I've been wanting to do two things: one really break in to MySQL and get comfortable with being able to program it on a or nearly a daily basis. Working on this project helped me get used to MySQL a lot. Secondly I've been desiring to setup my own control panel to centralize things. This security review however is my inquiry for areas of improvement as far as the installer goes. This script (at least for now) is not something I'm interested in putting on my site for download or to use in a live environment right now because I don't feel I grasp all the security concerns especially with the information that this installer requests. So the installer file works but getting it to work securely (and possibly more efficiently) are my areas of concern so that means I am not interested in any criticisms of style/design.

Any way there are a few files and there is one sub-folder so pay attention to how I have the file names / directories structured. Keep in mind if you test the installer out all the way (there are seven steps) and you arrive at the control panel the install.php file will be deleted. A couple things I tried doing is minimizing permissions (707), reducing load (offloading unique/rarely used functions to admin_tasks.php), and implementing mysql_real_escape_string. You can enter in fake information (and use SHIFT+Delete to remove it from auto-complete) as my intention up to this point was merely collecting information, storing it in a database, and being able to retrieve it however it will break the functionality of the installer and you'll receive error messages accordingly (it will attempt to verify things such as connecting to your FTP and such). Again more stuff for me to practice with PHP/MySQL.

One thing that I have yet to program that I intend to do so is to delete the session and force the initial sign in to the control panel. However to move forward while I'm waiting for replies I'll work on that and some other stuff centered around the control panel.

Also keep in mind you'll need access to a MySQL database however all the configuration is setup through the install.php file itself through the browser to connect to the DB and setup the tables for you. There should be no need to edit any files to get this to work.

If there is anything wrong with the files not working let me know and I'll correct my post...the site is not correctly previewing this for me. :| Again I'm mostly interested in input about security, still interested in efficiency, and completely uninterested in anything design related input.

admin.php

Code: Select all

<?php if (file_exists("install.php")) {die("You can not use the control panel while the install.php file is present!");} include("themes/header-00.php");?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Administrator Control Panel</title>
<link href="themes/style.css" media="screen" rel="stylesheet" title="Classic Theme" type="text/css" />
</head>
 
<body>
 
<h1>Administrator Control Panel</h1>
 
<div id="body">
<div id="content">
<p>content</p>
<p>content</p>
<p>content</p>
</div><!-- /#content -->
 
<div id="menu">
<div><a href="#">menu</a></div>
<div><a href="#">menu</a></div>
<div><a href="#">menu</a></div>
</div><!-- /#menu -->
</div><!-- /#body -->
 
</body>
</html>

install.php

Code: Select all

<?php
ini_set('display_errors',FALSE);
//ini_set('display_errors',TRUE);
session_name("installer"); session_start();
 
// STEP 1
if ($_GET['step'] == '1' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
$site = $_POST['site'];
$_SESSION['site'] = $site;
}
 
// STEP 2
else if ($_GET['step'] == '2' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $_SESSION['mysql_host'] = $_POST['mysql_host'];
 $_SESSION['mysql_user'] = $_POST['mysql_user'];
 $_SESSION['mysql_pass'] = $_POST['mysql_pass'];
 $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
 if (!$db) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=1&error");}
}
 
// STEP 3
else if ($_GET['step'] == '3' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
 if (!$db) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=1&error");}
 
 $selected = mysql_select_db($_SESSION['mysql_user'],$db) or die("Error 2: Could not select database.");
 
$result1 = mysql_query("DROP TABLE public_accounts");
if (!$result1) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=2&error");}
 
$result2 = mysql_query("DROP TABLE admin_global");
if (!$result2) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=2&error");}
 
$result3 = mysql_query("
CREATE TABLE public_accounts (
  id int(10) unsigned NOT NULL auto_increment,
  username varchar(32) NOT NULL,
  password varchar(32) NOT NULL,
  email varchar(32) NOT NULL,
  activation_key varchar(3) NOT NULL,
  activation_attempts varchar(1) default '0',
  date_0 varchar(19) NOT NULL,
  date_1 varchar(19) NOT NULL,
  date_2 varchar(19) NOT NULL,
  ip_0 int(11) UNSIGNED NOT NULL,
  ip_1 int(11) UNSIGNED NOT NULL,
  ip_2 int(11) UNSIGNED NOT NULL,
  PRIMARY KEY  (id)
) ENGINE=MyISAM DEFAULT CHARSET=hp8 AUTO_INCREMENT=1;
");
if (!$result3) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=2&error");}
 
/*///////////////////////////////
// $_SERVER['HTTP_HOST']
// MUST CHECK FOR THIS during installer
//
///////////////////////////////*/
 
 
$result4 = mysql_query("
CREATE TABLE admin_global (
  id int(10) unsigned NOT NULL auto_increment,
  site varchar(32) NOT NULL,
  ftp_host varchar(32) NOT NULL,
  ftp_user varchar(32) NOT NULL,
  ftp_pass varchar(32) NOT NULL,
  live_host varchar(32) NOT NULL,
  live_user varchar(32) NOT NULL,
  live_pass varchar(32) NOT NULL,
  local_host varchar(32) NOT NULL,
  local_user varchar(32) NOT NULL,
  local_pass varchar(32) NOT NULL,
  live_private varchar(64) NOT NULL,
  live_public varchar(64) NOT NULL,
  local_private varchar(64) NOT NULL,
  local_public varchar(64) NOT NULL,
  
  PRIMARY KEY  (id)
) ENGINE=MyISAM DEFAULT CHARSET=hp8 AUTO_INCREMENT=1;
");
if (!$result4) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=2&error");}
 
/*
let's add that user now
*/
$site = $_SESSION['site'];
$result5 = mysql_query("INSERT INTO admin_global (site) VALUES ('$site')");
if (!$result5) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=5&error");}
}
 
 
// STEP 4
else if ($_GET['step'] == '4' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $user = mysql_real_escape_string($_POST['username']);
 $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
 mysql_select_db($_SESSION['mysql_user']);
 $sql = "SELECT username FROM public_accounts WHERE username = '$user'";
 $result = mysql_query($sql); 
 
 if (mysql_num_rows($result) >= 1)
 {
  header("location:install.php?step=4");
 }
 else
 {
 if (!$db) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=1&error");}
 $user = mysql_real_escape_string($_POST['username']);
 $pass = mysql_real_escape_string($_POST['password']);
 $mail = mysql_real_escape_string($_POST['email']);
 $result5 = mysql_query("INSERT INTO public_accounts (username, password, email, date_0) VALUES ('$user', '$pass', 'email', NOW())");
 if (!$result5) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=3&error");}
 }
}
 
// STEP 5
else if ($_GET['step'] == '5' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
 mysql_select_db($_SESSION['mysql_user']);
 
 $live_private = mysql_real_escape_string($_POST['live_private']);
 $live_public = mysql_real_escape_string($_POST['live_public']);
 $local_private = mysql_real_escape_string($_POST['local_private']);
 $local_public = mysql_real_escape_string($_POST['local_public']);
//INSERT INTO admin_global (live_private, live_public, local_private, local_public) VALUES ('$live_private', '$live_public', '$local_private', '$local_public')
 $result = mysql_query("UPDATE admin_global SET live_private='$live_private', live_public='$live_public', local_private='$local_private', local_public='$local_public' WHERE id='1'");
 if (!$result) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=4&error");}
}
 
// STEP 6
else if ($_GET['step'] == '6' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
 mysql_select_db($_SESSION['mysql_user']);
 
 $live_host = mysql_real_escape_string($_POST['live_host']);
 $live_user = mysql_real_escape_string($_POST['live_user']);
 $live_pass = mysql_real_escape_string($_POST['live_pass']);
 $local_host = mysql_real_escape_string($_POST['local_host']);
 $local_user = mysql_real_escape_string($_POST['local_user']);
 $local_pass = mysql_real_escape_string($_POST['local_pass']);
 
 $result = mysql_query("UPDATE admin_global SET live_host='$live_host', live_user='$live_user', live_pass='$live_pass', local_host='$local_host', local_user='$local_user', local_pass='$local_pass' WHERE id='1'");
 if (!$result) {$_SESSION['error'] = mysql_error(); header("location:install.php?step=5&error");}
 else {$_SESSION['delete'] = $_SERVER['SCRIPT_FILENAME'];}
}
 
 
// STEP 7
else if ($_GET['step'] == '7' && $_SERVER['REQUEST_METHOD'] == 'POST')
{
 $ftp_host = mysql_real_escape_string($_POST['ftp_host']);
 $ftp_user = mysql_real_escape_string($_POST['ftp_user']);
 $ftp_pass = mysql_real_escape_string($_POST['ftp_pass']);
 if (@ftp_login($ftp_host, $ftp_user, $ftp_pass))
 {
  $db = mysql_connect($_SESSION['mysql_host'], $_SESSION['mysql_user'], $_SESSION['mysql_pass']);
  mysql_select_db($_SESSION['mysql_user']);
  $result = mysql_query("UPDATE admin_global SET ftp_host='$ftp_host', ftp_user='$ftp_user', ftp_pass='$ftp_pass' WHERE id='1'");
  if (!$result) {$_SESSION['error'] = 'unable to connect? 34?'; header("location:install.php?step=6&error");}
 }
}
 
 
header("Content-type: application/xhtml+xml");
echo'<?xml version="1.0" encoding="UTF-8"?>'."\n";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Installer</title>
<link href="themes/style.css" media="screen" rel="stylesheet" title="Classic Theme" type="text/css" />
<script type="text/javascript">
//<![CDATA[
// Class Change
function change(id, newClass) {identity=document.getElementById(id); identity.className=newClass;}
 
function check_admin() {
if (document.getElementById('username').value.length <= 4) {change('username', 'text status_invalid');}
else if (document.getElementById('username').value.length >= 4) {change('username', 'text status_valid');}
}
 
 
// Confirm Email
function check_email(id)
{
 var str = document.getElementById(id).value;
 if ((document.getElementById(id).value==null) || (document.getElementById(id).value=='') && (document.getElementById(id) != id)) {change(id, 'text status_invalid');}//alert('8: Please Enter your Email ID'); return false;}
 else if (id == 'emailconfirm')
 {
 if (document.getElementById('email').value == document.getElementById('emailconfirm').value) {change('emailconfirm', 'text status_valid');}
 else {change('emailconfirm', 'text status_invalid');}
 }
 
 
 else if (check_email_filters(id, str)==false)
 //check_email_filters(email_id.value)==false)
 {
 document.getElementById(id).value=''; document.getElementById(id).focus(); return false;
 }
}
 
 
function check_email_filters(id, str)
{
 var at='@'
 var dot='.'
 var lat=str.indexOf(at)
 var lstr=str.length
 var ldot=str.indexOf(dot)
 
 if (str.indexOf(at)==-1) {change(id, 'text status_invalid');}//alert('1: Invalid E-mail ID');}
 else if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr) {change(id, 'text status_invalid');}//alert('2: Invalid E-mail ID');}
 else if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr) {change(id, 'text status_invalid');}//alert('3: Invalid E-mail ID');}
 else if (str.indexOf(at,(lat+1))!=-1) {change(id, 'text status_invalid');}//alert('4: Invalid E-mail ID');}
 else if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot) {change(id, 'text status_invalid');}//alert('5: Invalid E-mail ID');}
 else if (str.indexOf(dot,(lat+2))==-1) {change(id, 'text status_invalid');}//alert('6: Invalid E-mail ID');}
 else if (str.indexOf(' ')!=-1) {change(id, 'text status_invalid');}//alert('7: Invalid E-mail ID');}
 else {change(id, 'text status_valid');}
}
 
 
 
// Check entire form's set of classes
function check_form(form_id)
{
var split_1 = document.getElementById('username').className.split(' ');
var split_2 = document.getElementById('password').className.split(' ');
var split_3 = document.getElementById('passwordconfirm').className.split(' ');
var split_4 = document.getElementById('email').className.split(' ');
var split_5 = document.getElementById('emailconfirm').className.split(' ');
 
// status_valid
if (split_1[1] == 'status_valid' && split_2[1] == 'status_valid' && split_3[1] == 'status_valid' && split_4[1] == 'status_valid' && split_5[1] == 'status_valid')
{document.getElementById(form_id).submit();}
else {{alert('invalid');}}
}
 
 
// Confirm Password
function check_email_confirm()
{
 var email1 = document.getElementById('email').value;
 var email2 = document.getElementById('emailconfirm').value;
 if (email1 == email2)
 {
  change('email', 'text status_valid');
  change('emailconfirm', 'text status_valid');
 }
 else
 {
 change('email', 'text status_invalid');
 change('emailconfirm', 'text status_invalid');
 }
}
 
// Confirm Password
function check_password()
{
 var pass1 = document.getElementById('password').value;
 var pass2 = document.getElementById('passwordconfirm').value;
 if (pass1 != pass2)
 {
 {change('password', 'text status_invalid'); change('passwordconfirm', 'text status_invalid');}
 }
 else if (pass1.length < 6)
 {
 {change('password', 'text status_invalid'); change('passwordconfirm', 'text status_invalid');}
 }
 else
 {
  change('password', 'text status_valid');
  change('passwordconfirm', 'text status_valid');
 }
}
 
// Check first password Length
function check_password_length()
{
 if (document.getElementById('password').value.length < 6) {change('password', 'text status_invalid'); document.getElementById('password').focus();}
 else {change('password', 'text status_valid');}
}
 
 
function warning_check(form_id) {if (document.getElementById('warning1') || document.getElementById('warning2')) {var answer = confirm('WARNING!\n\nIf you continue you may lose existing data in the tables listed on this page!\n\nPress \'Ok\' to continue, all existing data in the tables will be lost.\n\nPress \'Cancel\' if you want the chance to manually verify the data in the tables first.'); if (answer) {document.getElementById(form_id).submit();}} else {document.getElementById(form_id).submit();}}
//]]>
</script>
</head>
 
<body>
 
<h1>Installation</h1>
<div id="body">
 
<?php
if (!isset($_GET['step']))
{
?>
 
<form action="install.php?step=1" method="post">
<fieldset>
<legend>Introduction</legend>
 <p>The is the installer will assist you in minimizing the need to attend the installation of the script.
 &#160; When you are finished filling out any required data on any given step simply press the continue button.</p>
</fieldset>
<fieldset>
<legend>Site Address</legend>
 <p>The site address is the location of your main live website.
 &#160; You can use localhost for now if you don't have one.
 &#160; You can also add more sites later once you've completed the installation.</p>
 
<label for="site">Site Address</label><input class="text" id="site" name="site" type="text" value="<?php echo 'http://'.$_SERVER['HTTP_HOST'].'/';?>" />
<input class="button" type="submit" value="Continue to Step 1" />
</fieldset>
</form>
 
<?php
}
else if ($_GET['step'] == '1')
{
?>
 
<form action="install.php?step=2" method="post">
<fieldset>
<legend>Step 1 - Site Address</legend>
 <p>Your website's address will be remembered during the installation process and used for the default profile.</p>
<?php if (isset($_GET['error'])) {echo "\n".' <p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p>'."\n";}?>
</fieldset>
 
<fieldset>
<legend>Step 2 - MySQL Connection</legend>
 <p>The second step is to connect to your server's MySQL server.
 &#160; To do that you'll need to enter in the following information.</p>
 
<label for="mysql_host">Host</label><input class="text" id="mysql_host" name="mysql_host" type="text" value="" />
<label for="mysql_user">User</label><input class="text" id="mysql_user" name="mysql_user" type="text" value="" />
<label for="mysql_pass">Pass</label><input class="text" id="mysql_pass" name="mysql_pass" type="password" value="" />
<input class="button" type="submit" value="Continue to Step 2" />
</fieldset>
</form>
 
 
<?php
}
else if ($_GET['step'] == '2')
{
?>
 
<form action="install.php?step=3" method="post" id="form_2">
<fieldset>
<legend>Step 1 - Connect to MySQL</legend>
<p>You successfully connected to your server's database!</p>
</fieldset>
 
<fieldset>
<legend>Step 2 - Create Tables</legend>
<?php
$database_user = mysql_real_escape_string($_POST['mysql_user']);
 
$sql1 = "SELECT TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'public_accounts' AND TABLE_SCHEMA = '$database_user'";
$result = mysql_query($sql1);
if ($result)
{
 $row = mysql_fetch_assoc($result);
 $numRows = $row['TABLE_ROWS'];
 if ($row)
 {
  if ($numRows > 0) {echo '<p><b class="bad" id="warning1">WARNING!</b> There are <b>'.$numRows.'</b> row(s) of data in the table <em>public_accounts</em>!'."\n".' &#160; If you continue to step 3 <em>the data will be lost</em>!</p>';}
  else if ($numRows == 0) {echo '<p>The table <em>public_accounts</em> exists however it contains no data.</p>';}
 }
 else
 {
  echo '<p>The table <em>public_accounts</em> does not yet exist in database.</p>';
 }
}
 
 
$sql2 = "SELECT TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'admin_global' AND TABLE_SCHEMA = '$database_user'";
$result = mysql_query($sql2);
if ($result)
{
 $row = mysql_fetch_assoc($result);
 $numRows = $row['TABLE_ROWS'];
 if ($row)
 {
  if ($numRows > 0) {echo '<p><b class="bad" id="warning2">WARNING!</b> There are <b>'.$numRows.'</b> row(s) of data in the table <em>admin_global</em>!</p>';}
  else if ($numRows == 0) {echo '<p>The table <em>admin_global</em> exists however it contains no data.</p>';}
 }
 else
 {
  echo '<p>The table <em>admin_global</em> does not yet exist in database.</p>';
 }
}
?>
 <p>The installer will next create the tables needed in the database.
 &#160; Unrelated tables in the database will <em>not</em> be affected.</p>
<?php
if (isset($_GET['error'])) {echo "\n".'<p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p>'."\n";}
?>
<input onclick="warning_check('form_2')" type="button" value="Continue to Step 3" />
</fieldset>
</form>
 
<?php
}
else if ($_GET['step'] == '3')
{
?>
<form action="install.php?step=4" method="post" id="form_3">
<fieldset>
<legend>Step 2 - Create Tables</legend>
 <p>The tables have been successfully created!</p>
</fieldset>
 
<fieldset>
<legend>Step 3 - Administrator Account</legend>
 <p>Time to create the admin account...
 &#160; </p>
<?php if (isset($_GET['error'])) {echo "\n".' <p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p><p>'.$_SESSION['mysql_user'].' == session user</p>'."\n";}?>
 
<input name="formis" type="hidden" value="registration_start" />
<label for="username">User Name</label><input class="text required" id="username" name="username" onblur="check_admin();" type="text" value="" />
<br />
<label for="password">Password</label><input class="text required" id="password" name="password" onblur="check_password_length();" type="password" value="" />
<br />
<label for="passwordconfirm">Confirm Password</label><input class="text required" id="passwordconfirm" name="passwordconfirm" onblur="check_password();" type="password" value="" />
<br />
<label for="email">Email</label><input class="text required" id="email" name="email" onblur="check_email('email');" type="text" value="" />
<br />
<label for="emailconfirm">Confirm Email</label><input class="text required" id="emailconfirm" name="emailconfirm" onblur="check_email('emailconfirm');" type="text" value="" />
<br />
<input class="button" onclick="check_form('form_3');" type="button" value="Continue to Step 4" />
</fieldset>
</form>
 
<?php
}
else if ($_GET['step'] == '4')
{
?>
<form action="install.php?step=5" method="post">
<fieldset>
<legend>Step 3 - Administrator Account</legend>
 <p>The administrator account has been successfully created!</p>
</fieldset>
 
<fieldset>
<legend>Step 4 - Host Directories</legend>
 <p>Setting your host directories will synchronize them to run interchangeably both locally and live <em>and</em> naturally allows the ability to use custom paths should you require support for versioning. 
 &#160; The live paths are used by the public version of the site while the local paths are used by you to test the exact same code <em>before</em> you upload them to your live site.</p>
 
 <p>The private paths are used by PHP in regards to the local or live server's file system.
 &#160; The public paths are utilized by (X)HTML src values in conjunction with the base element.</p>
<?php if (isset($_GET['error'])) {echo "\n".' <p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p>'."\n";}?>
<label for="live_private">Live Private Path</label><input class="text required" id="live_private" name="live_private" type="text" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {$path = explode($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_FILENAME']); echo $path[0].'/';}?>" />
<br />
<label for="live_public">Live Public Path</label><input class="text required" id="live_public" name="live_public" type="text" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo 'http://'.$_SERVER['HTTP_HOST'].'/';}?>" />
<br />
<label for="local_private">Local Private Path</label><input class="text required" id="local_private" name="local_private" type="text" value="<?php if ($_SERVER['HTTP_HOST'] == "localhost") {$path = explode($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_FILENAME']); echo $path[0].'/';}?>" />
<br />
<label for="local_public">Local Public Path</label><input class="text required" id="local_public" name="local_public" type="text" value="<?php if ($_SERVER['HTTP_HOST'] == "localhost") {echo 'http://'.$_SERVER['HTTP_HOST'].'/';}?>" />
<br />
<input class="button" type="submit" value="Continue to Step 5" />
</fieldset>
</form>
 
<?php
}
else if ($_GET['step'] == '5')
{
?>
<form action="install.php?step=6" method="post">
<fieldset>
<legend>Step 4 - Host Directories</legend>
 <p>The host directories have been successfully set!</p>
</fieldset>
 
<fieldset>
<legend>Step 5 - Database Synchronization</legend>
 <p>Synchronizing your databases will allow you to develop and test locally with your local copy of your site.
 &#160; <em>However</em> it is up to you to manually synchronize file uploads.</p>
 
 <p>The connection information for your live host is for the public version of your site.
 &#160; The connection information for your local host is for the test version of your site.</p>
<?php if (isset($_GET['error'])) {echo "\n".' <p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p>'."\n";}?>
 
<label for="live_host">Live Host</label><input class="text required" id="live_host" name="live_host" type="text" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo $_SESSION['mysql_host'];}?>" />
<br />
<label for="live_user">Live User</label><input class="text required" id="live_user" name="live_user" type="text" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo $_SESSION['mysql_user'];}?>" />
<br />
<label for="live_pass">Live Pass</label><input class="text required" id="live_pass" name="live_pass" type="password" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo $_SESSION['mysql_pass'];}?>" />
<br />
<label for="local_host">Local Host</label><input class="text required" id="local_host" name="local_host" type="text" value="<?php if ($_SERVER['HTTP_HOST'] == "localhost") {echo $_SESSION['mysql_host'];}?>" />
<br />
<label for="local_user">Local User</label><input class="text required" id="local_user" name="local_user" type="text" value="<?php if ($_SERVER['HTTP_HOST'] == "localhost") {echo $_SESSION['mysql_user'];}?>" />
<br />
<label for="local_pass">Local Pass</label><input class="text required" id="local_pass" name="local_pass" type="password" value="<?php if ($_SERVER['HTTP_HOST'] == "localhost") {echo $_SESSION['mysql_pass'];}?>" />
<br />
<input class="button" type="submit" value="Continue to Step 6" />
</fieldset>
</form>
<?php
}
else if ($_GET['step'] == '6')
{
?>
<form action="install.php?step=7" method="post">
<fieldset>
<legend>Step 6 - Host Directories</legend>
 <p>The databases can now be synchronized together should you choose to do so in the control panel.</p>
</fieldset>
 
<fieldset>
<legend>Step 7 - FTP Connection</legend>
 <p>FTP connection information will allow the control panel to assist you with file permissions.</p>
<?php if (isset($_GET['error'])) {echo "\n".' <p><b class="bad">Warning!</b> The following error occured: <em>'.$_SESSION['error'].'</em>.</p>'."\n";}?>
 
<label for="ftp_host">FTP Host</label><input class="text required" id="ftp_host" name="ftp_host" type="text" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo $_SERVER['HTTP_HOST'];}?>" />
<br />
<label for="ftp_user">FTP User</label><input class="text required" id="ftp_user" name="ftp_user" type="text" value="<?php $doc_root = explode("/", $_SERVER['DOCUMENT_ROOT']); if ($doc_root[0][1] != ':' && $doc_root[1] == 'home') {echo $doc_root[2];}?>" />
<br />
<label for="ftp_pass">FTP Pass</label><input class="text required" id="ftp_pass" name="ftp_pass" type="password" value="<?php if ($_SERVER['HTTP_HOST'] != "localhost") {echo $_SESSION['mysql_pass'];}?>" />
<br />
<input class="button" type="submit" value="Continue to Step 7" /> 
</fieldset> 
</form>
<?php
}
else if ($_GET['step'] == '7')
{
?>
<form action="admin_tasks.php" method="post">
<fieldset>
<legend>Step 7 - FTP Connection</legend>
 <p>The installer was able to successfully connect to the FTP.</p>
</fieldset>
 
<fieldset>
<legend>Finished</legend>
 <p>The installation has finished, click continue to proceed to the control panel.
 &#160; The installation file will remove itself.</p>
 
<input class="button" type="submit" value="Continue to Control Panel" /> 
</fieldset> 
</form>
<?
} //end step
?>
</div><!-- /#body -->
 
</body>
</html>

themes/header-00.php

Code: Select all

<?php
session_name("member");
session_start();
     if ($_POST['formis'] == 'registration_start') {include("registration-01-start.php");}
else if ($_POST['formis'] == 'registration_activation' || $_GET['activate'] != '') {include("registration-02-activation.php");}
 
header("Content-type: application/xhtml+xml");
echo'<?xml version="1.0" encoding="UTF-8"?>'."\n";
?>

themes/style.css

Code: Select all

#body {background-color: #09c; margin: 0px auto 0px auto; overflow: auto; padding: 8px 0px 8px 0px; width: 80%;}
#content {background-color: #eee; float: right; margin: 2%; padding: 1%; width: 74%;}
#menu {float: left; margin: 2% 2% 0px 2%; width: 16%;}
#menu div a {background-color: #c60; border: #633 solid 4px; color: #fff; display: block; margin: 0px 0px 4px 0px; padding: 2px; text-decoration: none;}
#menu div a:hover, #menu div a:focus {background-color: #004; border: #9cac53 solid 4px; color: #eee; display: block;}
body, html {background-color: #036; color: #000;}
b.bad {color: #f00;}
b.good {color: #0f0;}
div.center {margin: 0px auto 0px auto; text-align: center;}
form fieldset {background-color: #eee; border: #ddd solid 1px; margin: 4px 16px 4px 16px;}
form input {background-color: #a7a68f; color: #000; border: #ebef92 solid 1px;}
form input:hover, form input:focus {background-color: #000; color: #a7a68f;}
form input.button {clear: left; display: block; float: left; margin: 4px;}
form input.button:hover, form input.button:focus {color: #0f0; outline: #9cf dotted 6px;}
form input.status_invalid {background-image: url(images/interface-icon-warning.gif); background-position: 204px 2px; background-repeat: no-repeat; border: #f00 solid 2px;}
form input.status_valid {background-image: url(images/interface-icon-valid.gif); background-position: 202px 2px; background-repeat: no-repeat; border: #0f0 solid 2px;}
form input.required {background-image: url(images/interface-icon-required.gif); background-position: 205px 1px; background-repeat: no-repeat;}
form input.required:hover, form input.required:focus {background-image: url(images/interface-icon-required-h.gif);}
form input.text {display: block; float: left; margin: 4px; width: 220px;}
form input.text:hover, form input.text:focus {outline: #9cf dotted 6px;}
form label {border: #ebef92 dotted 1px; clear: left; display: block; float: left; margin: 4px; padding: 0px 4px 0px 4px; width: 120px;}
form label:hover {border: #ebef92 solid 1px;}
form legend {background-color: #ddd; border: #ddd solid 1px; color: #000; padding: 0px 2px 0px 2px;}
form textarea {border: #a7a68f solid 1px; clear: right; display: block; float: left; margin: 4px; width: 400px;}
form textarea:hover, form textarea:focus {border: #00f solid 2px; clear: right; display: block; float: left; margin: 3px;}
h1 {background-color: #004; color: #9cac53; margin: 16px 10% 16px 10%; padding-left: 4px;}
h2 {color: #ebef92; width: 80%;}
Save this file as themes/images/interface-icon-required.gif...
http://img379.imageshack.us/img379/9553 ... redfc5.gif

Save this file as themes/images/interface-icon-required-h.gif...
http://img229.imageshack.us/img229/4313 ... edhba8.gif

Save this file as themes/images/interface-icon-valid.gif...
http://img134.imageshack.us/img134/2392 ... lidyr6.gif

Save this file as themes/images/interface-icon-warning.gif...
http://img361.imageshack.us/img361/9312 ... ingeo8.gif

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Mon Jul 21, 2008 2:04 pm
by Mordred
1. Why do you have security concerns for an installation procedure? Especially after you did the right thing and refuse to run the software with it still on the server.
2. You seem to correctly use mysql_real_escape_string
3. There is one instance of 'email' instead of '$email'
4. You seriously need to embrace a template solution.

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Mon Jul 21, 2008 2:33 pm
by JAB Creations
Whoa...I did good if you only had four lines to point out! :mrgreen:

I added mysql_real_escape_string today after rereading an earlier thread in the security forums that I originally posted in. I had a little difficulty getting it to work towards the top (trying to save a $_POST to a $_SESSION variable).

What line is the email without the $ present?

I do templating a lot however I coded it this way mainly to reduce the need to post tons of files. Besides this is mostly practice for me.

I am concerned about security in regards to if this were say more along the lines of a registration file. However doing registration didn't include doing what I knew I'd get in to with an installer.

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 3:07 am
by Mordred

Code: Select all

$mail = mysql_real_escape_string($_POST['email']);
 $result5 = mysql_query("INSERT INTO public_accounts (username, password, email, date_0) VALUES ('$user', '$pass', 'email', NOW())");
Actually there are a few minor issues, like not checking if $_POST['something'] exists before hitting it, or the hp8 charset, or the funky $_SERVER['REQUEST_METHOD'] == 'POST', which should make header("location:install.php?step=5&error"); not actually work. Note that I have only diagonally scanned the first half of the script (up to where the html stars), and got seriously bored afterwards, so there might be caveats below :) Readability is important :)

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 4:36 am
by JAB Creations
The only problem I've really encountered that I haven't been able to figure out is that when connecting to MySQL if I apply mysql_real_escape_string to the $_POST data the installer returns the error that I'm connecting as nobody'@'localhost (when I'm obviously providing the correct credentials).

Code: Select all

$_SESSION['mysql_host'] = mysql_real_escape_string($_POST['mysql_host']);
$_SESSION['mysql_user'] = mysql_real_escape_string($_POST['mysql_user']);
$_SESSION['mysql_pass'] = mysql_real_escape_string($_POST['mysql_pass']);
I attempted to get around it by doing this...

Code: Select all

$mysql_host = mysql_real_escape_string($_POST['mysql_host']);
 $mysql_user = mysql_real_escape_string($_POST['mysql_user']);
 $mysql_pass = mysql_real_escape_string($_POST['mysql_pass']);
 $_SESSION['mysql_host'] = $mysql_host;
 $_SESSION['mysql_user'] = $mysql_user;
 $_SESSION['mysql_pass'] = $mysql_pass;
I fixed the mail bug, thanks for spotting that.

The hp8 charset is English, I couldn't seem to get UTF8 to work for some reason.

I'm not sure why location:install.php?step=5&error would fail in conjunction with the post method?

So the initial $_POST that I can't seem to successfully apply mysql_real_escape_string and the inability to use the UTF8 charset are the only two issues I can't seem to get around.

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 5:17 am
by Mordred
Nonono.
Data in the session doesn't need to be escaped for mysql, it's a session, not a mysql database! mysql_real_escape_string() only things that go in mysql_query().
mysql_real_escape_string() works only with a valid mysql connection, that's why it gives you an error.

Your pages use utf-8, so the data that comes in GPC is utf-8. Depending on the mysql connection settings it will reach the database as something (utf8? hp8? something else?), and be stored as hp8. To avoid any possible mess, it's best if all instances just use utf-8.

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 5:33 am
by JAB Creations
I get the same result with this...

Code: Select all

$db = mysql_connect(mysql_real_escape_string($_POST['mysql_host']), mysql_real_escape_string($_POST['mysql_user']), mysql_real_escape_string($_POST['mysql_pass']));
...though I find it odd that we only check it before adding it to a database but not for PHP itself?

I changed the charset to "utf8" though at the bottom of the table list in PhpMyAdmin it says the Collation for all three tables *total/at the bottom* is latin1_swedish_ci while individually each table is set to utf8_general_ci?

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 6:37 am
by Mordred
"mysql_connect" != "mysql_query"
Do stop and read what I have already written, please. Don't use mres() here, as not only it's incorrect, but it can't possibly work (it needs a working connection to)

Re: Security Review - PHP/MySQL Control Panel Installer

Posted: Tue Jul 22, 2008 6:46 am
by JAB Creations
Oh ok! Heh I didn't make the connection between query and connection. Congrats on 1K posts btw.

I'm going to add a few things that shouldn't take me too long today and maybe get this over to the critique forum. I really do appreciate your help! Thanks!