I have been searching all day for a solution to this and searched here.
I have a central file for including functions for all sites on the server, this looks up to the database and if valid includes the file as a .inc as the sites could be on any server so has to process over a url. So I set up a subdomain to test this and everything works fine, however if someone where to look up the link in the site they can go direct and browse the .inc file.
I've tried looking up on here how to deny someone from browsing the file if they are viewing through the browser. This works, however if the website requesting/including the functions.inc are hosted on the same server then the requesting HTTP_HOST/REFFERER becomes the subdomain and the functions.inc file is exluded.
So far I had this:-
RewriteEngine on
RewriteCond %{SERVER_NAME} !^http://(www.)?subdomainchecker.mysite.co.uk/.*$ [NC]
RewriteRule .(inc)$ - [F]
See the subdomain acts like a service. And the reason I want to do this is that I want all the php functions in one place for everyone. that way I'm only maintaining one file. One bug fix etc.
Now I thought there has to be a way to check that there is a difference when using a subdomain.
However if there is a better way???
If this doesn't work maybe I could get htaccess to include (a virtual folder) to my subdomain folder so that I don't have to go over a url... but that wont work if the site gets hosted on another server?
Or... could I do a look up straight to the DB, as the user credentials only has SELECT privileges only. Could the DB contain all the functions and output them from a text field? Or have functions listings in a DB and retrieve the function when I do a database call?
Or... could I do a php XML request and return the php functions within an XML node?
I'd rather keep the functions and classes in a file than on a DB, but I am not sure how the best way to go about it is. All I want to do is keep my php functions in one place.
If anyone has any ideas?
Thanks
Andi
Ok So I answered my own question eventually like so.
Step 1) I password protected my .inc files using .htaccess in the directory that stores my include files on my webservice (subdomain). Protecting both .inc and .php
Options -Indexes
<FilesMatch "\.(inc|php|anyext)$">
AuthType Basic
AuthName "authenticate this puppy"
AuthUserFile /[servername]/[accountusernameOnServer]/.unseenfolder/public_html/[website_authentication_folder]/.htpasswd
Require valid-user
</FilesMatch>
This folder is now password protected by the encrypted .htpassword file outside my web root.
Step 2) Back in my now protected webserivce folder contains three files (one .php / two .inc files containing my functions and application file (session variables for the site)
authenticate_some_websitesite_against_my_own_DB.php
This contains the account verification process (lookup to a database on my own server), note the host is always Localhost and I am using PHP PDO for convenience (just in case you have a Postgre database or MSSQL etc)
application_for_site.inc
This contains/sets all the site session variables (user ID etc)
a file without a name called .anyext containing my global functions for all sites
Now here is the cool thing. THE PROCESS or how I got it to work.
I put my new website in a subfolder and include a file called authentication.php in my local folder in the site. I call this in the head of index.php in the site.
This file contains my webkey, usernames and passwords to my clients table in my DB which is used to verify in the file I call from my subdomain... authenticate_some_websitesite_against_my_own_DB.php
I put all these variables in a url variable which also include my username and password to my protected subdomain.
So now it looks something like this: Of course I set the variables above
$link = "authenticate_anewsite.php";
// Create Website check link criteria.
$link .= "?website=" . $_SERVER['HTTP_HOST'];
$link .= "&website_folder=$website_folder";
$link .= "&webkey=$webkey";
$link .= "&username=$username";
$link .= "&password=$password";
$link .= "&base_url=$base_url";
$link .= "&DBLangtype=$DBLangtype";
$link .= "&localDBtype=$localDBtype";
$link .= "&content_folder=$content_folder";
$link .= "&google_api=$google_api";
$link .= "&menu_folder=$menu_folder";
$link .= "&news_folder=$news_folder";
$link .= "&events_folder=$events_folder";
$link .= "&documents_folder=$documents_folder";
$link .= "&uploaded_images_folder=$uploaded_images_folder";
$link .= "&gallery_folder=$gallery_folder";
//// Do not delete required to access the link below
$PHP_AUTH_USER = "website_user"; /// Do NOT AMEND THIS
$PHP_AUTH_PW = "passw0rd"; /// Do NOT AMEND THIS
$path = "http://$PHP_AUTH_USER:$PHP_AUTH_PW#www.websitecheck.mydomain.com/"; /// Do NOT AMEND THIS LINK
$authCHK = $path . $link;
/// going to check that we connect
$handle = curl_init($authCHK);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
/* Get the HTML or whatever is linked in $url. */
$response = curl_exec($handle);
/* Check for 404 (file not found). */
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
/// If server can't connect
if($httpCode == 401) {
//set error handler
set_error_handler("customError", E_ALL);
/* Handle 404 here. */
trigger_error("<strong style='color:red;'>Error: SERVER - $httpCode</strong> $website failed to connect to authenticate site.<br />Connection string..:\n $authCHK");
// error_function(error_level,error_message,error_file,error_line,error_context)
} else {
require_once($authCHK);
} // end if
curl_close($handle);
Now the file successfully includes the .php file from the server because the username and password to it are parsed in the url.
in the authenticate_anewsite.php I just included (actually I did a require_once) this is the bit that authenticates my website against my clients table which runs these checks:
The MySQL database username and password are stored in this file. This account has only the priveliges of select.
checks clients for existence of a webkey which I give them
check the username against the clients table
checks the password
paid = true
active = true
So the SQL looks like this:
SELECT * FROM clients where paid=1 and active=1 and webkey = '$webkey' and username = '$username' and password = '$password'
If the required checks are verified then the num of records is 1, if this is >0 then my authenticate_anewsite.php includes the other two .inc files like this (the folder username and password have already been verified in the call.
if ($count_check > 0) {
$appliation = $path . 'application_for_my_site.inc';
$appliation = file_get_contents($appliation);
echo $appliation;
$functions = $path . '.anyext';
$functions = file_get_contents($functions);
echo $functions;
} else {
// redirect to the holding page
//header('Location: $base_url/500.shtml');
}
At this point its probably ok to set a session variable to not keep checking the database every time the index.php page is called from the actual site.
OK so this actually works although a little Archaic.
The advantages of all this:
Functions and application are served from one file in a central location (one bug fix can fix all sites)
Doesn't matter if the website is hosted on my server or on another
A user cannot browse the files directly, because htaccess has password protected them
Even if a user were to browse the subdomain/webservice in the browser by putting the link together with the folder username and password the browser, it doesn't server the PHP as is server sided script. It wont be able to see my username and database password, sql, or the name of the files I'm calling in by viewing source
I have my functions in a file with no file name and an extension that I have made up this is the purpose of the .anyext (htaccess treats this the same and protects it, but because its an extension that I made up it makes it harder to guess, and generally invisible)
indexes have been switched off so general browsing is not allowed on my webservice
OK so it took me two days to come up with this solution. I hope that my idea will help save someone a lot of time!
Bless You :o)
Andi Lee Davis
Related
I have this file which stores my db info
<?php
$DBServer = 'this';
$DBUser = 'is';
$DBPass = 'my';
$DBName = 'secret';
?>
And it is included where I need it to connect to the db. My question is, how can I prevent users from going to mywebsite/db_info.php ? I know it displays a blank to them and they don't have access to the info, but I'd like to redirect them to the index page. The problem comes when this file being included in another one, it will always redirect to the index page when used(when I will connect to the db).
With apache, You can put your file in a separate folder within a .htaccess file with this content:
Order deny,allow
Deny from all
So you will have:
/yourPrivateFolder/.htacces
/yourPrivateFolder/db_info.php
This will prevent external access to your file
First, what is the point to redirect a file with important information like database access? No users should have access to this file, or even his name and path.
There are some approaches you can choose, one security option it is to allocate your db_info.php file outside the public root of your domain. Exemple:
yourdomain.com = /home/user/www/
your file should be: /home/user/db_info.php (or outsite /www/ folder!)
I’m looking for a best-practice on storing database credentials for use with PDO.
My DB is stored on GoDaddy, and has a couple of hundred users (maybe).
I recently converted from using mysql_* to PDO and after much Googling for an answer I’ve come to the conclusion that no clear, concise method exists.
Currently I use a config.inc file that stores the credentials as;
<?php
$strHostName = “10.10.10.10”;
$strDbName = “dbname”;
$strUserName = “dbuser”;
$strPassword = “xxx***xxx”;
?>
I do the following in my code;
<?
….stufff
require_once(‘config.inc’);
$db_found = new PDO("mysql:host=$strHostName;dbname=$strDbName;charset=utf8", $strUserName, $strPassword, array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
…lots more stuff
?>
This works fine but I’m concerned about the security of the config.inc file. Is there a preferred method to do this?
Thanks…
I'm not sure how this works really as I haven't tried it, but learned about it the other day so I thought I'd share.
With GoDaddy you can point your primary domain name at a sub-directory, therefore creating a new document root before it, so to speak.
For example, create a new directory called 'application' in your root directory, upload your application's files there and point your domain there (You may need to remove the domain name first and then add it again with the specified directory). You can then include files - your database credentials for example - from before your new document root, which is now not available to the public but available to your application.
NEW STRUCTURE
DB Credentials:
/home/www/html/someSite/dbCredentials.php
Your Website (where primary domain is now pointed):
/home/www/html/someSite/application/index.php
EXAMPLE:
In dbCredentials.php add your credentials:
<?php
$strHostName = “10.10.10.10”;
$strDbName = “dbname”;
$strUserName = “dbuser”;
$strPassword = “xxx***xxx”;
?>
On your web page, include the file and use variables as normal:
<?php
require_once ('/home/www/html/someSite/dbCredentials.php');
$db_found = new PDO("mysql:host=$strHostName..........);
?>
SOURCE:
http://support.godaddy.com/help/article/4175/specifying-a-new-default-document-root-on-your-hosting-account?pc_split_value=4&countrysite=uk
If you try it, let me know how it goes.
Make sure the password is stored in a file that is either not readable, or accessible from the web.
Storing the password in a .php file is considered safe because you can not see the contents of a .php file from the web (only it's output).
You can also store the file outside of the webroot, which makes the file wholly inaccessible from the web.
Another solution is to use the native webserver ignore rules. Files that start with a . like .password are hidden on some webservers. Specifically Apache hides all files that start with .ht. These depend on webserver vendor though so be cautious.
Storing the password in config.inc runs the risk of accidentally exposing the contents when it's in a web-accessible folder.
You don't need to worry about someone gaining access to your server and reading the password from the file because you'll have bigger problems: they have access to your server :)
You could also place the password as an environment variable on your hosting server and use getenv from your php application to read the password.
I have a website which fetches data from some PHP files to display it on the website. However, to protect my data to be used by other people, I wish to protect my PHP file being called by crawlers, bot etc to gather data.
I have prevented it by checking referral URL , but that can be easily by-passed. So, is there any other way to protect my data . I wish that only my website can call to those files.
Thanks !!
Add Basic HTTP authentication in top of your php file:
if ( !isset($_SERVER['PHP_AUTH_USER']) ||
!isset($_SERVER['PHP_AUTH_PW']) ||
!($_SERVER['PHP_AUTH_USER'] == 'user' && $_SERVER['PHP_AUTH_PW'] == 'pw'))) {
header('WWW-Authenticate: Basic realm="Mirkwood"');
header('HTTP/1.0 401 Unauthorized');
die();
}
If you have Apache web server and in root directory of your site you create an .htaccess file (dot htaccess with no suffix).
Try this syntax to prevent access to specific file types:
<FilesMatch "\.(htaccess|htpasswd|ini|php)$">
Order Allow,Deny
Deny from all
</FilesMatch>
Another way is in all non-index php files you could include something like this:
In index.php, add an access value like this:
$access = 'my_value';
In every other file, include this check before even a single byte is echoed out by php:
if(empty($access)) {
header("location:index.php");
die();
}
I have a website which fetches data from some PHP files to display it on the website.
Move the files that contain the data outside of the document root. Assuming that the PHP files are just being accessed by another inside the docroot.
As suggested by DaveRandom, I finally used a cookie based authentication technique to avoid calling of PHP by other websites.
The server first sets a access code for each valid client. This access code is checked at the beginning of my PHP file.
Cookie is set a max time limit of 5 hrs and cookie is destroyed on window close. This is working pretty fine for me.
Please mention if there is any glitches in this part !!
On websites such as facebook and many others you see URLs such as www.facebook.com/username. How does a URL such as this actually load the users information from a MySQL database? and what is the actual file it is displaying on? I would assume there's not really a folder for each user that it is referring to. If my question doesn't make sense can you at least point me in the right direction to set something like this up through PHP?
Again, I want example.com/username to load my users profile. How does this work?
By using apache's .htaccess file to manage a RewriteEngine, all of your pages can be funneled through an index.php file. After confirming that the requested page is not actually a page that you've intended to be a default part of your web page, you can fall back on the code below, to discover a user account. If a user account is not discovered, then the likelihood is that the page being accessed is simply a 404, which you could then redirect to as a catch-all scenario
.htaccess file
RewriteEngine on
RewriteBase /
RewriteRule !\.(xml|js|ico|gif|jpg|png|css|swf|php|txt|html|otf)$ index.php
php logic to run after confirming the requested page, isn't something like a contact-us page, or any typical web page an end user would be attempting to access.
if(preg_match("/^\/(?P<username>[^\/]*)/", $_SERVER['REDIRECT_URL'], $matches)) {
$result = mysql_query("SELECT * FROM users WHERE username = '" . mysql_real_escape_string($matches['username']) . "'");
if($user_record = mysql_fetch_row($result)) {
echo "DO WHATEVER YOUR HEART CONTENTS HERE :)";
} else {
header("Location: error-404.php");
}
}
It is all loaded dynamically via the database. For example, my Facebook name is "benroux". In facebook's user table, there is going to be a unique column called, lets say, nickname. When I visit Facebook, they are parsing the path info and essentially calling a query in the form:
select * from user where nickname = "{$nickName}"
Now, this is an over simplified example, but I hope it gives you an idea of what is going on here. The key is that there are 2 types of url vars, the facebook.com/pagename.php?id=blah and the restful style path info vars facebook.com/pagename/var1/var2/
If you are looking to have example.com/benroux load my user page, you need to make your index.php (I'll use PHP) load the path info ( http://php.net/manual/en/function.pathinfo.php ) and then query the database as I have described above.
try to
print_r($_SERVER);
you will get that parameters. Then you just need to split them.
Something like
$directory = $_SERVER['REQUEST_URI'].split('/')[1];
So, put $directory into query
I have a web site which currently has over 900 html articles currently viewable to anyone. I want to change it to restrict viewing of certain articles by membership only. I have the articles in sql database with flag if restricted. There is an article index with links to each article. The process will be to check if article is restricted, check if user is member logged in, then display, otherwise send to login or subscribe pages. Since there is so many articles, I can't just add some php to not display if the article is accessed directly. My question is where in my web directory to I put these article pages, and how do you protect someone from directly accessing the page, but allow access once the user is authenticated? Any input is appreciated. Anyone know of good reference books on this either?
Move the files so that they're above your document root, and therefore inaccessible through the web server. Or, move the files to a directory which you protect with a password (.htaccess/.htpasswd pair). You never give out that password, it's only there to prevent direct access of the files.
Then, write a script which proxies the articles. That script checks if the user is logged in. If not, it redirects them to the login page. If it is, it reads the article HTML from its actual location, and sends it through.
Ex: http://www.example.com/article.php?view=cooking.html
session_start();
if (!isset($_SESSION['logged_in'])) {
header("Location: login.php");
} else {
readfile("/path/to/articles/" . $_GET['view']);
}
You'll want to do some kind of sanitation on $_GET['view'] to make sure it doesn't contain anything but the name of an article.
You can even keep your current URLs and links to the articles by rewriting them to the proxy script in your .httaccess/httpd.conf with mod_rewrite. Something like this:
RewriteEngine On
RewriteRule article/(.*)\.html articles.php?view=$1 [L]
If you don't already have any existing framework for PHP development that would help with security matters, you might consider something simpler than even using PHP to restrict access. Read up about .htaccess files, and how you can create a protected directory in which you could place all the restricted articles. Then you can setup user account and require people to authenticate themselves before they can read the restricted articles.
Here's a tutorial on how to setup .htaccess for user authorization/authentication:
http://www.javascriptkit.com/howto/htaccess3.shtml
You have a couple of basic options:
Add the code to each page. You can probably automate this, so its not as bad as it sounds. It really shouldn't be more than a single include.
Figure out how to get your web server software (e.g., apache) to do the authentication checks. Depending on how complicated your checks are, a mod_rewrite external mapping program may be able to do it. Other than that, there are existing authentication modules, or writing a fairly simple shim isn't that hard (if you know C)
Feed all page loads through PHP. This will probably break existing URLs, unfortunately. You pass the page you want to see as a parameter or part of the path (depending on server config), then do you checks inside your script, and finally send the page if the checks pass.
The simplest way would probably be to move all the aricle files outside the web root, and then use PHP to fetch them if the client is allowed to see it.
For example:
<?php
if (isset($_GET['id']))
{
$articleDir = "/var/articles/";
// Assuming a "?id=1" query string is used to pass a numberic ID of
// an article. (Like: example.com/showArticle.php?id=1)
$articleID = (int)$_GET['id'];
$articleFile = "article_{$articleID}.html";
// Look through your SQL database to see if the article is restricted.
// I'll leave the codeing to that up to you though.
if (!$isRestricted || $isLoggedIn)
{
$path = $articleDir . $articleFile;
if (file_exists($path))
{
include $path;
}
else
{
echo "The requested article does not exist.";
}
}
else
{
echo "You have to be logged in to see this article.";
}
}
else
{
echo "No article ID was passed. Did you perhaps follow a bad link?";
}
?>
Note that if you want to keep the old links alive, you can use Apache's mod_rewrite to rewrite incoming requests and route them to your PHP file.
Edit
This may help if you are new to mod_rewrite and/or regular expressions:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^article_(\d+)\.html$ fetchArticle.php?id=$1 [L]
</IfModule>
Routs any link such as example.com/article_123.html to example.com/fetchArticle.php?id=123 without the client noticing it.
Similar to what Dan Grossman did, but this one fetches only numbers.