上週為了讓同事拉一份檔案,我在測試機上把 IIS 專案資料夾開了個進階共用。東西傳完後我把共用關掉,繼續回頭改別的東西。

十分鐘後測試站同事回訊息:整個網站 HTTP 401,連 /favicon.ico 都打不開。

我第一個念頭是「我剛剛根本沒動 web.config 啊?」然後花了半小時繞遠路——這篇就是想分享這個坑,因為症狀跟原因之間的距離遠到不合理。

症狀

  • 瀏覽器吃到 401 Unauthorized
  • 連 CSS、圖片這類靜態檔都 401
  • IIS 沒有動過站點設定
  • 專案程式碼沒動過
  • App Pool 跑得好好的,沒當機、沒停
  • 重啟 IIS 沒用

翻開 IIS 記錄(C:\inetpub\logs\LogFiles\W3SVC...),關鍵那行:

1
2
sc-status: 401
sc-substatus: 3

401.3 的官方說明是 「Access is denied due to an ACL set on the requested resource」——翻譯:這不是 IIS 驗證設定的問題,是 NTFS 層級擋下來的。

我第一個走錯的方向

本能反應是去翻 App Pool 的 Identity。一講到「IIS 權限」,多數人腦中先跳出來的就是 IIS AppPool\網站名稱 這個虛擬帳號。

我還真的去 D:\Sites\YilanSewearV3 右鍵按屬性確認 IIS AppPool\YilanSewearV3 是不是被動到——在啊,好端端地躺在 ACL 裡。

一開始就搞錯抓誰了。

真正的犯人:IUSR 從 ACL 裡消失了

重新看一次屬性頁,才發現 IUSR 那一列整排不見了。

這個帳號我平常從來沒特別記過,存在感為零——直到它消失的那一刻才想起來:**IIS 站台預設開著 Anonymous Authentication,而這個匿名驗證預設用來檢查 NTFS 權限的身份就是 IUSR**(這個預設值其實可以改成 App Pool Identity,但多數情況沒人會去動它)。

靜態檔都讀不到,網站還沒跑到動態那一層就 401 了,完全合理。

修復(一行搞定)

1
icacls "D:\Sites\YilanSewearV3" /grant "IUSR:(OI)(CI)RX" /T

參數意思:

  • /grant "IUSR:...":授權給 IUSR
  • (OI) Object Inherit:子檔案繼承
  • (CI) Container Inherit:子資料夾繼承
  • RX:Read & Execute
  • /T:套到所有現存子目錄

跑完立刻活過來。

取消共用的副作用:一個我找不到官方答案的現象

老實說這段是我第二天補功課也沒完全搞清楚的部分。進階共用在開啟時會動到 NTFS ACL 這件事有跡可循;但關閉共用那一刻 IUSR 為什麼會連帶被掃掉,我在 Microsoft 官方文件裡翻不到明確說明。

我能講的只有實測:在同一台機器上另開測試資料夾跑了兩次(加 IUSR → 開進階共用 → 關共用),IUSR 都被清掉。所以這段請當成可重現的現象,不是已被官方定義的固定行為。IUSR 跟 SMB 共用其實完全沒關係,卻在這個過程裡被無辜波及——反覆踩過幾次之後我決定乖乖記下來。如果你在其他 Windows 版本上看到不一樣的結果,歡迎留言補充。

一次講清楚兩個常被搞混的身份

這次踩坑的根因,是我一開始沒把 IIS 的兩個身份分清楚:

帳號 什麼時候出場
IUSR 匿名驗證下,讀靜態檔案(HTML / CSS / JS / 圖片)的身份
IIS AppPool\你的網站名 執行動態程式碼(.NET、Node)、存資料庫、寫 log 用的身份

很多人(包括當下的我)會以為既然 App Pool 代表一個網站,那所有檔案 I/O 都會用 App Pool 的身份去檢查權限——實際上不是。更精準的說法是:請求仍是在該站台所屬 App Pool 的 worker process(w3wp.exe)裡處理,但在匿名驗證情境下,IIS 對檔案做 ACL 檢查時用的是匿名身份(預設就是 IUSR),而不是 process identity 本身。

這是 IIS 裡「process identity」跟「impersonated identity」分成兩條線看的典型例子——同一個 worker 跑,但對外存取資源時被「代換」成另一個身份。

所以下次遇到類似狀況,判準是:

  • 純靜態資源 401 → 先懷疑 IUSR
  • 靜態檔正常、動態頁面讀不到 DB / 寫不了 log → 再去翻 App Pool

兩條線分開查,少繞很多路。

下次我會怎麼做

正式機上的 IIS 專案資料夾,我不會再隨手開共用了。要交一份檔案給人,用 robocopy 或直接打包成 zip 都比開共用乾淨——沒有副作用、沒有權限被動到。

真的非開不可,關掉共用之後我會直接習慣性跑一次:

1
icacls "D:\Sites\專案名" | findstr "IUSR IIS_IUSRS"

確認兩個帳號都還在再走人。這個檢查花三秒,比下次再卡在 sc-substatus 3 跟 App Pool 之間繞半小時划算太多。