How to prevent the Path Traversal in Java - java

Recently, I used the AppScan Source to scan the coding, and it found out one of the finding which I don't know how to fix and pass to the scanner
Here's my code.
public void init()
{
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");
String pth = "C:\\wls1034\\user_projects\\domains\\base_domain\\servers\\AdminServer\\tmp\\_WL_user\\SimulationService\\39m5yi\\war\\WEB-INF";
String n= prefix+file;
File fileExists = new File(n);
if (fileExists.exists()) {
PropertyConfigurator.configure("C:\\wls1034\\user_projects\\domains\\base_domain\\servers\\AdminServer\\tmp\\_WL_user\\SimulationService\\39m5yi\\war\\WEB-INF" + file);
} else {
BasicConfigurator.configure();
}
}
I tried to add the if statement to check any special character in the path. However the scanner still report the finding in "File fileExists = new File(n);"
public void init()
{
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");
String pth = "C:\\wls1034\\user_projects\\domains\\base_domain\\servers\\AdminServer\\tmp\\_WL_user\\SimulationService\\39m5yi\\war\\WEB-INF";
String n= prefix+file;
//For Security Checking
if (file != null && !n.contains("../") && !n.contains("$") && !n.contains("*"))//Check the path whether it's included risk character
{
File fileExists = new File(n);
if (fileExists.exists()) {
PropertyConfigurator.configure("C:\\wls1034\\user_projects\\domains\\base_domain\\servers\\AdminServer\\tmp\\_WL_user\\SimulationService\\39m5yi\\war\\WEB-INF" + file);
} else {
BasicConfigurator.configure();
}
}
}

This is just a false positive by the scanner. There is no security risk with the above code as no user input involved in reading or writing to the path.

The scanner flags file paths with variables.
var sr = new StreamReader("C:\\....\\WEB-INF" + file);
As mentioned by Ahmad, it is usually a false positive. But it is a good idea to verify a malicious user could not exploit the code and to get access to files that was not intended.
To make the scanner happy, you could supply it with hard coded paths, or create a switch statement for every possible file path.
switch (fileId)
{
case "1":
sr = new StreamReader("C:\file-1");
break;
case "2":
sr = new StreamReader("C:\file-2");
break;
}
But who wants to do that!
Your best option is to ensure no threat exists and to convince the security folks to allow your code to proceed.

Related

Recursion method continues after returning value?

