htaccess Challenge: rewrite perfection for secure website structure - php

I am working on a new project where I want to improve the security by using 2 level folders.
The folder "Core" contains all the folders including the "public" which needs to be the only folder the visitor can access.
A short introduction about my webdir:
webdir
| - .htaccess (core)
| - classes
| - functions
| - public
| - .htaccess (public)
| - css
| - files
| - de
| - en
| - general
| - nl
| - images
| - index.php
| - js
| - swf
| - template
For your information:
My public/index.php file sorts out in which section the files are located via [geturl] and [section]. The request "http://example.com/nl/openfile" points to:
public/index.php
this file reads the $_GET and sees that [geturl] is "openfile" in the [section] "nl"
public/index.php wants to open: "files/nl/openfile.php"
this is how it works and I want it to work!
What I want to achieve with my .htaccess is the following:
The website supports 3 languages: en/de/nl. When no language is set then the nl language should be default.
http://example.com/nl/contact needs to target the file: public/files/nl/contact.php
Currently, when the visitor inputs http://example.com/nl/css (with no trailing slash, the problem doesn't occur when the trailing slash is added) the server translates this to http://example.com/public/css/?section=nl.
This is too much information for the visitor. I don't want users to see where the files are located.
The public folder should not be accessed directly. So when a users inputs http://example.com/public this should be redirected to http://example.com/nl/
My current .htaccess files:
.htaccess (core)
<IfModule mod_rewrite.c>
RewriteEngine on
Options +FollowSymLinks
Options -Indexes
RewriteCond %{HTTP_HOST} ^customer.com$ [NC]
RewriteRule ^(.*)$ http://www.customer.com/$1 [R=301,L]
RewriteRule ^company(.*)$ public/$1?section=company [L]
RewriteCond %{QUERY_STRING} (.*)
RewriteRule !(nl|en|de)/(.*).* /webdir/nl/ [R=301,L] # IF NO LANG ISSET THAN NL REDIRECT
RewriteRule ^error(.*).* public/?getpage=error&%1 [PT,L]
RewriteRule ^(nl|en|de)/(.*).* public/$2?section=$1&%1 [L]
</IfModule>
.htaccess (public)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} (.*)
RewriteRule ^(.*).* index.php?geturl=$1&%1 [PT,L]
</IfModule>
What am I doing wrong and how can I improve the .htaccess files?
Summarized, I want the .htaccess to do the following:
The website supports 3 languages: en/de/nl. When no language is set then the nl language should be default.
http://example.com/nl/contact needs to target the file: public/files/nl/contact.php
Currently, when the visitor inputs http://example.com/nl/css (with no trailing slash, the problem doesn't occur when the trailing slash is added) the server translates this to http://example.com/public/css/?section=nl.
This is too much information for the visitor. I don't want users to see where the files are located.
The public folder should not be accessed directly. So when a users inputs http://example.com/public this should be redirected to http://example.com/nl/

Do you know you can block an entire directory by putting an .htaccess with deny from all inside?
This way you can keep your project structure simpler and more portable.

Related

How to redirect based on country

My primary domain name is abcd.com. But when a user from India comes into my site I want to redirect him to in.abcd.com. There are several solutions to this using GeoPlugin. But the problem is site become so slow because of this API call. Is it possible to redirect other than this solution like using .htaccess or something else?
You need to install the mod_geoip module (GeoIP Extension) installed on your server. link for mod_geoip
Then, tweak your .htaccess file accordingly :
GeoIPEnable On
GeoIPDBFile /path/to/GeoIP.dat
# Start Redirecting countries
# Canada
RewriteEngine on
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^CA$
RewriteRule ^(.*)$ http://ca.abcd.com$1 [L]
# India
RewriteEngine on
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^IN$
RewriteRule ^(.*)$ http://in.abcd.com$1 [L]
# etc etc etc...

Define root in .htaccess

I am trying to make clean url in a website using RewriteRule . But when i call the page from different pages (eg. Header-included in different pages) , it shows 404 - object not found.
I observed that the url treated as different in each page. As per my observation i may need to set a root folder and have to redirect all pages based on that . So that it will redirect to the right destination.
Any information on .htaccess will be helpful
my .htaccess code as follows:
DirectoryIndex index2.php
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)/([a-zA-Z0-9]+)/songs?$ album.php?ad=$2 [QSA,NC]
RewriteRule ^category/([a-zA-Z0-9]+)?$ category.php?ct=$1 [QSA,NC]
RewriteRule ^(.*)/([a-zA-Z0-9]+)/cat?$ /category.php?ct=$2 [QSA,NC]
and my directory:
localhost
|
+mysite
|
+mp3
|
index2.php
category.php
album.php

