Apache-2.4

.htaccess 重寫 URL 並強制 https

  • December 5, 2020

網站:example.com

Joomla 子目錄:example.com/joomla

我希望在 example.com/joomla 上安裝的 Joomla 成為(或看起來是)網站的根目錄,即訪問 example.com 的人被重定向到 example.com/joompla/index.php 但仍然看到 example.com 在網址欄。我也想利用這個機會強制所有傳入連接使用 HTTPS。我已經能夠使用我在網上找到的腳本來做一個或另一個,但兩者都不是一致的。

這是我到目前為止的.htaccess:

RewriteEngine on
RewriteBase /

# Rewrites all URLS without joomla in them
RewriteCond %{REQUEST_URI} !^/joomla/

# Rewrites all URLS with example in them
RewriteCond %{HTTP_HOST} ^(www\.)?example\.

# Rewrite all those to insert /joomla
RewriteRule ^(.*)$ /joomla/$1 [L]

# This works SOME of the time to redirect to https
Header always set Content-Security-Policy "upgrade-insecure-requests;"

# If a request tries to access /joomla directly, redirect it to its secured canonical version
RewriteCond %{THE_REQUEST} joomla/
RewriteRule ^joomla/(.*) http://example.com/$1 [R=301,L]

這似乎在 Chrome 中的某些時候有效,重定向到 Joomla 安裝並切換到 https,但有時我需要反復強制重新載入才能到達那裡。它永遠不會在 Firefox 中執行,在極少數情況下它會完全載入該站點而停留在 http 上。

我對 .htaccess 很陌生,我不確定我是否已經為上述問題開發了最優雅或最全面的解決方案。我在網上看到過使用各種命令RewriteCond %{HTTPS} !=onRewriteCond %{SERVER_PORT} 80與各種RewriteRule命令一起使用的其他範例,但我不確定如何將這些命令與現有的 URL 重寫條件結合起來,因此我確信我錯過了邊緣場景。

有更多經驗的人可以指導我完成這個嗎?這將不勝感激。幾天來,我一直在嘗試在網上找到的各種腳本,但還沒有完全找到神奇的詞。

關於您現有指令的一些注意事項:

RewriteBase /

雖然您已經定義了RewriteBase,但它並未在您的任何指令中使用。RewriteBase僅適用於相對路徑替換(您在相關指令中明確使用了根相對 URL 路徑)。

# Rewrites all URLS with example in them
RewriteCond %{HTTP_HOST} ^(www\.)?example\.

需要檢查請求的主機名嗎?除非您託管多個域(或子域)並且不想應用此規則,否則此條件是多餘的。

# This works SOME of the time to redirect to https
Header always set Content-Security-Policy "upgrade-insecure-requests;"

永遠不會觸發“重定向”,所以我不確定您在網路流量中看到了什麼?

(實際上,您發布的程式碼中沒有任何內容會觸發從 HTTP 到 HTTPS 的“重定向”。)

此 HTTP 響應標頭導致瀏覽器自動“升級”來自初始 HTML(頁面)響應的任何連結資源(CSS、JS、圖像、外部資源等)請求,否則該響應將通過 HTTP(例如,因為實際URL 包含http://...) 以通過 HTTPS。不會發生實際的“重定向”。可能通過純 HTTP 的初始 HTML 響應沒有任何反應。

如果您已實現站點範圍的 HTTP 到 HTTPS 重定向並且您的所有連結資源已經是 HTTPS 或使用根相對(或協議相對)URL,則此標頭不是絕對必要的。但它確實提供了一個很好的安全網。但是請注意,任何不支持 HTTPS 的連結資源都將簡單地中斷 - 不會向使用者發出瀏覽器警告。如果沒有此標頭,則使用者可能會收到瀏覽器“混合內容”警告(連結資源失敗)。

# If a request tries to access /joomla directly, redirect it to its secured canonical version
RewriteCond %{THE_REQUEST} joomla/
RewriteRule ^joomla/(.*) http://example.com/$1 [R=301,L]

RewriteCond指令(用於防止“正常條件”下的重定向循環)匹配所請求 URL 中的任何位置,即使在查詢字元串中也是如此 - 這是不正確的,如果應該出現在 URL 路徑中的其他位置甚至joomla/可能導致不正確的重定向joomla/查詢字元串。例如,如果我只是附加?joomla/到任何 URL 的末尾,這將導致重定向循環。

這種“重定向”應該內部重寫之前進行。一般來說,“重定向”應該在“重寫”之前,以避免重定向重寫的 URL 並將重寫的 URL 暴露給您的使用者。

如評論中所述,此重定向是到 HTTP - 與您嘗試做的相反(並且在實現 HTTP 到 HTTPS 重定向時會導致一個小的重定向鏈)。

幾個假設:

  • SSL證書直接安裝在應用伺服器上,即。沒有 Cloudflare (Flexible-SSL) 或其他管理 SSL 的前端代理。
  • 您沒有使用任何其他子域。只是www
  • 規範主機名是非 www,即。example.com(來自您問題中的重定向)。
  • 您此時沒有實現 HSTS,因此您可以example.com在單個重定向中重定向到 HTTPS 和規範主機名(即。)。
  • Joomla 本身已經配置為/joomla從 URL 中省略子目錄。/joomla不存在於任何內部連結上,包括指向靜態資源(CSS、JS、圖像等)的連結
  • 您沒有從文件根目錄提供任何文件。一切都是去/joomla子目錄。

場景 #1 -.htaccess文件根目錄中的單個文件。

(如評論中所述。)

在這種情況下,安裝.htaccess子目錄/joomlaindex.php在這種情況下,index.php必須出現在 URL 中,並且您不能使用 Joomla 的“SEF” URL。

/.htaccess文件看起來像這樣:

RewriteEngine on

RewriteBase /joomla

# If a request tries to access /joomla directly, redirect it to its secured canonical 
RewriteCond %{THE_REQUEST} ^[A-Z]{3,7}\s/joomla
RewriteRule ^joomla(?:$|/(.*)) https://example.com/$1 [R=302,L]

# Canonicalise the hostname - ie. www to non-www and HTTPS
RewriteCond %{HTTP_HOST} ^www\.(.+?)\.?$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=302,L]

