Spring Boot 校驗(yàn)用戶上傳的圖片文件(兩種方式)
圖片上傳是現(xiàn)代應(yīng)用中非常常見的一種功能,也是風(fēng)險(xiǎn)比較高的一個(gè)地方。惡意用戶可能會上傳一些病毒、木馬。這些東西不僅嚴(yán)重威脅服務(wù)器的安全還浪費(fèi)了帶寬,磁盤等資源。所以,在圖片上傳的接口中,一定要對用戶上傳的文件進(jìn)行嚴(yán)格的校驗(yàn)。
本文介紹了 2 種對圖片文件進(jìn)行驗(yàn)證的方法可供你參考。
一、文件后綴校驗(yàn)
通過文件后綴(也就是文件擴(kuò)展名,通常用于表示文件的類型),進(jìn)行文件類型校驗(yàn)這是最常見的做法。
圖片文件的后綴類型有很多,常見的只有:jpg
、jpeg
、gif
、png
、webp
。我們可以在配置或者代碼中定義一個(gè)“允許上傳的圖片后綴”集合,用于校驗(yàn)用戶上傳的圖片文件。
package cn.springdoc.demo.web.controller; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Set; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/upload") public class UploadController { // 允許上傳的圖片類型的后綴集合 static final Set<String> imageSuffix = Set.of("jpg", "jpeg", "gif", "png", "webp"); @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<String> upload (@RequestParam("file") MultipartFile file ) throws IllegalStateException, IOException{ // 文件的原始名稱 String fileName = file.getOriginalFilename(); if (fileName == null) { return ResponseEntity.badRequest().body("文件名稱不能為空"); } // 解析出文件后綴 int index = fileName.lastIndexOf("."); if (index == -1) { return ResponseEntity.badRequest().body("文件后綴不能為空"); } String suffix = fileName.substring(index + 1); if (!imageSuffix.contains(suffix.trim().toLowerCase())) { return ResponseEntity.badRequest().body("非法的文件類型"); } // IO 到程序運(yùn)行目錄下的 public 目錄,這是默認(rèn)的靜態(tài)資源目錄 Path dir = Paths.get(System.getProperty("user.dir"), "public"); if (!Files.isDirectory(dir)) { // 創(chuàng)建目錄 Files.createDirectories(dir); } file.transferTo(dir.resolve(fileName)); // 返回相對訪問路徑 return ResponseEntity.ok("/" + fileName); } }
如上,代碼很簡單。先是獲取客戶端文件的名稱,再從名稱獲取到文件的后綴。確定是合法文件后再 IO 到本地磁盤。
二、使用 ImageIO 校驗(yàn)
由于文件的后綴是可編輯的,惡意用戶可以把一個(gè) exe
文件的后綴改為 jpg
再上傳到服務(wù)器。于是這種情況下,上面的這種校驗(yàn)方式就會失效,惡意文件會被 IO 到磁盤。
在基于上面的方法進(jìn)行校驗(yàn)后,我們可以先把文件 IO 到臨時(shí)目錄,再使用 ImageIO
類去加載圖片文件,如果 Images
加載的文件不是圖片,則會返回 null
。
package cn.springdoc.demo.web.controller; import java.awt.image.BufferedImage; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Set; import java.util.UUID; import javax.imageio.ImageIO; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/upload") public class UploadController { // 允許上傳的圖片類型的后綴集合 static final Set<String> imageSuffix = Set.of("jpg", "jpeg", "gif", "png", "webp"); @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) throws IllegalStateException, IOException { // 文件的原始名稱 String fileName = file.getOriginalFilename(); if (fileName == null) { return ResponseEntity.badRequest().body("文件名稱不能為空"); } // 解析出文件后綴 int index = fileName.lastIndexOf("."); if (index == -1) { return ResponseEntity.badRequest().body("文件后綴不能為空"); } String suffix = fileName.substring(index + 1); if (!imageSuffix.contains(suffix.trim().toLowerCase())) { return ResponseEntity.badRequest().body("非法的文件類型"); } // 獲取系統(tǒng)中的臨時(shí)目錄 Path tempDir = Paths.get(System.getProperty("java.io.tmpdir")); // 臨時(shí)文件使用 UUID 隨機(jī)命名 Path tempFile = tempDir.resolve(Paths.get(UUID.randomUUID().toString())); // copy 到臨時(shí)文件 file.transferTo(tempFile); try { // 使用 ImageIO 讀取文件 if (ImageIO.read(tempFile.toFile()) == null) { return ResponseEntity.badRequest().body("非法的文件類型"); } // 至此,這的確是一個(gè)圖片資源文件 // IO 到運(yùn)行目錄下的 public 目錄 Path dir = Paths.get(System.getProperty("user.dir"), "public"); if (!Files.isDirectory(dir)) { // 創(chuàng)建目錄 Files.createDirectories(dir); } Files.copy(tempFile, dir.resolve(fileName)); // 返回相對訪問路徑 return ResponseEntity.ok("/" + fileName); } finally { // 始終刪除臨時(shí)文件 Files.delete(tempFile); } } }
這種方式更為嚴(yán)格,不但要校驗(yàn)文件后綴還要校驗(yàn)文件內(nèi)容。弊端也顯而易見,會耗費(fèi)更多的資源!
1、ImageIO.read 方法
最后說一下 ImageIO.read
方法,它會從系統(tǒng)中已注冊的 ImageReader
中選擇一個(gè) Reader 對圖片進(jìn)行解碼,如果沒有 Reader 能夠解碼文件,則返回 null
。也就是說,如果上傳的圖片類型,在系統(tǒng)中沒有對應(yīng)的 ImageReader
也會被當(dāng)做是“非法文件”。
例如:webp
類型的圖片文件,ImageIO.read
就讀取不了,因?yàn)?JDK 沒有預(yù)置讀取 webp 圖片的 ImageReader
。
要解決這個(gè)問題,可以添加一個(gè) webp-imageio
依賴。
<!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio --> <dependency> <groupId>org.sejda.imageio</groupId> <artifactId>webp-imageio</artifactId> <version>0.1.6</version> </dependency>
webp-imageio
庫提供了 webp 圖片的 ImageReader
實(shí)現(xiàn),并以 SPI 的形式注冊到了系統(tǒng)中,不要寫其他任何代碼就可以成功讀取。
到此這篇關(guān)于Spring Boot 校驗(yàn)用戶上傳的圖片文件的文章就介紹到這了,更多相關(guān)Spring Boot 校驗(yàn)上傳圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVA(SpringBoot)集成Jasypt進(jìn)行加密、解密功能
Jasypt是一個(gè)Java庫,專門用于簡化加密和解密操作,提供多種加密算法支持,集成到SpringBoot等框架中,通過使用Jasypt,可以有效保護(hù)配置文件中的敏感信息,如數(shù)據(jù)庫密碼等,避免被未授權(quán)訪問,Jasypt還支持自定義加密器,提高擴(kuò)展性和安全性,適用于各種需要加密保護(hù)應(yīng)用場景2024-09-09Hibernate中Session.get()方法和load()方法的詳細(xì)比較
今天小編就為大家分享一篇關(guān)于Hibernate中Session.get()方法和load()方法的詳細(xì)比較,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03Java文件斷點(diǎn)續(xù)傳實(shí)現(xiàn)原理解析
這篇文章主要介紹了Java文件斷點(diǎn)續(xù)傳實(shí)現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05SpringBoot整合MyCat實(shí)現(xiàn)讀寫分離的方法
這篇文章主要介紹了SpringBoot整合MyCat實(shí)現(xiàn)讀寫分離的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04IDEA-Maven項(xiàng)目的jdk版本設(shè)置方法
我們需要設(shè)置jdk的版本,不然會提示導(dǎo)致語法錯(cuò)誤,這篇文章主要介紹了IDEA-Maven項(xiàng)目的jdk版本設(shè)置方法,小編覺得不錯(cuò),一起來了解一下2019-04-04