使用 POST 請求更新 IIS 端檔案 - 極簡做法
| | | 2 | |
先說我的需求:我在 IIS 有個 HTML 靜態網頁,任務是載入資料檔 JSON 提供統計資料互動式查詢。當資料有更新,受限於防火牆無法用 SFTP、SCP 或網路資料夾直接更新,需靠 RDP 登入再複製貼上,一來麻煩,二來無法自動化。
近期更新頻率變高,對重複手工操作忍耐度極低的我,就想在 IIS 上寫支小程式,支援以 HTTP POST 請求進行更新,讓更新作業可以自動化並從 1 分鐘縮短到 1 秒。
程式不難寫,重點在怎麼做到簡單又安全,以下是我想到的極簡版本,一個 .aspx 檔案打死,開箱即用,並提供最基本的安全防護:
<%@Page Language="C#"%>
<script runat="server">
// 來源 IP 檢查
static string[] allowedIPs = new string[] {
"::1", "127.0.0.1"
}
// 警告:請確認路徑為資料區之非可執行檔案,且不會因覆寫惡意內容導致風險,若無法確認安全性,請勿使用
// 註:Key 建議使用 GUID 等隨機唯一值,防止被暴力猜測覆寫
string dataFolder() => Server.MapPath("~/PostUpdate/Data");
static Dictionary<string, string> jsonPathMap = new Dictionary<string, string>() {
{ "93490a37-e6a0-4bf7-af75-2dfd882cd901", "test1.json" },
{ "a98589cc-cbe1-4ce4-8db7-0f2f292932f1", "test2.json" },
{ "3f47c425-e555-47a7-9022-debd6808ad12", "test3.json" }
};
protected void Page_Load(object sender, EventArgs e)
{
var key = Request["f"];
if (!allowedIPs.Contains(Request.UserHostAddress) ||
Request.HttpMethod != "POST" ||
string.IsNullOrEmpty(key) || !jsonPathMap.ContainsKey(key))
{
// 非允許 IP、非 POST 請求、缺少或無效的 key 都返回 404,降低網址洩漏風險
Response.StatusCode = 404; //
return;
}
var jsonPath = jsonPathMap[key];
try
{
System.IO.Directory.CreateDirectory(dataFolder()); // 確保資料夾存在
var fullPath = System.IO.Path.Combine(dataFolder(), jsonPath);
using (var reader = new System.IO.StreamReader(Request.InputStream))
{
var jsonContent = reader.ReadToEnd();
System.IO.File.WriteAllText(fullPath, jsonContent);
}
Response.StatusCode = 200; // OK
}
catch (Exception ex)
{
Response.StatusCode = 500; // Internal Server Error
Response.Write(ex.Message);
}
}
</script>
上面這個 UpdateJson.aspx 程式只有 50 行,不需要編譯及第三方程式庫,丟到 IIS 網站即可運行,用 PowerShell 或 curl 寫一行程式便能遠端更新資料檔。身為開發老鳥,知道這類上傳檔案寫入網站的方便功能,一旦被誤用極度危險,甚至有被滅門屠城的可能,所以我加了幾道安全防護:
- 限定上傳客戶端 IP 來源
- 限 POST 存取,防止即興修改瀏覽器 URL 探測網址
- 只能更新預先列舉路徑的檔案 (警告:此為開發天條,禁止客戶端自由指定讀寫路徑,一旦疏忽可能被屠城!)
- 需傳入 GUID 對映更新目標,防止暴力猜測
- 以上檢核未過時一律回傳 HTTP 404,降低更新介面曝露風險
以下是用 PowerShell 程式的驗證測試:
$data = Get-Date -Format "ssfff";
$f = New-Guid
try {
Invoke-WebRequest -Uri "http://localhost/AspNet/PostUpdate/UpdateJson.aspx?f=$f" -Method GET
}
catch {
# 使用 GET
if ($_.Exception.Response.StatusCode -eq 404) {
Write-Host "PASS: Not Found (404)" -ForegroundColor Green
}
else {
Write-Error "An error occurred: $($_.Exception.Message)"
}
}
try {
Invoke-WebRequest -Uri "http://localhost/AspNet/PostUpdate/UpdateJson.aspx?f=$f" -Method POST -Body $data | Out-Null
}
catch {
# GUID 不對
if ($_.Exception.Response.StatusCode -eq 404) {
Write-Host "PASS: Not Found (404)" -ForegroundColor Green
}
else {
Write-Error "An error occurred: $($_.Exception.Message)"
}
}
$f = '93490a37-e6a0-4bf7-af75-2dfd882cd901'
try {
$data = $data + "-PS"
Invoke-WebRequest -Uri "http://localhost/AspNet/PostUpdate/UpdateJson.aspx?f=$f" -Method POST -Body $data | Out-Null
Write-Host "PASS: Successfully updated by Invoke-WebRequest" -ForegroundColor Green
Get-Content ".\Data\test1.json" | Write-Host
# 改用 curl.exe 測試
$data = $data -replace "-PS", "-curl"
$status = & 'curl.exe' -s -o NUL -w "%{http_code}" -X POST --data $data "http://localhost/AspNet/PostUpdate/UpdateJson.aspx?f=$f"
$statusCode = [int]$status
if ($statusCode -eq 200) {
Write-Host "PASS: Successfully updated by curl.exe" -ForegroundColor Green
}
elseif ($statusCode -ge 400) {
Write-Error "An error occurred: HTTP $statusCode"
}
Get-Content ".\Data\test1.json" | Write-Host
}
catch {
Write-Error "An error occurred: $($_.Exception.Message)"
}

分享給有需要的朋友,大家若發現弱點或有強化建議,也歡迎回饋!
Describes a minimal, secure ASP.NET WebForms (.aspx) HTTP POST endpoint on IIS to automate JSON data updates behind a firewall. Uses IP filtering, POST-only access, GUID-based file mapping, and 404 responses to reduce exposure and enable safe automation.
Comments
# by 路過
怎麼不用公私鑰對內容加解密?
# by Jeffrey
to 路過,好奇增加非對稱加密可加強防堵的漏洞為何?