Secure password list in PHP - php

I'm thinking about storing list of passwords for users (eventually more info about them) of small-scale (max. 20 users) app in PHP file in directory like public_html_root/system/config/
<?php if($calledByApp !== true) die();
$pwds['username1'] = 'hispassword';
$pwds['username2'] = 'herpassword';
$pwds['username3'] = 'anotheroned';
?>
Now. hispassword is actually hashed version
$hashedpasword = sha1($password.sha1($salt));
This way, if file is included, it checks for $calledByApp, which is set upon starting from entry point - i.e. index.php in root, so we could say it's safe this way. If it's called directly from browser - it won't get served as text file, but rather as PHP file - and it will die also, since $calledByApp will return null or false.
Also, if another user is stored/deleted, the file gets rebuilt, so it reflects all users. And after including this file, we have all users in pretty array, so if we call
if (is_string($pwds[$sanitized_username])
&& ($pwds[$sanitized_username] === $sanitized_sha1_userpassword))
we'll do login.
My question is: Is this safe enough?
Clarification: DB for users seems to be a bit overkill - another table for max 20 users. Also, while this doesn't check if user is real, it won't do anything with DB - looks like added security too.

If for some reason mod_php has a hiccup it could result in httpd showing the uninterpreted file; store the script outside of the document root in order to fix this.

I would rather place that file outside of document root instead of relying on the PHP interpreter not failing for any reason.

No - this is a really bad idea.
By making your souce code files writeable you open a whole avenue for attacking your system.
Embedding data into source code is a messy practice - not least because it will not scale.
What happens if the file is locked for an update when a script tries to include it?
What happens when the connection to the browser is lost part way through writing the file?
If you're quite sure that you'll only ever have a very small number of users and a low level of concurrency then abetter solution by far would be to have a seperate directory, with all http access denied, containing one file per user, named with the username (or a hash of it if you prefer) containing the hashed password.
C.

It's always safer to store the encrypted passwords in a database.
If you are using a database then I would store user data in there. If not then I would look to start using one.

Related

Set up PDO connection without password

