Files
2026-11-09 15:02:34 +01:00

471 lines
11 KiB
C#
Executable File

using System;
using System.IO;
using System.Security;
using System.Web;
using System.Web.UI;
namespace FileSharePortal
{
public partial class View : Page
{
private const string ShareRoot =
@"\\LAN-DC1\Fileshare";
protected void Page_Load(
object sender,
EventArgs e)
{
Response.Cache.SetCacheability(
HttpCacheability.NoCache);
Response.Cache.SetNoStore();
string relativePath =
Request.QueryString["path"];
if (string.IsNullOrWhiteSpace(relativePath))
{
Response.StatusCode = 400;
CompleteResponse();
return;
}
string physicalPath;
try
{
physicalPath =
GetSafePhysicalFilePath(
relativePath);
}
catch (UnauthorizedAccessException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
catch (SecurityException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
catch (FileNotFoundException)
{
Response.StatusCode = 404;
CompleteResponse();
return;
}
catch (DirectoryNotFoundException)
{
Response.StatusCode = 404;
CompleteResponse();
return;
}
catch
{
Response.StatusCode = 400;
CompleteResponse();
return;
}
if (!File.Exists(physicalPath))
{
Response.StatusCode = 404;
CompleteResponse();
return;
}
/*
* ====================================================
* BERECHTIGUNG PRÜFEN
* ====================================================
*
* Durch ASP.NET Impersonation läuft der Zugriff
* unter dem angemeldeten AD-Benutzer.
*/
try
{
using (
FileStream stream =
new FileStream(
physicalPath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite |
FileShare.Delete))
{
}
}
catch (UnauthorizedAccessException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
catch (IOException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
string extension =
Path.GetExtension(
physicalPath)
.ToLowerInvariant();
string fileName =
Path.GetFileName(
physicalPath);
/*
* ====================================================
* MIME-TYP
* ====================================================
*/
string contentType =
GetContentType(
extension);
/*
* ====================================================
* INLINE ODER DOWNLOAD
* ====================================================
*
* Nur ausdrücklich erlaubte Dateitypen werden
* inline angezeigt.
*
* Alles andere wird als Download behandelt.
*/
bool inline =
IsInlineType(extension);
Response.Clear();
Response.Buffer = false;
Response.ContentType =
contentType;
/*
* UTF-8-Dateiname.
*/
string encodedFileName =
Uri.EscapeDataString(
fileName);
if (inline)
{
Response.AddHeader(
"Content-Disposition",
"inline; filename*=UTF-8''" +
encodedFileName);
}
else
{
Response.AddHeader(
"Content-Disposition",
"attachment; filename*=UTF-8''" +
encodedFileName);
}
FileInfo fileInfo =
new FileInfo(
physicalPath);
Response.AddHeader(
"Content-Length",
fileInfo.Length.ToString());
/*
* Datei ohne komplettes Einlesen in den
* Arbeitsspeicher übertragen.
*/
Response.TransmitFile(
physicalPath);
CompleteResponse();
}
/*
* ========================================================
* INLINE DATEITYPEN
* ========================================================
*/
private bool IsInlineType(
string extension)
{
switch (extension)
{
/*
* PDF
*/
case ".pdf":
/*
* Bilder
*/
case ".jpg":
case ".jpeg":
case ".png":
case ".gif":
case ".webp":
case ".bmp":
case ".ico":
/*
* Text
*/
case ".txt":
case ".log":
case ".csv":
case ".json":
case ".xml":
/*
* Audio
*/
case ".mp3":
case ".wav":
case ".ogg":
/*
* Video
*/
case ".mp4":
case ".webm":
case ".ogv":
return true;
/*
* Alles andere herunterladen.
*
* Insbesondere:
*
* DOC
* DOCX
* XLS
* XLSX
* PPT
* PPTX
* ZIP
* EXE
* MSI
*
* usw.
*/
default:
return false;
}
}
/*
* ========================================================
* MIME TYPES
* ========================================================
*/
private string GetContentType(
string extension)
{
switch (extension)
{
case ".pdf":
return "application/pdf";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".png":
return "image/png";
case ".gif":
return "image/gif";
case ".webp":
return "image/webp";
case ".bmp":
return "image/bmp";
case ".ico":
return "image/x-icon";
/*
* Text-Dateien bewusst als text/plain
* behandeln.
*
* Dadurch werden z.B. HTML-Inhalte nicht
* als HTML ausgeführt.
*/
case ".txt":
case ".log":
case ".csv":
case ".json":
case ".xml":
return "text/plain; charset=utf-8";
case ".mp3":
return "audio/mpeg";
case ".wav":
return "audio/wav";
case ".ogg":
return "audio/ogg";
case ".mp4":
return "video/mp4";
case ".webm":
return "video/webm";
case ".ogv":
return "video/ogg";
default:
return MimeMapping.GetMimeMapping(
"file" + extension);
}
}
/*
* ========================================================
* SICHEREN DATEIPFAD ERMITTELN
* ========================================================
*/
private string GetSafePhysicalFilePath(
string relativePath)
{
string decoded =
HttpUtility.UrlDecode(
relativePath);
decoded =
decoded.Replace(
'/',
'\\');
/*
* Keine absoluten Pfade.
*/
if (
decoded.StartsWith("\\") ||
decoded.Contains(":"))
{
throw new SecurityException();
}
/*
* Path Traversal verhindern.
*/
string[] parts =
decoded.Split(
new[] { '\\' },
StringSplitOptions.RemoveEmptyEntries);
foreach (
string part
in parts)
{
if (
part == "." ||
part == "..")
{
throw new SecurityException();
}
}
string fullPath =
Path.GetFullPath(
Path.Combine(
ShareRoot,
decoded));
string normalizedRoot =
Path.GetFullPath(
ShareRoot)
.TrimEnd('\\') +
"\\";
/*
* Der Pfad darf ausschließlich unterhalb
* unseres Shares liegen.
*/
if (
!fullPath.StartsWith(
normalizedRoot,
StringComparison.OrdinalIgnoreCase))
{
throw new SecurityException();
}
if (!File.Exists(fullPath))
{
throw new FileNotFoundException();
}
return fullPath;
}
private void CompleteResponse()
{
HttpContext.Current
.ApplicationInstance
.CompleteRequest();
}
}
}