1、一般狀況下,驗證一個文件是否圖片,能夠經過如下三種方式:php
1)、判斷文件的擴展名是不是要求的圖片擴展名html
這種判斷是用得比較多的一種方式,不過這種方式很是的不妥,別人稍微的把一個不是圖片的文件的擴展名修改成圖片的擴展名,就繞開了你的這種校驗,若是這上傳的文件是shell、php或者jsp,那你的網站基本上能夠說就在別人的手裏面了。java
不過這種判斷方式也不是徹底沒有用,咱們能夠把它放在判斷圖片的最外層,若是一個文件連擴展名都不是咱們所要求的圖片擴展名,那就根本不用後面的內容格式檢查了,從必定程度上說,對減小服務器的壓力仍是有必定的幫助,不然全部的文件都等上傳完後成後再經過服務器去判斷,那會在必定程度上浪費器資源的。shell
2)、根據文件的前面幾個字節,即常說的魔術數字進行判斷,不一樣文件類型的開頭幾個字節,能夠查看個人另一篇專站介紹:表示不一樣文件類型的魔術數字。安全
可是這種判斷方式也是很是不靠譜的,由於他只可以驗證文件的前面幾個字節,如此時有人把一個可執行的PHP文件的擴展名修改成PNG,而後再在前面補上」89 50″兩個字節,就又繞開了這種驗證方式。服務器
如下是一段經過JAVA代碼獲取文件前面兩個字節的示例程序: app
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class ImageTypeCheck { public static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } public static void main(String[] args) throws IOException { String imagePath = "c:/favicon.png"; File image = new File(imagePath); InputStream is = new FileInputStream(image); byte[] bt = new byte[2]; is.read(bt); System.out.println(bytesToHexString(bt)); } }
不過這種判斷方式和判斷擴展名同樣,也不是徹底沒有用,至少能夠在前期在簡單的檢查,爲進入下一步檢查作鋪墊。jsp
3)、獲取圖片的寬高屬性
若是可以正常的獲取到一張圖片的寬高屬性,那確定這是一張圖片,由於非圖片文件咱們是獲取不到它的寬高屬性的,如下是用於獲取根據是否能夠獲取到圖片寬高屬性來判斷這是否一張圖片的JAVA代碼:網站
/** * 經過讀取文件並獲取其width及height的方式,來判斷判斷當前文件是否圖片,這是一種很是簡單的方式。 * * @param imageFile * @return */ public static boolean isImage(File imageFile) { if (!imageFile.exists()) { return false; } Image img = null; try { img = ImageIO.read(imageFile); if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) { return false; } return true; } catch (Exception e) { return false; } finally { img = null; } }
2、圖片文件的安全檢查處理
好了,咱們終於判斷出一個文件是否圖片了,但是若是是在一個能夠正常瀏覽的圖片文件中加入一些非法的代碼呢:ui
這就是在一張正常的圖片末尾增長的一些iframe代碼,我曾經嘗試過單獨打開這張圖片,也將這張圖片放於網頁上打開,雖然這樣都不會被執行,但並不表明插入其它的代碼也並不會執行,殺毒軟件(如AVAST)對這種修改是會報爲病毒的。
那咱們要如何預防這種東西,便可以正常打開,又具備正確的圖片文件擴展名,還能夠獲取到它的寬高屬性?呵,咱們這個時候能夠對這個圖片進地重寫,給它增長水印或者對它進行resize操做,這樣新生成的圖片就不會再包含這樣的惡意代碼了,如下是一個增長水印的JAVA實現:
/** * 添加圖片水印 * * @param srcImg 目標圖片路徑,如:C:\\kutuku.jpg * @param waterImg 水印圖片路徑,如:C:\\kutuku.png * @param x 水印圖片距離目標圖片左側的偏移量,若是x<0, 則在正中間 * @param y 水印圖片距離目標圖片上側的偏移量,若是y<0, 則在正中間 * @param alpha 透明度(0.0 -- 1.0, 0.0爲徹底透明,1.0爲徹底不透明) * @throws IOException */ public final static void addWaterMark(String srcImg, String waterImg, int x, int y, float alpha) throws IOException { // 加載目標圖片 File file = new File(srcImg); String ext = srcImg.substring(srcImg.lastIndexOf(".") + 1); Image image = ImageIO.read(file); int width = image.getWidth(null); int height = image.getHeight(null); // 將目標圖片加載到內存。 BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufferedImage.createGraphics(); g.drawImage(image, 0, 0, width, height, null); // 加載水印圖片。 Image waterImage = ImageIO.read(new File(waterImg)); int width_1 = waterImage.getWidth(null); int height_1 = waterImage.getHeight(null); // 設置水印圖片的透明度。 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); // 設置水印圖片的位置。 int widthDiff = width - width_1; int heightDiff = height - height_1; if (x < 0) { x = widthDiff / 2; } else if (x > widthDiff) { x = widthDiff; } if (y < 0) { y = heightDiff / 2; } else if (y > heightDiff) { y = heightDiff; } // 將水印圖片「畫」在原有的圖片的制定位置。 g.drawImage(waterImage, x, y, width_1, height_1, null); // 關閉畫筆。 g.dispose(); // 保存目標圖片。 ImageIO.write(bufferedImage, ext, file); }
經過以上幾種方式,應該能夠避免絕大部份圖片中帶惡意代碼的安全問題,若有其餘方式,望告知。