I'm trying to connect to my database, but I changed my database's root password in the interest of security. However, in order to connect to the database and use PDO, I apparently have to pass my password in the php, which obviously is not good for security:
$hsdbc = new PDO('mysql:dbname=hs database;host=127.0.0.1;charset=utf8', 'root','passwordgoeshere');
$hsdbc->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$hsdbc->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Am I being stupid and that because it's PHP no-one but the person who views the actual file will be able to see the password, or is there some way to do it without passing the password in the file.
Generally speaking it's not bad practice to have connection strings in files that are not user facing. If you don't want to have your personal password in the php file, then you can create a new mysql user for php.
You can also restrict the user's IP address in MySQL to the server hosting your php scripts. This way if a nefarious person browsing the web somehow was able to see the database password, they would have more difficulty accessing it.
People are not able to just go and read into your files. They should be safe on the place where you host it. They are only able to get into to files if they are able to get into the place when you host your stuff. Which should not be possible if they don't have the info to get there.(which should only be known to you).
This is not just for PDO. but also my mysql and mysqli to do it like this
Going to extend SupSon (SC2 Select fan?)'s answer:
PHP itself is server coded language.
There are only 3 ways (maybe more if someone want to add to it) that code can be shown to an outside user:
By having an unsecure .htaccess file that shows php file as text
file (then you should move servers at that point because normally
this doesn't happen)
Somehow your operating on debug mode and something in your page
triggers this mode and you get a whole bunch of PHP code gets shown
FTP/SSH access to your .php file (then you have more than a PDO
problem in your hands)
So if one of these cases is happening, coding into a .php file your username/password won't be a breach in security.
I have seen websites that expose PHP code, when the Apache type handler for PHP becomes unconfigured by accident. Then the code in .php files is displayed instead of executed. There's also an Apache type handler to display PHP source deliberately, though this is not usually configured.
To avoid this vulnerability, it's a good practice to put your sensitive PHP code outside your htdocs directory. Instead, put in your htdocs directory a minimal PHP script that loads the rest of the code using include() or require().
An alternative is to put your MySQL credentials in a config file instead of PHP code at all. For example, the file format used by /etc/my.cnf and $HOME/.my.cnf is readable by the PHP function parse_ini_file(). It's easy to store your MySQL password outside of your code this way.
For example, read user and password from the [mysql] or [client] sections of /etc/my.cnf:
$ini = parse_ini_file("/etc/my.cnf", true);
if (array_key_exists("mysql", $ini)) {
$connect_opts = array_merge($connect_opts, $ini["mysql"]);
} else if (array_key_exists("client", $ini)) {
$connect_opts = array_merge($connect_opts, $ini["client"]);
}
$pdo = new PDO($dsn, $connect_opts["user"], $connect_opts["password"]);
Yes it seems insecure at first, but once you get the hang of it and know how to manage your files to minimize potential security breaches, you can minimize the risks associated with having passwords stored in plain text in potentially publicly exposed spaces. Yet AFAIK PDO doesn't even let you form a connection without supplying a password. The solutions are a combination of what everyone has said and then some. Here's my quick guide for what I do.
Separate SQL users for separate purposes (minimizes damage from SQL injection or hacked accounts):
There should be a PHP-specific user for each table you need to access. That user will be granted only enough rights to handle as much of that table that he needs to, if it doesn't need to delete then don't grant it delete. If it doesn't need to select then don't grant it select. It seems fussy but very quickly you'll have a copy-paste template to make the users, give them the right(s) they need, and document it. If there's a joined table, you'll want to also grant the user access to that table also, naturally.
-- a single user account for a specific purpose:
CREATE USER 'usermanager'#'localhost' IDENTIFIED BY '5765FDJk545j4kl3';
-- You might not want to give access to all three here:
GRANT SELECT, UPDATE, INSERT ON db.users to 'usermanager'#'localhost';
The purpose of this is so that if you have a bug in your code that lets people SQL inject, they won't be able to cause any harm beyond the scope of what that role can do.
Stupid mistake can reveal PHP code and files if left in-directory, move them out:
Never mind revealing the source code, even just trying to access php files "out of order" can be destructive.
Move as many files to an out-of-scope directory as possible. Then call them like so:
require_once('../lib/sql_connectors.php');
This should escape your html / webdir and you should hopefully be able to store all sorts of fun stuff outside the scope of what a stupid admin mistake could reveal.
You can even have a php file that gets pictures and videos from outside your webdir, that's how streaming sites protect their resources and also conduct php-based authentication to file access. To learn how to do that you'll want to look up assigning your own etag headers to make sure browsers cache your php-retrieved files otherwise you'll have a very busy server, here's a short introduction.
Block wrongful access to PHP that are left in-directory:
All of your in-directory PHP files can be protected by checking that the $_SERVER['REQUEST_URI'] isn't itself. If it is, you can have a function called show404() that loads the 404.php page and dies there or just directly call your 404.php with an include. That way, even if you have hackers trying to brute force your php files they'll never see them because they'll get 404 errors (fools the bots) and they'll see the 404 page (fools the humans).
I avoid using .php in any publicly visible paths, to do that, I make rewrite rules in my .htaccess files that look like this:
RewriteEngine On
RewriteRule ^login$ login.php [L,QSA]
The L makes it stop running other rules.
The QSA preserves the $_GET tags.
The first lines of code for every file (consider prepending) could be:
// they should be connecting via a redirect, not directly:
$fileName = basename(__FILE__);
if ($_SERVER['REQUEST_URI'] === '/' . $fileName) {
error_log('Security Warning: [' . $_SERVER['REMOTE_ADDR'] . '] might be trying to scrape for PHP code. URI: [' . $_SERVER['REQUEST_URI'] . ']');
include('404.php'); // should point to your 404 ErrorDocument
exit();
}
// redirect to actual file
include('../hidden/php/' . $fileName);
In this example, assuming you have the redirect in your .htaccess, a login.php with the code above, and a login.php in your hidden directory, the user would experience the following two scenarios: attempt to connect to '/login' and see the hidden '/login.php' page; attempt to connect to the visible '/login.php' directly and get a 404 error.
Those are the 3 big things, lots of small limited accounts to minimize damage in case of security failure, keep all possible files outside the web directory, and make all in-directory php files produce an error letting only non-php links access them.

PHP variable authentication

Is it a bad idea to write a file with php for authentication?
An example:
A user submits a login form. If the credentials are invalid, the PHP writes a new file with the filename as the attempted username, and the contents would have a variable containing the number of attempts. Then that file would be included for the next login attempt, and if login attempts= 2 or whatever, display a reCaptcha.
Are there any obvious flaws with such a technique? I see most suggest using a database to store the login attempts and such, and I have no problem with doing it that way, but I was just curious.
A file is just another form of a database. If you implement this solution carefully, there is no real difference between implementing this via a database or via files.
The problem is the extra overhead of managing the sessions via files and writing all the code to do this properly.
In the end a database operates on files as well except for databases in memory.
Handling files yourself is not very efficient. Databases solve some complicated problems that you will face when writing/reading to files yourself like mentioned here database vs. flat files

PHP Do something when session gets expired

So let's say user did something on my website, for example uploaded some images or whatever, and he left without logging out and never came back or let's say he did come back after few months.
So my question would be, is there some kind of way for example to delete his uploaded files after session have expired, let's say after 30 mins (keep in mind that user never reloaded page), so that would need to run entirely on server side without user interfering at all.
EDIT Thank you all for your wonderful answers, it gave me quite a few great ideas, i wish i could accept all of your answers :)
Good question! My first idea was to use a database based solution. If you don't already, you'd keep track of all active sessions in a table sessions which contains, among other things you may need, the session_id and the last_visited_time. This entry would be updated every time a user visits your site:
UPDATE sessions WHERE session_id = "<current session id>" SET last_visited_time = NOW()
The second part of the mechanism would be a cronjob that scans the the sessions table for sessions whose last_visisted_time hasn't been updated lately (in whatever time interval you'd like) and deletes the files for that session.
One way would be to call
$thePath = session_save_path();
and iterate over all saved session file, unserialze each and check them for the specified timeout property.
Unfortunately, you need to scan the whole directory to find all session files, which are older than a defined period of time. You'd use start() to figure out the age of a session file.
On a well-maintained server, each virtual host should have a separate directory for its session data. A not-so-well-maintained might store all sessions in a unified shared directory. Therefore, ensure that you don't read or delete other virtual hosts' session data.
Better Approach using a database
Therefore I propose to save session data to your application's backend database. Using SQL, it would be trivial to find all outdated session files.
The documentation for session_set_save_handler() provides a sample, which explains this whole process quite nicely based on objects.
I like all the answers above, but a different solution would be to name the uploaded files in a way that you know they are "temporary", for example prepending their name with a timestamp. This way, a periodic process would clean any such files, unless your program decides that they should be kept after all, renaming them accordingly.

