Go语言 通过文件流判断文件头来识别文件类型

系统中需要用到文件上传的功能,但是从系统安全的角度上来说需要判断上传文件的格式,防止将病毒木马等有害的文件上传到服务器上。

判断文件类型有三种方式

1、通过文件后缀名

这个方法简单容易,但是也是最容易被欺骗的方法,修改文件的后缀名即可实现欺骗系统。

2、通过Content-Type判断

这个是通过判断文件的MIME类型进行判断,我们在通过form表单上传文件时,在上传的request域里面会获取当前文件的MIME类型,我们可以通过控制接收文件的MIME类型进行判断。这个方法如果通过抓包的形式进行修改类型也不安全。

安全问题详解:

https://www.cnblogs.com/dunitian/p/5645339.html

注意:现在遇见一个问题就是在angular框架下通过consumes参数进行控制上传文件类型时,当错误类型时会产生415(不被允许的多媒体类型),但是正确类型时,会产生ERROR_CONNECTION_RESET连接重定向错误。(待解决)

3、通过文件流判断文件头

package utils

import (
    "bytes"
    "encoding/hex"
    "strconv"
    "strings"
    "sync"
)

var fileTypeMap sync.Map

func init() {
    fileTypeMap.Store("ffd8ffe000104a464946", "jpg")  //JPEG (jpg)
    fileTypeMap.Store("89504e470d0a1a0a0000", "png")  //PNG (png)
    fileTypeMap.Store("47494638396126026f01", "gif")  //GIF (gif)
    fileTypeMap.Store("49492a00227105008037", "tif")  //TIFF (tif)
    fileTypeMap.Store("424d228c010000000000", "bmp")  //16色位图(bmp)
    fileTypeMap.Store("424d8240090000000000", "bmp")  //24位位图(bmp)
    fileTypeMap.Store("424d8e1b030000000000", "bmp")  //256色位图(bmp)
    fileTypeMap.Store("41433130313500000000", "dwg")  //CAD (dwg)
    fileTypeMap.Store("3c21444f435459504520", "html") //HTML (html)   3c68746d6c3e0  3c68746d6c3e0
    fileTypeMap.Store("3c68746d6c3e0", "html")        //HTML (html)   3c68746d6c3e0  3c68746d6c3e0
    fileTypeMap.Store("3c21646f637479706520", "htm")  //HTM (htm)
    fileTypeMap.Store("48544d4c207b0d0a0942", "css")  //css
    fileTypeMap.Store("696b2e71623d696b2e71", "js")   //js
    fileTypeMap.Store("7b5c727466315c616e73", "rtf")  //Rich Text Format (rtf)
    fileTypeMap.Store("38425053000100000000", "psd")  //Photoshop (psd)
    fileTypeMap.Store("46726f6d3a203d3f6762", "eml")  //Email [Outlook Express 6] (eml)
    fileTypeMap.Store("d0cf11e0a1b11ae10000", "doc")  //MS Excel 注意:word、msi 和 excel的文件头一样
    fileTypeMap.Store("d0cf11e0a1b11ae10000", "vsd")  //Visio 绘图
    fileTypeMap.Store("5374616E64617264204A", "mdb")  //MS Access (mdb)
    fileTypeMap.Store("252150532D41646F6265", "ps")
    fileTypeMap.Store("255044462d312e350d0a", "pdf")  //Adobe Acrobat (pdf)
    fileTypeMap.Store("2e524d46000000120001", "rmvb") //rmvb/rm相同
    fileTypeMap.Store("464c5601050000000900", "flv")  //flv与f4v相同
    fileTypeMap.Store("00000020667479706d70", "mp4")
    fileTypeMap.Store("49443303000000002176", "mp3")
    fileTypeMap.Store("000001ba210001000180", "mpg") //
    fileTypeMap.Store("3026b2758e66cf11a6d9", "wmv") //wmv与asf相同
    fileTypeMap.Store("52494646e27807005741", "wav") //Wave (wav)
    fileTypeMap.Store("52494646d07d60074156", "avi")
    fileTypeMap.Store("4d546864000000060001", "mid") //MIDI (mid)
    fileTypeMap.Store("504b0304140000000800", "zip")
    fileTypeMap.Store("526172211a0700cf9073", "rar")
    fileTypeMap.Store("235468697320636f6e66", "ini")
    fileTypeMap.Store("504b03040a0000000000", "jar")
    fileTypeMap.Store("4d5a9000030000000400", "exe")        //可执行文件
    fileTypeMap.Store("3c25402070616765206c", "jsp")        //jsp文件
    fileTypeMap.Store("4d616e69666573742d56", "mf")         //MF文件
    fileTypeMap.Store("3c3f786d6c2076657273", "xml")        //xml文件
    fileTypeMap.Store("494e5345525420494e54", "sql")        //xml文件
    fileTypeMap.Store("7061636b616765207765", "java")       //java文件
    fileTypeMap.Store("406563686f206f66660d", "bat")        //bat文件
    fileTypeMap.Store("1f8b0800000000000000", "gz")         //gz文件
    fileTypeMap.Store("6c6f67346a2e726f6f74", "properties") //bat文件
    fileTypeMap.Store("cafebabe0000002e0041", "class")      //bat文件
    fileTypeMap.Store("49545346030000006000", "chm")        //bat文件
    fileTypeMap.Store("04000000010000001300", "mxp")        //bat文件
    fileTypeMap.Store("504b0304140006000800", "docx")       //docx文件
    fileTypeMap.Store("d0cf11e0a1b11ae10000", "wps")        //WPS文字wps、表格et、演示dps都是一样的
    fileTypeMap.Store("6431303a637265617465", "torrent")
    fileTypeMap.Store("6D6F6F76", "mov")         //Quicktime (mov)
    fileTypeMap.Store("FF575043", "wpd")         //WordPerfect (wpd)
    fileTypeMap.Store("CFAD12FEC5FD746F", "dbx") //Outlook Express (dbx)
    fileTypeMap.Store("2142444E", "pst")         //Outlook (pst)
    fileTypeMap.Store("AC9EBD8F", "qdf")         //Quicken (qdf)
    fileTypeMap.Store("E3828596", "pwl")         //Windows Password (pwl)
    fileTypeMap.Store("2E7261FD", "ram")         //Real Audio (ram)
}

