Dateien nach "/" hochladen
This commit is contained in:
1 parent
a50893a9b3
commit
9f73c84805
3 files changed
+548
No files matched your search
+471
@@ -0,0 +1,471 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<%@ Page
|
||||||
|
Language="C#"
|
||||||
|
ResponseEncoding="utf-8"
|
||||||
|
ContentType="text/html; charset=utf-8"
|
||||||
|
AutoEventWireup="true"
|
||||||
|
CodeFile="View.aspx.cs"
|
||||||
|
Inherits="FileSharePortal.View"
|
||||||
|
%>
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<system.web>
|
||||||
|
|
||||||
|
<!-- ASP.NET Framework-Version -->
|
||||||
|
<compilation debug="false" targetFramework="4.8" />
|
||||||
|
|
||||||
|
<httpRuntime targetFramework="4.8" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
IIS authentifiziert den Benutzer per Basic Authentication.
|
||||||
|
|
||||||
|
ASP.NET verwendet die Windows-Identität für die Anwendung.
|
||||||
|
-->
|
||||||
|
<authentication mode="Windows" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ASP.NET läuft unter dem authentifizierten Benutzer.
|
||||||
|
Dadurch greifen die NTFS-/Share-Berechtigungen dieses Benutzers
|
||||||
|
auch beim Zugriff auf \\LAN-DC1\Fileshare.
|
||||||
|
-->
|
||||||
|
<identity impersonate="true" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Nicht authentifizierte Benutzer dürfen das Portal nicht aufrufen.
|
||||||
|
-->
|
||||||
|
<authorization>
|
||||||
|
<deny users="?" />
|
||||||
|
</authorization>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Zeichencodierung.
|
||||||
|
requestEncoding, responseEncoding und fileEncoding
|
||||||
|
gehören in den globalization-Abschnitt.
|
||||||
|
-->
|
||||||
|
<globalization requestEncoding="utf-8" responseEncoding="utf-8" fileEncoding="utf-8" culture="de-DE" uiCulture="de-DE" />
|
||||||
|
|
||||||
|
</system.web>
|
||||||
|
|
||||||
|
|
||||||
|
<system.webServer>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Default.aspx ist die Startseite des ASP.NET-Portals.
|
||||||
|
-->
|
||||||
|
<defaultDocument enabled="true">
|
||||||
|
|
||||||
|
<files>
|
||||||
|
|
||||||
|
<clear />
|
||||||
|
|
||||||
|
<add value="Default.aspx" />
|
||||||
|
|
||||||
|
</files>
|
||||||
|
|
||||||
|
</defaultDocument>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Das Portal verwendet seine eigene Dateiansicht.
|
||||||
|
IIS Directory Browsing soll hier nicht verwendet werden.
|
||||||
|
-->
|
||||||
|
<directoryBrowse enabled="false" />
|
||||||
|
|
||||||
|
</system.webServer>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
Reference in new issue
Block a user