説明
アップロードされたファイルを検証しなかったり、その内容をHTMLとして配信したりすると、攻撃者がスクリプトを含むファイルをアップロードして実行させるおそれがあります。
想定される影響
- 保存型XSS、悪意のあるファイルの配布、コンテンツタイプの混同につながる可能性があります。
対処方法
ファイルのサイズ、拡張子、MIMEタイプ、保存場所を検証し、アップロードされたファイルは安全なコンテンツタイプで配信してください。
例
変更前
csharp
using Microsoft.AspNetCore.Mvc;
public sealed class UploadController : Controller
{
public IActionResult View(string id)
{
var fileBytes = System.IO.File.ReadAllBytes("/tmp/uploads/" + id);
return File(fileBytes, "text/html");
}
}
変更後
csharp
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.IO;
using System.Threading.Tasks;
public sealed class UploadController : Controller
{
public async Task<IActionResult> Upload([FromForm] IFormFile file)
{
if (file.Length is <= 0 or > 1_048_576) return BadRequest();
if (!string.Equals(
Path.GetExtension(file.FileName), ".txt",
StringComparison.OrdinalIgnoreCase)) return BadRequest();
// このパスと親ディレクトリには、サービスだけが書き込めるようにしてください。
var uploadRoot = Path.GetFullPath("/var/lib/app/uploads");
Directory.CreateDirectory(uploadRoot);
var storedName = $"{Guid.NewGuid():N}.txt";
var destination = Path.Combine(uploadRoot, storedName);
await using var output = new FileStream(
destination, FileMode.CreateNew, FileAccess.Write, FileShare.None);
await file.CopyToAsync(output);
return Accepted(new { id = storedName });
}
}
解説:
- 変更前: アップロードされたファイルを検証せずに保存し、HTMLとして配信すると、含まれるスクリプトがブラウザーで実行されるおそれがあります。
- 変更後: サイズと許可する拡張子を制限し、クライアントのファイル名の代わりにサーバーが生成した名前を使って、Webルートの外に新しいファイルだけを作成します。実際のサービスでは内容に基づく形式の検証とマルウェア検査も追加し、ダウンロード時に実行可能なHTMLのMIMEタイプで配信しないでください。