1. 首页 > 知识 > 技术

.htaccess简介和简单应用

一、.htaccess简介

1.什么是.htaccess

.htaccess是一个纯文本文件,里面存放着Apache服务器配置相关的一些指令,它类似于Apache的站点配置文件,如httpd.conf(Apache2已经支持多站点,因此你的站点配置文件可能在/etc/apache2/conf.d/目录下)。 .htaccess与httpd.conf配置文件不同的是,它只作用于当前目录。另外httpd.conf是在Apache服务启动的时候就加载的,而.htaccess只有在用户访问目录时加载,开销大、速度慢。 既然如此,为什么我们还要用.htaccess呢?因为它配置起来简单,它还支持重定向、URL重写以及访问验证,另外它管理起来很方便,可以很好适应网站迁移。总之,各有优缺点,主要就看你是要从全局考虑还是只配置单个目录。

2.AllowOverride All

通常情况下,Apache是默认启用.htaccess的,但是为了以防万一,请检查一下自己站点的配置文件,如httpd.conf,是否有这行:

AllowOverride All

这行允许重写配置文件。也就是如果能够从.htaccess加载配置文件,那么就以.htaccess为配置文件对其所在目录进行配置。

3.500错误

如果你租用了云服务提供商的主机或者空间,那么他们可能不会给你读写httpd.conf文件的权限,你也不可能检查AllowOverride命令参数是否为All,这时,你可以新建一个目录,在里面写一个.htaccess文件,文件中随意写入一些服务器看不懂的东西,然后访问该目录里的一个页面,耐心等待500错误的出现。 如果没有出现,那么.htaccess没有被启用,你需要向你的服务供应商寻求帮助;如果出现了,那么恭喜你,你可以对当前目录重写Apache配置。 

/!\注意:.htaccess语法错误可能会影响整个站点,如果你不确定这样做是否安全,请联系你的云服务供应商。

4.有用的知识点

  • .htaccess正则表达式

  • HTTP协议重定向编码

二、.htaccess访问控制(Allow/Deny)

1.访问控制基础:Order命令

为了限制用户访问一些关键目录,.htaccess可以提供目录访问限制。你只需要在要限制的目录中,加入如下.htaccess文件:

# no one gets in here!
deny from all

这会限制所有用户通过浏览器访问该目录,这太一刀切了,因此我们还可以增加一些特定的条件,如允许指定IP地址的访问:

Order Allow,Deny
Deny from All
Allow from 192.168.0.0/24
Order命令

Order命令是一个难点,也是配置apache的基础,它决定了Apache处理访问规则的顺序。

  • 通过Allow,Deny参数,Apache首先找到并应用Allow命令,然后应用Deny命令,以阻止所有访问。

  • 通过Deny,Allow参数,Apache首先找到并应用Deny命令,然后应用Allow命令,以允许所有访问。

了解Order的用法后,再仔细考虑下上面的例子,你或许能够发现Deny命令是多余的,以下用法和之前的描述语义相同:

Order Allow,Deny
Allow from 192.168.0/24

2.利用.htaccess过滤域名或网络主机(Allow/Deny)

下例可以限制所有含有“domain.com”的网络主机访问网站:

Order Allow,Deny
Allow from all
Deny from .*domain\.com.*

{!}Info:有关htaccess的正则表达式用法

$     匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,请使用 \$。

^      匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 \^。

      换行符以外的所有字符

\w       匹配字母或数字或下划线或汉字

\s       匹配任意的空白符

\d       匹配数字

\b       匹配单词的开始或结束

 *       重复零次或更多次

 +       重复一次或更多次

 ?           重复零次或一次

 {n}         重复n次

 {n,}        重复n次或更多次

 {n,m}       重复n到m次

 () $1 $2        一个括号代表一个分组,第一个括号里匹配的内容就用$1引用,第二个括号匹配的内容用$2引用,以此类推......

3.利用.htaccess禁止访问指定文件(Files)

Files命令可以用于过滤指定文件:

# secure htaccess file
<Files .htaccess>
 order allow,deny
 deny from all
</Files>

4.利用.htaccess禁止访问指定文件类型(FilesMatch)

下面的代码将限制访问所有.log和.exe文件:

<FilesMatch ".(log|exe)$">
 Order allow,deny
 Deny from all
