Two-Factor Authentication và ứng dụng
2fa
1
Security
29
golang
49
White

Thach Le viết ngày 26/05/2018

Trong thế giới của việc thông tin cá nhân đang ngày càng bị xâm phạm và tấn công, đến thời điểm này đã có gần 10 tỷ accounts bị leaked thì chuyện phải implement một phương pháp đăng nhập có tính bảo mật cao hơn là một chuyện bất cứ cá nhân/tổ chức nào cũng aware được.

Two-factor Authentication là một trong số đó. Trong bài này mình sẽ chia sẻ những kiến thức đã tổng hợp được trong quá trình làm việc với 2FA.

alt text

Two-Factor Authentication (2FA) là gì?

Two-Factor Authentication (2FA) hay còn gọi là Bảo mật 2 lớp, là một phương thức để chứng thực user bằng việc combine 2 factors khác nhau từ bộ source:

  • Một cái gì đó bạn biết.
  • Một cái gì đó bạn có.
  • Một cái gì đó mà nó mặc nhiên như vậy.

Một ví dụ khá cơ bản của 2FA đó là khi bạn rút tiền ở ATM, bạn cần 2 thứ, một là cái thẻ (bạn có) và mã PIN (bạn biết) mới có khả năng thực hiện rút tiền.

Như vậy nó áp dụng trong online authentication như thế nào?

Với bảo mật thông thường, bạn chỉ cần nhập username và password để đăng nhập tài khoản của mình, thứ bảo vệ duy nhất của bạn là mật khẩu. Đây là cái mà "bạn biết". 2FA sẽ thêm một extra layer để bạn cần provide cái mà "bạn có" nữa.

Các loại 2FA

  • Hardware Token
  • SMS/Voice based
  • Software Token
  • Push notification
  • Các loại khác

Như bạn thấy, có rất nhiều cách để mô phỏng cái mà "bạn có".

Chẳng hạn, SMS là một sự lựa chọn không tồi, server gửi SMS về cho user để đăng nhập. Nhưng SMS lại không quá an toàn (có thể bị intercepted), và bị vấn đề về network, việc delay có thể làm ảnh hưởng tới authentication process.

Vì nhiều lí do khác nhau nên team quyết định chọn dùng Software Token cho 2FA. Và từ bây giờ trong bài viết mình 2FA cũng được ám chỉ tới phương pháp sử dụng cryptographically key của Software Token.

2FA hoạt động như thế nào?

Mình lấy ví dụ gitlab.
Đây là lúc đăng nhập, mình sẽ provide user và password.

alt text

Sau khi đăng nhập xong, vì mình có enable 2FA nên nó sẽ redirect mình tới trang điền code (soft token).

alt text

Code này sẽ được lấy từ Authentication application, có thể là Authy, Google authenticator ...

alt text

Ví dụ như mình dùng Authy để lấy được code. Mỗi code sẽ được thay đổi sau 30s.

Với code này mình sẽ đăng nhập thành công.

Cơ chế hoạt động internally của 2FA

Khi bạn enable 2FA cho tài khoản của mình, bạn sẽ nhận được một secret key based 32. Tùy vào mức độ security, độ dài của secret key có thể là 80, 128 hoặc 160 bit.

Các authenticator application sẽ scan secret này dưới dạng QR code (hoặc manually) và dùng nó để generate ra một HMAC-SHA1. Chuỗi HMAC này có thể là một trong 2 dạng:

Sau đó HMAC này sẽ được extracted và lấy ra 1 số int 4 byte, đó chính là code.

Một mã code sẽ valid trong 30 giây. Tuy nhiên không phải ai cũng có clock synced giống nhau, vì network latency các kiểu nên thường mọi người hay cho phép ở phạm vi cộng trừ 1 code, tức là 1 code sẽ valid trong 1 phút 30 giây. Điều này có thể giảm tính an toàn, nhưng lại tăng sự trải nghiệm đáng kể.