I'm writing a quick Java recursion method that, given a root folder and filename, searches your files for said file name.
import Java.io.File;
public static String searchForFile(File currentFolder, String filename)
{
try
{
File[] path = currentFolder.listFiles();
for (int i = 0; i < path.length; i++)
{
if (path[i].isDirectory())
{
System.out.println("Directory: " + path[i].toString());
searchForFile(path[i], filename);
}
else
{
System.out.println("File: " + path[i].toString());
if(path[i].getName().equals(filename))
{
System.out.println("Your file has been found!";
return path[i].toString();
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null; // Omitting this line yields compiling errors, not sure why?
}
public static void main(String[] args)
{
System.out.println("Hello, enter the root folder and file name.");
String rootFolder = "Desktop";
String fileName = "Hello.txt";
File f = new File("C:\\Users\\Me\\" + rootFolder);
searchForFile(f, fileName);
}
The program itself technically works, however searchForFile() keeps iterating even after the requested file is found. For example, I'd get an output such as:
File: C:\Users\Me\Desktop\My Stuff\NotHello.txt
**File: C:\Users\Me\Desktop\My Stuff\Hello.txt**
Your file has been found!
File: C:\Users\Me\Desktop\My Stuff\AlsoNotHello.txt
File: C:\Users\Me\Desktop\My Stuff\StillNotHello.txt
File: C:\Users\Me\Desktop\My Stuff\WhyIsThisMethodStillRunning.txt
I've been scratching my head at this for awhile now. I thought return always exits the method, so why does the recursion continue even after it returns a value? I haven't found any similar questions asked, so any help would be much appreciated!
(Also, how could I edit the method so that it returns a blank "" string if the requested file is not found?)
You are returning from the innermost call, when you've found the file. But when you are scanning a directory, you are not using the return value.
Change this:
searchForFile(path[i], filename);
to:
String result = searchForFile(path[i], filename);
if (result != null) {
return result;
}
The return null; in the bottom of your method is there because all methods needs to return a value. No matter if the file is found or not. If the file is not found within the current directory (or one of its subdirectories), you can return null; to indicate that it wasn't found.
Side suggestion: Use Optional in Java 8 instead of null.

How to solve my try-catch exception handling?

I'm having problems with my try-catch exception here. Actually what it does is to prompt the user for the name of a text file say, Robot.txt but if say the file does not exist, I have to make sure that the application reprompts the user for the file name. Hope you guys can understand I'm still a newbie here so please feel free to provide suggestions or advices on my coding etc. Cheers!
Main method class:
import java.io.*;
import java.util.Scanner;
import java.util.Vector;
class TestVector3 {
public static void main(String [] args)
{
System.out.println("Please enter the name of the text file to read: ");
Scanner userInput = new Scanner(System.in);
Vector <KillerRobot> robotDetails = new Vector <KillerRobot>();
KillerRobot robot;
Scanner fileInput = null;
try
{
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
System.out.println("Re-enter file name :"); //Reprompt user for name of the text file
fileInput = new Scanner(userInput.nextLine());
}
while(fileInput.hasNext())
{
robot = new KillerRobot();
String first = fileInput.next();
robot.setName(first);
String second = fileInput.next();
robot.setMainWeapon(second);
int third = fileInput.nextInt();
robot.setNumberOfKills(third);
robotDetails.add(robot);
}
for(KillerRobot i : robotDetails)
{
System.out.println(i);
}
fileInput.close();
}
}
KillerRobot class file:
class KillerRobot {
private String name;
private String mainWeapon;
private int numberOfKills;
KillerRobot()
{
}
public String getName()
{
return name;
}
public String getMainWeapon()
{
return mainWeapon;
}
public int getNumberOfKills()
{
return numberOfKills;
}
public String toString()
{
return name + " used a " + mainWeapon + " to destroy " + numberOfKills + " enemies ";
}
public void setName(String a)
{
name = a;
}
public void setMainWeapon(String b)
{
mainWeapon = b;
}
public void setNumberOfKills(int c)
{
numberOfKills = c;
}
}
As you state that you are a beginner, let us first look at the relevant part of your code, to make sure that we talk about the same thing:
Scanner fileInput = null;
try {
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e) {
System.out.println("Error - file not found!");
System.out.println("Re-enter file name :");
fileInput = new Scanner(userInput.nextLine());
}
You have an input and you want to check this input for a condition and require a new input until this condition is fulfilled. This problem can be solved using a loop like the following:
Scanner fileInput = null;
do {
System.out.println("Enter file name :");
try {
fileInput = new Scanner(new File(userInput.nextLine()));
} catch (FileNotFoundException e) {
System.out.println("Error - file not found!");
}
} while(fileInput == null);
So finally, why does this work? The fileInput variable is set to null and will remain null until the given file is successfully read from standard input because an exception is thrown otherwise what prevents the fileInput variable to be set. This procedure can be repeated endlessly.
On a side note, for performance reasons, it is normally not a good idea to implement control flow that is based on exceptions. It would be better to check for a condition if a file exists via File::exists. However, if you read the file after checking for its existence, it might have been deleted in the meantime which introduces a racing condition.
Answer to your comment: In Java (or almost any programming language), you can inline expressions. This means that instead of calling two methods in two different statements as in
Foo foo = method1();
Bar bar = method2(foo);
you can simply call
Bar bar = method2(method1());
This way, you save yourself some space (what becomes more and more important if your code gets longer) as you do not need the value that you saved in foo at any other place in your code. Similarly, you can inline (which is how this pattern is called) from
File file = new File(userInput.nextLine())
fileInput = new Scanner(file);
into
fileInput = new Scanner(new File(userInput.nextLine()));
as the file variable is only read when creating the Scanner.
Try putting the try-catch in a loop like below:
Scanner fileInput = null;
while (fileInput==null)
{
try
{
System.out.println("Please enter the file name.");
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
}
}
Next you could think of moving the File creation part into separate method, so that the code was cleaner.
Do not fall for try-catch instead add this as your functionality. Exceptions are naturally for run time error handling not for logic building.
Check if file exists at given location.
File textFile = new File(userInput.nextLine());
// Check if file is present and is not a directory
if(!textFile.exists() || textFile.isDirectory()) {
System.out.println("Error - file not found!");
//Reprompt user for name of the text file
System.out.println("Re-enter file name :");
fileInput = new Scanner(userInput.nextLine());
}
You can put while loop instead of if loop if you want to continuously prompt user until correct path is entered.
You can call back your main(), like following
try
{
File textFile = new File(userInput.nextLine());
fileInput = new Scanner(textFile);
}
catch (FileNotFoundException e)
{
System.out.println("Error - file not found!");
main(args); // recursively call main() method
}
Now if user first attempt wrong then your code will asked to re enter file name.
How to check isFile exist?
File file = new File(filePathString);
if(file.exists() && !file.isDirectory()){
System.out.println("file exist");
}
This really is an XY problem because you assumed the only way to check for a file existence is by catching a FileNotFoundException (hence asking about try-catch exception handling) whereas other means exist to help you avoid a try-catch idiom in an elegant manner.
To check if a file exists at the given path or not you can simply use the File.exists method. Please also see the File.isFile method and/or the File.isDirectory method to verify the nature of the targeted File object.
EDIT : As stated by raphw, this solution is best used in simple scenario since it can incur a race condition in the case of concurrent file deletion happening during the file existence check. See his answer for handling more complex scenario.

Java desktop app cannot write a file on C:\ drive

I am trying to write a file on a C:\ drive, but I get an exception.
java.io.IOException: Access denied.
Code:
public class Test {
public static void main(String[] args) {
try {
StringBuilder sb = new StringBuilder(File.separator);
sb.append("index.txt");
// sb is "\\index.txt"
File f = new File(sb.toString());
boolean isCreated = f.createNewFile();
System.out.println(isCreated);
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Actually, I get it, I don't have permission to write a file there, but I am quite sure it can be done somehow. If I had an applet, I'd just obtain a permission, but here, I don't know how to do it.
The probable solution may be checking if I can write a file there, but to check it I might try to write a file first adn then delete it in order to check if it is possible to write a file there, but I don't find this solution an optimal way.
The easiest way to check is to use File.canWrite().
Having said that, it looks like you're writing into the root of the drive. On Windows that's probably not a good idea, and you may want to consider writing elsewhere - e.g. a temp dir.
I have written a method, that takes a String to a directory, and checks, whether you can write a file out there:
static boolean canWrite(String folderPath) {
File file = new File(folderPath);
String new_file = "HastaLaVistaBaby";
if (file.isDirectory()) {
try {
new File(file + "\\" + new_file).createNewFile();
} catch (IOException e) {
return false;
}
new File(file + "\\" + new_file).delete();
return true;
} else {
return false;
}
}
To improve it, you may check, whether file.isFile() and get a parent directory and call this method.
This line should be:
sb.append("C:\\index.txt");
The extra backslash escapes a backslash.
Whether you hard-code a file name, like I did, or you get a file name from the user, you need the full path and file name.

How do I call method if exception thrown?

I have a method called readinFile and if the user enters a wrong file instead of exiting I wanted to call the method readinFile again inside the readinFile method I ask the user for new filename. The problem I am running into is the first time it goes through it and gives the exception file not found than it goes through the catch(). I want it to call the method and not run the last inputStream.
try
{
inputStream = new Scanner(new FileInputStream(fileName));
}
catch(FileNotFoundException E)
{
readinfile(table, numberOfColumns, header,
original, sntypes,displaySize,
writeOut,inputStream,fileName );
System.out.print("It got here after doing the method call");
}
You should generally not use exceptions for branching. Just check for the existance of the file using File.exists, like so:
new File(fileName).exists()
You probably want to do something like this:
String fileName;
do {
System.out.println("Please enter filename");
fileName = getFileNameFromInput();
File file = new File(fileName);
} while (!file.exists());
readFile(file);
EDIT:
As Bruno Reis has pointed out, this will only check if the file exists when the user specified the file name. If the file was to be moved/deleted between specifying the file name and reading it then a FileNotFoundException would still be thrown.
To reduce the risk of this you can lock the file as discussed in this question.
bool invalidFilename = true;
string fileName;
while(invalidFilename)
{
readinfile(...);
invalidFilename = !new File(fileName).exists();
}
inputStream = new Scanner(new FileInputStream(fileName));
You can check if the filename the user input does exists or not, and don't need to catch the exception. (which is not a good design code, decrease the readability of the code)....
as inflagranti said,
you can do this pseudocode
if (!new File(filename).exists()){
//read your other file from user
readinfile(....)
}
To get what you are after, without the chance of the file being deleted after you check for it existing but before you open it do something like:
boolean done = false;
String fileName = fileNameParameter;
while(!done)
{
try
{
inputStream = new Scanner(new FileInputStream(fileName));
done = true;
}
catch(FileNotFoundException E)
{
fileName = /* ask the user for the file name */
}
}

problem with deleting files

private static void deletefile(String file) {
int fileName = 500;
int z;
String[] File = new String[fileName];
for (z = 0; z < fileName; z++) {
File f1 = new File(
"C:\\Users\\user\\fypworkspace\\TextRenderer\\abc" + z
+ ".txt");
boolean success = f1.delete();
if (!success) {
System.out.println("Deletion failed.");
System.exit(0);
} else {
System.out.println("File deleted.");
}
}
}
public static void main(String[] args) throws IOException {
switch (args.length) {
case 0:
System.out.println("File has not mentioned.");
System.exit(0);
case 1:
deletefile(args[0]);
System.exit(0);
default:
System.out.println("Multiple files are not allow.");
System.exit(0);
hi, this is my code for attempting to delete a certain files in java. It prints out file has not mentioned.i was trying to delete a set of txt files in a certain folder. The program should continue with the next file once a file is missing. Can anyone point out my mistake ? thanks..
Apparently you did not pass any command line parameters to your program.
(Although even if you did, it is not used anywhere in deletefile() - your method attempts to delete a fixed set of files in a specific directory, and if any of these is missing or you don't have permissions to delete it, it exits with an error message.)
You have to specify the file name as command line argument when running your Java program.
java MyClass file_to_delete
You need to have some check or catch exception when you create a new file so it wont stop when the file is not found.

Categories

Resources