, October 26, 2021

0 kết quả được tìm thấy

Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!


  •   4 min reads
Upload File từ Frontend đến Backend mà rất nhiều bạn vẫn đang làm sai!!

1. Client encode file (base64) rồi gởi về backend

200Lab đã từng thấy nhiều bạn backend developer yêu cầu phía frontend làm như vậy. Cách này nhược điểm là xử lý rất nặng ở cả 2 phía. Vì frontend phải encode mà backend cũng phải decode.

200Lab đã từng thấy nhiều bạn backend developer yêu cầu phía

Trong cách này nếu backend không decode để tái tạo lại file mà lưu hết base64 string vào DB sẽ là một sai lầm rất nghiêm trọng. Khi ấy DB chúng ta rất nặng vì chứa cả file vật lý. Khi truy xuất tốn CPU và băng thông rất lớn.

=> Rõ ràng đây không phải là một giải pháp tốt.

2. Client(Front-end) dùng API + Secret Key để thực hiện upload trực tiếp lên các Cloud Storage

Đây là một giải pháp nhanh gọn, đỡ phải qua backend, NHƯNG cực kì tệ. Lý do rất đơn giản là vì secret key dễ dàng bị leak chỉ với một thủ pháp đơn giản là… capture/debug request upload file.

Một khi secret key bị lộ, người tấn công có thể toàn quyền với key ấy. Nhẹ thì storage của chúng ta bị xài free. Nặng thì bị kéo toàn bộ file hoặc xoá toàn bộ file trên storage (nếu key có quyền xoá).

Nếu vậy thì làm sao cho ĐÚNG? Có 2 cách các bạn có thể tham khảo:

Cách 1: Upload trung gian qua backend:

Client upload file lên backend nhưng không cần thực hiện base64 encode. Chúng ta chỉ cần sử dụng multipart form data là ổn. Khi ấy backend nhận file xong có thể lựa chọn upload tiếp lên Cloud Storage hoặc một nơi nào đó bảo mật mà chỉ có backend biết.

Như vậy client không cần secret key nên không sợ lộ nữa. Backend khi cần có thể chuyển đổi được dịch vụ Cloud nhanh chóng.Tuy nhiên cách này có nhược điểm:

  • Client sẽ đợi lâu hơn đáng kể để nhận phản hồi từ backend. Vì backend phải upload lại qua Cloud.
  • Băng thông tiêu thụ ở backend sẽ gấp đôi. VD nhận file 10MB, upload đi 10MB là 20MB băng thông I/O.

Cách 2: Client upload file lên Cloud Storage NHƯNG dùng Presigned URL từ backend:

Để giải quyết tốt hơn cho bài toán trên, các nhà điều hành Cloud Storage đã nghĩ ra một giải pháp để vừa có thể đảm bảo tính bảo mật và backend cũng không cần tốn băng thông. Đó là Presigned URL.

Presigned URL đại khái là một URL với các thông số bảo mật, cung cấp một permission tạm thời để đọc và tạo file trên Cloud. Để tạo thành công Presigned URL, chúng ta cần backend làm điều này. Một lần nữa, 200Lab nhấn mạnh và khuyên rằng chúng ta không nên làm việc này ở Client/Frontend.

Cách implement API upload này khá đơn giản, các bạn có thể viết một API GET trả về một đường link đặc biệt (Presigned URL). Client sử dụng link này để upload file lên (hay đúng hơn là PUT Object lên S3).

VD cách lấy Presigned URL với Golang:

package main

import (
    "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
    "log"
    "time"
)

func main() {
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("your bucket region")},
        Credentials: credentials.NewStaticCredentials(
			"your api key", // Access key ID
			"your secret key", // Secret access key
			"token (optional)",
        )
    )

    // Create S3 service client
    svc := s3.New(sess)

    req, _ := svc.PutObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String("myBucket"),
        Key:    aws.String("myFileName"),
    })
    urlStr, err := req.Presign(5 * time.Minute)

    if err != nil {
        log.Println("Failed to sign request", err)
    }

    log.Println("The URL is", urlStr)
}
Presigned URL có hạn sử dụng trong 5 phút

Còn với NodeJS thì đại khái như sau:

var req = require('request');
var fs = require('fs');
var AWS = require('aws-sdk');

AWS.config.update({
  accessKeyId: "your api key",
  secretAccessKey: "your secret key"
});

var s3 = new AWS.S3();
var params = {Bucket: 'bucket-name', Key: 'myFileName', Expires: 5 * 60 };
var url = s3.getSignedUrl('putObject', params);

console.log(url);

Client có thể dùng URL này để upload file trực tiếp vào (method PUT với body file content cần upload). Như vậy backend không cần phải “trung chuyển” file nữa. Từ đó vấn đề băng thông được giải quyết. Resource được giải phóng. Hoá đơn tính tiền cũng nhẹ gánh rất đáng kể.

Tóm lại:

Hy vọng rằng với chia sẻ trên, các bạn Backend sẽ làm API Upload file chuẩn chỉnh hơn.

Bên cạnh đó giải pháp này cũng thường được dùng để download file (GET Object S3) với một URL có hiệu lực tạm thời, và cũng chính là PresignedURL. Với cách này, hy vọng các bạn đã có thể tăng bảo mật cho S3 của mình nhé :D.

Bài viết liên quan

Tất cả những điều cần biết về Microservices

Ở nhiều nơi, các tổ chức đang áp dụng kiến ​​trúc microservices và đầu tư rất nhiều tiền vào việc chuyển đổi các monolith củ kĩ thành các dịch vụ mới mẻ như microservices...

Tất cả những điều cần biết về Microservices
Microservices: Những sai lầm và chiến lược chuyển đổi từ Monolith

Microservices vs Monolith: những khó khăn, sai lầm và chiến lược chuyển đổi hợp lý. FREE DOWNLOAD full slide: 500K CCU với Microservices....

Microservices: Những sai lầm và chiến lược chuyển đổi từ Monolith
Tìm hiểu ngôn ngữ lập trình Golang. Tại sao bạn nên học Golang vào bây giờ?

Golang là ngôn ngữ lập trình mã nguồn mở giúp xây dựng phần mềm dễ dành, tin cậy và hiệu quả. Hiện tại Golang đang dần trở nên phổ biến trên thế giới, rất nhiều nơi đã chuyển đổi hệ thống về Golang, trong đó có cả Việt Nam....

Tìm hiểu ngôn ngữ lập trình Golang. Tại sao bạn nên học Golang vào bây giờ?
gRPC là gì? Vũ khí tối thượng tăng tải Microservices

gRPC là một framework RPC mã nguồn mở, hiện đại và hiêu năng cao. Đây được cho là một thế hệ tiếp theo của RPC đặc biệt là trong mô hình Microservices....

gRPC là gì? Vũ khí tối thượng tăng tải Microservices
REST API là gì? Cách thiết kế REST API có thể bạn chưa biết

REST API không còn là khái niệm xa lạ với tất cả anh em dev từ frontend tới backend. Tuy nhiên để hiểu rõ và làm đúng các chỉ dẫn tiêu chuẩn (convention) của REST thì có thể nhiều bạn vẫn chưa biết....

REST API là gì? Cách thiết kế REST API có thể bạn chưa biết
You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.