Apache 配置:.htaccess

[an error occurred while processing the directive]

重定向

有时我们需要告诉用户资源已移动,无论是临时移动还是永久移动。这就是我们使用 Redirect 和 RedirectMatch 的原因。

apacheconf

# Redirect to a URL on a different host

Redirect "/service" "http://foo2.example.com/service"

# Redirect to a URL on the same host

Redirect "/one" "/two"

# Equivalent redirect to URL on the same host

Redirect temp "/one" "/two"

# Permanent redirect to a URL on the same host

Redirect permanent "/three" "/four"

# Redirect to an external URL

# Using regular expressions and RedirectMatch

RedirectMatch "^/oldfile\.html/?$" "http://example.com/newfile.php"

第一个参数的可能值如下所列。如果未包含第一个参数,则默认为 temp。

permanent

返回永久重定向状态 (301),表示资源已永久移动。

temp

返回临时重定向状态 (302)。这是默认值。

seeother

返回“See Other”状态 (303),表示资源已被替换。

gone

返回“Gone”状态 (410),表示资源已被永久删除。使用此状态时,应省略 URL 参数。

跨域资源

第一组指令控制从服务器访问资源的 CORS(跨域资源共享)。CORS 是一种基于 HTTP 头的机制,允许服务器指示浏览器应允许加载资源的外部来源(域、协议或端口)。

出于安全原因,浏览器会限制从脚本发起的跨域 HTTP 请求。例如,XMLHttpRequest 和 Fetch API 遵循同源策略。使用这些 API 的 Web 应用程序只能从加载该应用程序的同源请求资源,除非来自其他来源的响应包含适当的 CORS 头。

通用 CORS 访问

此指令将为目录中来自任何网站的所有资源添加 CORS 头。

apacheconf

Header set Access-Control-Allow-Origin "*"

除非您稍后在配置中或在设置此指令的下级目录配置中覆盖该指令,否则来自外部服务器的每个请求都将被接受,这不太可能是您想要的。

另一种方法是明确说明哪些域可以访问您网站的内容。在下面的示例中,我们将访问权限限制为我们主站点 (example.com) 的子域。这更安全,也可能是您想要做的。

apacheconf

Header set Access-Control-Allow-Origin "subdomain.example.com"

跨域图像

正如 Chromium 博客 所报道并记录在 允许跨域使用图像和画布 中,可能会导致 指纹识别 攻击。

为了减轻这些攻击的可能性,您应该在请求的图像中使用 crossorigin 属性,并在 .htaccess 中使用下面的代码片段来设置来自服务器的 CORS 头。

apacheconf

SetEnvIf Origin ":" IS_CORS

Header set Access-Control-Allow-Origin "*" env=*IS_CORS*

Google Chrome 的 Google 字体故障排除指南 告诉我们,虽然 Google 字体可能会在每个响应中发送 CORS 头,但一些代理服务器可能会在浏览器使用它来渲染字体之前将其剥离。

apacheconf

Header set Access-Control-Allow-Origin "*"

跨域资源计时

资源计时 规范定义了一个接口,用于 Web 应用程序访问文档中资源的完整计时信息。

Timing-Allow-Origin 响应头指定允许查看通过资源计时 API 功能检索的属性值的源,否则这些属性值会因跨域限制而被报告为零。

如果资源未附带 Timing-Allow-Origin,或者在发出请求后标头中未包含源,则 PerformanceResourceTiming 对象的某些属性将设置为零。

apacheconf

Header set Timing-Allow-Origin: "*"

自定义错误页面/消息

Apache 允许您根据用户收到的错误类型为他们提供自定义错误页面。

错误页面以 URL 形式呈现。这些 URL 可以以斜杠 (/) 开头表示本地 Web 路径(相对于 DocumentRoot),也可以是客户端可以解析的完整 URL。

有关更多信息,请参阅 HTTPD 文档站点上的 ErrorDocument 指令 文档。

apacheconfErrorDocument 500 /errors/500.html

ErrorDocument 404 /errors/400.html

ErrorDocument 401 https://example.com/subscription_info.html

ErrorDocument 403 "Sorry, can't allow you access today."

错误预防

此设置会影响 MultiViews 对其应用配置的目录的工作方式。

