Nội dung bài viết
Video học lập trình mỗi ngày
Hệ thống web hay ứng dụng của bạn có thực sự an toàn không? Mỗi ngày có gần 2K users vào trang tips javascript. Ở đây đa số là hiện tại là những lập trình viên và cũng có thể là những developers tương lai. Nhưng có một điểm chung như thế này đó là việc ai cũng mong muốn viết code làm sao cho xong ứng dụng của mình mà quên đi việc nó có an toàn về bảo mật cho hệ thống mình hay chưa?
Câu trả lời có lẽ là ít hoặc không quan tâm nó chạy đến đâu. Nếu đến đâu thì fix đến đó. Tôi cũng vậy, một thời cặm cụi viết code chạy là xong. Từ đó mới có bài viết về câu chuyện về bảo mật dữ liệu này. Một bài viết mà tôi đã từng gặp phải và tham khảo trên khắp diễn đàn. Hy vọng bài viết này sẽ làm nền tảng cho các bạn để bước vào tương lai bảo mật tốt hơn.
Một tổ kiến làm sụp đổ một bờ kè ngàn dặm
Bạn có nghe về câu chuyện này chưa? Để tôi nói sơ qua nhé.
“Bờ kè ngàn dặm, cũng sập vì hang kiến. Nhà cao trăm tầng, vì khói trong ống khói mà cháy”, nghĩa là, một tổ kiến nhỏ bé, có thể khiến bờ kè cao trăm dặm đổ sập, cũng như vậy, chuyện nhỏ không cẩn thận sẽ gây ra họa lớn. Trong lịch sử đã xảy ra thảm kịch tàu Titanic, một trong những nguyên nhân có thể khiến nó bị chìm đó là vì một chiếc chìa khoá rất bình thường. Khi bàn giao để con tàu Titanic rời bến cảng, chiếc chìa khoá tủ chứa kính viễn vọng đã nằm trong túi áo khoác của một sĩ quan hạng nhì tên là David Blair. Có điều, Blair đã không theo con tàu Titanic, mà lại thực hiện nhiệm vụ ở một con tàu khác. Do đó, trong suốt chặng đường, đống kính viễn vọng của Titanic đã nằm lăn lóc trong tủ và không thể được sử dụng.
Cũng giống như trong hệ thống ứng dụng web hay app, một sơ hở nhỏ thôi cũng thường có thể gây ra hậu quả cực kỳ nghiêm trọng. Do đó, bảo mật là một vấn đề phải được quan tâm khi thiết kế, phát triển và vận hành mỗi hệ thống của mỗi cá nhân hay doanh nghiệp. Ngày nay, các biện pháp phòng vệ được nhiều hệ thống Web áp dụng thiên về cơ bản và đơn giản, và thường chỉ bảo vệ chống lại các lỗ hổng bảo mật phổ biến, chẳng hạn như:
- Csrf
- XSS
- Sql injection
Trên đó là một vài lý do và nhiều thứ khác nữa đừng ngừng lại tại đây và vỗ ngực xưng tên nên đọc tiếp nhé. Các biện pháp phòng thủ cơ bản này phải được thực hiện, và chi phí thực hiện không cao, nhưng chúng chỉ là phần cơ bản của phòng thủ an ninh hệ thống. Vì vậy cho nên đừng nổ như bom nữa hén. Nhiều lập trình viên nghĩ rằng làm tốt điều này là đủ để đối phó với hầu hết các tình huống, suy nghĩ này rất nguy hiểm và chủ quan.
Trên thực tế, bên cạnh những lỗ hổng cơ bản và được tiêu chuẩn hóa này, bản thân logic nghiệp vụ của mỗi hệ thống kinh doanh cũng có khả năng trở thành mục tiêu tấn công của hacker. Một khi bị gặp sự cố vấn đề với hackers, hậu quả sẽ rất nghiêm trọng. Sau đây sẽ liệt kê một số lỗ hổng logic nghiệp vụ phổ biến mà có thể bạn chưa biết, những lỗ hổng này cũng là những lỗ hổng đã từng dẫm phải khi phát triển hệ thống trước đây mà tôi và nhiều người cũng từng gặp, mong rằng sẽ truyền cảm hứng cho mọi người trong bài viết này.
Quản lý thông tin đăng nhập khó hiểu
Ở những tuần trước tôi đã viết một loại bài về 4 có chế đăng nhập phổ biến được sử dụng rộng rãi hiện nay trong đó có cơ chế xác thực bằng token. Và nó có liên quan đến ví dụ mà tôi sắp nói dưới đây. Đầu tiên chúng ta đều biết rằng bản thân HTTP là không trạng thái (http là gì? Vì sao http là không trạng thái). Để cho trình duyệt và máy chủ biết danh tính của nhau và tin tưởng lẫn nhau, hầu hết các hệ thống web được triển khai bằng cách sử dụng xác thực thông qua token hay còn gọi là mã thông báo. Mã thông báo sẽ được tạo sau khi người dùng đăng nhập.
Và token đó sẽ trở nên không hợp lệ sau khi người dùng chủ động thoát (logout) hoặc hết hạn sau một khoảng thời gian mà được set trong back-end. Nói cách khác, nếu đưa token để xác thực thì nếu hợp lệ thì có thể get data cho người dùng và ngược lại thì sẽ trả lại lỗi. Có thể tham khảo những quy trình xác thực token và refreshToken ở những bài viết trước. Đây dường như không phải là vấn đề, nhưng như trên đã nói một ổ kiến có thể gây ra một sai lầm lớn và ở đây cũng vậy có thể tiềm ẩn những sơ hở trong quá trình triển khai thực tế về token.
Hãy xem ví dụ:
Ví dụ như một front-end viết một chứ năng logic để người dùng nhấp vào nút đăng xuất (logout), anh ấy chỉ cần xóa giá trị mã thông báo trong cookie hoặc localstorage (mã thông báo thường được lưu trữ ở hai nơi này) và anh ấy không yêu cầu server set hết hạn cho token này? Sau đó bạn chợt nhận thấy rằng, về cơ bản là tính hợp lệ của token này vẫn còn giá trị vì nó chưa hết hạn tại thời điểm user logout.
Về sâu hơn thì đó là một rủi ro lớn và sai lầm lớn. Nếu giả sử token của bạn đã được lưu vào một log nào đó thì việc sau khi bạn logout thì token đó được khai thác bởi những hackers và tiếp theo đó mạo danh bạn một cách công khai. Từ đó có thể thay đổi thông tin, lấy cắp thông tin, đặt hàng... Có nhiều rủi ro sau tai nạn này. Nên chú ý cho mấy bạn làm back-end.
Khắc phục điều này thì việc đơn giản là mỗi khi logout bạn hãy thiết lập cho token này hết hạn như thế sẽ an toàn hơn.
Kiểm tra chủ quan dẫn đến thất bại
Tải file (tệp) lên hệ thống là một chức năng thường được sử dụng trên các ứng dụng web, chẳng hạn như tải lên hình đại diện, tải video, hình ảnh lên mạng xã hội, v.v.
Người dùng độc hại có thể tải lên các tệp như trojan horse, viruts, hay những tập tin đại loại là độc hại ... khi chúng được tải lên. Việc thực thi các tệp này trên máy chủ sẽ mang lại hậu quả nghiêm trọng. Phương thức tấn công này có chi phí thấp và dễ bị kẻ tấn công sử dụng hơn. Càng nhiều loại tệp được phép tải lên, khả năng bị tấn công càng lớn. Khi chương trình độc hại được tải lên thành công, nó có thể được người dùng tải xuống và nó có thể bị nhiễm độc sau khi được thực thi trên máy tính của người dùng.
Cũng có thể thực thi các chương trình độc hại trên máy chủ, khiến máy chủ bị điều khiển, sau đó máy chủ bị tê liệt và mất dữ liệu. là điều khó tránh khỏi. Trong các trường hợp bình thường mà những lập trình viên thường làm là, chương trình sẽ đánh giá loại tệp và chỉ cho phép các tệp mà chúng tôi cho là hợp pháp tải lên máy chủ. Tuy nhiên, trong một số chương trình web, nhận định này chỉ được thực hiện ở front end thì xem ra bạn đã quá chủ quan, không phải ở back end. Điều này tạo cơ hội cho kẻ tấn công, kẻ có thể dễ dàng và thông đồng yêu cầu tải lên các tệp bất hợp pháp.
Cách tiếp cận chính xác phải dành cho phần cuối để thực hiện phán đoán phần mở rộng tệp, phát hiện MIME và giới hạn kích thước của tệp đã tải lên để bảo vệ. Ngoài ra, bạn có thể lưu tệp trên máy chủ cách ly với doanh nghiệp để ngăn các tệp độc hại tấn công máy chủ của doanh nghiệp và khiến dịch vụ không hoạt động. Đó là một sai lầm tôi đã mắc phải cách đây 8 năm và trả giá bằng 6000 EUR thời đó :(.
Thông báo lỗi khiến lỗ hổng càng trầm trọng
Có một thực tế thế này. Nhưng bạn làm cầu kỳ hay làm cho code đẹp hay dính những lỗi này. Đó là việc thông báo lỗi cho người dùng mỗi khi sai một cách tỉ mỉ. Để nói rõ hơn. Khi đăng nhập vào hệ thống, hầu hết các hệ thống sẽ xác định xem người dùng có tồn tại hay không khi người dùng đăng nhập, sau đó đưa ra thông báo nhắc nhở như "Tài khoản chưa được đăng ký số điện thoại".
Nếu logic này được thực hiện với một giao diện riêng biệt, sẽ có nguy cơ bị liệt kê vào món ăn yêu thích của những thằng hackers. Kẻ tấn công có thể sử dụng nhiều số điện thoại di động khác nhau để yêu cầu điều tra thông qua giao diện này, xác định những số điện thoại di động nào đã được đăng ký trong hệ thống và mang đến cơ hội để thực hiện lấy lại mật khẩu trong bước tiếp theo. Các bạn hiểu ý tôi nói chứ? Đối với vấn đề này, đề xuất là thông báo lỗi trong giao diện xác minh đăng nhập và không trả lại lời nhắc rõ ràng.
Bạn sẽ thấy rằng trên trang web được xây dựng tốt, thông thường nó sẽ nhắc "Số điện thoại chưa được đăng ký hoặc mật khẩu sai hoặc gì gì đó". Nói chung là chung chung mặc dù điều này làm ảnh hưởng đến trải nghiệm người dùng, nhưng nó cũng an toàn hơn so với quá rõ ràng.
Lỗ hổng phân quyền
Xác minh ủy quyền là chức năng cơ bản của hệ thống Web, chẳng hạn như hệ thống quản lý cơ cấu tổ chức công ty, cung cấp các chức năng sửa đổi tên bộ phận và người quản lý bộ phận. Cùng với xác minh quyền có thể ngăn cản bất kỳ người dùng nào có thể sửa đổi thông tin mà họ không có quyền thông qua các chức năng này.
Xác minh thẩm quyền chắc chắn sẽ được thực hiện trong các hệ thống như vậy, nhưng nó thực sự được thực hiện đúng không? Giả sử chúng ta quy định một người dùng trong hệ thống cần đáp ứng hai điều kiện là có quyền quản lý vượt cấp và thuộc bộ phận A trước khi sửa đổi tên bộ phận. Thông thường trong việc triển khai mã thực tế, nhà phát triển chỉ đánh giá liệu người dùng có phải là người quản lý cấp cao hay không, nhưng không đánh giá liệu người dùng có thuộc bộ phận hay không. Trong trường hợp này, chúng ta có thể sử dụng tài khoản quản lý cấp cao của bộ phận B để sửa đổi tên của bộ phận A, tương đương với việc sửa đổi tên của bộ phận A. Đây rõ ràng không phải là kết quả mà chúng ta mong đợi.
Ngay cả khi người dùng quản lý cấp cao của phòng B không thể tìm thấy mục sửa đổi tên bộ phận của phòng A trên giao diện, vẫn có thể thực hiện được bằng cách lấy yêu cầu sửa đổi thông số. Ngoài việc sửa đổi trái phép, tất nhiên bạn cũng có thể xem nó. Chúng tôi chắc chắn không mong đợi những người quản lý cấp cao của bộ phận A nhìn thấy thông tin bộ phận của bộ phận B, phải không? Hệ thống của bạn nên kiểm tra nghiêm ngặt và hạn chế quyền truy cập của người dùng vào các vai trò trong hệ thống phân quyền.
An ninh không phải là vấn đề nhỏ, như đã đề cập ở phần đầu, bất kỳ sơ hở nào cũng có thể giáng một đòn nặng nề. Mong mọi người xem xét nghiêm túc. Chú ý không chỉ đến thiết kế kinh doanh mà còn xem xét mã để tránh các lỗ hổng cấp thấp do quá trình triển khai gây ra. Trên đây chỉ là một phần nhỏ trong số rất nhiều lỗ hổng bảo mật nếu bạn là người nghiêm túc và trách nhiệm với công việc của mình thì nên tham khảo nhiều trên google. Đó là một nơi chúng ta khi bế tắc, thì có nơi để về.