Control Access to Server Files
- 6 minutes to read
To prevent unauthorized access to files/folders stored on a server, you should follow industry-accepted best practices including the following:
Validate File Paths
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);
}
Protect Temporary Files
To ensure uploaded temporary files are inaccessible to third parties, you should:
- Store temporary files in a folder inaccessible by URL.
- Use a dedicated file extension for temporary files.
- Call the GetRandomFileName method to assign random file names to uploaded files.
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);
}
Protect Thumbnails
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:
- A threat actor can access private thumbnails if these thumbnails are in a public folder.
- If you change the RootFolder property value dynamically, multiple thumbnails can use the same relative path and file name. In this instance, the control may display incorrect thumbnails.
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);
}
Restrict Access to Files and Folders
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:
- Specify only one permission in an access rule object.
- Access rule order corresponds to rule order in the
AccessRules
collection. - An access rule with a higher index has a higher priority and can override a preceding rule.
- Security permissions are prioritized over access rules if they affect the same file or folder.
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.