Secure a Flat File Using a .php Extension
php security web developmentHere’s the deal: I need to store some sensitive data (user names and passwords) in a flat file. I don’t want to make any use of databases because this would defeat the whole purpose of the project. Of course, the passwords will be md5 encrypted in the file, but this wouldn’t be enough.
This neat little login system, Micro Login System, seems to have the basic stuff for me to start with but, as said it stores the user info in a text file.
The contents of userpwd.txt would have been:
admin:3089af3a625carf15ed2a1a93684413ffa user1:75580656a394292460ebb4b036ebeaf1 user2:c67ac4665947cd23ff7d1d180b8e41d5
That’s user : md5( password ).
I was concerned about this because anyone who knew about the system could have entered address/userpwd.txt in the address box and gotten that info.
My solution
Php files are pretty secure right?…
scroll down to the conclusion to skip the whole story
They’re processed on the server before the client gets the output. How about giving the file a php extension instead of txt?
Of course this wouldn’t be enough, because the output would be exactly the same as the file’s contents. But now that it’s a php, we can write php code in it. What if the userpwd.php looked like this:
<?php header("HTTP/1.0 404 Not Found"); die(); ?> admin:3089af3a625carf15ed2a1a93684413f user1:75580656a394292460ebb4b036ebeaf1 user2:c67ac4665947cd23ff7d1d180b8e41d5
The login system can be made to ignore the first line when doing its thing, because it runs server side and can read the contents of userpwd.php as it is on the server (like it was reading the txt version of the file), so there’s no problem here.
But if a client tries to open userpwd.php in his browser, the die(); function will be executed when the server processes the php code in the file and the script is terminated, thus outputing a blank page.
Optional stuff
The header(”HTTP/1.0 404 Not Found”), is an attempt to mislead anyone trying to type in the file name by sending the browser a 404 Page Not Found status. I even went as far as adding an error message as a parameter for the die function that looks like the default html for a 404 error in most browsers:
die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"> <html><head> \n<title>404 Not Found</title> \n</head><body> \n<h1>Not Found</h1> \n<p>The requested URL was not found on this server.</p> \n</body></html>");
So our userpwd.php would look like this:
<?php header("HTTP/1.0 404 Not Found"); die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"> <html><head> \n<title>404 Not Found</title> \n</head><body> \n<h1>Not Found</h1> \n<p>The requested URL was not found on this server.</p> \n</body></html>"); ?> admin:3089af3a625carf15ed2a1a93684413f user1:75580656a394292460ebb4b036ebeaf1 user2:c67ac4665947cd23ff7d1d180b8e41d5
And now, if anyone ware to open the file in their browser, they’ll get a page with this source code:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html> <head> <title>404 Not Found</title> </head> <body> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> </body> </html>
Background story
I’m gonna start working on a simple CMS which I’ll be releasing open source. Now this should be really simple as in:
- user already has his/her own site (probably a static html site)
- user uploads a folder to his/her root dir via ftp—and that’s all, without having any database involved
- pages are editable in certain ways by a script in that folder
And that about covers it (until further development). But before I actually start putting things together I was exploring possibilities and ran into this.
Conclusions
The most secure txt file is a php file
So let’s take a look at it again…
If you don’t need/don’t want to use mySQL or any other database but have some sensitive data to store in a flat file:
- give it a .php extension
- it should have this text on the first line: <?php die(); ?>
Optional: Or to fake it into looking like a 404 Not Found page, it should have this first line (instead of the above):
<?php header("HTTP/1.0 404 Not Found"); die("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"> <html><head> \n<title>404 Not Found</title> \n</head><body> \n<h1>Not Found</h1> \n<p>The requested URL was not found on this server.</p> \n</body></html>"); ?>
If you’re interested in the login system I’ve been talking about, you can download it and read a tutorial explaining how it works here: Micro Login System.
Think different?
Can you think of any reason for this not be secure? Do you think I’m reinventing the wheel here?
Mention it in a comment here, or leave me a private note via my contact form if you think I’m missing anything.
1 week ago #
Hey, im not sure if I have mis-understood your problem but if you want to store data purely for use within a PHP script for user validation why not just store all of the information in a associative array in a separate PHP file? i.e.
$users = array(
‘admin’ => ‘c080af3a615carf15ed2a1a91684413g’,
‘user1′ => ‘75580656a394292460ebb4b036ebeaf1′
);
As those variables are now stored within the PHP file to access them its as simple as including the user file within your main PHP file to access the information. e.g.
include(’userinfo.php’);
if ($users[$_POST['username']] == md5($_POST['password'])){
//user and password ok
}else{
//user doesnt exist or password is wrong
}
This also means there is no way to access this information except for altering the file, however if anyone tries to browse to it, nothing will be revealed. Sorry for the long post, hope that helps and I haven’t completely misread the situation!
1 week ago #
Interesting idea. Another thought is to store the data file, text or php of the web root so it is not accessible from the browser at all. The scripts would still be able to include it and process it. If you have to store it in the web accessible folders, you could probably place it in some obscure folder name and use htaccess to prevent any direct access to it. Just some thoughts.
1 week ago #
Just placing the file outside of your web root folder will secure it plenty. No need for all the extra stuff!
1 week ago #
@Jez: The problem is that these information should have to be stored in such a way that would make them easily comprehensible (readable, deletable, updatable) by other scripts. Like a CSV (comma separated values) or in this case, colon separated values.
It should allow to easily simulate the main operations you could do on the data in a database for example… at a very simplified level, of course.
This is because someone should be able to manage the users, users should be able to manage their own accounts and so on.
1 week ago #
@dean: I thought about that too. But it would complicate things a little for the general public. Nonetheless, I agree, it’s a safe classic method.
@LGR: Same thing, about the root folder.
And as for the obscure folder… I’m planning to release the final product open source. So anyone who would know that a site uses this could study the scripts and file structure and exploit it.
And speaking of which, one more step regarding security, is to encourage users to change the name of their data file.
1 week ago #
You could just use htaccess to block access the file in question. The general public would not have to deal with the technical issues as you could ship the product with the htacess file in place already (have the flatfile inside a seperate folder to avoid conflicts with already existing htaccess files (read: so you dont overwrite them).
1 week ago #
Another point. If, for some reason the server is not configured correctly to process php files server side then it is entirely possible that the raw php source file could be sent to the user (this happened to facebook a while back)