Backup codes

Backup codes hay recovery codes sẽ được sử dụng trong trường hợp bạn không thể sử dụng điện thoại, bạn có thể dùng chúng để đăng nhập. Có 2 loại backup codes:

  • Multiple backup codes: Ví dụ github sẽ cho bạn 10 codes, và mỗi code sẽ được sử dụng 1 lần.
  • Single backup code: Bạn dùng cái code này đồng nghĩa với việc bạn có thể đăng nhập, nhưng phải setup lại 2FA (nó assume bạn bị mất điện thoại).

Làm thế nào để apply 2FA vào dự án của mình?

Khá đơn giản, hầu hết ngôn ngữ đều open source implementation của mình. Mình code Go, library mà mình chọn là github.com/dgryski/dgoogauth được viết bởi Damian Gryski, một gopher rất nổi tiếng.

Flow chương trình
alt text

Khi một user muốn enable 2FA, App sẽ gọi RequestGenerate2FA API.

Trong API này sẽ generate ra một temporary secret và lưu vào redis, trong thời gian expire 5 phút.

GenerateSecret thì khá đơn giản thôi.

// GenerateSecret generates a 10 byte secret string.
func GenerateSecret() (string, error) {
    random := make([]byte, 10)
    _, err := rand.Read(random)
    if err != nil {
        return "", err
    }
    return base32.StdEncoding.EncodeToString(random), nil
}

Sau khi app nhận được secret, sẽ turn thành QR code và đưa cho user. QR code này sẽ được user dùng Authenticator application để quét.

Khi đã có code, user input vào và app sẽ tiếp tục make request lên API Generate2FA. Nếu thành công thì user đã được enable 2FA.

Trong hàm Generate2FA chúng ta cần verify được code gửi lên và secret lấy từ redis có valid hay không. Sử dụng library trên như sau:

otpc := &dgoogauth.OTPConfig{
      Secret:      info.Secret,
      WindowSize:  3,
      HotpCounter: 0,
}

valid, err := otpc.Authenticate(req.Code)
if err != nil || !valid {
    return errors.New("Invalid authenticate code")
}

// success validation

(Các bạn có thể đọc thêm source code để biết function Authenticate hoạt động như thế nào, chỉ có 1 file go thôi).

Sau khi validate xong thì mình trả về Recovery codes luôn (cho tiện ở phía application).

Còn đây thì flow khi login, nếu cần thêm 2FA thì sẽ require code từ user, sau đó upgrade cái access token đó (simply add thêm 1 fields 2fa: true) để nhận dạng là đã 2FA authenticated rồi.
alt text

Kết luận

2FA là một kĩ thuật dùng để enhance security layer của một application. Hay nói cách khác, bạn khóa 1 cửa bằng 2 cái khóa luôn an toàn hơn 1 cái. Trong xã hội đầy loạn lạc này thì ứng dụng nào quan trọng, chứa nhiều sensitive data và liên quan tới tiền bạc thì cứ auto bật 2FA thôi.

References

Bài viết được trích ra từ blog Runikitkat

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Thach Le

7 bài viết.
131 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
44 3
Chắc các bạn cũng không lạ lẫm gì Go nữa, Go là một ngôn ngữ backend được phát triển bởi Google. (Ảnh) Một vài điểm mạnh nổi bật trong Go: Stati...
Thach Le viết 1 năm trước
44 3
White
40 5
Dạo này Rust đang nổi lên như một thế lực khiến một hispter như mình không thể không để tâm. Sau vài ngày dig deeper vào Rust, mình cho rằng Rust l...
Thach Le viết hơn 1 năm trước
40 5
White
34 7
GraphQL được tạo ra bởi Facebook vào năm 2012, production ready năm 2016 nhưng hiện tại vẫn chưa phổ biến lắm với cộng đồng developers, đặc biệt là...
Thach Le viết 11 tháng trước
34 7
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
7 bài viết.
131 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!