# Redirect remaining requests from HTTP to HTTPS
# The hostname must already be canonical at this point
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

# Rewrite everything to the /joomla subdirectory
# Uses the value defined in the RewriteBase directive above
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) $1 [L]

# Ensure that any linked resources are requested over HTTPS
Header always set Content-Security-Policy "upgrade-insecure-requests;"

請注意,我在這裡使用 302(臨時)重定向進行測試。始終首先使用 302 重定向進行測試,並且只有在確認可以正常工作後才更改為 301(永久)。301 被瀏覽器永久記憶體,因此可能會使測試出現問題。

REDIRECT_STATUS環境變數用於確保我們只重寫直接請求而不是重寫請求,與第一條規則中使用的方式大致相同THE_REQUESTREDIRECT_STATUS在初始請求中為空,並在第一次成功重寫後設置為“200”(如 200 OK HTTP 響應狀態)。該指令RewriteRule (.*) $1 [L]起初可能看起來有點奇怪(它看起來像是重寫了自己),但是,RewriteBase作為結果替換的前綴,所以它實際上重寫為/joomla/<url>.

場景 #2 - 兩個.htaccess文件:文件根目錄和子目錄

子目錄中的文件將是 Joomla 附帶的合理標准.htaccess文件。這會將所有請求路由到 Joomla 前端控制器(即。)並啟用 Joomla 的“SEF” URL(即,您不需要顯式包含在 URL 中)。/joomla``.htaccess``index.php``index.php

/.htaccess文件看起來像這樣:

RewriteEngine on

RewriteBase /joomla

# Canonicalise the hostname - ie. www to non-www and HTTPS
RewriteCond %{HTTP_HOST} ^www\.(.+?)\.?$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=302,L]

# Redirect remaining requests from HTTP to HTTPS
# The hostname must already be canonical at this point
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

# Rewrite everything to the /joomla subdirectory
# Uses the value defined in the RewriteBase directive above
RewriteRule (.*) $1 [L]

# Ensure that any linked resources are requested over HTTPS
Header always set Content-Security-Policy "upgrade-insecure-requests;"

請注意,從 URL 中刪除子目錄的重定向/joomla已被刪除,需要放入/joomla/.htaccess文件中。(如果留在這裡就完全是多餘的了。)

這次您不需要檢查REDIRECT_STATUSenv var,因為它/joomla/.htaccess會在重寫後擷取請求。(假設未啟用 mod_rewrite 繼承。)

如果您願意,可以將該Header指令移至/joomla/.htaccess- 這是可選的,因為無論如何它將被“繼承”。

然後,該/joomla/.htaccess文件將包含如下內容:

# JOOMLA: Set Options here

RewriteEngine on

# If a request tries to access here directly then redirect back to root
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*) https://example.com/$1 [R=302,L]

# JOOMLA: Rewrite rules to block out some common exploits.
# :

# Leave the RewriteBase directive commented out - it's not required
#RewriteBase /joomla

## Begin - Joomla! core SEF Section.
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

RewriteRule ^index\.php$ - [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
## End - Joomla! core SEF Section.

/joomla/.htaccess文件大致基於Joomla 網站上的程式碼,但是,我省略了常見元素/註釋並將“SEF 部分”更改為與子目錄相關。(Joomla 也使用效率較低的正則表達式.*而不是簡單的^.)

引用自:https://serverfault.com/questions/1044973