<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                路徑操作(Path Manipulation)的漏洞,簡言之就是在路徑中包含有一些特殊字符(… 或者 / 等),導致可以訪問到期望目錄之外的文件。 比如路徑地址是`/usr/local/myapp/../../../etc/passwd`,對應到訪問到的文件就是`/etc/passwd`, 而這個文件是系統的文件,保存用戶密碼。 使用Coverity 掃描的信息如下: ``` Filesystem path, filename, or URI manipulation An attacker may access, modify, or corrupt files that contain sensitive information or are critical to the application. ``` 關于路徑操作漏洞,可以參考: [軟件弱點預防之 —— Filesystem path, filename, or URI manipulation - 操控文件系統路徑、文件名或 URI](https://blog.csdn.net/oscar999/article/details/127293940) 本篇介紹在 Java應用中如何防御路徑操作(Path Manipulation)的攻擊。 ## 防御方法分析 在代碼層面來看, 防御路徑操作的方法就是對輸入進行驗證,根據對字符是否合法的角度來看, 可以分為兩種: 1. 黑名單 : 將不安全的字符列入黑名單, 2. 白名單 : 將預期的字符加入白名單。 或者更嚴格一點,創建一份合法資源名的列表,并且規定用戶只能選擇其中的文件名。 黑名單的方式實現起來較為簡單, 將一些不安全的字符進行轉義或者過濾, 比如 `..` 上一級目錄字符 和絕對路徑目錄, 但是這種方式的安全性可能不是很高, 可能會遺漏一些特殊字符。 白名單的安全性較高, 但是需要窮舉所有的合法路徑相對比較困難, 如果某個路徑不包含在里面, 則可能會導致應用的功能不能正常工作。 本篇介紹使用白名單的方式進行防御, 也就是哪些路徑是有效的路徑。 ## 路徑操作的漏洞掃描 路徑操作的弱點很容易被Coverity等靜態掃描工具掃描出來, 比如下面的代碼就是存在路徑操縱漏洞的: ``` @RequestMapping("/unsafe") public void unsafe(String filefullName, HttpServletRequest request) { new File(filefullName); } ``` 要規避靜態掃描其實很容易,只需要對路徑使用函數轉換一下, 類似下面: ``` @RequestMapping("/scanSafe") public void scanSafe(String filefullName, HttpServletRequest request) { new File(cleanFilePath(filefullName)); } public static String cleanFilePath(String filePath) { if (filePath != null) { char[] originalChars = filePath.toCharArray(); char[] chars = new char[originalChars.length]; for (int i = 0; i < originalChars.length; i++) { chars[i] = originalChars[i]; } return new String(chars); } else { return null; } } ``` 上面的cleanFilePath 其實沒有對路徑做任何改動, 也就是說這個函數沒有任何作用, 但是這樣的改動卻是可以騙過Coverity, Coverity會認為 `new File(cleanFilePath(filefullName));` 這個代碼是安全的, 當其實這個代碼還是存在風險的。 以調用的cleanFilePath() 函數的效果來看, 路徑完全沒變化。 ``` @Test public void cleanFilePath() { String fileFullName = "C:\\temp\\..\\Windows\\system.ini"; Assertions.assertTrue("C:\\temp\\..\\Windows\\system.ini".equals(cleanFilePath(fileFullName))); } ``` 但是網絡上還是有很多煞有介事的代碼, 對路徑進行轉化: 比如: #### 錯誤解法1 ``` public static String cleanString(String aString) { if (aString == null) return null; String cleanString = ""; for (int i = 0; i < aString.length(); ++i) { cleanString += cleanChar(aString.charAt(i)); } return cleanString; } private static char cleanChar(char aChar) { // 0 - 9 for (int i = 48; i < 58; ++i) { if (aChar == i) return (char) i; } // 'A' - 'Z' for (int i = 65; i < 91; ++i) { if (aChar == i) return (char) i; } // 'a' - 'z' for (int i = 97; i < 123; ++i) { if (aChar == i) return (char) i; } // other valid characters switch (aChar) { case '/': return '/'; case '.': return '.'; case '-': return '-'; case '_': return '_'; case ' ': return ' '; } return '%'; } ``` 上面的代碼試圖將路徑中的不合法的字符替換為 %, 僅認為字母、數字以及`/ . -` 等字符是有效字符。 這個轉化不僅沒有解決路徑操作的風險,而且路徑轉換也是錯的,比如調用示例: ``` @Test public void cleanString() { String fileFullName = "C:\\temp\\..\\Windows\\system.ini"; fileFullName = cleanString(fileFullName); System.out.println(fileFullName); //轉化后的結果 C%%temp%..%Windows%system.ini } ``` #### 錯誤解法2 還有的解法似乎考慮周全, 將中文字符也考慮進來了, 但是同樣是漏洞沒解決, 功能反而是錯的。 ``` public static String normalizeFilePath(String filePath) { if (filePath != null) { char[] originalChars = filePath.toCharArray(); char[] chars = new char[originalChars.length]; for (int i = 0; i < originalChars.length; i++) { if (isValidPathChar(originalChars[i])) { chars[i] = originalChars[i]; } else { chars[i] = '-'; } } return new String(chars); } else { return null; } } public static boolean isValidPathChar(char c) { boolean isValid = false; String whiteListpathChars = "abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/_-:\\."; if (whiteListpathChars.indexOf(c) > 0) { isValid = true; } return isValid; } public static boolean isChineseChar(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION; } ``` ## 正確姿勢 比較簡易的正確方式是先對路徑進行規范化處理, 再判斷路徑是否在合法的路徑列表中。 所謂路徑歸一化就是將路徑中的 `..` 和 `.` 進行處理, 比如 ``` Path path = Paths.get("D:\\temp\\subfold1\\..\\..\\subsubfolder1"); path = path.normalize(); Assert.assertEquals("D:\\subsubfolder1", path.toString()); ``` 基于Java 的路徑類Path 對路徑進行歸一化, 之后在對歸一化之后的路徑進行白名單的判斷, 完整的示例代碼如下: ``` @RequestMapping("/safeRightWay") public void safeRightWay(String filefullName, HttpServletRequest request) { Path path = Paths.get(filefullName); path = path.normalize(); String filePath = path.getParent().toString(); if(isValidPath(filePath)) { File file = path.toFile(); } } public boolean isValidPath(String filePath) { List<String> list = new ArrayList<String>(); list.add("D:\\temp1"); list.add("D:\\temp2"); return list.contains(filePath); } ``` 如果感覺Path 使用繁瑣的話,也可以導入 apache common io 進行歸一化處理, 首先導入依賴包: ``` <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> ``` 導入之后就可以使用 FilenameUtils.normalize(fileFullName);進行歸一化處理了,類似: ``` @Test public void normalize() { String fileFullName = "C:\\temp\\..\\Windows\\system.ini"; fileFullName = FilenameUtils.normalize(fileFullName); System.out.println(fileFullName); // C:\Windows\system.ini } ``` ## 安全的解法 需要注意的是上面使用 Path只是對路徑進行規范化處理,并沒有進行路徑操縱的防御,所以使用Coverity 進行掃碼時, `Path path = Paths.get(filefullName);` 這一句還是會被掃描到存在風險。 ``` @RequestMapping("/safeRightWayButScan") public void safeRightWayButScan(String filefullName, HttpServletRequest request) { Path path = Paths.get(filefullName); path = path.normalize(); String filePath = path.getParent().toString(); if(isValidPath(filePath)) { path.toFile(); } } ``` 所以, 安全的解法是結合 FilenameUtils.normalize(fileFullName) 進行處理, 代碼如下: ``` @RequestMapping("/safeRightWay") public void safeRightWay(String filefullName, HttpServletRequest request) { filefullName = FilenameUtils.normalize(filefullName); if(isValidPath(filefullName)) { new File(filefullName); } } ``` 注意: 這里只是解決了風險, 但是使用Coverity 掃描時依舊還是掃出了風險,使用Coverity掃描的狀況下, 如何完美處理Path Manipulation風險,請參考: [結合Coverity掃描Spring Boot項目進行Path Manipulation漏洞修復](https://blog.csdn.net/oscar999/article/details/128961641) ***** *****
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看