PHP how to restrict folder and website content to different users? - php

I've been googling for days now and have come across different ways to secure folders (htaccess, using a PHP page with a password) but these don't tackle my issue.
The problem:
I need to have a site where different clients can access ONLY THEIR content. Client-A needs to be able to access all their Flash content and websites. Client-B and Client-C need to do the same but none of them can access each others content (even by directly linking to it). A username/password system won't work because each client has 400-1000 users and neither myself or the client has time to manage all these users.
I looked into htaccess and htpasswd but I prefer not to use any username/password combo's. Ideally, I'd like a "secret word" or "passphrase" I could pass from an iPad app or Air program to the server to get the content I need. Anyone have some ideas on the best way to handle this?
EDIT: To simplify things... I want to have HTML sites and Flash swf's above my web root and be able to display them to users. How can I make this happen? I have HTML sites that use relative links so using php's readfile() causes these sites to break since those links aren't correct.

What RDBMS are you using ?
With mod_authn_dbd and a basic authentification you would be able to do so.
Something like this,
AuthType Basic
AuthName "My Server"
AuthBasicProvider dbd
# core authorization configuration
Require valid-user
# mod_authn_dbd SQL query to authenticate a user
AuthDBDUserPWQuery "SELECT password FROM authn WHERE user = %s"

If you have control over the software which sends the requests, you could add an own X-header to every request which identifies the user.
With apache_request_headers() you can get your own request header from the request:
http://www.php.net/manual/en/function.apache-request-headers.php
==============
Edit after first comment:
Some code for example:
globals.php
$headers = apache_request_headers();
$key = $headers["X-Authorization-Key"];
$authorized = checkAuthorization($key);
if(!$authorized) {
header('HTTP/1.1 403 Forbidden');
echo "Access denied!";
exit;
}
//... db connection or something else to get user specific definitions, paths, ...
//e.g.:
$user = $users[$key];
define("CONTENT_PATH", "/var/www/mypage/data/".$user);
function checkAuthorization($key) {
//... db connection or something else where the authorization-information are stored in
//check whether the $key is in the auth-info and return true / false for the result
return true; //or false
}
in every script on top:
<?php
require_once("globals.php");
//... work with the user specific definitions, paths
include(CONTENT_PATH."/...");
//...

What you do is when the user creates their login account, they have the option to select what group they are using. Then when page info is displayed, it displays the normal page, but with the permissions name included in it. You would have to build 3 seperate content pages, but they would only see what the content of their chosen group.
homegroup1.php
homegroup2.php
homegroup3.php
if the user is in group one, the direct would be home"group".php for the display. It would call for the group on the site they go to.

Related

Can HTTP basic authentication be applied outside of assigned realm with PHP?

I am using PHP to implement HTTP Basic Authentication on the Apache HTTP Server (version 2.2). The only directory I want to password-protect is a sub-directory of the main public web root of my website (for example purposes, let's call the protected directory '/private', and its realm "Private”).
If possible, I want users that have already been authenticated in the “Private” realm – and those users only – to see customised content on the web site’s home page (and any other web page, for that matter).
What I want to know is, is it possible to do this without forcing a login prompt at the top-level of my domain's top-level (e.g. www.jdclark.org or, for that matter, any other URIs outside if the “Private” realm)?
EDIT:
One technique that I have thought about applying to achieve the above is as follows: When a user has been authenticated into the “Private” realm via the access control in the ’/private’ directory, a session cookie could be set in PHP.
I could then check for the presence of this cookie (which could possibility contain a session ID or some kind of unique random string), but although I’m don’t proclaim to be an IT security expert, this method feels a bit “hackish,” and something tells me that this is insecure (e.g. would it be trivial for a malicious user to spoof that cookie with an HTTP header?).
Any advice would be very much appreciated.
Check for the presence of the HTTP authentication headers and use this to determine what to display.
if (isset($_SERVER['PHP_AUTH_USER'])) {
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
// validate login credentials
$private = true; // or false if validation fails
}
if ($private) {
// load special view
}
else {
// load normal view
}
This will not prompt the user to log in if they have not already done so elsewhere.
If you are going to be doing this in multiple places it would make sense to have a single re-usable class or file that provided a function to check for the headers and validate the credentials (returning true on success, false on fail) rather than duplicating code.

Protecting PHP files from being called by other websites

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 !!

How do I password protect resources in a ModX Website using htaccess and htpasswd?

We are trying to protect a couple of different resources in our ModX installation. The current .htaccess code is as follows (not including all of the ModX stuff)
AuthName "Dialog prompt"
AuthType Basic
AuthUserFile /var/www/vhosts/mywebsite.co.uk/.htpasswd
<FilesMatch ^index.php\?q=71$>
require valid-user
</FilesMatch>
The object of the exercise is to protect the following resources:
http://mywebsite.co.uk/index.php?q=71
http://mywebsite.co.uk/area/protected
I have tried various combinations of LocationsMatch, Locations, Files and Filesmatch and can't get it to work.
Thank you in advance
You probably dont need htaccess. You can send HTTP authentication headers http://php.net/manual/en/features.http-auth.php from correct system event
This is what the total solution was:
If anyone else needs to know, I created a snippet called passwordprotect and put at the top of the page: [[passwordprotect]]. I then put in the following code (an adaptation of the above response):
<?php
if(isset($_SERVER['PHP_AUTH_USER']) && ($_SERVER['PHP_AUTH_USER']=='user') && ($_SERVER['PHP_AUTH_PW']=='password'))
{
echo 'You are successfully logged in.';
} else {
header('WWW-Authenticate: Basic realm="Protected area"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
}
EDIT: If you are finding that this sometimes does work and sometimes doesn't work, this is probably because using [[passwordprotect]], modx will cache the snippet. I got better success with: [[!passwordprotect]] on Revolution. I think the code is [!passwordprotect!] on Evolution. The exclamation marks just denote not to cache the snippet. Hope that helps someone!
There is absolutely no reason to do this and voids the entire purpose of the MODX Revolution ACLs. The correct answer is to:
Establish a user group with a minimum role which can access the resources.
Create a test resources within the resource group.
Add the site admin to the resource group.
Create a test user in the resource group.
Refresh the site cache.
Log out all users - including yourself.
Test the ACLs - with the site administrator both in the manager and on the front end.
Log out or use a completely different browser and test with the test user.
Once it is working move the protected documents to the resource group.
Add users to the group who you want to have access.
Remove the snippet.
If you need more help get a copy of my book or visit my site.

Can a Directory alone load specific query on a page?

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

design of website with membership to restricted content

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.

Categories