react-native 项目怎么做上传的魔数校验
·
最近接触了一个react-native的项目,在浏览底层代码的时候发现他们的上传是直连oss的,并不像react/vue项目掉用后端接口去做的。这样就会有一个问题:如果用户手动修改了文件的后缀名那么还是能直接上传上去。这对项目的安全有一定的危害⚠️,并且像一切大型及保密性高的项目,他们会有不定时的风险漏洞扫描。
所以我翻阅了很多资料,但是并没有找到一个比较安全的npm包来使用。所以我尝试自己写了一套,欢迎大家评论沟通。
正片开始:
首先我们要用到两个npm包
import RNFS from 'react-native-fs'
import base64 from 'base-64'
react-native-fs是来读文件的
base64是用来转base64字符串的
先定义了对应格式的16进制编码
const FileTypeCode = {
jpg: 'FFD8FF',
JPG: 'FFD8FF',
png: '89504E47',
PNG: '89504E47',
gif: '47494638',
GIF: '47494638',
tif: '49492A00',
TIF: '49492A00',
bmp: '424D',
BMP: '424D',
dwg: '41433130',
DWG: '41433130',
html: '68746D6C3E',
HTML: '68746D6C3E',
rtf: '7B5C727466',
RTF: '7B5C727466',
xml: '3C3F786D6C',
XML: '3C3F786D6C',
zip: '504B0304',
ZIP: '504B0304',
rar: '52617221',
RAR: '52617221',
psd: '38425053',
PSD: '38425053',
eml: '44656C69766572792E3C',
EML: '44656C69766572792E3C',
dbx: 'CFAD12FEC5FD746F',
DBX: 'CFAD12FEC5FD746F',
pst: '2142444E',
PST: '2142444E',
xls: 'D0CF11E0',
XLS: 'D0CF11E0',
doc: 'D0CF11E0',
DOC: 'D0CF11E0',
mdb: '5374616E64617264204A',
MDB: '5374616E64617264204A',
wpd: 'FF575043',
WPD: 'FF575043',
eps: '252150532D41646F6265',
EPS: '252150532D41646F6265',
ps: '252150532D41646F6265',
PS: '252150532D41646F6265',
pdf: '255044462D312E',
PDF: '255044462D312E',
pwl: 'E3828596',
PWL: 'E3828596',
wav: '57415645',
WAV: '57415645',
avi: '41564920',
AVI: '41564920',
ram: '2E7261FD',
RAM: '2E7261FD',
rm: '2E524D46',
RM: '2E524D46',
mpg: '000001BA',
MPG: '000001BA',
mov: '6D6F6F76',
MOV: '6D6F6F76',
asf: '3026B2758E66CF11',
ASF: '3026B2758E66CF11',
mid: '4D546864',
MID: '4D546864',
jpeg: 'FFD8FFE0',
JPEG: 'FFD8FFE0',
mp4: '00000020667479706D70',
MP4: '00000020667479706D70',
mp3: '49443303000000002176',
MP3: '49443303000000002176',
}
我们使用RNFS读取文件并转化为base64字符串,计算MD5的值
这里我是截取的前30位字符串来进行对比的,我们计算出来的MD5的值是一大串字符串,但是这里不可以使用包含来进行对比,MD5的值的开头就是这个文件原本格式对应的编码
但是我们不知道他有多少位(提前规定有点不现实了哈),所以我们直接去FileType,对应的值都是【image/jpg】... 这是图片的,文件的同样,所以我们可以直接截取 / 后面的,然后去我们定义的FileTypeCode里面找到对应的编码,最后和我们计算出来的MD5的值进行开头比较。
如果一样,那么他就是没有修改后缀名,相反,他的后缀名就并不是真实的
这个逻辑走完之后,我们就避免了一个相对来说比较大的安全性的问题
RNFS.readFile(fileUrl, 'base64')
.then(res => {
try {
const binaryString = base64.decode(res)
const head30 = binaryString.slice(0, 30)
let hexString = ''
for (let i = 0; i < head30.length; i++) {
const hex = head30.charCodeAt(i).toString(16).padStart(2, '0')
hexString += hex
}
const fileType = Info && Info.type ? Info.type.split('/')[1] : ''
const expectedPrefix = (
FileTypeCode && FileTypeCode[fileType]
? String(FileTypeCode[fileType])
: ''
).toLowerCase()
const isMatch =
expectedPrefix && hexString.toLowerCase().startsWith(expectedPrefix)
if (!isMatch) {
Toast.info('请勿修改文件后缀')
return
}
} catch (e) {
console.error('Base64 转 16 进制失败:', e)
}
})
.catch(err => {
console.error(err.message, err.code)
})
写完发现自己的组织能力有待提升😭(感觉像程序员的通病啊😭😭😭),欢迎大家给予批评、讨论!
更多推荐
所有评论(0)