MultiViews 的效果如下:如果服务器收到对 /some/dir/foo 的请求,如果 /some/dir 启用了 MultiViews,并且 /some/dir/foo 不存在,那么服务器将读取目录以查找名为 foo.* 的文件,并有效地伪造一个类型映射,该映射命名所有这些文件,为其分配与客户端按名称请求其中一个文件时相同的媒体类型和内容编码。然后,它选择最符合客户端要求的匹配项。

此设置禁用此配置所应用的目录的 MultiViews,并防止 Apache 在同名目录不存在时因重写而返回 404 错误。

apacheconfOptions -MultiViews

媒体类型和字符编码

Apache 使用 mod_mime 通过将 URI 或文件名中的模式映射到元数据值来为 HTTP 响应选择的内容分配内容元数据。

例如,内容文件的文件名扩展名通常定义内容的 Internet 媒体类型、语言、字符集和内容编码。此信息在包含该内容的 HTTP 消息中发送,并在选择替代方案时用于内容协商,以便在选择要服务的几种可能内容之一时尊重用户的偏好。

更改文件的元数据不会更改 Last-Modified 标头的值。因此,客户端或代理可能仍会使用以前缓存的副本,并带有以前的标头。如果您更改元数据(语言、内容类型、字符集或编码),您可能需要“触碰”受影响的文件(更新其最后修改日期),以确保所有访问者都收到更正的内容标头。

使用适当的媒体类型(又称 MIME 类型)提供资源

将媒体类型与一个或多个扩展名关联,以确保资源将得到适当的服务。

服务器应按照 HTML 规范 的指示,对 JavaScript 资源使用 text/javascript

apacheconf

# Data interchange

AddType application/atom+xml atom

AddType application/json json map topojson

AddType application/ld+json jsonld

AddType application/rss+xml rss

AddType application/geo+json geojson

AddType application/rdf+xml rdf

AddType application/xml xml

# JavaScript

AddType text/javascript js mjs

# Manifest files

AddType application/manifest+json webmanifest

AddType application/x-web-app-manifest+json webapp

AddType text/cache-manifest appcache

# Media files

AddType audio/mp4 f4a f4b m4a

AddType audio/ogg oga ogg opus

AddType image/bmp bmp

AddType image/svg+xml svg svgz

AddType image/webp webp

AddType video/mp4 f4v f4p m4v mp4

AddType video/ogg ogv

AddType video/webm webm

AddType image/x-icon cur ico

# HEIF Images

AddType image/heic heic

AddType image/heif heif

# HEIF Image Sequence

AddType image/heics heics

AddType image/heifs heifs

# AVIF Images

AddType image/avif avif

# AVIF Image Sequence

AddType image/avis avis

# WebAssembly

AddType application/wasm wasm

# Web fonts

AddType font/woff woff

AddType font/woff2 woff2

AddType application/vnd.ms-fontobject eot

AddType font/ttf ttf

AddType font/collection ttc

AddType font/otf otf

# Other

AddType application/octet-stream safariextz

AddType application/x-bb-appworld bbaw

AddType application/x-chrome-extension crx

AddType application/x-opera-extension oex

AddType application/x-xpinstall xpi

AddType text/calendar ics

AddType text/markdown markdown md

AddType text/vcard vcard vcf

AddType text/vnd.rim.location.xloc xloc

AddType text/vtt vtt

AddType text/x-component htc

设置默认字符集属性

网络上的每段内容都有一个字符集。大多数(如果不是全部)内容都是 UTF-8 Unicode。

使用 AddDefaultCharset 为所有标记为 text/html 或 text/plain 的资源提供 UTF-8 字符集。

apacheconf

AddDefaultCharset utf-8

为特定媒体类型设置字符集

使用 mod_mime 中可用的 AddCharset 指令,提供以下文件类型,并将 charset 参数设置为 UTF-8。

apacheconf

AddCharset utf-8 .appcache \

.bbaw \

.css \

.htc \

.ics \

.js \

.json \

.manifest \

.map \

.markdown \

.md \

.mjs \

.topojson \

.vtt \

.vcard \

.vcf \

.webmanifest \

.xloc

Mod_rewrite 和 RewriteEngine 指令

mod_rewrite 提供了一种根据正则表达式规则动态修改传入 URL 请求的方法。这允许您以您喜欢的任何方式将任意 URL 映射到您的内部 URL 结构。