</FilesMatch>

我们还可以通过Files命令描述文件类型,但是需要在命令后面加一个波浪线(~),该符号启用Files命令的正则表达解析功能:

<Files ~ "^.*\.([Ll][Oo][Gg])|([eE][xX][eE])">
 Order allow,deny
 Deny from all
 Satisfy All
</Files>

有以下几点需要读者注意:

Files之后的波浪线用于开启“正则表达式”分析。请注意,这是个过时的用法,Apache更推荐使用<FilesMatch>指令

  • 正则表达式必须在双引号之间,有关htaccess的正则表达式用法,请参考{!}Info注释

  • 双引号中的“管道符”(|)用于将两种文件类型(.log和.exe)分开,相当于逻辑“或”

  • Order命令必须嵌在Files节(Section)中,否则将会应用到所有文件

  • Satisfy All表示必须同时满足主机级别(Allow/Denay)和用户级别(Require)的限制,All是默认值,该行可以省略。

5.高级访问控制(Rewrite)

我们还可以通过运用Rewrite实现更强大的访问控制,但是Rewrite不是本文讨论的内容。读者可以参看:第五部分

三、利用.htaccess进行密码保护与验证

1.配置.htaccess

AuthType Basic
AuthName "restricted area"
AuthUserFile /usr/local/var/www/html/.htpasses
require valid-user

这个配置文件可以保护.htaccess所在的整个目录,简单说明下参数:

  • AuthType:验证类型为基本类型,密码以明文方式传输到服务器上

  • AuthName:验证提示,会出现在验证对话框中

  • AuthUserFile:验证配置文件,用于匹配用户名与密码,该密码是加密保存的

  • require valid-user:只有在AuthUserFile中出现的用户才可以通过验证

如果验证失败,则会出现401错误。

2.生成.htpasses文件

如何生成.htpasses文件呢?我们通过htpasswd命令生成密码文件:

htpasswd -c /usr/local/var/www/html/.htpasses lesca

它会提示你输入密码,并确认。之后将密码文件.htpasses保存在/usr/local/var/www/html/目录下。

3.对文件进行密码保护

保护与.htaccess在同一目录下的文件secure.php

# password-protect single file
<Files secure.php>
AuthType Basic
AuthName "Prompt"
AuthUserFile /home/path/.htpasswd
Require valid-user
</Files>

保护.htaccess所在目录下的多个文件:

# password-protect multiple files
<FilesMatch "^(execute|index|secure|insanity|biscuit)*$">
AuthType basic
AuthName "Development"
AuthUserFile /home/path/.htpasswd
Require valid-user
</FilesMatch>

4.对指定IP进行密码保护

仅允许IP地址为99.88.77.66的主机直接访问该目录,其他IP需要验证。

AuthType Basic
AuthName "Personal"
AuthUserFile /home/path/.htpasswd
Require valid-user
Allow from 99.88.77.66
Satisfy Any

5.安全性

出于安全考虑,将.htpasses文件存放在WEB目录树之外也许是个好方法,但是由于.htpasses是隐藏文件,而且Apache不会输出隐藏文件,因此可以满足基本的安全要求。这是通过在主配置文件中加入如下限制实现的:

<Files ~ "^\.ht">
 Order allow,deny
 Deny from all
 Satisfy All
</Files>

一般而言,这是默认设置,用户无需手动添加。我们唯一需要担心的是密码在网络传输过程中是明文形式,这很容易被黑客破译。Coz提供了一个开源项目Pajamas可以在本地利用JS对密码进行MD5加密,有兴趣的读者可以前去研究一下。

四、目录浏览与主页

如果你打开本站的下载页面http://download.qiheo.com/,就会发现你可以看见这个站点下的所有文件。像这样的特性也可以通.htaccess来设置用户是否有权限浏览服务器目录。

1.启用目录浏览

# enable directory browsing
Options All +Indexes

2.禁用目录浏览

# disable directory browsing
Options All -Indexes

我们还可以通过IndexIgnore指令来禁用目录浏览。

# prevent folder listing
IndexIgnore *

通过IndexIgnore指令,我们可以禁止对指定类型的文件浏览:

# prevent display of select file types
IndexIgnore *.wmv *.mp4 *.avi *.etc

3.自定义目录浏览