download via HTTP_REFERER in .htaccess

I have 2 domains, one is allow-site.com and the other is resource.com.
resource.com's file structure is:
root
|--- videos
| |---> 01.mp4
| |---> 02.avi
|--- index.php
|--- .htaccess
|
index.php contains a download link like:
<a href="http://localhost/resource/videos/01.mp4" download>Download</a>
In .htaccess I only allow the allow-site.com domain via an HTTP_REFERER RewriteCond, which allows allow-site.com's video players to play the videos correctly.
The .htaccess file is:
RewriteEngine On
RewriteBase /
# allow these referers to passthrough
RewriteCond %{HTTP_REFERER} ^http://localhost/allow [NC]
RewriteRule ^ - [L]
# redirect everything else
RewriteRule ^ https://google.com/ [R,L]
I don't want anybody to use the video links except if they come from allow-site.com, which is the purpose of this .htaccess file, and it works fine.
But the main problem is when I click on the download link, it downloads an HTML file not the video. If I ignore RewriteRule ^ https://google.com/ [R,L], it works as expected (the video downloads fine) but the videos can be used by anybody, from any other domain.
I don't understand how to solve the problem.
Thanks.
The download attribute on links probably strips the referrer by default, hence the user downloading the source of Google's homepage and not the video, because the RewriteCond is not met and the RewriteRule kicks in.
You could try to force a referrerpolicy="origin" on the link and see if it fixes the issue, but it doesn't seem to be well supported at the moment (http://caniuse.com/#feat=referrer-policy)
Also, your rewrite rules can be simplified to:
RewriteEngine On
RewriteBase /
# allow these referers to passthrough
RewriteCond %{HTTP_REFERER} !^http://localhost/allow [NC]
RewriteRule ^ https://google.com/ [R,L]

Emulating Node/Express Routes in .htaccess

