Files
FileShare_Website/Download.aspx.cs
T
2026-09-24 12:38:47 +00:00

342 lines
8.3 KiB
C#

using System;
using System.IO;
using System.Security;
using System.Web;
using System.Web.UI;
namespace FileSharePortal
{
public partial class Download : Page
{
private const string ShareRoot =
@"\\LAN-DC1\Fileshare";
protected void Page_Load(
object sender,
EventArgs e)
{
/*
* Kein Caching.
*/
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;
}
/*
* Die Datei muss existieren.
*/
if (!File.Exists(physicalPath))
{
Response.StatusCode = 404;
CompleteResponse();
return;
}
/*
* ====================================================
* ZUGRIFF DES AKTUELL ANGEMELDETEN BENUTZERS PRÜFEN
* ====================================================
*
* Wegen
*
* <identity impersonate="true" />
*
* läuft dieser Zugriff unter dem angemeldeten
* AD-Benutzer.
*/
try
{
using (
FileStream stream =
new FileStream(
physicalPath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite |
FileShare.Delete))
{
/*
* Datei erfolgreich geöffnet.
*
* Es wird hier absichtlich nichts gelesen.
* Das Öffnen reicht als Berechtigungsprüfung.
*/
}
}
catch (UnauthorizedAccessException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
catch (IOException)
{
Response.StatusCode = 403;
CompleteResponse();
return;
}
/*
* ====================================================
* DOWNLOAD AUSLIEFERN
* ====================================================
*/
string fileName =
Path.GetFileName(
physicalPath);
string encodedFileName =
Uri.EscapeDataString(
fileName);
string contentType =
MimeMapping.GetMimeMapping(
physicalPath);
Response.Clear();
Response.Buffer = true;
Response.ContentType =
contentType;
/*
* UTF-8-Dateiname.
*
* Funktioniert auch für:
*
* Müller.pdf
* Änderungen.docx
* Köln.xlsx
* Rechnung März 2026.pdf
*/
Response.AddHeader(
"Content-Disposition",
"attachment; filename*=UTF-8''" +
encodedFileName
);
/*
* Dateigröße setzen.
*/
FileInfo fileInfo =
new FileInfo(
physicalPath);
Response.AddHeader(
"Content-Length",
fileInfo.Length.ToString()
);
/*
* Datei übertragen.
*/
Response.TransmitFile(
physicalPath);
CompleteResponse();
}
/*
* ========================================================
* SICHEREN DATEIPFAD ERMITTELN
* ========================================================
*/
private string GetSafePhysicalFilePath(
string relativePath)
{
/*
* URL-Decoding.
*/
string decoded =
HttpUtility.UrlDecode(
relativePath);
/*
* URL-Pfade in Windows-Pfade umwandeln.
*/
decoded =
decoded.Replace(
'/',
'\\');
/*
* Keine absoluten Pfade erlauben.
*
* Verboten wären z.B.:
*
* \Windows\System32
* C:\...
* \\Server\Share
*/
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();
}
}
/*
* Vollständigen Dateipfad erzeugen.
*/
string fullPath =
Path.GetFullPath(
Path.Combine(
ShareRoot,
decoded));
/*
* Root normalisieren.
*/
string normalizedRoot =
Path.GetFullPath(
ShareRoot)
.TrimEnd('\\') +
"\\";
/*
* Der Pfad MUSS unterhalb von
* \\LAN-DC1\Fileshare bleiben.
*/
if (
!fullPath.StartsWith(
normalizedRoot,
StringComparison.OrdinalIgnoreCase))
{
throw new SecurityException();
}
/*
* Datei muss existieren.
*/
if (!File.Exists(fullPath))
{
throw new FileNotFoundException();
}
return fullPath;
}
/*
* ========================================================
* RESPONSE BEENDEN
* ========================================================
*
* Kleine Hilfsmethode, damit Response.End()
* nicht unnötig in mehreren Stellen steht.
*/
private void CompleteResponse()
{
HttpContext.Current.ApplicationInstance
.CompleteRequest();
}
}
}