如果你希望Apache在展示你的WEB目录时看起来与众不同,那么你需要启用FancyIndexing选项:

<IfModule mod_autoindex.c>
 IndexOptions FancyIndexing 
</ifModule>

通过这个选项,你可以实现自定义图标、添加文件类型描述、按日期排序等。

4.配置目录主页文件

即使启用了目录浏览,Apache未必会展示该目录的内容,因为该目录可能存在像index.htm这样的默认主页文件。Apache会有限展示主页文件,我们可以通过.htaccess设置:

DirectoryIndex index.html index.php index.htm

5.配置错误页面

如果Apache遇到错误,就会输出错误页面。配置自定义的错误页面,也许可以挽留即将离开的用户。

# custom error documents
ErrorDocument 401 /err/401.php
ErrorDocument 403 /err/403.php
ErrorDocument 404 /err/404.php
ErrorDocument 500 /err/500.php

五、URL重写与URL重定向

URL重定向是.htaccess的重头戏,它可以将长地址转为短地址、将动态地址转为静态地址、重定向丢失的页面、防止盗链、实现自动语言转换等。笔者觉得难点是在正则表达式的运用和理解上。

一、准备开始:mod_rewrite

实现所有这些神奇功能的模块叫做mod_rewrite,请确保你的服务器安装并启用了该模块:

sudo a2enmod rewrite

我们一般会把所有涉及URL重写或者重定向的代码这样放置:

# Turn on rewrite engine
Options +FollowSymlinks
RewriteEngine on
# More rules below
...

一些我们需要注意的地方:

  • FollowSymlinks必须启用,这是rewrite引擎的安全需求。

  • 通常FollowSymlinks在Apache的主配置文件中就已经启用了,所以通常可以省略。

  • RewriteEngine命令用于启用rewrite引擎

  • IfModule命令用于判断Apache是否安装了mod_rewrite模块,之后笔者会省略该命令,但不代表这是个好习惯。

  • mod_rewrite会处理所有提交给Apache的URL请求,并与之后的规则进行匹配

下面我们开始讲解一些例子。

二、利用.htaccess实现URL重写(rewrite)与URL重定向(redirect)

1.将.htm页面映射到.php
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^(.*)\.htm$ $1.php [NC]

注意事项

  • 该RewriteRule能够将.htm静态页面映射到.php动态页面

  • 如果通过.htm进入,浏览器地址栏显示的是.htm扩展名,但服务器上实际执行的是.php

  • 必须保证服务器上有对应的.php,否则会404

  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页

  • 如果该目录上存在.htm,将被忽略

  • [NC]表示“不区分大小写”,更多类似定义请参考正则表达式

2.临时重定向(R=302)与永久重定向(R=301)
RewriteEngine on
RewriteBase /
RewriteRule ^(.*)\.htm$ $1.php [R,NC,L]

注意事项

  • 该RewriteRule能够将.htm静态页面重定向到.php动态页面

  • 如果通过.htm进入,浏览器地址栏会自动转为.php,这也是重定向的本质

  • 必须保证服务器上有对应的.php,否则会404

  • 浏览器和搜索引擎可以同时通过.htm和.php访问网页

  • 如果该目录上存在.htm,将被忽略

  • RewriteBase定义了重写基准目录。

  • 例如,如果你将虚拟站点设置在/var/www目录下,删除这行将会导致重定向到http://yourdomain.com/var/www/1.php。显然这是找不到的,而且你也不会希望用户看见你的服务器的目录结构。

  • 再举个例子,如果RewriteBase /base/,那么将会重定向到http://yourdomain.com/base/1.php。

  • 对于重写基准目录,我们还可以通过将$1.php变成/$1.php实现直接变换,这时就可以将RewriteBase省略。

  • 字母R表示临时重定向,相当于[R=302,NC]。

  • 字母L表示如果能匹配本条规则,那么本条规则是最后一条(Last),忽略之后的规则。

在讨论R=302临时重定向后,理解R=301永久重定向也就容易多了:

RewriteEngine on
RewriteRule ^(.*)$ http://newdomain.com/$1 [R=301,NC,L]
  • 这个规则告诉浏览器和搜索引擎,网站地址发生了永久性变更,用户的URL请求将会被发送给新的域名(主机)处理。

  • 由于是重定向到新的主机地址,RewriteBase也就没有出现的必要了。

