Bởi Alex Nadalin
Giới Thiệu Về Bảo Mật Ứng Dụng Web
Ảnh bởi Liam Tucker trên Unsplash
Hãy mở đầu loạt bài về Bảo mật Ứng dụng Web với giải thích về những gì trình duyệt làm và cách chúng làm. Vì hầu hết khách hàng của bạn sẽ tương tác với ứng dụng web qua trình duyệt, việc hiểu cơ bản về những chương trình tuyệt vời này là điều bắt buộc.
Trình duyệt là một движок hiển thị (rendering engine). Nhiệm vụ của nó là tải xuống một trang web và hiển thị nó theo cách con người có thể hiểu được.
Dù đây là một sự đơn giản hóa gần như "phạm tội", nhưng đó là tất cả những gì chúng ta cần biết cho lúc này.
- Người dùng nhập địa chỉ vào thanh địa chỉ trình duyệt.
- Trình duyệt tải xuống "tài liệu" tại URL đó và hiển thị nó.

Bạn có thể quen làm việc với các trình duyệt phổ biến như Chrome, Firefox, Edge hoặc Safari, nhưng không có nghĩa là không có các trình duyệt khác.
Ví dụ lynx là một trình duyệt dựa trên văn bản, nhẹ lượng, hoạt động từ dòng lệnh. Cốt lõi của lynx dựa trên chính xác các nguyên tắc bạn tìm thấy trong bất kỳ trình duyệt "chính thống" nào. Người dùng nhập địa chỉ web (URL), trình duyệt tải tài liệu và hiển thị nó — sự khác biệt duy nhất là lynx không dùng движок hiển thị trực quan mà dùng giao diện dựa trên văn bản, khiến các trang như Google trông như thế này:

Chúng ta hiểu khái quát trình duyệt làm gì, nhưng hãy nhìn sâu hơn vào các bước những ứng dụng thông minh này thực hiện cho chúng ta.
Trình Duyệt Làm Gì?
Tóm lại, công việc của trình duyệt chủ yếu bao gồm:
- Phân giải DNS
- Trao đổi HTTP
- Hiển thị (Rendering)
- Lặp lại quá trình
Phân Giải DNS
Quá trình này đảm bảo khi người dùng nhập URL, trình duyệt biết phải kết nối đến máy chủ nào. Trình duyệt liên hệ máy chủ DNS để tìm ra google.com dịch sang 216.58.207.110, một địa chỉ IP mà trình duyệt có thể kết nối.
Trao Đổi HTTP
Khi trình duyệt đã xác định máy chủ nào sẽ phục vụ yêu cầu, nó sẽ khởi tạo kết nối TCP và bắt đầu trao đổi HTTP. Đây đơn giản là cách trình duyệt giao tiếp với máy chủ về thứ nó cần, và máy chủ phản hồi lại.
HTTP là tên của giao thức phổ biến nhất để giao tiếp trên web, và trình duyệt chủ yếu nói chuyện qua HTTP khi giao tiếp với máy chủ. Một lần trao đổi HTTP bao gồm client (trình duyệt của chúng ta) gửi một yêu cầu (request), và máy chủ phản hồi lại với một phản hồi (response).
Ví dụ, sau khi trình duyệt kết nối thành công đến máy chủ phía sau google.com, nó sẽ gửi yêu cầu trông như sau:
GET / HTTP/1.1
Host: google.com
Accept: */*
Hãy phân tích yêu cầu, dòng per dòng:
GET / HTTP/1.1: Dòng đầu tiên này, trình duyệt yêu cầu máy chủ truy xuất tài liệu tại vị trí/, thêm rằng phần còn lại của yêu cầu sẽ tuân theo giao thức HTTP/1.1 (có thể dùng1.0hoặc2)Host: google.com: Đây là header HTTP duy nhất bắt buộc trong HTTP/1.1. Vì máy chủ có thể phục vụ nhiều domain (google.com,google.co.uk, v.v), client ở đây đề cập rằng yêu cầu dành cho host cụ thể đóAccept: */*: Một header tùy chọn, nơi trình duyệt nói với máy chủ rằng nó sẽ chấp nhận bất kỳ loại phản hồi nào. Máy chủ có thể có tài nguyên có sẵn ở định dạng JSON, XML hoặc HTML, nên nó có thể chọn định dạng nào nó thích
Sau khi trình duyệt, đóng vai trò client, xong yêu cầu, đến lượt máy chủ phản hồi. Đây là hình dạng phản hồi:
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Set-Cookie: NID=1234; expires=Fri, 18-Jan-2019 18:25:04 GMT; path=/; domain=.google.com; HttpOnly
<!doctype html><html>......</html>
Wow, đó là nhiều thông tin để tiêu hóa. Máy chủ cho biết yêu cầu thành công (200 OK) và thêm một vài header vào phản hồi, ví dụ nó quảng cáo máy chủ nào xử lý yêu cầu của chúng ta (Server: gws), chính sách X-XSS-Protection của phản hồi này, v.v.
Lúc này, bạn không cần hiểu từng dòng trong phản hồi. Chúng ta sẽ đề cập đến giao thức HTTP, các header của nó, v.v sau trong loạt bài này.
Hiện tại, bạn chỉ cần hiểu client và máy chủ đang trao đổi thông tin và họ làm vậy qua HTTP.
Hiển Thị (Rendering)
Cuối cùng nhưng không kém phần quan trọng, quá trình hiển thị (rendering). Trình duyệt có ích gì nếu nó chỉ hiển thị cho người dùng một danh sách các ký tự lạ?
<!doctype html><html>......</html>
Trong phần thân (body) của phản hồi, máy chủ bao gồm biểu diễn phản hồi theo header Content-Type. Trong trường hợp của chúng ta, content type được đặt là text/html, nên chúng ta mong đợi mã đánh dấu HTML trong phản hồi — chính xác là những gì chúng ta tìm thấy trong body.
Đây là nơi trình duyệt thực sự tỏa sáng. Nó phân tích cú pháp HTML, tải các tài nguyên bổ sung có trong mã đánh dấu (ví dụ: có thể có file JavaScript hoặc tài liệu CSS để tải) và trình bày chúng cho người dùng sớm nhất có thể.
Kết quả cuối cùng là thứ mà "người thường" có thể hiểu.

