Spring Boot 校驗(yàn)用戶上傳的圖片文件(兩種方式)
圖片上傳是現(xiàn)代應(yīng)用中非常常見的一種功能,也是風(fēng)險(xiǎn)比較高的一個(gè)地方。惡意用戶可能會(huì)上傳一些病毒、木馬。這些東西不僅嚴(yán)重威脅服務(wù)器的安全還浪費(fèi)了帶寬,磁盤等資源。所以,在圖片上傳的接口中,一定要對(duì)用戶上傳的文件進(jìn)行嚴(yán)格的校驗(yàn)。
本文介紹了 2 種對(duì)圖片文件進(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));
// 返回相對(duì)訪問路徑
return ResponseEntity.ok("/" + fileName);
}
}如上,代碼很簡單。先是獲取客戶端文件的名稱,再從名稱獲取到文件的后綴。確定是合法文件后再 IO 到本地磁盤。
二、使用 ImageIO 校驗(yàn)
由于文件的后綴是可編輯的,惡意用戶可以把一個(gè) exe 文件的后綴改為 jpg 再上傳到服務(wù)器。于是這種情況下,上面的這種校驗(yàn)方式就會(huì)失效,惡意文件會(huì)被 IO 到磁盤。
在基于上面的方法進(jìn)行校驗(yàn)后,我們可以先把文件 IO 到臨時(shí)目錄,再使用 ImageIO 類去加載圖片文件,如果 Images 加載的文件不是圖片,則會(huì)返回 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));
// 返回相對(duì)訪問路徑
return ResponseEntity.ok("/" + fileName);
} finally {
// 始終刪除臨時(shí)文件
Files.delete(tempFile);
}
}
}這種方式更為嚴(yán)格,不但要校驗(yàn)文件后綴還要校驗(yàn)文件內(nèi)容。弊端也顯而易見,會(huì)耗費(fèi)更多的資源!
1、ImageIO.read 方法
最后說一下 ImageIO.read 方法,它會(huì)從系統(tǒng)中已注冊(cè)的 ImageReader 中選擇一個(gè) Reader 對(duì)圖片進(jìn)行解碼,如果沒有 Reader 能夠解碼文件,則返回 null。也就是說,如果上傳的圖片類型,在系統(tǒng)中沒有對(duì)應(yīng)的 ImageReader 也會(huì)被當(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 的形式注冊(cè)到了系統(tǒng)中,不要寫其他任何代碼就可以成功讀取。
到此這篇關(guān)于Spring Boot 校驗(yàn)用戶上傳的圖片文件的文章就介紹到這了,更多相關(guān)Spring Boot 校驗(yàn)上傳圖片內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud?Nacos服務(wù)分級(jí)存儲(chǔ)模型詳解
Nacos服務(wù)分級(jí)存儲(chǔ)模型是Nacos存儲(chǔ)服務(wù)注冊(cè)信息和配置信息的核心模型之一,本文將對(duì)?Nacos?服務(wù)分級(jí)存儲(chǔ)模型進(jìn)行深入解析,感興趣的朋友一起看看吧2024-02-02
java 同步器SynchronousQueue詳解及實(shí)例
這篇文章主要介紹了java 同步器SynchronousQueue詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05
SpringBoot應(yīng)用快速部署到K8S的詳細(xì)教程
這篇文章主要介紹了SpringBoot應(yīng)用快速部署到K8S的詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
SpringBoot使用SensitiveWord實(shí)現(xiàn)敏感詞過濾
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何使用SensitiveWord實(shí)現(xiàn)敏感詞過濾功能,文中示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-01-01
Spring將MultipartFile轉(zhuǎn)存到本地磁盤的三種方式
在Java中處理文件向來是一種不是很方便的操作,然后隨著Spring框架的崛起,使用Spring框架中的MultipartFile來處理文件也是件很方便的事了,今天就給大家介紹Spring將MultipartFile轉(zhuǎn)存到本地磁盤的方式,需要的朋友可以參考下2024-10-10
關(guān)于Netty--Http請(qǐng)求處理方式
這篇文章主要介紹了關(guān)于Netty--Http請(qǐng)求處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06