3.为什么要用重定向?——重定向和URL重写的区别
  • 通过重定向,浏览器知道页面位置发生变化,从而改变地址栏显示的地址

  • 通过重定向,搜索引擎意识到页面被移动了,从而更新搜索引擎索引,将原来失效的链接从搜索结果中移除

  • 临时重定向(R=302)和永久重定向(R=301)都是亲搜索引擎的,是SEO的重要技术

  • URL重写用于将页面映射到本站另一页面,若重写到另一网络主机(域名),则按重定向处理

4.长短地址转换

利用URL重写,我们可以很方便地实现长短地址的转换,但是用重定向就不合适了。

RewriteEngine On
RewriteRule ^grab /public/files/download/download.php

若访问

http://mysite/grab?file=my.zip

则会执行该页面:

http://mysite/public/files/download/download.php?file=my.zip

5.去掉www
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*) [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]
6.加上www
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*)$
RewriteRule (.*) http://www\.%1/$1 [R=301,L]
7.支持多域名访问

如果你不凑巧买到了不支持多域名的主机,那么.htaccess或许可以帮助你。现在假设你有域名domain-one.com和domain-two.com,并且在服务器根目录有对应文件夹one和two,那么通过下面的改写就能让Apache同时接受者两个域名的请求:

#two domains served from one root..
RewriteCond %{HTTP_HOST} domain-one.com
RewriteCond %{REQUEST_URI} !^/one
RewriteRule ^(.*)$ /one/$1 [L]

RewriteCond %{HTTP_HOST} domain-two.com
RewriteCond %{REQUEST_URI} !^/two
RewriteRule ^(.*)$ /two/$1 [L]

三、改写查询字符串QUERY_STRING

查询字符串是指URL请求中“问号”后面的部分。比如,http://mysite/grab?foo=bar中粗体部分就是查询字符串,其中变量名是foo,值是bar。

1.利用QSA转换查询字符串QUERY_STRING

QSA标志( Query String Appending)用于在URI中截取查询字符串,这个截取操作是通过小括号正则表达式实现的:

RewriteEngine On
RewriteRule /pages/(.+) /page.php?page=$1 [QSA]
  • 将会把请求/pages/123?one=two 映射到 /page.php?page=123&one=two

  • 注意粗体部分几乎是相同的,除了“问号”变成了“与”符号

  • 如果没有QSA标志,那么会映射到/page.php?page=123。

  • 如果没有用到小括号正则表达式,就不需要QSA,这在上节“长短地址转换”中已经例证过了。

  • 小括号正则表达式可以截取查询字符串中的内容,但是如果没有开启QSA标志,那么在/page.php?page=$1中“问号”之后将会被剥离丢弃。这种特性可以用于实现“剥离查询字符串”

通过QSA,我们可以将简单链接/simple/flat/link/ 映射成 server-side.php?first-var=flat&second-var=link

RewriteEngine On
RewriteRule ^/([^/]+)/([^/]+)/? /index.php?first-var=$1&second-var=$2 [QSA]
2.利用RewriteCond改写查询字符串QUERY_STRING
RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.*)
RewriteRule ^grab(.*) /page.php?bar=%1
  • 该规则将访问请求http://mysite/grab?foo=bar转换为http://mysite/page.php?bar=bar

  • RewriteCond用于捕获查询字符串(QUERY_STRING)中变量foo的值,并存储在%1中

  • QUERY_STRING是Apache定义的“变量=值”向量(数组)

3.QSA与RewriteCond双剑齐发
RewriteEngine On
RewriteCond %{QUERY_STRING} foo=(.+)
RewriteRule ^grab/(.*) /%1/index.php?file=$1 [QSA]
  • 会把/grab/foobar.zip?level=5&foo=bar 映射到 /bar/index.php?file=foobar.zip&level=5&foo=bar

  • 转换后根目录是bar目录

  • foobar.zip?level=5中的“问号”变成了foobar.zip&level=5中的“与”符号

4.剥离查询字符串

只需在要开始剥离的链接后面加个“问号”,并且不要启用QSA标志,就可剥离查询字符串

RewriteEngine On
# Whatever QS is
RewriteCond %{QUERY_STRING} . 
# I don't want it with Question mark
RewriteRule foo.php(.*) /foo.php? [L]

