rewritecond %{HTTP_REFERER} !^http://www.yoursite.com/page
rewriterule ^/css - [F]
normally all the requests to css files are coming with a referer set to the page that uses the css. so you can forbid access to css files if the request comes with a referer different than http://yoursite.com/page/
full example:
apache vhost config:
<virtualhost *:80>
servername t1
serversignature off
documentroot /var/www/t1
rewriteengine on
rewriteloglevel 9
rewritelog /var/log/apache2/rewrite.log
rewritecond %{HTTP_REFERER} !^http://t1/page
rewriterule ^/css - [F]
the docroot setup:
root@pinkpony:/var/www/t1/css# ls -al /var/www/t1/{page,css}
/var/www/t1/css:
total 12
drwxr-xr-x 2 root root 4096 2011-05-22 14:07 .
drwxr-xr-x 5 root root 4096 2011-05-22 14:05 ..
-rw-r--r-- 1 root root 11 2011-05-22 14:07 x.css
/var/www/t1/page:
total 12
drwxr-xr-x 2 root root 4096 2011-05-22 14:07 .
drwxr-xr-x 5 root root 4096 2011-05-22 14:05 ..
-rw-r--r-- 1 root root 117 2011-05-22 14:07 x.html
root@pinkpony:/var/www/t1/css#
issuing a direct request to /css/x.css, rewrite.log snip:
192.168.1.4 - - [22/May/2011:14:11:57 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a17ec60/initial] (2) init rewrite engine with requested uri /css/x.css
192.168.1.4 - - [22/May/2011:14:11:57 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a17ec60/initial] (3) applying pattern '^/css' to uri '/css/x.css'
192.168.1.4 - - [22/May/2011:14:11:57 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a17ec60/initial] (4) RewriteCond: input='' pattern='!^http://t1/page' => matched
192.168.1.4 - - [22/May/2011:14:11:57 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a17ec60/initial] (2) forcing responsecode 403 for /css/x.css
issuing a request to /page/x.html, page content is:
root@pinkpony:/var/www/t1/css# cat ../page/x.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://t1/css/x.css">
</head>
<body>
blah
</body>
</html>
request to http://t1/page/x.html:
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a184c90/initial] (2) init rewrite engine with requested uri /page/x.html
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a184c90/initial] (3) applying pattern '^/css' to uri '/page/x.html'
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a184c90/initial] (1) pass through /page/x.html
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a182c80/initial] (2) init rewrite engine with requested uri /css/x.css
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a182c80/initial] (3) applying pattern '^/css' to uri '/css/x.css'
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a182c80/initial] (4) RewriteCond: input='http://t1/page/x.html' pattern='!^http://t1/page' => not-matched
192.168.1.4 - - [22/May/2011:14:13:19 +0300] [t1/sid#7f4c69ceb210][rid#7f4c6a182c80/initial] (1) pass through /css/x.css
so it works as expected. however, no one stops anyone to issue a fake referer with the request. the technique I described is used to kill leeches.