If I have a web method that deletes a file when called and it accepts three parameters (cNum, year, and fileName). Do I need to be worried about exploits of this method. The only thing I could think of would be using ..\..\..\ to drive the delete further up the folder structure. that should be pretty easy to remove that. But is there anything else that I should be worried about?
[WebMethod(EnableSession = true,
Description = "Method for deleting files uploaded by customers")]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
try
{
if (String.IsNullOrEmpty(cNum)
|| String.IsNullOrEmpty(year)
|| String.IsNullOrEmpty(fileName))
throw new Exception();
string path = Server.MapPath(#"~\docs\custFiles\"
+ year + #"\"
+ cNum + #"\" + fileName);
File.Delete(path);
}
catch
{
throw new Exception("Unable to delete file");
}
return true;
}
I would recommend using the GetFileName method on the Path class to cleanse the filename parameter, like so:
public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
// Cleanse fileName.
fileName = Path.GetFileName(fileName);
The GetFileName method strips all directory information from a path, which is exactly what you want to do here.
With input like:
..\..\..\filename.ext
You would get:
filename.ext
In return, you don't have to worry about someone injecting a path which would escape the directory that you are targeting (assuming that this filename is user-input or from an open endpoint where someone could enter any input they want).
This then allows you to then append your custom path to fileName.
This only works of course if all of your files are in a pre-defined directory, which it seems it is.
This does not however, do anything to handle deleting files that a user doesn't have access to. If the files belong to another user in that directory, then there's no check here to see if that's the case (but if all users have rights to delete these files, then it's ok).
Also, you might want to use the Combine method on the Path class to combine your paths, like so:
string path = Server.MapPath(#"~\docs\custFiles\")
path = Path.Combine(path, year);
path = Path.Combine(path, cNum);
path = Path.Combine(path, fileName);
If you're using .NET 4.0 or above, you can use the overload of the Combine method that takes the parts of the path as a parameter array:
string path = Path.Combine(
Server.MapPath(#"~\docs\custFiles\"),
year, cNum, fileName);
Finally, as Shai points out, if possible (for a complete solution), to make this even more secure you should be enabling permissions on the file-system level.
If you are impersonating the user or using a constrained user account to handle all of the requests, then you should grant that user access to just the ~\docs\custFiles\ directory (and any sub directories).
Anything above that directory the user account should have no access to.
It is a good idea to check the file names and directory names if they are valid file names or not, check them against this char array:
Path.GetInvalidFileNameChars
EDIT:
And you should probably also validate the year and number like this:
bool valid = int.TryParse(num, out temp);
You may also want to consider using built in security on the file system to prevent users from deleting files in unwanted directories. If the web app is running under a specific user that has rights to delete files in only one directory, no matter what the user tries, the app will not have the rights to perform the delete.
In addition, this would make maintenance (ie: adding new directories) pretty easy without redeploying the app.
You could then catch the attempt to access the invalid access attempt and do something with it if you so desire.
[WebMethod(EnableSession = true,
Description = "Method for deleting files uploaded by customers")]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public Boolean deleteCustFiles(string cNum, string year, string fileName)
{
try
{
if (String.IsNullOrEmpty(cNum) || String.IsNullOrEmpty(year) ||
String.IsNullOrEmpty(fileName))
throw new Exception();
string path =
Server.MapPath(#"~\docs\custFiles\" + year + #"\" + cNum +
#"\" + fileName);
File.Delete(path);
}
catch (System.Security.SecurityException e)
{
throw new Exception("Unauthorized attempt to delete file");
}
catch
{
throw new Exception("Unable to delete file");
}
return true;
}
Related
static void SendMail()
{
String SystemErrors = DateTime.Now.ToString("d");
String filepath = #"C:\Windows\Boot\";
string filepath2 = filepath + #"\SystemErrors\somefile.text";
{
if (!Directory.Exists(filepath2))
Directory.CreateDirectory(#"c:\Windows\Boot\SystemErrors\somefile.txt");
if (!File.Exists(filepath2))
File.Create(filepath2);
}
Im trying to create a new folder and file.text, but nothing seems to work.
I don't think you're using the Exists methods correctly.
You must call File.Exists when you want to check if a file exists, and you must provide the path to the file.
Directory.Exists must be called when you want to check if a directory exists, and you must provide the path to the directory.
I have a DirectoryNotFoundException on a .txt file if I use the full path it's working but I don't want to use the full path because I want the program work no matter where it is placed (compatibilty with the maximum of computer)
Here's my code
private void SaveClose_Click(object sender, RoutedEventArgs e)
{
if (Windowed.IsChecked == true)
windowed = true;
else
windowed = false;
string textWriteWindowed;
if (windowed == true)
{
textWriteWindowed = "-screen-fullscreen 0" + Environment.NewLine;
}
else
{
textWriteWindowed = "-screen-fullscreen 1" + Environment.NewLine;
}
var selectedResolution = ResolutionBox.SelectedItem.ToString();
var split = selectedResolution.Split('x');
widthChoose = Int32.Parse(split[0]);
heightChoose = Int32.Parse(split[1]);
string textWriteWidth;
textWriteWidth = "-screen-width " + widthChoose + Environment.NewLine;
string textWriteHeight;
textWriteHeight = "-screen-height " + heightChoose + Environment.NewLine;
File.WriteAllText(#"\Resources\arguments.txt", textWriteWindowed);
File.AppendAllText(#"\Resources\arguments.txt", textWriteWidth);
File.AppendAllText(#"\Resources\arguments.txt", textWriteHeight);
this.Close();
}
The first argument of File.WriteAllText takes a path as input. Whatever you have mentioned is not the absolute path but it is just the relative path of the file. WriteAllText creates the file but doesn't create the directory by itself. So something like:
File.WriteAllText(#"\arguments.txt", textWriteWindowed);
shall work (and create the file in the respective drive), but
File.WriteAllText(#"\Resources\arguments.txt", textWriteWindowed);
shall not work. Hence, if you want to create a file in the path where the application resides, you can do something like:
string folder=Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
File.WriteAllText(#"\arguments2.txt", "ABC");
If you want to create a directory, then you could do something like:
System.IO.FileInfo file = new System.IO.FileInfo(filePath);
file.Directory.Create();// If the directory already exists, this method does nothing.
System.IO.File.WriteAllText(file.FullName, textWriteWindowed);
Hope this answers your query.
you have to check whether the folder is exist before save the file,
if folder not exist create it using
Directory.CreateDirectory(...)
Directory.Exists(..)
you can use to check folder existence
IF you wanted to get the local path of the file you are executing use this:
var fInfo = new FileInfo(System.Reflection.Assembly.GetCallingAssembly().Location);
From there, you would do the following:
var parentDir = new DirectoryInfo(fInfo.DirectoryName);
var subDir = new DirectoryInfo(parentDir.FullName + "Resource");
if(!subDir.Exists)
subDir.Create();
This would ensure that you always have a folder in the directory of your executable. But just so you know, this is absolutely horrible code and should never ever be implemented in a production like environment. What if some knucklehead sysAdmin decides to place your program/folder in an area that the current user does not have access/writes too? The best place to write to is %APPDATA%, this will ensure the user always has read/write permissions to what you are trying to accomplish.
I don't know how but doing that worked for me :
File.WriteAllText(#"./arguments.txt", textWriteWindowed);
File.AppendAllText(#"./arguments.txt", textWriteWidth);
File.AppendAllText(#"./arguments.txt", textWriteHeight);
I have my program setup to rename and store a file according to checkbox input. I used another stackoverflow post for my template. Only problem is when I tried setting it up for sub-folders, it never puts it in the correct folder. I have a label folder with two sub folders called L-Labels and B-Labels. The user checks which label type it is and the file gets renamed and placed in the according sub-folder. When I used breakpoint my variables are getting the correct value so I don't see what's wrong I have provided my variables and code for relocating the file. What is causing this to not put it in my sub-folder?
Varibales:
string oldPath = lblBrowseName.Text;
string newpathB = #"C:\Users\Public\Labels\B_Labels";
string newpathL = #"C:\Users\Public\Labels\L_Labels";
Method:
if (rChkBoxBizerba.Checked == true)
{
string newFileName = rtxtBoxNewVersion.Text;
FileInfo f1 = new FileInfo(oldPath);
if (f1.Exists)
{
if (!Directory.Exists(newpathB))
{
Directory.CreateDirectory(newpathB);
}
f1.CopyTo(string.Format("{0}{1}{2}", newpathB, newFileName, f1.Extension));
if (System.IO.File.Exists(lblBrowseName.Text))
System.IO.File.Delete(lblBrowseName.Text);
}
I would say this is the problem:
f1.CopyTo(string.Format("{0}{1}{2}", newpathB, newFileName, f1.Extension));
You declare your path but it doesn't have a trailing directory separator, so when you combine all the parts, as above, the actual result is invalid.
You really should use Path.Combine() to combine parts of paths together, this uses the correct directory separator and makes additional checks.
Try something like this:
// Build actual filename
string filename = String.Format("{0}{1}",newFileName, f1.Extension));
// Now build the full path (directory + filename)
string full_path = Path.Combine(newpathB,filename);
// Copy file
f1.CopyTo(full_path);
So something must be wrong with my string.
I am grabbing the value from a SQL database which comes out like this:
while (reader.Read())
{
// Row Values
// 0 = UID
// 1 = CreatedDate
// 2 = Location
documentID = reader.GetGuid(0);
fileName = reader.GetSqlValue(0).ToString() + ".zip";
location = reader.GetString(2);
createdDate = reader.GetDateTime(1);
The values returned from the database are as follows:
GUID: DC5A30D7-D528-4BA4-AA5A-5ECEB2CD9006
fileName: DC5A30D7-D528-4BA4-AA5A-5ECEB2CD9006.zip
Location: \\192.168.22.1\documentation
if (!DoesFileExist(location + fileName))
{
// Log error to database
}
static bool DoesFileExist(string location)
{
bool doesExist = false;
if (File.Exists(location))
{
doesExist = true;
}
return doesExist;
}
When it gets to the part File.Exists(location) it passes over it as if it dind't exist. Bur it does... When I navigate to it in an Explorer I find the zip file just fine...
What am I doing wrong here?
UID CreatedDate Location
DC5A30D7-D528-4BA4-AA5A-5ECEB2CD9006 2009-10-28 11:17:06.690 \\192.168.22.1\documentation
As it is written in the example above, the Location + Filename doesn't produce a correct full filename. There is no backslash to separate the path from the filename.
I suggest to use the appropriate method Path.Combine from the class (System.IO.Path) to make the correct full filename
if (!DoesFileExist(Path.Combine(location, fileName)))
The way I see it, you're sending: "\192.168.22.1\documentationDC5A30D7-D528-4BA4-AA5A-5ECEB2CD9006.zip" to the method.
Try putting another "\" there.
Most of the time I have a problem like that, it is because of permissions. Often, the user for the file explorer is different that is trying to find the file with file exists. If everything is correct with the location, the next place to look would be the permissions.
I have an application written in C#, and I am seeking to write some information to the hidden ProgramData in order to access the same connection string from both the application's front end and back end.
I am accessing the directory using path variables as follows:
private bool ProgramDataWriteFile(string contentToWrite)
{
try
{
string strProgramDataPath = "%PROGRAMDATA%";
string directoryPath = Environment.ExpandEnvironmentVariables(strProgramDataPath) + "\\MyApp\\";
string path = Environment.ExpandEnvironmentVariables(strProgramDataPath)+"\\MyApp\\ConnectionInfo.txt";
if (Directory.Exists(directoryPath))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
else
{
Directory.CreateDirectory(directoryPath);
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
return true;
}
catch (Exception e)
{
}
return false;
}
This seems to work correctly. However, my question is, when I used this path variable: %AllUsersProfile%(%PROGRAMDATA%)
instead, it expanded into an illegal(and redundant) file path : C:\ProgramData(C:\ProgramData)\
However, I thought that the latter path variable was the correct full name. Was I just using it incorrectly? I need to ensure that this connection info will be accessible to all users, will just using %PROGRAMDATA% allow that? I am using Windows 7 in case that is relevant.
From here:
FOLDERID_ProgramData / System.Environment.SpecialFolder.CommonApplicationData
The user would never want to browse here in Explorer, and settings changed here should affect every user on the machine. The default location is %systemdrive%\ProgramData, which is a hidden folder, on an installation of Windows Vista. You'll want to create your directory and set the ACLs you need at install time.
So, just use %PROGRAMDATA%, or better still:
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)