I have been trying to emulate how nodejs/express work with their routes. I am forwarding all traffic to index.php to process routes (using AltoRouter).
My file struture is something like this:
-/
--public/
|- assets
|- ...
--routes/
|- route.php
|- ...
--index.php
Take these urls for instance (all should return/redirect 404):
http://testsite.com/routes
http://testsite.com/routes/route.php
http://testsite.com/somefile.php
However only assets should be directly accessible like so (I dont want to include /public/:
http://testsite.com/assets/image.png
http://testsite.com/assets/styles/style.css
This is what I have so far:
# Make sure mod_rewrite is on
<IfModule mod_rewrite.c>
RewriteEngine on
# This should allow us to get our assets and keep them public
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.(gif|jpg|png|jpeg|css|js|swf)$ /public/$1.$2 [L,NC]
# Forward other traffic to index.php
RewriteRule ^.+$ index.php [L]
</IfModule>
One issue i've come accross is going: http://testsite.com/routesproduces:
I Guess my main question is anything that isnt in public shouldnt be accessable (not sure if .htacces is the way to go or not)
You don't have to bury your files above web root if you use the right rules. Private files can easily be made inaccessible.
<IfModule mod_rewrite.c>
RewriteEngine on
# transform assets URLs to correct path, and proceed to next rule
# checking existence in RewriteConds is useless here since public URLs are not 1:1 physical paths
RewriteRule ^assets/.+ public/$0 [NS,DPI]
# send *all* URLs to index.php except those that point to an asset file that exists
RewriteCond $1 !=public/assets/ [OR]
# change the slash in next condition to your sub-directory if not serving from the web root, e.g. %{DOCUMENT_ROOT}/project/root/$0
RewriteCond %{DOCUMENT_ROOT}/$0 !-f
RewriteRule ^((?:[^/]+/){2})?.+ index.php [NS,END]
</IfModule>

How do I parse URL query via .htaccess with unknown number of preset parameters

I need help with Apache's mod_rewrite rules.
I am very beginning with PHP and .htaccess. I am stuck trying to get user's query URL string, parse "language" and "page" as GET variables, pass them to index.php file in root, and respond to user with compiled webpage. Also I need my script correctly understand default language ("ee") and page ("index") values when one or both parameters in user's URL are not set. Examples:
1) "example.com/" --> "example.com/index.php?page=index&lang=ee"
2) "example.com/se/samples" --> "example.com/index.php?page=samples&lang=se"
3) "example.com/se/" --> "example.com/index.php?page=index&lang=se"
4) "example.com/contact" --> "example.com/index.php?page=contact&lang=ee"
5) "example.com/ru/contact" --> "example.com/index.php?page=contact&lang=ru"
I need Apache always show "clear URLs" only, like: example.com/se/samples. "Ugly URLs" with GET queries are for technical reasons only and should not be visible to users and/or search engines. I am also concerned with security issues, thus I am comfortable with using a white-list of manually set allowed parameters in .htaccess and/or index.php.
I have following website file structure on server side:
www:
| .htaccess
| __php__.php
| index.php <-- controller
|
+---css [...]
|
+---img [...]
|
+---js [...]
|
+---lang <-- arrays of languages
| lang_ee.json
| lang_en.json
| lang_ru.json
| lang_se.json
| sliders.json
|
\---tmpl <-- layout templates of pages
contact.php
footer.php
header.php
index.php
nav.php
retail.php
samples.php
services.php
I need following sitemap structure on front-end side:
lang=ee page=index example.com/
lang=ee page=services example.com/services
lang=ee page=retail example.com/retail
lang=ee page=samples example.com/samples
lang=ee page=contact example.com/contact
lang=en page=index example.com/en/
lang=en page=services example.com/en/services
lang=en page=retail example.com/en/retail
lang=en page=samples example.com/en/samples
lang=en page=contact example.com/en/contact
lang=ru page=index example.com/ru/
lang=ru page=services example.com/ru/services
lang=ru page=retail example.com/ru/retail
lang=ru page=samples example.com/ru/samples
lang=ru page=contact example.com/ru/contact
lang=se page=index example.com/se/
lang=se page=services example.com/se/services
lang=se page=retail example.com/se/retail
lang=se page=samples example.com/se/samples
lang=se page=contact example.com/se/contact
My current index.php:
<?php
if (isset($_GET['page'])) {
$page=$_GET['page'];
} else {
$page='index';
}
if (isset($_GET['lang'])) {
$lang=$_GET['lang'];
}
else { $lang='ee'; }
// Include configs
include('__php__.php');
// Assign template
include (ROOT_DIR.'tmpl/'.$page.'.php');
?>
My current .htaccess consists of several unlucky attempts:
# URLs rewrite
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
#RewriteRule ^(services|retail|samples|contact)/?$ $1.php [L]
#RewriteRule ^(index|services|retail|samples|contact)$ index.php?page=$1&lang=ee [L]
#RewriteRule ^([^/].*)([^/].*)$ index.php?page=$2&lang=$1 [L]
#RewriteRule ^(en|ru|se)/(index|services|retail|samples|contact)$ index.php?page=$2&lang=$1 [L]
#RewriteRule ^([^(en|ru|se)].*)/$ index.php?page=$1&lang=ee [N]
#RewriteRule ^(.*)/(.*)$ index.php?page=$2&lang=$1 [L]
#RewriteRule ^(en|ru|se)/(services|retail|samples|contact)/?$ $1/$2.php [L]
#FFFFFUUU..
I have managed to make it work with one or two parameters set (e.g. example.com/se/ or example.com/se/contact), but I am out of ideas where to dig further to make script universal. Pardon my rusty English.
EDIT
I do only need my script to "listen to" following languages: en/ru/se and ee if not set; and pages: services, retail, samples, contact and index if not set. I still need 404 page on e.g. example.com/blabla. This is what I meant by "preset parameters" in question header.
This might work:
RewriteEngine on
RewriteRule ^([A-Za-z]{2}+)/?$ /index.php?page=index&lang=$1 [R=301,NC,L]
RewriteRule ^([A-Za-z]{2}+)/(.*)$ /index.php?page=$2&lang=$1 [R=301,NC,L]
RewriteRule ^$ /index.php?page=index&lang=ee [R=301,NC,L]
RewriteRule ^((?!index.php).*)$ /index.php?page=$1&lang=ee [R=301,NC,L]
EDIT:
RewriteRule ^$ /index.php?page=index&lang=ee [NC,L]
RewriteRule ^(services|retail|samples|contact)/?$ /index.php?page=$1&lang=ee [NC,L]
RewriteRule ^(en|ru|se)/?$ /index.php?page=index&lang=$1 [NC,L]
RewriteRule ^(en|ru|se)/(services|retail|samples|contact)?$ /index.php?page=$2&lang=$1 [NC,L]

Categories