四、利用RewriteCond和RewriteRule进行访问控制

我们在.htaccess基础中提到了很多有用的访问控制方法,其实通过Rewrite也能实现类似的功能,而且可以更强大!

1.文件访问控制

之前利用Order、Files及FilesMatch命令实现的访问控制可以满足大部分要求,但是当用户被拒绝时,他们看到的是硕大的“403 Forbidden”,如果你不想伤害用户的感情,就需要显示一些别的东西,通过Rewrite就可以实现这个特性:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^(.+)\.css$
RewriteCond %{REQUEST_FILENAME} !^(.+)\.js$
RewriteCond %{REQUEST_FILENAME} !special.zip$
RewriteRule ^(.+)$ /chat/ [NC]
  • 该规则将仅允许用户请求.css, .js类型的文件,还有special.zip文件

  • RewriteRule 后面指定了限制规则:映射到/char/目录下处理

  • RewriteCond 后面的“感叹号”(!)起到了“否定”作用,它表明,对不满足后面正则表达式者应用RewriteRule规则,也就是对当前类型的文件将不应用规则

  • RewriteCond 之间是以逻辑“与”连接的,也就是只有当三个条件都不满足时才执行RewriteRule

  • 该规则也会限制访问.htm, .jpg等格式

  • 该规则不可以放在虚拟站点根目录(/)下,否则会死循环

  • 如果是二级目录,如/test/,那么传入RewriteCond的参数是以/test/开始的,因此从(.+)获得的文件名也含有/test/,读者必须对此多加小心

  • 要想仅获得文件名,可以将(.+)替换成([^/]+),并且去掉符号^,如下所示:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !([^/]+)\.css$
RewriteCond %{REQUEST_FILENAME} !([^/]+)\.js$
RewriteRule ^(.+)$ /chat/ [NC]
2.用.htaccess阻止User-agent

什么是User-agent?User-agent用于浏览器向服务器“自报家门”,更确切的说是所有HTTP客户端都得用User-agent向服务器“自报家门”,以便服务器对不同的客户端作出不同响应。比如,某站点可能需要对浏览器、搜索引擎crawl还有各类下载工具作出不同的响应。服务器就是通过所谓的User-agent进行区分的。

如果你的服务器提供某些资源的下载,那么你就必须多加小心诸如“迅雷”等下载软件,因为它们可能把你网站资源吸干,并且影响你的正常访客访问。为此,我们可以利用Rewrite限制某些UA的访问:

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC]
RewriteRule . abuse.txt [L]
  • 该规则限制“迅雷”客户端下载资源,并将下载文件重置到abuse.txt

  • HTTP_USER_AGENT是Apache的内置变量

  • 2.0.50727是迅雷User-agent的特征字符串

  • RewriteRule后面的“点”表示“任意URI”,也就是不管请求的是什么,都输出abuse.txt

通常,我们不会仅限制一个UA。利用[OR]即可实现对多个UA作出统一处理:

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} 2.0.50727 [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^BlackWidow [NC,OR]
# etc..
RewriteCond %{HTTP_USER_AGENT} ^Net\ Vampire [NC]
RewriteRule . abuse.txt [L]
3.用.htaccess阻止盗链(hot-linking)

盗链,特别是图片,是非常可耻的!哪怕将图片复制到自己服务器上,也比盗用他人的图片链接来得光彩!(吐糟完毕)

.htaccess的Rewrite功能可以提供非常简单、有效的方法阻止这种可耻行为:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?lesca\.me/ [NC]
RewriteCond %{REQUEST_URI} !hotlink\.png [NC]
RewriteRule .*\.(gif|jpg|png)$ /hotlink.png [NC]

简单解释一下该规则的功能:

  • 除本站以外其他网站都不得引用本站图片,具体可以理解为

  • 如果引用站点为“空”或者是“本站”,或者,所引用对象是“hotlink.png”,那么就允许访问

  • 再次提醒,RewriteCond之间默认的逻辑连接词是逻辑“与”

  • 这里的难点是理解逻辑转换,即德·摩根定律


本文由傻鸟发布,不代表傻鸟立场,转载联系作者并注明出处:https://www.shaniao.net/jishu/147.html

加载中~

联系我们

在线咨询:点击这里给我发消息

微信号:

工作日:10:30-15:30,节假日休息