aspnet-404858-security-considerations-file-upload-control-access-to-server-files.md
To prevent unauthorized access to files/folders stored on a server, you should follow industry-accepted best practices including the following:
Always validate file paths that include untrusted file or folder names. Do not trust user entered file/folder names as this can generate a path outside the upload folder when combining file names with the upload folder path.
The following example validates uploaded file paths:
<dx:ASPxUploadControl ID="UploadControl" runat="server" ShowUploadButton="True"
OnFileUploadComplete="FileUploadComplete">
</dx:ASPxUploadControl>
protected void FileUploadComplete(object sender, DevExpress.Web.FileUploadCompleteEventArgs e) {
string uploadFolder = "~/App_Data/UploadFiles/";
string fileName = Path.Combine(uploadFolder, e.UploadedFile.FileName);
if (e.IsValid && IsValidVirtualPath(fileName, uploadFolder)) {
e.UploadedFile.SaveAs(Server.MapPath(fileName), true);
}
}
bool IsValidVirtualPath(string sourceVirtualPath, string folderVirtualPath) {
var sourceFullPath = Server.MapPath(sourceVirtualPath);
return IsValidFullPath(sourceFullPath, folderVirtualPath);
}
bool IsValidFullPath(string sourceFullPath, string folderVirtualPath) {
var folderFullPath = Server.MapPath(folderVirtualPath);
if (sourceFullPath.EndsWith(@"\"))
sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1);
if (folderFullPath.EndsWith(@"\"))
folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1);
return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
|| sourceFullPath.StartsWith(folderFullPath + @"\", StringComparison.OrdinalIgnoreCase);
}
Protected Sub FileUploadComplete(ByVal sender As Object, ByVal e As DevExpress.Web.FileUploadCompleteEventArgs)
Dim uploadFolder As String = "~/App_Data/UploadFiles/"
Dim fileName As String = Path.Combine(uploadFolder, e.UploadedFile.FileName)
If e.IsValid AndAlso IsValidVirtualPath(fileName, uploadFolder) Then
e.UploadedFile.SaveAs(Server.MapPath(fileName), True)
End If
End Sub
Function IsValidVirtualPath(ByVal sourceVirtualPath As String, ByVal folderVirtualPath As String) As Boolean
Dim sourceFullPath = Server.MapPath(sourceVirtualPath)
Return IsValidFullPath(sourceFullPath, folderVirtualPath)
End Function
Private Function IsValidFullPath(ByVal sourceFullPath As String, ByVal folderVirtualPath As String) As Boolean
Dim folderFullPath = Server.MapPath(folderVirtualPath)
If sourceFullPath.EndsWith("\")
Then sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1)
If folderFullPath.EndsWith("\")
Then folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1)
Return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
OrElse sourceFullPath.StartsWith(folderFullPath & "\", StringComparison.OrdinalIgnoreCase)
End Function
To ensure uploaded temporary files are inaccessible to third parties, you should:
The following code sample saves temporary files using industry-accepted best practices:
<dx:ASPxUploadControl ID="UploadControl" runat="server" UploadMode="Advanced" ShowUploadButton="True"
OnFilesUploadComplete="FilesUploadComplete">
<AdvancedModeSettings EnableMultiSelect="True" />
</dx:ASPxUploadControl>
protected void FilesUploadComplete(object sender, DevExpress.Web.FilesUploadCompleteEventArgs e) {
if (UploadControl.UploadedFiles != null && UploadControl.UploadedFiles.Length > 0) {
for (int i = 0; i < UploadControl.UploadedFiles.Length; i++) {
UploadedFile file = UploadControl.UploadedFiles[i];
string uploadFolder = "~/App_Data/UploadFiles/";
if (file.IsValid && file.FileName != "") {
string fileName = Path.Combine(Server.MapPath(uploadFolder), Path.GetRandomFileName() + ".tmp");
if (IsValidFullPath(fileName, uploadFolder)){
file.SaveAs(fileName, true);
// Process the uploaded file here
}
}
}
}
}
bool IsValidFullPath(string sourceFullPath, string folderVirtualPath) {
var folderFullPath = Server.MapPath(folderVirtualPath);
if (sourceFullPath.EndsWith(@"\"))
sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1);
if (folderFullPath.EndsWith(@"\"))
folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1);
return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
|| sourceFullPath.StartsWith(folderFullPath + @"\", StringComparison.OrdinalIgnoreCase);
}
Protected Sub FilesUploadComplete(ByVal sender As Object, ByVal e As DevExpress.Web.FilesUploadCompleteEventArgs)
If UploadControl.UploadedFiles IsNot Nothing AndAlso UploadControl.UploadedFiles.Length > 0 Then
For i As Integer = 0 To UploadControl.UploadedFiles.Length - 1
Dim file As UploadedFile = UploadControl.UploadedFiles(i)
Dim uploadFolder As String = "~/App_Data/UploadFiles/"
If file.IsValid AndAlso file.FileName <> "" Then
Dim fileName As String = Path.Combine(Server.MapPath(uploadFolder), Path.GetRandomFileName() & ".tmp")
If IsValidFullPath(fileName, uploadFolder) Then
file.SaveAs(fileName, True)
' Process the uploaded file here
End If
End If
Next
End If
End Sub
Private Function IsValidFullPath(ByVal sourceFullPath As String, ByVal folderVirtualPath As String) As Boolean
Dim folderFullPath = Server.MapPath(folderVirtualPath)
If sourceFullPath.EndsWith("\")
Then sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1)
If folderFullPath.EndsWith("\")
Then folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1)
Return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
OrElse sourceFullPath.StartsWith(folderFullPath & "\", StringComparison.OrdinalIgnoreCase)
End Function
The DevExpress File Manager automatically creates content-based thumbnails and stores them in the ThumbnailFolder. Subfolder structure is based on the File Manager’s folder structure. Before the File Manager displays a thumbnail for the first time, the control checks for an existing thumbnail with a corresponding path/name. If the thumbnail does not exist, the control generates a new thumbnail file.
Consider the following when using the File Manager:
In multi-user applications or if you dynamically change the root folder, use the ThumbnailFolder property to specify the thumbnail folder dynamically based on the current user.
<dx:ASPxComboBox ID="ComboBox" runat="server" AutoPostBack="True" SelectedIndex="0" DataSecurityMode="Strict">
<Items>
<dx:ListEditItem Text="Common" Value="Common files" Selected="True" />
<dx:ListEditItem Text="User 1" Value="User1" />
<dx:ListEditItem Text="User 2" Value="User2" />
<dx:ListEditItem Text="User 3" Value="User3" />
</Items>
</dx:ASPxComboBox>
<dx:ASPxFileManager ID="FileManager" runat="server">
<Settings RootFolder="~/Content/Common files" ThumbnailFolder="~/Content/Thumbs/Common files" />
</dx:ASPxFileManager>
protected void Page_Load(object sender, EventArgs e) {
string userSubFolder = ComboBox.Value.ToString();
string rootFolder = Path.Combine("~/Content/", userSubFolder);
string thumbnailFolder = Path.Combine("~/Thumbs/", userSubFolder);
bool foldersAreValid = IsValidVirtualPath(rootFolder, "~/Content/")
&& IsValidVirtualPath(thumbnailFolder, "~/Thumbs/");
if (foldersAreValid) {
FileManager.Settings.RootFolder = rootFolder;
FileManager.Settings.ThumbnailFolder = thumbnailFolder;
}
}
bool IsValidVirtualPath(string sourceVirtualPath, string folderVirtualPath) {
var sourceFullPath = Server.MapPath(sourceVirtualPath);
return IsValidFullPath(sourceFullPath, folderVirtualPath);
}
bool IsValidFullPath(string sourceFullPath, string folderVirtualPath) {
var folderFullPath = Server.MapPath(folderVirtualPath);
if (sourceFullPath.EndsWith(@"\"))
sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1);
if (folderFullPath.EndsWith(@"\"))
folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1);
return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
|| sourceFullPath.StartsWith(folderFullPath + @"\", StringComparison.OrdinalIgnoreCase);
}
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim userSubFolder As String = ComboBox.Value.ToString()
Dim rootFolder As String = Path.Combine("~/Content/", userSubFolder)
Dim thumbnailFolder As String = Path.Combine("~/Thumbs/", userSubFolder)
Dim foldersAreValid As Boolean = IsValidVirtualPath(rootFolder, "~/Content/")
AndAlso IsValidVirtualPath(thumbnailFolder, "~/Thumbs/")
If foldersAreValid Then
FileManager.Settings.RootFolder = rootFolder
FileManager.Settings.ThumbnailFolder = thumbnailFolder
End If
End Sub
Function IsValidVirtualPath(ByVal sourceVirtualPath As String, ByVal folderVirtualPath As String) As Boolean
Dim sourceFullPath = Server.MapPath(sourceVirtualPath)
Return IsValidFullPath(sourceFullPath, folderVirtualPath)
End Function
Private Function IsValidFullPath(ByVal sourceFullPath As String, ByVal folderVirtualPath As String) As Boolean
Dim folderFullPath = Server.MapPath(folderVirtualPath)
If sourceFullPath.EndsWith("\")
Then sourceFullPath = sourceFullPath.Substring(0, sourceFullPath.Length - 1)
If folderFullPath.EndsWith("\")
Then folderFullPath = folderFullPath.Substring(0, folderFullPath.Length - 1)
Return sourceFullPath.Equals(folderFullPath, StringComparison.OrdinalIgnoreCase)
OrElse sourceFullPath.StartsWith(folderFullPath & "\", StringComparison.OrdinalIgnoreCase)
End Function
The File Manager allows you to specify access rules and security permissions for files/folders. A folder access rule affects the folder, its subfolders, and files. A file access rule affects all files whose path matches a specified pattern. Unlike access rules, each security permission affects an individual file or folder and allows you to implement complex user access logic.
Use the SettingsPermissions.AccessRules property to specify access rules and apply appropriate security permissions. Note the following:
AccessRules collection.The following example restricts editing operations for the entire file system:
<dx:ASPxFileManager ID="FileManager" runat="server">
<SettingsPermissions>
<AccessRules>
<dx:FileManagerFolderAccessRule Edit="Deny" />
<dx:FileManagerFileAccessRule PathPattern="*" Download="Deny" />
</AccessRules>
</SettingsPermissions>
</dx:ASPxFileManager>
Refer to the following topics for additional information/guidance: Access Rules and Permissions.
See Also