Dateien nach "/" hochladen
This commit is contained in:
commit
a50893a9b3
4 files changed
+2584
No files matched your search
@@ -0,0 +1,342 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user