mysql php security

On my php pages, at the top i connect to the database like this
$db = mysql_connect("mysql.site.com","thedb", "pass");
mysql_select_db("dbase",$db);
Is this secure? Could someone somehow scan and view my code, therefore get access to the database?
UPDATE
Reason I ask is because a user was able to get access to my database, and im pretty sure it wasn't through sql injection.
It would be better if you move this snippet to an include file outside of your document root — this will prevent people reading it in case your webserver somehow gets misconfigured and starts serving PHP files as plain text. Although, just by itself, it is secure enough — it is unlikely that somebody will be able to misconfigure your server like this on purpose.
If someone did have access to your code, then yes, they would be able to read the password out.
There isn't a huge amount you can do about this, but ensuring that this code is a directory up from your web root would help.
(i.e. if you are serving your site from the folder /usr/htdocs/mysite, change it to /usr/htdocs/mysite/public, then put your includes in mysite rather than public.)
You should always apply multiple layers of defense:
Remove the credentials from the source code and place them outside the web server’s document root.
Restrict access to your database, possibly only via localhost or via socket.
Restrict the user’s privileges to only those necessary.
That's ok, the important thing I could say, go to your database and give to that user restricted permission, I mean only select, insert , update and delete the tables that it need.. beside that, create a file with that info and just include when you need it, that's my advice.
If someone go through your code will be able to see that info, but try to reduce always the damage impact

How to secure sensitive PHP files that process Jquery data?

On my website, I have a search.php page that makes $.get requests to pages like search_data.php and search_user_data.php etc.
The problem is all of these files are located within my public html folder.
Even though someone could browse to www.mysite.com/search_user_data.php, all of the data processed is properly escaped and handled, but on a professional level this is inadequate to even have this file within public reach.
I have tried moving the sensitive files to my web root, however since Jquery is making $.get requests and passing variables in the URL, this doesn't work.
Does anyone know any methods to firmly secure these vulnerable pages?
What you describe is normal.
You have PHP files that are reachable in your www directory so apache (or your favored webserver) can read and process them.
If you move them out you can't reach them anymore so there is no real option of that sort.
After all your PHP files for AJAX are just regular php files, likely your other project also contains php files. Right ? They are not more or less at risk than any script on your server.
Make sure you program "clean". Think about evil requests when writing your php functions, not after writing them.
As you already did: correctly quote all incoming input that might hit a database or sensitive function.
You can add security checks on your incoming values and create an automated email if you detect someone trying evil stuff. So you'll likely receive a warning in such cases.
But on the downside: You'll regularly receive warnings because some companies automatically scan websites for possible bugs. So you will receive a warning on such scans as well.
On top of writing your code as "secure" as you can, you may want to add a referer check in your code. That means your PHP file will only react if your website was given as referer when accessing it. That's enough to block 80% of the kids out there.
But on the downside: a few internet users do not send a referer at all, some proxies filter that. (I personally would ignore them, half the (www) internet breaks on them anyway)
One more layer of protection can be added by htaccess, you can do most within PHP but it might still be of interest for you: http://httpd.apache.org/docs/2.0/howto/htaccess.html
You can store a uid each time your page is loaded and store it in $_SESSION['uid']. You give this uid to javascript by doing :
var uid = <?php print $_SESSION['uid']; ?>;
Then you pass it with your get request, compare it to your $_SESSION :
if($_GET['uid'] != $_SESSION['uid']) // Stop with an error message or send a forbidden header.
If it's ok, do what you need.
It's not perfect since someone can request search.php and get the current uid, and then request the other pages, but it may be the best possible solution.

Categories