Để có phiên bản chi tiết hơn về những gì thực sự xảy ra khi chúng ta nhấn Enter trong thanh địa chỉ trình duyệt, tôi đề xuất đọc "What happens when…", một nỗ lực rất chi tiết giải thích cơ chế đằng sau quy trình.
Vì đây là loạt bài tập trung vào bảo mật, tôi sẽ gợi ý dựa trên những gì vừa học: kẻ tấn công dễ dàng kiếm sống nhờ các lỗ hổng trong phần trao đổi HTTP và hiển thị. Lỗ hổng và người dùng độc hại tiềm ẩn ở nơi khác nữa, nhưng cách tiếp cận bảo mật tốt hơn ở những cấp độ đó đã cho phép bạn tiến bộ trong việc cải thiện tư thế bảo mật.
Các Nhà Cung Cấp (Vendors)
4 trình duyệt phổ biến nhất thuộc về các nhà cung cấp khác nhau:
- Chrome bởi Google
- Firefox bởi Mozilla
- Safari bởi Apple
- Edge bởi Microsoft
Bên cạnh việc cạnh tranh nhau để tăng thâm nhập thị trường, các nhà cung cấp cũng tương tác với nhau để cải thiện chuẩn web, những thứ giống như "yêu cầu tối thiểu" cho trình duyệt.
W3C là cơ quan đứng sau việc phát triển các chuẩn, nhưng không hiếm khi trình duyệt phát triển tính năng riêng cuối cùng trở thành chuẩn web, và bảo mật không phải ngoại lệ.
Chrome 51, ví dụ, giới thiệu SameSite cookies, tính năng cho phép ứng dụng web loại bỏ một loại lỗ hổng cụ thể gọi là CSRF (sẽ nói thêm sau). Các nhà cung cấp khác quyết định đây là ý tưởng tốt và làm theo, dẫn đến SameSite trở thành chuẩn web: cho đến nay, Safari là trình duyệt chính thống duy nhất không hỗ trợ SameSite cookie.