它支持无限数量的规则以及每个规则无限数量的附加规则条件,以提供真正灵活而强大的 URL 操作机制。URL 操作可以依赖于各种测试:服务器变量、环境变量、HTTP 头、时间戳、外部数据库查找以及各种其他外部程序或处理程序,可以用于实现细粒度的 URL 匹配。

启用 mod_rewrite

启用 mod_rewrite 的基本模式是使用它的所有其他任务的先决条件。

所需步骤是

根据 RewriteEngine 文档,打开重写引擎(这对于 RewriteRule 指令的工作是必需的)

如果尚未启用,请启用 FollowSymLinks 选项。请参阅 核心选项 文档

如果您的 Web 主机不允许 FollowSymlinks 选项,您需要将其注释掉或删除,然后取消注释 Options +SymLinksIfOwnerMatch 行,但请注意 性能影响

一些云托管服务会要求您设置 RewriteBase

请参阅 Rackspace 常见问题解答 和 HTTPD 文档

根据您的服务器设置方式,您可能还需要使用 RewriteOptions 指令为重写引擎启用某些选项

apacheconf

RewriteEngine On

Options +FollowSymlinks

# Options +SymLinksIfOwnerMatch

# RewriteBase /

# RewriteOptions

强制 HTTPS

这些重写规则将把 URL 的 http:// 不安全版本重定向到 https:// 安全版本,如 Apache HTTPD wiki 中所述。

apacheconf

RewriteEngine On

RewriteCond %{HTTPS} !=on

RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]

如果您使用 cPanel AutoSSL 或 Let's Encrypt webroot 方法创建 TLS 证书,如果验证请求被重定向到 HTTPS,则证书验证将失败。请打开您需要的条件。

apacheconf

RewriteEngine On

RewriteCond %{HTTPS} !=on

RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/

RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[\w-]+$

RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$

RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

从 www. URL 重定向

这些指令会将 www.example.com 重写为 example.com。

您不应在多个来源(有 www 和无 www)中复制内容。这可能会导致 SEO 问题(重复内容),因此,您应该选择其中一个替代方案并重定向另一个。您还应该使用 规范 URL 来指示搜索引擎应该抓取哪个 URL(如果它们支持此功能)。

设置 %{ENV:PROTO} 变量,以允许重写自动重定向到适当的方案 (http 或 https)。

该规则默认假定 HTTP 和 HTTPS 环境都可用于重定向。

apacheconf

RewriteEngine On

RewriteCond %{HTTPS} =on

RewriteRule ^ - [E=PROTO:https]

RewriteCond %{HTTPS} !=on

RewriteRule ^ - [E=PROTO:http]

RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]

RewriteRule ^ %{ENV:PROTO}://%1%{REQUEST_URI} [R=301,L]

在 URL 开头插入 www.

这些规则将在 URL 的开头插入 www.。重要的是要注意,您绝不应该在两个不同的 URL 下提供相同的内容。

这可能会导致 SEO 问题(重复内容),因此,您应该选择其中一个替代方案并重定向另一个。对于支持它们的搜索引擎,您应该使用 规范 URL 来指示搜索引擎应该抓取哪个 URL。

设置 %{ENV:PROTO} 变量,以允许重写自动重定向到适当的方案 (http 或 https)。

该规则默认假定 HTTP 和 HTTPS 环境都可用于重定向。如果您的 TLS 证书无法处理重定向期间使用的其中一个域,则应打开该条件。

如果您为网站的某些部分使用“真实”子域,则以下内容可能不是一个好主意。

apacheconf

RewriteEngine On

RewriteCond %{HTTPS} =on

RewriteRule ^ - [E=PROTO:https]

RewriteCond %{HTTPS} !=on

RewriteRule ^ - [E=PROTO:http]

RewriteCond %{HTTPS} !=on

RewriteCond %{HTTP_HOST} !^www\. [NC]

RewriteCond %{SERVER_ADDR} !=127.0.0.1

RewriteCond %{SERVER_ADDR} !=::1

RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

帧选项

以下示例发送 X-Frame-Options 响应头,值为 DENY,通知浏览器不要在任何帧中显示网页内容,以保护网站免受 点击劫持 的攻击。

这可能不适合所有人。您应该阅读有关 X-Frame-Options 头部的其他两个可能值 的信息:SAMEORIGIN 和 ALLOW-FROM。

