如此處所述,您無法重定向到設定了自訂標頭的另一個網域,無論您使用什麼語言或框架。 HTTP 協定中的重新導向基本上是與回應關聯的標頭(即位置),並且不允許新增任何指向目標位置的標頭。當您在範例中新增授權標頭時,您基本上是為指示瀏覽器重定向的回應設定該標頭,而不是為重定向本身設定該標頭。換句話說,您將該標頭傳回客戶端。
至於HTTP cookie,瀏覽器將伺服器發送的cookie 與回應一起儲存(使用Set-Cookie header),然後將cookie 與請求傳送至Cookie HTTP 標頭內的同一伺服器 。根據文件:
Set-Cookie HTTP 回應標頭用於將 cookie 從
伺服器傳送到使用者代理,以便使用者代理可以將其傳回
伺服器之後。若要傳送多個 cookie,應在相同回應中傳送多個 Set-Cookie
標頭。
因此,如果這是來自一個應用程式的重定向(帶有子域,例如abc.example.test )到另一個(具有子域,例如xyz.example.test),兩者都具有相同(父)網域(並且在建立cookie 時網域標誌設定為example.test),cookie 將在兩個應用程式(就像指定了網域一樣,則始終包含子網域)。瀏覽器將使 cookie 可用於給定網域(包括任何子網域),無論使用哪種協定 (HTTP/HTTPS) 或連接埠。您可以使用網域和路徑標誌限制 cookie 的可用性,也可以使用 secure 和 httpOnly 標誌限制對 cookie 的存取(請參閱此處和此處,以及 Starlette 文件)。如果沒有設定 httpOnly 標誌,潛在的攻擊者可以透過 JavaScript(JS)讀取和修改訊息,而帶有 httpOnly 屬性的 cookie 只會傳送到伺服器,客戶端的 JS 無法存取。
但是,您不能為不同的網域設定cookie。如果允許這樣做,將會帶來巨大的安全缺陷。因此,由於您“嘗試將使用者從一個應用程式(網域)重定向到設定了某些cookie 的另一個應用程式(網域),...*”,因此它不會工作,因為cookie 只會被傳送向同一域發出請求。
解 1
如此處所述的解決方案是讓網域(應用程式)A 將使用者重新導向至網域(應用程式)B,並在 URL 中傳遞存取權杖作為查詢參數。然後,網域 B 將讀取令牌並設定自己的 cookie,以便瀏覽器將儲存該 cookie 並將其與每個後續請求一起傳送至網域 B。
請注意,您應該考慮使用安全性 (HTTPS) 通信,以便令牌被加密傳輸,並在建立 cookie 時設定安全標誌。另請注意,在查詢字串中包含令牌會帶來嚴重的安全風險,因為敏感資料永遠不應在查詢字串中傳遞。這是因為作為 URL 一部分的查詢字串出現在瀏覽器的網址列中;因此,允許使用者查看帶有令牌的 URL 並將其添加為書籤(意味著它保存在磁碟上)。此外,該 URL 還將進入瀏覽歷史記錄,這意味著它無論如何都會被寫入磁碟並出現在「歷史記錄」標籤中(按 Ctrl H 查看瀏覽器的歷史記錄)。上述兩種情況都會允許攻擊者(以及與您共用電腦/行動裝置的人)竊取此類敏感資料。此外,許多瀏覽器外掛程式/擴充功能會追蹤使用者的瀏覽活動 - 您造訪的每個 URL 都會傳送到他們的伺服器進行分析,以便偵測惡意網站並提前警告您。因此,在使用以下方法之前,您應該考慮上述所有內容(有關此主題的相關帖子,請參閱此處、此處和此處)。
為了防止在網址列中顯示 URL,請使用下列方法也在網域 B 內使用重新導向。一旦網域 B 收到以令牌作為查詢參數的對 /submit 路由的請求,網域 B 將會重新導向到其中不包含令牌的裸 URL(即其首頁)進行回應。由於此重定向,帶有令牌的 URL 最終不會出現在瀏覽歷史記錄中。雖然這提供了一些針對前面描述的某些攻擊的保護,但這並不意味著瀏覽器擴充功能等仍然無法捕獲帶有令牌的 URL。
如果您正在測試此在本機上,您需要為應用程式B 提供不同的網域名稱;否則,如前所述,cookie 將在具有相同網域的應用程式之間共享,因此,您最終將收到為域A 設定的cookie,並且無法判斷該方法是否有效。為此,您必須編輯 /etc/hosts 檔案(在 Windows 上,該檔案位於 C:WindowsSystem32driversetc 中)並將主機名稱指派給 127.0.0.1。例如:
127.0.0.1 example.test
您不應該將方案或連接埠新增至網域中,也不應該使用常見的副檔名,例如.com、.net等,否則可能會發生衝突存取網路上的其他網站。
存取下方的網域 A 後,您需要按一下提交按鈕對 /submit 路由執行 POST 請求以開始重新導向。 POST 請求的唯一原因是因為您在範例中使用它,並且我假設您必須發布一些表單資料。否則,您也可以使用 GET 請求。在應用程式 B 中,當執行從 POST 路由(即 /submit)到 GET 路由(即 /)的 RedirectResponse 時,回應狀態碼將變更為 status.HTTP_303_SEE_OTHER,如此處、此處和此處所述。應用程式 A 正在偵聽連接埠 8000,而應用程式 B 正在偵聽連接埠 8001。
執行以下兩個應用程序,然後透過 http://127.0.0.1:8000/ 存取網域 A。
appA.py
127.0.0.1 example.test
appB.py
<code class="python">from fastapi import FastAPI, FastAPI from fastapi.responses import RedirectResponse, HTMLResponse import uvicorn app = FastAPI() @app.get('/', response_class=HTMLResponse) def home(): return """" <!DOCTYPE html> <html> <body> <h2>Click the "submit" button to be redirected to domain B</h2> <form method="POST" action="/submit"> <input type="submit" value="Submit"> </form> </body> </html> """ @app.post("/submit") def submit(): token = 'MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3' redirect_url = f'http://example.test:8001/submit?token={token}' response = RedirectResponse(redirect_url) response.set_cookie(key='access-token', value=token, httponly=True) # set cookie for domain A too return response if __name__ == '__main__': uvicorn.run(app, host='0.0.0.0', port=8000)</code>
另一個解決方案是使用Window.postMessage(),它可以實現Window物件之間的跨來源通訊;例如,頁面和它產生的彈出視窗之間,或者頁面和嵌入其中的iframe 之間。有關如何新增事件偵聽器以及如何在視窗之間進行通訊的範例可以在此處找到。遵循的步驟為:
步驟 1: 將隱藏的 iframe 加入到域 A 到域 B。例如:
<code class="python">from fastapi import FastAPI, Request, status from fastapi.responses import RedirectResponse import uvicorn app = FastAPI() @app.get('/') def home(request: Request): token = request.cookies.get('access-token') print(token) return 'You have been successfully redirected to domain B!' \ f' Your access token ends with: {token[-4:]}' @app.post('/submit') def submit(request: Request, token: str): redirect_url = request.url_for('home') response = RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER) response.set_cookie(key='access-token', value=token, httponly=True) return response if __name__ == '__main__': uvicorn.run(app, host='0.0.0.0', port=8001)</code>
步驟 2 : 一旦您從
取得授權令牌以上是如何在網域之間重定向並設定 Cookie 或標頭?的詳細內容。更多資訊請關注PHP中文網其他相關文章!