// 获取前面结果字节的二进制
func bytesToHexString(src []byte) string {
    res := bytes.Buffer{}
    if src == nil || len(src) <= 0 {
        return ""
    }
    temp := make([]byte, 0)
    for _, v := range src {
        sub := v & 0xFF
        hv := hex.EncodeToString(append(temp, sub))
        if len(hv) < 2 {
            res.WriteString(strconv.FormatInt(int64(0), 10))
        }
        res.WriteString(hv)
    }
    return res.String()
}

// 用文件前面几个字节来判断
// fSrc: 文件字节流(就用前面几个字节)
func GetFileType(fSrc []byte) string {
    var fileType string
    fileCode := bytesToHexString(fSrc)

    fileTypeMap.Range(func(key, value interface{}) bool {
        k := key.(string)
        v := value.(string)
        if strings.HasPrefix(fileCode, strings.ToLower(k)) ||
            strings.HasPrefix(k, strings.ToLower(fileCode)) {
            fileType = v
            return false
        }
        return true
    })
    return fileType
}

测试:

func TestGetFileType(t *testing.T) {
    //f, err := os.Open("C:\\Users\\Administrator\\Desktop\\api.html")
    f, err := os.Open("C:\\Users\\Administrator\\Desktop\\Wildlife.wmv")
    if err != nil {
        t.Logf("open error: %v", err)
    }

    fSrc, err := ioutil.ReadAll(f)
    t.Log(GetFileType(fSrc[:10]))
}

结果:

D:\GoWorks\src\server\web\backend\src\utils>go test -v
=== RUN   TestGetFileType
--- PASS: TestGetFileType (0.00s)
    regexp_test.go:39: html
PASS
ok      server/web/backend/src/utils    0.547s

D:\GoWorks\src\server\web\backend\src\utils>go test -v
=== RUN   TestGetFileType
--- PASS: TestGetFileType (0.07s)
    regexp_test.go:40: wmv
PASS
ok      server/web/backend/src/utils    0.480s

转载于:https://www.cnblogs.com/enjong/articles/10741244.html

你可能感兴趣的:(Go语言 通过文件流判断文件头来识别文件类型)