虽然您可以为网站的所有页面发送 X-Frame-Options 标头,但这可能会带来负面影响,因为它甚至会禁止框架化您的内容(例如:当用户使用 Google 图片搜索结果页面访问您的网站时)。

尽管如此,您仍应确保为所有允许用户执行状态更改操作的页面发送 X-Frame-Options 标头(例如:包含一键购买链接、结账或银行转账确认页面、进行永久配置更改的页面等)。

apacheconf

Header always set X-Frame-Options "DENY" "expr=%{CONTENT_TYPE} =~ m#text/html#i"

内容安全策略(CSP)

CSP (内容安全策略) 通过设置 Content Security Policy 来允许您网站信任的内容来源,从而降低跨站脚本和其他内容注入攻击的风险。

没有适用于所有网站的策略,以下示例旨在作为您可以为您的网站修改的指南。

为了简化 CSP 的实现,您可以使用在线 CSP 标头生成器。您还应该使用 验证器 来确保您的标头按您希望的方式工作。

apacheconf

Content-Security-Policy "default-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests" "expr=%{CONTENT_TYPE} =~ m#text\/(html|javascript)|application\/pdf|xml#i"

目录访问

此指令将阻止访问没有服务器配置使用的任何格式的索引文件的目录,例如 index.html 或 index.php。

apacheconf

Options -Indexes

阻止访问隐藏文件和目录

在 Macintosh 和 Linux 系统中,以句点开头的文件是隐藏的,但如果您知道它们的名称和位置,则无法阻止访问。这些类型的文件通常包含用户偏好设置或实用程序的保留状态,并且可能包含相当私密的位置,例如 .git 或 .svn 目录。

.well-known/ 目录代表“已知位置”的 标准 (RFC 5785) 路径前缀(例如:/.well-known/manifest.json, /.well-known/keybase.txt),因此,不应阻止对其可见内容的访问。

apacheconf

RewriteEngine On

RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]

RewriteCond %{SCRIPT_FILENAME} -d [OR]

RewriteCond %{SCRIPT_FILENAME} -f

RewriteRule "(^|/)\." - [F]

阻止访问包含敏感信息的文件

阻止访问一些文本编辑器可能留下的备份和源文件,当任何人都可以访问它们时,这可能会构成安全风险。

更新以下示例中的 正则表达式,以包含任何可能最终出现在您的生产服务器上并可能泄露有关您网站敏感信息的文件。这些文件可能包括配置文件或包含项目元数据的文件等。

apacheconf

Require all denied

HTTP 严格传输安全 (HSTS)

如果用户在浏览器中输入 example.com,即使服务器将他们重定向到网站的安全版本,攻击者仍然有一个机会窗口(初始 HTTP 连接)来降级或重定向请求。

以下标头确保浏览器仅通过 HTTPS 连接到您的服务器,无论用户在浏览器地址栏中输入什么。

请注意,严格传输安全不可撤销,您必须确保在 max-age 指令中指定的时间内能够通过 HTTPS 提供站点。如果您不再拥有有效的 TLS 连接(例如,由于 TLS 证书过期),即使尝试通过 HTTP 连接,您的访问者也会看到错误消息。

apacheconf

# Header always set

Strict-Transport-Security "max-age=16070400; includeSubDomains" "expr=%{HTTPS} == 'on'"

# (1) Enable your site for HSTS preload inclusion.

# Header always set

Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"

阻止某些浏览器对响应进行 MIME 嗅探

通过将 default-src 指令设置为 'self',默认情况下将所有抓取限制为当前网站的源 - 这作为所有 抓取指令 的回退。

这很方便,因为您无需指定适用于您网站的所有 Fetch 指令,例如:connect-src 'self'; font-src 'self'; script-src 'self'; style-src 'self' 等

此限制也意味着您必须明确定义允许您的网站从哪些站点加载资源。否则,它将被限制为与发出请求的页面相同的来源

禁止在网站上使用 元素。这是为了防止攻击者更改从相对 URL 加载资源的位置

如果您想使用 元素,请改用 base-uri 'self'

仅允许表单提交来自当前源,使用:form-action 'self'

通过设置 frame-ancestors 'none',阻止所有网站(包括您自己的网站)将您的网页嵌入到例如