Điều này cho chúng ta 2 điều:
- Safari dường như không đủ quan tâm đến bảo mật người dùng (chỉ đùa thôi: SameSite cookies sẽ có sẵn trong Safari 12, có thể đã phát hành khi bạn đọc bài này)
- Vai một lỗ hổng trên một trình duyệt không có nghĩa là tất cả người dùng của bạn đều an toàn
Điểm đầu tiên là châm chọc Safari (như đã nói, chỉ đùa!), trong khi điểm thứ hai thực sự quan trọng. Khi phát triển ứng dụng web, chúng ta không chỉ cần đảm bảo chúng trông giống nhau trên các trình duyệt khác nhau, mà còn đảm bảo người dùng được bảo vệ theo cùng cách trên các nền tảng.
Chiến lược bảo mật web của bạn nên thay đổi tùy theo những gì nhà cung cấp trình duyệt cho phép chúng ta làm. Ngày nay, hầu hết trình duyệt hỗ trợ cùng tập tính năng và hiếm khi lệch khỏi lộ trình chung, nhưng các trường hợp như trên vẫn xảy ra, và đó là điều chúng ta cần cân nhắc khi xác định chiến lược bảo mật.
Trong trường hợp của chúng ta, nếu quyết định giảm thiểu tấn công CSRF chỉ qua SameSite cookies, chúng ta nên nhận thức rằng chúng ta đang đặt người dùng Safari ở rủi ro. Và người dùng của chúng ta cũng nên biết điều đó.
Cuối cùng, bạn nên nhớ rằng bạn có thể quyết định có hỗ trợ phiên bản trình duyệt nào hay không: hỗ trợ mọi phiên bản trình duyệt sẽ không thực tế (nghĩ về Internet Explorer 6). Đảm bảo vài phiên bản mới nhất của các trình duyệt chính được hỗ trợ, tuy nhiên, thường là quyết định tốt. Nếu bạn không định cung cấp bảo vệ trên nền tảng cụ thể, thường nên cho người dùng biết.
Mẹo chuyên nghiệp: Bạn không bao giờ nên khuyến khích người dùng dùng trình duyệt lỗi thời, hoặc chủ động hỗ trợ chúng. Dù bạn đã lấy mọi biện pháp phòng ngừa, các nhà phát triển web khác có thể chưa làm vậy. Khuyến khích người dùng dùng phiên bản mới nhất được hỗ trợ của một trong các trình duyệt chính.
Lỗi Của Nhà Cung Cấp Hay Chuẩn?
Thực tế người dùng trung bình truy cập ứng dụng của chúng ta qua client bên thứ 3 (trình duyệt) thêm một cấp độ gián tiếp khác về trải nghiệm duyệt web an toàn, rõ ràng: chính trình duyệt có thể trình bày lỗ hổng bảo mật.
Các nhà cung cấp thường cung cấp phần thưởng (aka bug bounties) cho nhà nghiên cứu bảo mật tìm ra lỗ hổng trên chính trình duyệt. Những bug này không gắn liền với việc triển khai của bạn, mà liên quan đến cách trình duyệt xử lý bảo mật trên riêng nó.
Chương trình thưởng của Chrome, ví dụ, cho phép kỹ sư bảo mật liên hệ đội ngũ bảo mật Chrome để báo cáo lỗ hổng họ tìm thấy. Nếu lỗ hổng được xác nhận, bản vá được phát hành, thông báo bảo mật thường được công bố, và nhà nghiên cứu nhận được phần thưởng (thường là tài chính) từ chương trình.
Các công ty như Google đầu tư một số vốn khá lớn vào chương trình Bug Bounty, vì nó cho phép họ thu hút nhà nghiên cứu bằng cách hứa hẹn lợi ích tài chính nếu họ tìm thấy vấn đề với ứng dụng.
Trong chương trình Bug Bounty, mọi người đều thắng: nhà cung cấp cải thiện được bảo mật phần mềm, và nhà nghiên cứu được trả tiền cho phát hiện. Chúng ta sẽ thảo luận các chương trình này sau, vì tôi tin các sáng kiến Bug Bounty xứng đáng có mục riêng trong cảnh quan bảo mật.
Jake Archibald là developer advocate tại Google gần đây phát hiện lỗ hổng ảnh hưởng nhiều trình duyệt. Anh đã ghi chép nỗ lực, cách tiếp cận các nhà cung cấp khác nhau, và phản ứng của họ trong bài blog thú vị mà tôi khuyên bạn đọc.
Trình Duyệt Cho Nhà Phát Triển
Lúc này, chúng ta nên đã hiểu một khái niệm đơn giản nhưng quan trọng: trình duyệt đơn giản là HTTP client được xây dựng cho người lướt web trung bình.
Chắc chắn chúng mạnh hơn HTTP client gốc của nền tảng (nghĩ về require('http') của NodeJS, ví dụ), nhưng cuối ngày, chúng chỉ là "sự tiến hóa tự nhiên" của các HTTP client đơn giản hơn.
Là nhà phát triển, HTTP client lựa chọn của chúng ta có thể là cURL bởi Daniel Stenberg, một trong những chương trình phổ biến nhất nhà phát triển web dùng hàng ngày. Nó cho phép chúng ta làm trao đổi HTTP ngay lập tức, bằng cách gửi yêu cầu HTTP từ dòng lệnh:
$ curl -I localhost:8080
HTTP/1.1 200 OK
server: ecstatic-2.2.1
Content-Type: text/html
etag: "23724049-4096-"2018-07-20T11:20:35.526Z"
last-modified: Fri, 20 Jul 2018 11:20:35 GMT
cache-control: max-age=3600
Date: Fri, 20 Jul 2018 11:21:02 GMT
Connection: keep-alive
Trong ví dụ trên, chúng ta yêu cầu tài liệu tại localhost:8080/, và máy chủ cục bộ phản hồi thành công.
Thay vì đổ body phản hồi ra dòng lệnh, ở đây chúng ta dùng flag -I báo cho cURL chúng ta chỉ quan tâm header phản hồi. Tiến xa một bước, chúng ta có thể yêu cầu cURL dump thêm thông tin, bao gồm yêu cầu thực tế nó thực hiện, để nhìn rõ hơn toàn bộ trao đổi HTTP. Option cần dùng là -v (verbose):
$ curl -I -v localhost:8080
* Rebuilt URL to: localhost:8080/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> HEAD / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< server: ecstatic-2.2.1
< Content-Type: text/html
< etag: "23724049-4096-"2018-07-20T11:20:35.526Z"
< last-modified: Fri, 20 Jul 2018 11:20:35 GMT
< cache-control: max-age=3600
< Date: Fri, 20 Jul 2018 11:25:55 GMT
< Connection: keep-alive
* Connection #0 to host localhost left intact
Gần như cùng thông tin có sẵn trong trình duyệt chính thống qua DevTools của chúng.
Như đã thấy, trình duyệt không hơn gì các HTTP client phức tạp. Chắc, chúng thêm lượng khổng lồ tính năng (nghĩ về quản lý thông tin đăng nhập, bookmark, lịch sử, v.v) nhưng sự thật là chúng sinh ra như HTTP client cho con người. Điều này quan trọng, vì trong hầu hết trường hợp bạn không cần trình duyệt để kiểm tra bảo mật ứng dụng web, bạn có thể đơn giản "curl nó" và xem phản hồi.
Một điều cuối cùng muốn nhấn mạnh: bất cứ thứ gì có thể là trình duyệt. Nếu bạn có ứng dụng di động tiêu thụ API qua giao thức HTTP, thì ứng dụng đó là trình duyệt của bạn — nó chỉ xảy ra là trình duyệt tùy chỉnh cao do bạn tự xây dựng, trình duyệt chỉ hiểu loại phản hồi HTTP cụ thể (từ API của chính bạn).
Đi Sâu Vào Giao Thức HTTP
Như đã đề cập, giai đoạn trao đổi HTTP và hiển thị là những gì chúng ta sẽ đề cập nhiều nhất, vì chúng cung cấp số lượng lớn nhất vector tấn công cho người dùng độc hại.
Trong bài tiếp theo, chúng ta sẽ nhìn sâu hơn vào giao thức HTTP và cố gắng hiểu biện pháp nào chúng ta nên lấy để bảo mật trao đổi HTTP.
Được xuất bản gốc tại odino.org (29 tháng 7 năm 2018).
Bạn có thể theo dõi tôi trên Twitter - sự phàn nàn được chào đón! ?
Học lập trình miễn phí. Chương trình mở của freeCodeCamp đã giúp hơn 40.000 người tìm được việc làm lập trình viên. Bắt đầu ngay