Series bảo mật trong ASP.NET MVC - 4: Upload các tệp tin có hại
Qua 3 bài trước chúng ta đã từng tìm hiểu về cách bảo vệ tất cả các trường nhập liệu. Nhưng chúng ta đã bỏ qua một trường chính là trường File Upload mà chúng ta cần bảo vệ và kiểm tra kỹ càng, control này bị hầu hết các hacker khai thác để upload các tệp tin có hại. Các hacker có thể thay đổi đuôi của tệp tin (ví dụ tuto.exe sang tuto.jpeg] sau đó các đoạn mã có hạo có thể được upload như một file ảnh. Hầu hết các developer chỉ nhìn vào đuôi file và lưu chúng vào thư mục hoặc database nhưng thực tế có thể là loại file khác.

Giải pháp:-
- Đầu tiên chúng ta cần validate file tải lên.
- Thứ 2 là chỉ cho phép truy cập các file extension cụ thể
- Kiểm tra file header.
Đầu tiên thêm mới các file upload vào view.
Thêm upload control

Chúng ta đã thêm file upload control vào View sau đó validate nó ở nút submit.
Validate file trong action method
Đầu tiên chúng ta kiểm tra thuộc tính Content-Length nếu là 0 sau đó chúng ta không upload file lên.
Nếu Content-Length lớn hơn 0 thì chúng ta sẽ đọc tên file, loại file và kích thước file.
[HttpPost]
[ValidateAntiForgeryToken]
publicActionResult Index(EmployeeDetailEmployeeDetail)
{
if (ModelState.IsValid)
{
HttpPostedFileBase upload = Request.Files["upload"];
if (upload.ContentLength == 0)
{
ModelState.AddModelError("File", "Please Upload your file");
}
elseif(upload.ContentLength > 0)
{
stringfileName = upload.FileName; // getting File Name
stringfileContentType = upload.ContentType; // getting ContentType
byte[] tempFileBytes = newbyte[upload.ContentLength]; // getting filebytes
var data = upload.InputStream.Read(tempFileBytes, 0, Convert.ToInt32(upload.ContentLength));
var types = MvcSecurity.Filters.FileUploadCheck.FileType.Image; // Setting Image type
var result = FileUploadCheck.isValidFile(tempFileBytes, types, fileContentType); // Validate Header
if (result == true)
{
intFileLength = 1024 * 1024 * 2; //FileLength 2 MB
if (upload.ContentLength > FileLength)
{
ModelState.AddModelError("File", "Maximum allowed size is: " + FileLength + " MB");
}
else
{
stringdemoAddress = Sanitizer.GetSafeHtmlFragment(EmployeeDetail.Address);
dbcon.EmployeeDetails.Add(EmployeeDetail);
dbcon.SaveChanges();
return View();
}
}
}
}
return View(EmployeeDetail);
}
Các validate cơ bản đã xong, hãy validate file upload được viết trong một class static với tên là FileUploadCheckin, class này có cá phương thức để kiểm tra các loại file khác nhau. Tôi sẽ chỉ cho bạn làm sao để validate các file image và chỉ cho phép file image mà thôi.
FileUploadCheck Class

