AWS- 子域不支持 HSTS

AWS- subdomain doesn't support HSTS

我正在使用 Semrush,我收到了一条通知,它真的很困扰我,我想摆脱它。 1 个子域不支持子域的 HSTS:www.domain.com,这是我的 .htdocs 文件:

Options -Indexes

<IfModule mod_rewrite.c>
    Options +FollowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/ [L]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP_USER_AGENT} ^(.+)$
    RewriteCond %{SERVER_NAME} ^example\.com$
    RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header always set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

我把这部分加在最后:

<IfModule mod_headers.c>
        <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
            Header always set Strict-Transport-Security "max-age=31536000"
        </If>
    </IfModule>

但是还是没有,我哪里做错了?

您是否尝试过通过 DNS 记录和 .vconfig 文件修复此问题?对于我的网站,我有:

  1. 主域的 DNS A 记录 (A domain.com 123.123.123.123)
  2. www 的第二个 DNS A 记录 (A www 123.123.123.123)

然后在 domain.com.vhost:

<VirtualHost *:80>

    DocumentRoot /var/www/path_to_root

    ServerName domain.com
    ServerAlias domain.com

    RewriteEngine on
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]

</VirtualHost>

重写规则强制使用 HTTPS。

如果您想为特定域强制使用 HTTPS,无论是在 .vhost 还是 .htaccess 中,您都可以使用:

RewriteEngine On 
RewriteCond %{HTTP_HOST} ^yourdomain1.com [NC] 
RewriteCond %{HTTPS} off 
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

对于特定文件夹:

RewriteEngine On 
RewriteCond %{HTTPS} off 
RewriteRule ^(folder1|folder2|folder3) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

确保将文件夹引用更改为实际目录名称。

如果您能够通过 Cloudflare 路由您的 DNS(即使是他们的免费计划),您将能够通过单击按钮启用 HSTS(包括子域)。在速度和安全性方面还有很多其他好处,这也可能有助于您的 SEMRush 报告

Options -Indexes

<IfModule mod_rewrite.c>
    Options +FollowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php/ [L]
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP_USER_AGENT} ^(.+)$
    RewriteCond %{SERVER_NAME} ^example\.com$
    RewriteRule .* https://www.%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    Header add Strict-Transport-Security "max-age=300"
</IfModule>
<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header always set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

这里有许多问题会阻止 HSTS 正常工作,并且应该进行一些额外的优化。

  1. 您没有将 http://www.example.com(即 www 子域)重定向到 HTTPS。您需要将 HTTP+WWW 重定向到 HTTPS+WWW 才能符合 HSTS。

  2. 您正在重定向 http://example.com/(即 HTTP + non-www)到 HTTPS + WWW。为了符合 HSTS,您需要先在 同一主机 上重定向到 HTTPS。 IE。 http://example.com/https://example.com/https://www.example.com(是的,这是两个重定向,但它也很少见,并且每个 user-agent 最多只会出现一次,因为 STS header 返回)。

  3. 您的指令顺序错误。您的规范重定向(即 HTTP 到 HTTPS 和 non-www 到 www)需要 before 您的 front-controller 重写(第一条规则)。通过将它们放在 front-controller 之后,除了主页、目录和静态资源之外,它们永远不会被处理。例如。 http://example.com/<some-url> 永远不会被所写的规则重定向。不确定您如何测试 HSTS 与 SEMrush 的合规性,但是使用当时编写的指令 http://example.com/<some-url> 会失败,因为它没有被重定向。

  4. 您应该删除第一个 Header 指令 - 这与第二个(正确的)Header 指令直接冲突。 always 条件(在第二个实例中使用)是必需的,以便将 header 设置为 HTTPS 301 重定向(即非 2xx 响应)从 non-www 到 www.

  5. 您应该在 Strict-Transport-Security header 中包含 includeSubDomains 指令,以便在请求域顶点时覆盖 www 子域。不过,所有 子域现在都将被隐式包含在内。否则,需要明确请求 www 子域。 (好吧,无论如何你都将在下一个请求中重定向到 www。)

  6. 您应该删除 <IfModule> 包装器;他们不是必需的。这些指令是强制性的,它们不是 可选的 (这些包装器的存在暗示了这一点)。如果 mod_rewrite 不可用,您的站点可能会失败,并且您将不符合 HSTS。

    有关此问题的更多信息,请参阅 my answer 网站管理员堆栈中的以下问题:
    Is Checking for mod_rewrite Really Necessary?

  7. 我从早期的 HTTP + non-www 重定向假设你不在管理你的 SSL 的 front-end 代理(或负载平衡器)后面,在这种情况下检查for %{HTTP:X-Forwarded-Proto} in the later <If> expression should be removed.如果您不在“代理”后面,则可以伪造请求以防止 STS header 被发回(用户不应该这样做)。

    相反,如果您在“代理”后面,那么检查 %{REQUEST_SCHEME} == 'https' 是多余的 - 但不会造成任何伤害。顺便说一句,REQUEST_SCHEME 的使用假定您使用的是 Apache 2.4+(我希望您是),但是,如果您仍在使用 Apache 2.2,则此检查将失败并且 STS header 将不会设置。

所以,考虑到以上几点,你的.htaccess文件应该这样写:

Options +FollowSymLinks -Indexes

RewriteEngine On

# Redirect HTTP to HTTPS on the same host (requirement of HSTS)
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect non-www to www (HTTPS only)
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Front-controller
RewriteRule ^index\.php/ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/ [L]

<If "%{REQUEST_SCHEME} == 'https'>
    # The "always" condition is required to set the header on the HTTPS redirect
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</If>

补充说明:

  • 我使用 HTTP_HOST 而不是 SERVER_NAME 因为您 需要 请求中的主机名。默认情况下 SERVER_NAMEHTTP_HOST 相同,但这可能因服务器配置而异。

  • 没有理由仅在请求中存在 non-empty User-Agent 字符串时才应用规范重定向(恶意请求可能会抑制 User-Agent string) 和原来一样,所以我删除了这个条件。如果有的话,你会阻止这样的请求。

  • RewriteRule模式中的正则表达式^.*更优化,因为它只需要成功 - 它实际上不需要 匹配 任何东西,因为它以后不会被使用。

  • “front-controller”之前的附加 RewriteRule ^index\.php/ - [L] 指令只是一种优化,可防止重写的 URL 不必要地通过随后的文件系统检查。

参考/另请参阅:


更新: 请尝试以下操作。由于您在 AWS 上,您可能需要检查 X-Forwarded-Proto HTTP 请求 header 而不是 HTTPS Apache 服务器变量以确定对客户端的请求是否安全或没有。

需要更改的是 HTTP 到 HTTPS 重定向(第一条规则)和末尾的 <If> 表达式。

Options +FollowSymLinks -Indexes

RewriteEngine On

# Redirect HTTP to HTTPS on the same host (requirement of HSTS)
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect non-www to www (HTTPS only)
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Front-controller
RewriteRule ^index\.php/ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php/ [L]

<If "%{HTTP:X-Forwarded-Proto} == 'https'>
    # The "always" condition is required to set the header on the HTTPS redirect
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</If>