首頁>技術>

允許使用者上傳圖片資源(頭像,發帖)是APP常見的需求,特別需要把使用者的資源IO到磁碟情況下,需要防止壞人提交一些非法的檔案,例如木馬,webshell,可執行程式等等。這類非法檔案不僅會導致客戶端圖片資源顯示失敗,而且還會給伺服器帶來安全問題。

通過檔案字尾判斷檔案的合法性

這種方式比較常見,也很簡單,是目前大多數APP選擇的做法。

public Object upload (@RequestParam("file") MultipartFile multipartFile) throws IllegalStateException, IOException {\t\t// 原始檔名稱\tString fileName = multipartFile.getOriginalFilename();\t\t// 解析到檔案字尾,判斷是否合法\tint index = fileName.lastIndexOf(".");\tString suffix = null;\tif (index == -1 || (suffix = fileName.substring(index + 1)).isEmpty()) {\t\treturn "檔案字尾不能為空";\t}\t\t// 允許上傳的檔案字尾列表\tSet<String> allowSuffix = new HashSet<>(Arrays.asList("jpg", "jpeg", "png", "gif"));\tif (!allowSuffix.contains(suffix.toLowerCase())) {\t\treturn "非法的檔案,不允許的檔案型別:" + suffix;\t}\t\t// 序列化到磁碟中的檔案上傳目錄, /upload\t// FileCopyUtils.copy 方法會自動關閉流資源\tFileCopyUtils.copy(multipartFile.getInputStream(), Files.newOutputStream(Paths.get("D://upload", fileName), StandardOpenOption.CREATE_NEW));\t\t// 返回相對訪問路徑,檔名極有可能帶中文或者空格等字元,進行uri編碼\treturn "/" + UriUtils.encode(fileName, StandardCharsets.UTF_8);}
使用 ImageIO 判斷是否是圖片

這個方法就比較嚴格了,在判斷後綴的基礎上,使用Java的ImageIO類去載入圖片,嘗試讀取其寬高資訊,如果不是合法的圖片資源。則無法讀取到這兩個資料。就算是把非法檔案修改了字尾,也可以檢測出來。

public Object upload (@RequestParam("file") MultipartFile multipartFile) throws IllegalStateException, IOException {\t\t// 原始檔名稱\tString fileName = multipartFile.getOriginalFilename();\t\t// 解析到檔案字尾\tint index = fileName.lastIndexOf(".");\tString suffix = null;\tif (index == -1 || (suffix = fileName.substring(index + 1)).isEmpty()) {\t\treturn "檔案字尾不能為空";\t}\t\t// 允許上傳的檔案字尾列表\tSet<String> allowSuffix = new HashSet<>(Arrays.asList("jpg", "jpeg", "png", "gif"));\tif (!allowSuffix.contains(suffix.toLowerCase())) {\t\treturn "非法的檔案,不允許的檔案型別:" + suffix;\t}\t\t// 臨時檔案\tFile tempFile = new File(System.getProperty("java.io.tmpdir"), fileName);\t\ttry {\t\t// 先把檔案序列化到臨時目錄\t\tmultipartFile.transferTo(tempFile);\t\ttry {\t\t\t// 嘗試IO檔案,判斷檔案的合法性\t\t\tBufferedImage bufferedImage = ImageIO.read(tempFile);\t\t\tbufferedImage.getWidth();\t\t\tbufferedImage.getHeight();\t\t} catch (Exception e) {\t\t\t// IO異常,不是合法的圖片檔案,返回異常資訊\t\t\treturn "檔案不是圖片檔案";\t\t}\t\t// 複製到到上傳目錄\t\tFileCopyUtils.copy(new FileInputStream(tempFile), Files.newOutputStream(Paths.get("D://upload", fileName), StandardOpenOption.CREATE_NEW));\t\t// 返回相對訪問路徑\t\treturn "/" + UriUtils.encode(fileName, StandardCharsets.UTF_8);\t} finally {\t\t// 響應客戶端後,始終刪除臨時檔案\t\ttempFile.delete();\t}}
總結

使用ImageIo的方式隨便保險,但是需要多幾次IO操作。比較消耗效能。而且今天APP大都是用雲端儲存服務,類似於阿里雲的OSS。直接就把客戶端上傳的檔案PUT到了雲端,才不管使用者上傳的圖片是不是真正的圖片,非法上傳,最多導致客戶端不能顯示而已,但是威脅不了伺服器的安全。

110

Java

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • uni-app使用Vue.js 開發小程式、H5、App的統一前端框架