|
| 1 | +# Uncontrolled data used in path expression |
| 2 | +Accessing paths controlled by users can allow an attacker to access unexpected resources. This can result in sensitive information being revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files. |
| 3 | + |
| 4 | +Paths that are naively constructed from data controlled by a user may contain unexpected special characters, such as "..". Such a path may potentially point anywhere on the file system. |
| 5 | + |
| 6 | + |
| 7 | +## Recommendation |
| 8 | +Validate user input before using it to construct a file path. |
| 9 | + |
| 10 | +The choice of validation depends on whether you want to allow the user to specify complex paths with multiple components that may span multiple folders, or only simple filenames without a path component. |
| 11 | + |
| 12 | +In the former case, a common strategy is to make sure that the constructed file path is contained within a safe root folder, for example by checking that the path starts with the root folder. Additionally, you need to ensure that the path does not contain any ".." components, since otherwise even a path that starts with the root folder could be used to access files outside the root folder. |
| 13 | + |
| 14 | +In the latter case, if you want to ensure that the user input is interpreted as a simple filename without a path component, you can remove all path separators ("/" or "\\") and all ".." sequences from the input before using it to construct a file path. Note that it is *not* sufficient to only remove "../" sequences: for example, applying this filter to ".../...//" would still result in the string "../". |
| 15 | + |
| 16 | +Finally, the simplest (but most restrictive) option is to use an allow list of safe patterns and make sure that the user input matches one of these patterns. |
| 17 | + |
| 18 | + |
| 19 | +## Example |
| 20 | +In this example, a file name is read from a `java.net.Socket` and then used to access a file and send it back over the socket. However, a malicious user could enter a file name anywhere on the file system, such as "/etc/passwd". |
| 21 | + |
| 22 | + |
| 23 | +```java |
| 24 | +public void sendUserFile(Socket sock, String user) { |
| 25 | + BufferedReader filenameReader = new BufferedReader( |
| 26 | + new InputStreamReader(sock.getInputStream(), "UTF-8")); |
| 27 | + String filename = filenameReader.readLine(); |
| 28 | + // BAD: read from a file without checking its path |
| 29 | + BufferedReader fileReader = new BufferedReader(new FileReader(filename)); |
| 30 | + String fileLine = fileReader.readLine(); |
| 31 | + while(fileLine != null) { |
| 32 | + sock.getOutputStream().write(fileLine.getBytes()); |
| 33 | + fileLine = fileReader.readLine(); |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +``` |
| 38 | +Simply checking that the path is under a trusted location (such as a known public folder) is not enough, however, since the path could contain relative components such as "..". To fix this, check that it does not contain ".." and starts with the public folder. |
| 39 | + |
| 40 | + |
| 41 | +```java |
| 42 | +public void sendUserFileGood(Socket sock, String user) { |
| 43 | + BufferedReader filenameReader = new BufferedReader( |
| 44 | + new InputStreamReader(sock.getInputStream(), "UTF-8")); |
| 45 | + String filename = filenameReader.readLine(); |
| 46 | + // GOOD: ensure that the file is in a designated folder in the user's home directory |
| 47 | + if (!filename.contains("..") && filename.startsWith("/home/" + user + "/public/")) { |
| 48 | + BufferedReader fileReader = new BufferedReader(new FileReader(filename)); |
| 49 | + String fileLine = fileReader.readLine(); |
| 50 | + while(fileLine != null) { |
| 51 | + sock.getOutputStream().write(fileLine.getBytes()); |
| 52 | + fileLine = fileReader.readLine(); |
| 53 | + } |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +``` |
| 58 | + |
| 59 | +## References |
| 60 | +* OWASP: [Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal). |
| 61 | +* Common Weakness Enumeration: [CWE-22](https://cwe.mitre.org/data/definitions/22.html). |
| 62 | +* Common Weakness Enumeration: [CWE-23](https://cwe.mitre.org/data/definitions/23.html). |
| 63 | +* Common Weakness Enumeration: [CWE-36](https://cwe.mitre.org/data/definitions/36.html). |
| 64 | +* Common Weakness Enumeration: [CWE-73](https://cwe.mitre.org/data/definitions/73.html). |
0 commit comments