I have some down time and I am think of picking a new project for fun. I am a college student and every year we have a online pitch competition. I want to create a project for this pitch competition that is approx 9 months from now. The problem is the project requires very high security and the competition is a very competitive.
Things I need to be able to do: 1. Store HIPAA or ePHI (.pdf|.gif|.jpg|.doc) 2. Strong access control 3. Support large number of users and files (1 million +) 4. Full Audit Reports (oh ePhi you are such a pain) 5. Encryption
Proposed Solutions
0) Place the web app on a secure dedicated sever behind a firewall
1) Store files in a file say “secure_files/” and then use mod_rewrite to restrict access to this directory.
Something on the lines of:
#Removes access to the secure_files folder by users.
RewriteCond %{REQUEST_URI} ^secure_files.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
Then use a php script to open the files if the user has privileges to do so. So Could I just use:
------
-SQL
------
------
- create files table
-----
CREATE TABLE `files` (
id INT NOT NULL AUTO_INCREMENT,
file_name VARCHAR(50) NOT NULL,
PRIMARY KEY('id')
);
------
- create files table
-----
CREATE TABLE `privileges` (
uesr_id INT NOT NULL,
file_id INT NOT NULL,
);
------
- create users table
-----
CREATE TABLE `users` (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
email VARCHAR(50) NOT NULL,
password CHAR(40) NOT NULL,
PRIMARY KEY('id')
);
<?php
public function get_user_files($filename)
{
//this is set during login
$user_id = $this->session->userdata('user_id');
//check to see if the user has privileges to access the file and gets the file name
$query = $this->db->join('privileges','privileges.id = files.id')
->select('files.file_name')
->where('privileges.user_id',$user_id)
->where('files.file_name',$file_name)
->limit(1)
->get('files');
$file = $query->row()->files.file_name;
if($file)
{
//user has privileges to access the file so include it
$handle = fopen($file, "rb");
$data['file'] = fread($handle, filesize($file));
fclose($handle);
}
$this->load->view('files',$data);
}
?>
2) Use CI sessions class to add a “user” to the session.
The controller checks to see if the session is set:
<?php
public function __construct()
{
parent::__construct();
if($this->secure(array('userType' => 'user')) == FALSE)
{
$this->session->set_flashdata('flashError', 'You must be logged into a valid user account to access this section.');
$this->session->sess_destroy();
redirect('login');
}
}
function secure($options = array())
{
$userType = $this->session->userdata('userType');
if(is_array($options['userType']))
{
foreach($options['userType'] as $optionUserType)
{
if($optionUserType == $userType) return true;
}
}
else
{
if($userType == $options['userType']) return true;
}
return false;
}
?>
3) Rotate round robin between multiple web severs. I have never done this so I have no idea how to do this. I have no idea how to deal with the multiple database servers. Any ideas/suggestions?
4) Use Oracle Enterprise Standard Database Auditing. I wish I could use MySQL, but I cannot find any auditing support. I could use MySQL and use PITA. Has anyone used point-in-time architecture (PITA) with MySQL? can you share your experience?
5) So obviously I can hash the passwords with a one way salted hash. But do I need to encrypt everything? Also I don’t see how AES_ENCRYPT(str,key_str) improves secuirty at all. I guess it could prevent an admin from looking at a database? Can/should I encrypt everything in the “secure_files/” folder? Could I just use full disk encryption like BitLocker?
Basically can I achieve online bank level security with php and CI? Can you make any other suggestions besides the worthless “your an idiot go pay an expert because you know nothing” suggestions?
Thank you for taking the time to read through this.
adopted from Redux Auth
With regards to one-way hash. My mistake for saying encryption. I usually do the do something similar to:
/* * Class Auth * * */
class Auth { private $salt_length;
public function __construct()
{
$this->salt_length = '9';
}
public function hash($password = false)
{
$salt_length = $this->salt_length;
if ($password === false)
{
return false;
}
$salt = $this->salt();
$password = $salt . substr(hash('sha256',$salt . $password), 0, -$salt_length);
return $password;
}
private function salt()
{
return substr(md5(uniqid(rand(), true)), 0, $this->salt_length);
}
} ?>