1. Giới thiệu về Xác thực hai yếu tố (2FA)
1.1. Xác thực hai yếu tố (2FA) là gì?
Xác thực hai yếu tố (2FA) là một lớp bảo mật bổ sung được thêm vào quy trình xác thực dựa trên tên người dùng và mật khẩu tiêu chuẩn. Nó yêu cầu người dùng cung cấp hai loại bằng chứng hoặc yếu tố khác nhau để chứng minh danh tính của họ trong quá trình xác thực. Những yếu tố này thường bao gồm thông tin người dùng biết (ví dụ: mật khẩu) và thông tin người dùng có (ví dụ: mã được gửi đến điện thoại của họ). Bằng cách kết hợp hai yếu tố này, cơ hội truy cập trái phép sẽ giảm đáng kể.
1.2. Tại sao nên sử dụng Xác thực hai yếu tố?
Xác thực hai yếu tố bổ sung thêm một lớp bảo vệ cho tài khoản người dùng, khiến kẻ tấn công khó truy cập trái phép hơn. Nó đặc biệt hữu ích trong các trường hợp mật khẩu có thể bị xâm phạm, vì yếu tố bổ sung có thể giúp ngăn chặn truy cập trái phép. Việc triển khai 2FA trong các ứng dụng web có thể tăng sự tin tưởng của người dùng và cải thiện bảo mật tổng thể.
2. Thiết lập ứng dụng Node.js Express
2.1. điều kiện tiên quyết
Để làm theo hướng dẫn này, bạn nên có:
- Đã cài đặt Node.js và npm
- Hiểu biết cơ bản về JavaScript và Node.js
- Quen thuộc với Express web framework
2.2. Tạo một ứng dụng nhanh mới
Đầu tiên, hãy tạo một ứng dụng Node.js Express mới. Trong thiết bị đầu cuối của bạn, hãy chạy các lệnh sau:
1 2 3 4 5 | $ <span class="token function">mkdir</span> node-2fa $ <span class="token builtin class-name">cd</span> node-2fa $ <span class="token function">npm</span> init -y $ <span class="token function">npm</span> <span class="token function">install</span> express |
Tạo một tệp app.js
trong thư mục gốc và thêm đoạn mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'express'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token string">'Hello, Two-Factor Authentication!'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token constant">PORT</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">.</span> <span class="token constant">PORT</span> <span class="token operator">||</span> <span class="token number">3000</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">listen</span> <span class="token punctuation">(</span> <span class="token constant">PORT</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">Server is running on port </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Bây giờ, khởi động ứng dụng bằng cách chạy lệnh sau:
1 2 | $ node app.js |
Truy cập http://localhost:3000
trong trình duyệt của bạn để xem thông báo chào mừng.
3. Triển khai 2FA bằng Mật khẩu hai bên dựa trên thời gian (TOTP)
3.1. Mật khẩu Onnee-Time Dựa trên Thời gian (TOTP) là gì?
Mật khẩu một lần dựa trên thời gian (TOTP) là một thuật toán được sử dụng để tạo mật khẩu một lần dựa trên thời gian hiện tại. Nó thường được sử dụng cho Xác thực hai yếu tố kết hợp với ứng dụng dành cho thiết bị di động hoặc thiết bị khác tạo mã TOTP. Thuật toán TOTP được định nghĩa trong tiêu chuẩn RFC 6238
.
3.2. Cài đặt các phụ thuộc cần thiết
Chúng tôi sẽ sử dụng thư viện speakeasy
để tạo mã TOTP và thư viện qrcode
để tạo mã QR để dễ dàng thiết lập các ứng dụng TOTP như Google Authenticator. Cài đặt các phụ thuộc này bằng cách chạy:
1 2 | $ <span class="token function">npm</span> <span class="token function">install</span> speakeasy qrcode |
3.3. Tạo bí mật TOTP
Trước tiên, hãy tạo một lộ trình để tạo bí mật TOTP cho người dùng. Cập nhật app.js
của bạn bằng mã sau:
1 2 3 4 5 6 7 | <span class="token keyword">const</span> speakeasy <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'speakeasy'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/generate-secret'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> secret <span class="token operator">=</span> speakeasy <span class="token punctuation">.</span> <span class="token function">generateSecret</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> length <span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> secret <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Bây giờ, bạn có thể truy cập http://localhost:3000/generate-secret
để tạo bí mật TOTP mới.
3.4. Tạo mã QR cho Bí mật TOTP
Chúng tôi sẽ tạo mã QR có thể được quét bằng ứng dụng TOTP như Google Authenticator, sau đó ứng dụng này sẽ tạo mã chính xác dựa trên bí mật. Cập nhật app.js
của bạn bằng mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">const</span> QRCode <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'qrcode'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'/generate-qr'</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> secret <span class="token operator">=</span> speakeasy <span class="token punctuation">.</span> <span class="token function">generateSecret</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> length <span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> qrCodeUrl <span class="token operator">=</span> <span class="token keyword">await</span> QRCode <span class="token punctuation">.</span> <span class="token function">toDataURL</span> <span class="token punctuation">(</span> secret <span class="token punctuation">.</span> otpauth_url <span class="token punctuation">)</span> <span class="token punctuation">;</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> <div> <h2>Scan the QR Code with a TOTP App</h2> <img src="</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> qrCodeUrl <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">" alt="QR Code"> <p><strong>Secret:</strong> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> secret <span class="token punctuation">.</span> base32 <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string"></p> </div> </span><span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Bây giờ, hãy truy cập http://localhost:3000/generate-qr
để xem mã QR được tạo và bí mật TOTP tương ứng.
4. Xác thực mã TOTP
4.1. Cài đặt Middleware để phân tích cú pháp JSON
Chúng tôi sẽ nhận mã TOTP và bí mật từ ứng dụng khách dưới dạng dữ liệu JSON. Để phân tích cú pháp dữ liệu JSON, chúng ta cần cài đặt và sử dụng phần mềm trung gian body-parser
. Cài đặt nó bằng cách chạy:
1 2 | $ <span class="token function">npm</span> <span class="token function">install</span> body-parser |
Bây giờ, hãy thêm đoạn mã sau vào app.js
để sử dụng phần mềm trung gian:
1 2 3 | <span class="token keyword">const</span> bodyParser <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'body-parser'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> bodyParser <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
4.2. Tạo một tuyến đường để xác minh mã TOTP
Bây giờ, hãy tạo một lộ trình để xác minh mã TOTP do người dùng gửi. Cập nhật app.js
của bạn bằng mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | app <span class="token punctuation">.</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token string">'/verify-totp'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">req <span class="token punctuation">,</span> res</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> token <span class="token punctuation">,</span> secret <span class="token punctuation">}</span> <span class="token operator">=</span> req <span class="token punctuation">.</span> body <span class="token punctuation">;</span> <span class="token keyword">const</span> verified <span class="token operator">=</span> speakeasy <span class="token punctuation">.</span> totp <span class="token punctuation">.</span> <span class="token function">verify</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> secret <span class="token operator">:</span> secret <span class="token punctuation">,</span> encoding <span class="token operator">:</span> <span class="token string">'base32'</span> <span class="token punctuation">,</span> token <span class="token operator">:</span> token <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> verified <span class="token punctuation">)</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> status <span class="token operator">:</span> <span class="token string">'success'</span> <span class="token punctuation">,</span> message <span class="token operator">:</span> <span class="token string">'Two-Factor Authentication successful!'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> res <span class="token punctuation">.</span> <span class="token function">send</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> status <span class="token operator">:</span> <span class="token string">'error'</span> <span class="token punctuation">,</span> message <span class="token operator">:</span> <span class="token string">'Invalid token. Please try again.'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Tuyến này nhận mã TOTP và bí mật từ máy khách, sau đó sử dụng phương thức speakeasy.totp.verify
để kiểm tra xem mã được cung cấp có chính xác hay không.
5. Thử nghiệm Xác minh TOTP
Để kiểm tra xác minh TOTP, bạn có thể sử dụng công cụ như Postman
hoặc Curl
để gửi yêu cầu POST tới tuyến /verify-totp
với tải trọng JSON chứa token
và secret
. Mã thông báo có thể được tạo bằng ứng dụng TOTP như Google Authenticator và bí mật có thể được lấy từ tuyến /generate-qr
.
Đây là một ví dụ về cách kiểm tra tuyến đường bằng Curl:
1 2 | $ <span class="token function">curl</span> -X POST -H <span class="token string">"Content-Type: application/json"</span> -d <span class="token string">'{"token": "123456", "secret": "your-secret-here"}'</span> http://localhost:3000/verify-totp |
Thay thế ” 123456
” bằng mã thông báo được tạo bởi ứng dụng TOTP của bạn và ” your-secret-here
” bằng mã bí mật thu được từ tuyến /generate-qr
.
Phần kết luận
Trong hướng dẫn này, chúng tôi đã triển khai Xác thực hai yếu tố (2FA) trong ứng dụng Node.js Express bằng cách sử dụng Mật khẩu một lần dựa trên thời gian (TOTP). Chúng tôi đã sử dụng thư viện speakeasy
để tạo và xác minh mã TOTP cũng như thư viện qrcode
để tạo mã QR nhằm dễ dàng thiết lập với các ứng dụng TOTP như Google Authenticator. Bằng cách tích hợp 2FA vào ứng dụng của mình, bạn có thể tăng cường đáng kể tính bảo mật và bảo vệ tài khoản người dùng khỏi bị truy cập trái phép.
Trong tương lai, bạn có thể cải thiện hơn nữa việc triển khai này bằng cách:
- Tích hợp chức năng đăng ký và đăng nhập người dùng
- Lưu trữ bí mật TOTP một cách an toàn cho mỗi người dùng trong cơ sở dữ liệu
- Thêm các tùy chọn khôi phục, chẳng hạn như mã dự phòng hoặc khôi phục dựa trên email/SMS, trong trường hợp người dùng mất quyền truy cập vào ứng dụng TOTP của họ
Bằng cách tiếp tục khám phá và nâng cao các tính năng bảo mật cho ứng dụng của mình, bạn có thể đảm bảo rằng bạn đang cung cấp trải nghiệm người dùng tốt nhất có thể trong khi vẫn giữ cho dữ liệu người dùng an toàn và bảo mật.
Và cuối cùng
Như mọi khi, tôi hy vọng bạn thích bài viết này và có một cái gì đó mới. Xin cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo!
Nếu các bạn thích bài viết này thì hãy cho mình 1 like và subscribe để ủng hộ mình nhé. Cảm ơn.