Ảnh chụp trên có một enum là ImageFileExtension chứa danh sách các đuôi cho phép định dạng ảnh và các file type cho phép.
private enum ImageFileExtension
{
none = 0,
jpg = 1,
jpeg = 2,
bmp = 3,
gif = 4,
png = 5
}
public enum FileType
{
Image = 1,
Video = 2,
PDF = 3,
Text = 4,
DOC = 5,
DOCX = 6,
PPT = 7,
}
Nếu đã qua được các validate căn bản chúng ta sẽ gọi phương thức ValidFileMethod theo byte, loại file, FileContentType
public static bool isValidFile(byte[] bytFile, FileType flType, String FileContentType)
{
bool isvalid = false;
if (flType == FileType.Image)
{
isvalid = isValidImageFile(bytFile, FileContentType);//we are going call this method
}
else if (flType == FileType.Video)
{
isvalid = isValidVideoFile(bytFile, FileContentType);
}
else if (flType == FileType.PDF)
{
isvalid = isValidPDFFile(bytFile, FileContentType);
}
return isvalid;
}
Sau khi gọi phương thức isValidFile sẽ gọi dựa trên loại file.
Nếu loại file là image thì sẽ gọi đến phương thức isValidImageFile, nếu là video thì sẽ gọi phương thức isValidVideoFile, và tương tự như thế với PDF.
Dưới đây là đoạn code kiểm tra của phương thức isValidImageFile
Trong phương thức này chúng ta sẽ giới hạn các đuôi cho phép upload hình ảnh như [jpg, jpeg, png, bmp, gif]
Làm việc với phương thức isValidImageFile
Khi chúng ta pass qua bytes và FileContentType phương thức này sẽ kiểm tra FileContentType
Sau đó nó sẽ kiểm tra các bytes quy định header của file được tải lên đúng với loại file.
public static bool isValidImageFile(byte[] bytFile, String FileContentType)
{
bool isvalid = false;
byte[] chkBytejpg = { 255, 216, 255, 224 };
byte[] chkBytebmp = { 66, 77 };
byte[] chkBytegif = { 71, 73, 70, 56 };
byte[] chkBytepng = { 137, 80, 78, 71 };
ImageFileExtensionimgfileExtn = ImageFileExtension.none;
if (FileContentType.Contains("jpg") | FileContentType.Contains("jpeg"))
{
imgfileExtn = ImageFileExtension.jpg;
}
else if (FileContentType.Contains("png"))
{
imgfileExtn = ImageFileExtension.png;
}
else if (FileContentType.Contains("bmp"))
{
imgfileExtn = ImageFileExtension.bmp;
}
else if (FileContentType.Contains("gif"))
{
imgfileExtn = ImageFileExtension.gif;
}
if (imgfileExtn == ImageFileExtension.jpg || imgfileExtn == ImageFileExtension.jpeg)
{
if (bytFile.Length >= 4)
{
int j = 0;
for (Int32 i = 0; i <= 3; i++)
{
if (bytFile[i] == chkBytejpg[i])
{
j = j + 1;
if (j == 3)
{
isvalid = true;
}
}
}
}
}
if (imgfileExtn == ImageFileExtension.png)
{
if (bytFile.Length >= 4)
{
int j = 0;
for (Int32 i = 0; i <= 3; i++)
{
if (bytFile[i] == chkBytepng[i])
{
j = j + 1;
if (j == 3)
{
isvalid = true;
}
}
}
}
}
if (imgfileExtn == ImageFileExtension.bmp)
{
if (bytFile.Length >= 4)
{
int j = 0;
for (Int32 i = 0; i <= 1; i++)
{
if (bytFile[i] == chkBytebmp[i])
{
j = j + 1;
if (j == 2)
{
isvalid = true;
}
}
}
}
}
if (imgfileExtn == ImageFileExtension.gif)
{
if (bytFile.Length >= 4)
{
int j = 0;
for (Int32 i = 0; i <= 1; i++)
{
if (bytFile[i] == chkBytegif[i])
{
j = j + 1;
if (j == 3)
{
isvalid = true;
}
}
}
}
}
return isvalid;
}
Gọi phương thức isValid file
Chúng ta sẽ gọi FileUploadCheck.isValidFile và đưa tham số File Bytes, Types, FileContentType.
Phương thức này sẽ trả về giá trị Boolean nếu file validate true và ngược lại là false.
string fileName = upload.FileName; // getting File Name
string fileContentType = upload.ContentType; // getting ContentType
byte[] tempFileBytes = new byte[upload.ContentLength]; // getting filebytes
var data = upload.InputStream.Read(tempFileBytes, 0, Convert.ToInt32(upload.ContentLength));
var types = MvcSecurity.Filters.FileUploadCheck.FileType.Image; // Setting Image type
var result = FileUploadCheck.isValidFile(tempFileBytes, types, fileContentType); //Calling isValidFile method
Sau khi hiểu đoạn code bạn sẽ nhìn một demo sau
Form dưới đây hiển thị nhập Employee với upload control
Chúng ta sẽ nhập các form dưới đây và chọn 1 file valid

Chọn một file .jpg và kiểm tra
Chọn 1 ảnh .jpg từ ổ đĩa


Debug phương thức
Trong phần này chúng ta đã đăng Employee với 1 file chúng ta có thể thấy các validate cơ bản.

Sau khi submit form để lưu dữ liệu, hiển thị giá trị thực của file đã upload.

Hình chụp của class FileUploadCheck trong khi phương thức isValidFile được gọi.
Trong phần này gọi phương thức isValidfile nó sẽ goi phương thức khác theo FileContentType.

Phương thức isValidImageFile trong khi kiểm tra các byte header.
Trong phương thức này nó sẽ kiểm tra các byte đầu tiên quy định kiểu file upload là image.

Trích nguồn từ: codeproject.com
Bài viết liên quan
Làm việc với User Secrets trong ứng dụng ASP.NET Core
Chúng ta tìm hiểu cách làm việc với UserSecrets để quản lý các thông tin cấu hình nhạy cảm và bí mật của ứng dụng.
Đọc thêm
Tổng quan các loại thuật toán mã hoá dữ liệu
Bài viết rất hay giới thiệu về tổng quan các loại thuật toán mã hoá dữ liệu dành cho những bạn nào muốn tìm hiểu về thuật toán mã hoá.
Đọc thêm
Series bảo mật trong ASP.NET MVC - 5: Rỏ rỉ thông tin máy chủ
Các thông tin về phiên bản được sử dụng bởi một kẻ tấn công sẽ khai thác để tấn công vào hệ thống.
Đọc thêm
Series bảo mật trong ASP.NET MVC - 3: Tấn công Cross-Site Scripting (XSS)
Tấn công Cross-site Scripting (XSS) là cách tấn công bằng việc đẩy các đoạn mã javascript vào hệ thống thông qua các trường nhập liệu
Đọc thêm
Series bảo mật trong ASP.NET MVC - 2: Cross-Site Request Forgery (CSRF)
Cách tấn công CSRF này gọi là giả mạo request khi chúng giả mạo một request không phải từ chính website mà hacker sẽ giả lập request để gửi các thông tin lên server mà không qua hệ thống website.
Đọc thêm
Series bảo mật trong ASP.NET MVC - 1: Cấu hình Custom Error Page
Trong loại tấn công này, tin tặc sẽ lấy dữ liệu từ form được gửi lên từ người dùng và thay đổi giá trị sau đó gửi dữ liệu đã được sửa lên server
Đọc thêm
7 thủ thuật giúp bảo mật ứng dụng ASP.NET developer cần biết
Là một nhà phát triển web chuyên nghiệp, bạn phải biết được các chiêu thức để giúp ứng dụng bảo mật hơn. Trong bài viết này mình sẽ liệt kê và giải thích 7 thủ thuật bảo mật ứng dụng web.
Đọc thêm