首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Core / MVC 圖片上傳完整實作:驗證、命名、儲存與安全防護

     編輯:ASP.NET 基礎

功能需求

  • 支援單檔上傳 (HTTP POST)
  • 限制副檔名:.png、.gif、.jpg、.jpeg
  • 限制檔案大小:不超過 500 KB
  • 自動產生唯一檔名避免衝突:時間戳 + 隨機數 + 原副檔名
  • 自動建立上傳目錄
  • 回傳 JSON 格式結果:成功回傳檔名,失敗回傳錯誤訊息

控制器實作

[HttpPost]
public async Task<IActionResult> UploadImage(IFormFile uploadFile)
{
    // 1. 基本防禦性檢查
    if (uploadFile == null || uploadFile.Length == 0)
        return Json(new { success = false, message = "未收到檔案" });

    // 2. 副檔名驗證 (不區分大小寫)
    string fileExt = Path.GetExtension(uploadFile.FileName).ToLowerInvariant();
    string[] allowedExts = { ".png", ".gif", ".jpg", ".jpeg" };
    if (!allowedExts.Contains(fileExt))
        return Json(new { success = false, message = "圖片類型僅限 gif、png、jpg、jpeg" });

    // 3. 檔案大小驗證 (500 KB = 512,000 bytes)
    const long maxSize = 500 * 1024;
    if (uploadFile.Length > maxSize)
        return Json(new { success = false, message = "圖片大小不能超過 500 KB" });

    // 4. 產生唯一檔名:yyyyMMddHHmmss + 6位隨機數 + 副檔名
    string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
    string randomPart = RandomNumberGenerator.GetInt32(100000, 999999).ToString();
    string saveFileName = $"{timestamp}{randomPart}{fileExt}";

    // 5. 確保目錄存在
    string uploadFolder = Path.Combine(_hostEnvironment.WebRootPath, "UploadImages");
    if (!Directory.Exists(uploadFolder))
        Directory.CreateDirectory(uploadFolder);

    string savePath = Path.Combine(uploadFolder, saveFileName);

    try
    {
        // 6. 非同步儲存檔案
        using (var stream = new FileStream(savePath, FileMode.Create))
        {
            await uploadFile.CopyToAsync(stream);
        }

        // 7. 回傳成功結果 (可擴充回傳相對路徑供前端預覽)
        return Json(new { success = true, fileName = saveFileName, url = $"/UploadImages/{saveFileName}" });
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "圖片上傳失敗");
        return Json(new { success = false, message = "伺服器內部錯誤,請稍後再試" });
    }
}

前端呼叫範例 (jQuery AJAX)

<form id="uploadForm" enctype="multipart/form-data">
    <input type="file" name="uploadFile" id="fileInput" accept="image/*" />
    <button type="button" id="btnUpload">上傳</button>
</form>
<div id="preview" style="margin-top:10px;"></div>

<script>
$('#btnUpload').click(function() {
    var file = $('#fileInput')[0].files[0];
    if (!file) return alert('請選擇檔案');

    var formData = new FormData();
    formData.append('uploadFile', file);

    $.ajax({
        url: '/Home/UploadImage',
        type: 'POST',
        data: formData,
        processData: false,
        contentType: false,
        success: function(res) {
            if (res.success) {
                $('#preview').html(`<img src="${res.url}" style="max-width:300px;" /><br>檔名: ${res.fileName}`);
            } else {
                alert('上傳失敗:' + res.message);
            }
        },
        error: function() { alert('網路錯誤'); }
    });
});
</script>

安全性強化建議 (生產環境必做)

🛡️ 關鍵防護措施

  1. MIME Type 二次驗證:不要只信任副檔名,讀取檔案 Header (Magic Bytes) 確認真實格式
    // 簡易 PNG/JPEG/GIF Magic Bytes 檢查
    byte[] header = new byte[8];
    await uploadFile.OpenReadStream().ReadAsync(header, 0, 8);
    bool isValid = header.Take(4).SequenceEqual(new byte[]{0x89,0x50,0x4E,0x47}) || // PNG
                   header.Take(2).SequenceEqual(new byte[]{0xFF,0xD8}) ||             // JPEG
                   header.Take(6).SequenceEqual(new byte[]{0x47,0x49,0x46,0x38,0x37,0x61}) || // GIF87a
                   header.Take(6).SequenceEqual(new byte[]{0x47,0x49,0x46,0x38,0x39,0x61});    // GIF89a
  2. 禁用執行權限:上傳目錄在 IIS 設定「執行權限 = 無」或放在 WebRoot 外部
  3. 檔案重命名:絕對不要使用原始檔名,防止路徑遍歷攻擊
  4. 病毒掃描整合:整合 ClamAV 或商業反病毒 API 掃描上傳檔案
  5. 大小限制在伺服器層:web.config 設定 <requestLimits maxAllowedContentLength="524288" /> (500KB)
  6. CSRF 保護:加入 AntiForgeryToken 驗證

擴充方向

  • 支援多檔上傳 (IFormFileCollection)
  • 圖片壓縮/縮圖生成 (引用 ImageSharp 或 SkiaSharp)
  • 雲端儲存整合 (Azure Blob、AWS S3、阿里云 OSS)
  • 資料庫記錄上傳日誌 (檔名、大小、上傳者、IP、時間)
  • 臨時檔案自動清理排程
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved