Lỗ hổng thường gặp trong phát triển ứng dụng web và cách phòng tránh

Lỗ hổng thường gặp trong phát triển ứng dụng web và cách phòng tránh

459 | ★★★★☆Bảo mật luôn là một vấn đề phức tạp và tốn kém cũng chính là trách nhiệm của rất nhiều bên trong đó có người lập trình. Người phát triển ứng dụng web bên cạnh để ứng dụng hoạt động được mà còn phải bảo về hệ thống bảo vệ người dùng. Trong phạm vi bài viết sẽ giới thiệt tới đoc giả một số kỹ thuật phòng tránh lỗ hỏng trong ứng dụng của mình

    1. Kiểm soát truy vấn cơ sỡ dữ liệu để tránh lỗ hổng SQL Injection

    - Nguy cơ: Khi truy vấn tới cơ sở dữ liệu, lập trình viên thường sử dụng cách cộng xâu Input từ người dùng, các câu truy vấn này có thể bị mắc lỗi SQL Injection hoặc HQL Injection (nếu sử dụng Hibernate). Bằng việc lợi dụng các lỗi này, kẻ tấn công có thể xem, sửa, xóa dữ liệu trong database, từ đó chiếm được tài khoản admin, lấy cắp thông tin người dùng ....

    - Phòng chống:

    a.không được sử dụng cách cộng xâu trong truy vấn. Truy vấn SQL phải dùng PrepareStatement, tất cả tham số phải được add bằng hàm (setParam...),

    b. Với một số trường hợp sử dụng ORDER BY, không thể dùng được hàm setParam thì có thể định nghĩa một mảng chứa toàn bộ các column (field) cần ORDER BY gọi là whitelist. Mỗi khi cần ORDER BY thì kiểm tra lại xem column (field) đó có thuộc mảng whitelist đã định nghĩa không. 

    Ví dụ 1: Đoạn code kiểm tra đăng nhập với username/password do người dùng nhập vào:

    String sql = "select * from users where user_name = "' + userName + '" and password = "' + encrypt(password) + '";
    Statement statement = connection.createStatement();
    ResultSet rs = statement.excuteQuery(sql);
    if (!rs.next()) {
        bResult = false;
        } else {
        bResult = true;
        }
    

    --> Với đoạn code trên, khi nhập vào username là test' or '1'='1 thì câu query sẽ là: select from users where user_name='test' or '1'='1' and password='...'. Mệnh đề where sẽ tương đương với user_name = 'test'. Như vậy, dù không có password vẫn đăng nhập được vào hệ thống.

    --> Sửa đoạn code trên lại như sau, với userName và password được tham số hóa khi đưa vào câu truy vấn sẽ tránh được lỗi SQL Injection:

    String sql = "select * from users where user_name = ? and password = ?";
    PreparedStatement statement = connection.preparedStatement(sql);
    statement.setString(0, userName);
    statement.setString(1, encrypt(password));
    ResultSet rs = statement.excuteQuery(sql);
    if (!rs.next()) {
        bResult = false;
        } else {
        bResult = true;
        }
    

         Ví dụ 2: Một số trường hợp không thể ngăn chặn được lỗi SQL Injection qua lệnh "order by". Do không sử dụng được hàm setParam thì có thể sử dụng phương pháp sau:

    // Mảng lưu danh sách các column (field) của BO cần order by (hay gọi là whitelist)
    private static List columnSort = new ArrayList();
    public static String getColumnSort(String sortField) {
        // Thực hiện 1 lần và lấy ra toàn bộ mảng column cần order và add vào whitelist
        if (columnSort.size() == 0) {
            // Danh sách BO cho phép order by
            String[] arrTableName = {"ActionLog", "BanPosition", "Category", ...};
        };
        // Lấy ra toàn bộ các column (field) BO cần order by
        for (String tableName : arrTableName) {
            try {
                Class class = Class.forName("com.demo.DEMO.database.BO." + tableName);
                Field[] fieldArr = class.getDeclaredFields();
                for (int i = 0; i< fieldArr.length; i++) {
                    String fieldName = fieldArr[i].getName();
                    // add các column vào 1 mảng
                    columnSort.add(fieldName);
                }
            } catch (ClassNotFoundException ex) {
            }
        }
    }
    // Cắt ký tự "-" ở đầu field sort
    String sort = sortField;
    if (sortField != null && sortField.startsWith("-")) {
        sortField = sortField.substring(1);
    }
    // Kiểm tra field cần order by có nằm trong danh sách field cho phép sort hay không
    if (sortField != null && columnSort.contains(sortField)) {
        return sort;
    }
    return null;
    

    c. Không hiển thị exception, message lỗi: Hacker dựa vào message lỗi để tìm ra cấu trúc database. Khi có lỗi, ta chỉ hiện thông báo lỗi chứ đừng hiển thị đầy đủ thông tin về lỗi, tránh hacker lợi dụng.

    d. Phân quyền rõ ràng trong DB: Nếu chỉ truy cập dữ liệu từ một số bảng, hãy tạo một account trong DB, gán quyền truy cập cho account đó chứ đừng dùng account root hay sa. Lúc này, dù hacker có inject được sql cũng không thể đọc dữ liệu từ các bảng chính, sửa hay xoá dữ liệu.

    e. Lọc dữ liệu từ người dùng: Sử dụng filter để lọc các kí tự đặc biệt (; ” ‘) hoặc các từ khoá (SELECT, UNION) do người dùng nhập vào.

    2. Xử lý dữ liệu đầu vào để tránh lỗ hổng XSS

    - Nguy cơ: Kết quả server trả về cho người dùng chủ yếu dưới dạng HTML. Nội dung trả về thường bao gồm cả những giá trị mà người dùng nhập vào hệ thống có thể bị mắc lỗi XSS nếu không kiểm soát dữ liệu đầu vào. XSS (Cross-Site Scripting) là một kỹ thuật tấn công bằng cách chèn vào các website động (JSP, ASP, PHP ...) những thẻ HTML hay những đoạn mã script nguy hiểm có thể gây nguy hại cho những người sử dụng khác. Trong đó, những đoạn mã nguy hiểm được chèn vào hầu hết được viết bằng Cross-Site Scrip như JavaScript, JScript, DHTML và cũng có thể là cả các thẻ HTML.

    - Phòng chống:

       Encode dưới dạng HTML các ký tự đặc biệt do client gửi đến bao gồm: <,>,&,',",/ trong các trường hợp

    --> Dữ liệu client gửi lên máy chủ.

    --> Dữ liệu lấy ra từ database khi trả về cho client. Bảng chất của việc encode là thay thế các ký tự trên bằng chuỗi tương ứng trong bảng bên dưới:

    | STT | Ký tự | HTML    |
    | --- | ----- | ------- |
    | 1   |   "   | &quot;  |
    | 2   |   &   | &amp;   |
    | 3   |   '   | &#x27;  |
    | 4   |   /   | &#x2Ft; |
    | 5   |   <   | &lt;    |
    | 6   |   >   | &gt;    |
    

    Ví dụ 1: Trang JSP bên dưới hiển thị lên lời chào với tên người dùng được lấy từ client

    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
            <title>JSP Page</title>
        </head>
        <body>
            <%
                String user = request.getParameter("user");
                request.setAttribute("user", user);
            %>
            <h1> Hello ${user}! </h1>
        </body>
    </html>
    

    --> Khi nhập vào địa chỉ trình duyệt http://localhost/example?user=abc thì trên trình duyệt sẽ hiện thị dòng Hello abc!

    --> Khi nhập vào địa chỉ trình duyệt http://localhost/example?user=abc<script>alert('XSS')</script> thì trên trình duyệt sẽ thực hiện đoạn JavaScript thông báo XSS.

    --> Để khắc phục lỗi này ta có thể dùng thư viên JSTL để encode HTML biến user

    <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
            <title>JSP Page</title>
        </head>
        <body>
            <%
                String user = request.getParameter("user");
                request.setAttribute("user", user);
            %>
            <h1> Hello ${fn:escapeXml(user)}! </h1>
        </body>
    </html>
    

    3. Sử dụng token để tránh lỗ hổng CSRF

    - Nguy cơ: CSRF (Cross-site request forgery) là phương pháp mượn quyền của người dùng khác để thực hiện một hành động không cho phép. Ví dụ: để có thể xóa một bài viết trên diễn đàn một member có thể mượn tay của admin để làm việc đó, vì member không đủ quyền. Kẻ tấn công lừa admin truy cập vào trang web có chứa đoạn mã xóa bài viết trên diễn đàn (Admin đang đăng nhập vào diễn đàn), như vậy admin đã gửi yêu cầu xóa bài viết trên diễn đàn mà không hề hay biết.

    - Phòng chống: Đối với các yêu cầu ảnh hưởng tới dữ liệu, quá trình hoạt động và có khả năng làm mất an toàn thôn tin hệ thống, ví dụ: yêu cầu đọc, ghi, sửa, xóa thông tin, dữ liệu hệ thống phải sử dụng thêm biến token. Trên server sẽ kiểm tra token trong yêu cầu gửi lên từ client, nếu token không hợp lệ thì yêu cầu sẽ không được thực hiện. *Ví dụ 1:*Ứng dụng struts cho phép hiển thị lời chào với tên người dùng nhập từ form: index.jsp

    <%@taglib prefix="s" uri="/struts-tags"%>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        </head>
        <body>
            <h2>Hello World!</h2>
            Struts 2 Mesage: <s:property value="message" default="Guest."/>
            <s:form method="GET" action="/HelloStruts2World.action">
            Enter your name: <s:textfield name="userName"/>
            <s:submit value="Submit"/>
        </body>
    </html>
    

    struts.xml

    <struts>
        <package name="/" extends="struts-default">
            <action name="HelloStruts2World" class="hello.HelloStruts2World">
                <result name="success">/index.jsp</result>
            </action>
         </package>
    </struts>
    

    helloStruts2World.java

    package hello;
    import com.opensymphony.xwork2.ActionSupport;
    public class HelloStruts2World extends ActionSupport {
        private String userName;
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        
        private String message;
        public String getMessage() {
            return message;
        }
        
        @Override
        public String execute() {
            message = "Hello, " +userName+ ".";
            return SUCCESS;
        }
    }
    

    --> Tuy nhiên, yêu cầu trên có thể được thực hiện mà không cần phải nhập userName từ form bằng cách đưa trực tiếp vào URI http://localhost/TestStruts/HelloStruts2World.action?userName=acb

    --> Để khắc phục lỗi trên, ta có thể sử dụng token intercepter đã có sẵn của struts.

    index.jsp

    <%@taglib prefix="s" uri="/struts-tags"%>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        </head>
        <body>
            <h2>Hello World!</h2>
            Struts 2 Mesage: <s:property value="message" default="Guest."/>
            <s:form method="GET" action="/HelloStruts2World.action">
            <s:token/>
            Enter your name: <s:textfield name="userName"/>
            <s:submit value="Submit"/>
        </body>
    </html>
    

    struts.xml

    <struts>
        <package name="/" extends="struts-default">
            <interceptor>
                <interceptor-stack name="defaultSecurityStack">
                    <interceptor-ref name="defaultStack"/>
                    <interceptor-ref name="tokenSession">
                        <param name="excludeMethods">*</param>
                    </interceptor-ref>
                </interceptor-stack>
            </interceptor>
            <default-interceptor-ref name="defaultSecurityStack"/>
            <global-results>
                <result name="invalid.token">/error.jsp</result>
            </global-results>
            <action name="HelloStruts2World" class="hello.HelloStruts2World">
                <result name="success">/index.jsp</result>
            </action>
         </package>
    </struts>
    

    4. Kiểm soát file upload lên hệ thống

    - Nguy cơ: Các thao tác với file thường sử dụng tên file, đường dẫn file được gửi lên từ client, nếu ứng dụng không kiểm soát tốt các giá trị này (việc kiểm soát phải được thực hiện phía server) có thể dẫn đến việc download hoặc upload các file không hợp lệ.

    - Phòng chống: Kiểm soát phía server tên file, đường dẫn file được gửi lên từ client

    --> Kiểm soát phần mở rộng của file, chỉ cho phép thực hiện với các file có định dạng theo yêu cầu. Không bắt buộc phải kiểm tra nội dung file.

    --> Các hàm liên quan đọc ghi file, biến đường dẫn file phải được lọc /,\ và kí tự null.

    --> Phần filename ban đầu người dùng upload lên server phải bỏ đi, dùng 1 chuỗi mới ngẫu nhiên thay thế cho tên file. Tên này được sinh ra ngẫu nhiên không được dùng các thuật toán md5, sha256 ... Thay vào đó có thể sử dụng các hàm sinh chuỗi ngẫu nhiên có sẵn trong ngôn ngữ lập trình để sinh ra tên. Ví dụ 1: Tạo tên file cho file ảnh định dạng jpg với hàm UUID có sẵn như sau:

    import uuid
    filename='%032x' % uuid.uuid4() + '.jpg'
    

    Tên file ban đầu là shell.php.jpg upload lên server thì đổi thành 6817c84abd3d4c9abfee21a01cb39b98.jpg

    5. Bảo vệ các form File Upload

    Các form này cho phép người dùng tải lên các tệp tin, đây có thể là một rủi ro an ninh rất lớn, nếu các form này không được kiểm duyệt, kiểm soát chặt chẽ, tin tặc có thể vượt qua để tài lên các tệp tin độc hại. Đây sẽ là các điểm yếu chết người trên website.

    Nếu website có một form upload thì form này phải được kiểm duyệt chặt chẽ và kết hợp nhiều yếu tố trước khi ghi file vào ổ cứng của máy chủ. Bao gồm: tên file, phần mở rộng, MIME TYPE, kích thước… Ngoài ra bạn có thể đảm bảo an toàn bằng cách không cho phép thực thi tệp tin trong các thư mục chứa tài liệu upload. Một vài lựa chọn có thể dùng là đổi tên file đã được tải lên nhằm đảm bảo đúng phần mở rộng, hoặc thay đổi quyền của tệp tin, ví dụ chmod 0666 không thể thực thi. Nếu bạn sử dụng máy chủ Apache, bạn có thể tạo một tệp tin .htaccess file như sau (Lưu ý là dòng mã .htacces phía dưới phải đặt tại thư mục mà bạn cần kiểm soát file upload):

      deny from all
        <Files ~ "^\w+\.(gif|jpe?g|png)$">
        order deny,allow
        allow from all
        </Files>

    Để chống hack website, giải pháp được khuyến cáo khác là ngăn sự sự truy cập trực tiếp đến các file được tải lên. Theo cách này, bất cứ file nào tải lên website đều được lưu trữ trong một thư mục ngoài webroot hoặc trong cơ sở dữ liệu dưới dạng blob. Nếu tệp tin của bạn không thể truy cập trực tiếp, bạn cần tạo ra một script lấy file từ thư mục riêng (hoặc một HTTP xử lý trong .NET) và chuyển chúng đến trình duyệt.

    Ngoài ra, nếu có thể hãy đặt cơ sở dữ liệu ở máy chủ khác máy chủ web. Máy chủ cơ sở dữ liệu sẽ không thể truy cập trực tiếp từ bên ngoài, chỉ máy chủ web mới có thể truy cập được nó, giảm thiểu rủi ro rò rỉ dữ liệu.

    Cuối cùng, đừng quên cách li truy cập vật lí đến máy chủ.

    6. Triển khai HTTPs

    SSL là một giao thức cung cấp chuẩn an ninh thông qua Internet để mã hóa các dữ liệu được gửi trên đường truyền và chống hack website. 

    7. Kiểm thử an toàn cho website, máy chủ

    Nếu website của bạn đã đảm bảo được 9 yếu tố trên, website của bạn chưa hẳn đã an toàn. Để chống bị hack website bạn nên thực hiện việc kiểm thử độ an toàn website, tìm kiếm các lỗ hổng khác của website. Cách hiệu quả nhất là thông qua một số dịch vụ, các chuyên gia về An toàn thông tin có thể hỗ trợ bạn tìm kiếm các lỗ hổng, hỗ trợ khắc phục và ứng cứu khi có sự cố xảy ra. Tại Việt Nam hiện nay có khá nhiều đơn vị cung cấp các dịch vụ về Kiểm tra, đánh giá bảo mật cho website, máy chủ với giá tiền hợp lý, các dịch vụ này sẽ giúp bạn đảm bảo an toàn tuyệt đối cho website của mình.

    Các mạng quảng cáo ngoài Google Adsense hấp dẫn nhất 2019
    View 286 - Rating ★★★★☆

    Các mạng quảng cáo ngoài Google Adsense hấp dẫn nhất 2019

    Mô tả: Nếu bạn quan tâm đến đặt quảng cáo trên website/blog để kiếm tiền thì Google AdSense luôn là sự lựa chọn hàng đầu. Trong bài viết này, mình sẽ giới thiệu tới bạn các mạng quảng cáo ngoài Google Adsense được nhiều người yêu thích và tin dùng hiện nay.

    [Phần 2]Ý tưởng sáng tạo kiến tiền trên mạng người làm văn phòng cần biết
    View 994 - Rating ★★★★☆

    [Phần 2]Ý tưởng sáng tạo kiến tiền trên mạng người làm văn phòng cần biết

    Mô tả: Hiện nay có rất nhiều cách thức đầu tư hoặc kiến tiền trong môi trường trực tuyến hiện nay. Thông qua bài viết Ý tưởng kiến tiền trên mạng sáng tạo mà người làm văn phòng cần biết, chúng tôi hy vọng phần nào sẽ giúp các bạn tăng thêm thu nhập trong công việc.

    [Phần 1]Ý tưởng sáng tạo kiến tiền trên mạng người làm văn phòng cần biết
    View 985 - Rating ★★★★☆

    [Phần 1]Ý tưởng sáng tạo kiến tiền trên mạng người làm văn phòng cần biết

    Mô tả: Hiện nay có rất nhiều cách thức đầu tư hoặc kiến tiền trong môi trường trực tuyến hiện nay. Thông qua bài viết Ý tưởng kiến tiền trên mạng sáng tạo mà người làm văn phòng cần biết, chúng tôi hy vọng phần nào sẽ giúp các bạn tăng thêm thu nhập trong công việc.

    Chia sẽ cách kiếm tiền online bền vững và kinh nghiệm cần biết
    View 984 - Rating ★★★★☆

    Chia sẽ cách kiếm tiền online bền vững và kinh nghiệm cần biết

    Mô tả: Hiện có rất nhiều bài viết về thủ thuật việc kiếm tiền trên mạng . Bài viết này chúng tôi xin được chia sẽ cách kiếm tiền online một cách bền vững nhất và kinh nghiệm cần biết trong quá trình thực hiện. Chúc các bạn thành công

    Hướng dẫn cài đặt Adobe Premiere Pro CC 2018 cực đơn giản
    View 636 - Rating ★★★★☆

    Hướng dẫn cài đặt Adobe Premiere Pro CC 2018 cực đơn giản

    Mô tả: Adobe Premiere Pro CC 2018 là một phần mềm biên tập và chỉnh sữa video chuyên nghiệp hay được dùng trong các studio, chương trình có khả năng ghép sửa, chỉnh màu sắc, lồng nhạc. Sau đâu là phần download và hướng dẫn cài đặt Adobe Premiere Pro CC 2018 cực kỳ dễ dàng

    Adobe Premiere Pro CC 2018 và cách sử dụng miễn phí
    View 642 - Rating ★★★★☆

    Adobe Premiere Pro CC 2018 và cách sử dụng miễn phí

    Mô tả: Adobe Premiere Pro CC 2018 là một phần mềm biên tập và chỉnh sữa video chuyên nghiệp hay được dùng trong các studio, chương trình có khả năng ghép sửa, chỉnh màu sắc, lồng nhạc. Phần mềm kết hợp hiệu suất đáng kinh ngạc với giao diện người dùng cải tiến, đẹp mắt cùng một loạt các tính năng mới

    20 bài hát intro dành cho các bạn reup
    View 466 - Rating ★★★★☆

    20 bài hát intro dành cho các bạn reup

    Mô tả: Bạn đang săn lùng phần giới thiệu hấp dẫn hay nhạc outro cho loạt YouTube của mình? Thật khó để tìm thấy một bài hát hoàn hảo, đặc biệt là sau tất cả công việc bạn đã đưa vào để trau dồi kênh của mình, đó là lý do tại sao chúng tôi đã tuyển chọn 20 bài nhạc miễn phí bản quyền từ các tệp được xếp hạng cao nhất trong thư viện của chúng tôi.

    TechSmith Camtasia Studio Vesion 2018 hướng dẫn cài đặt  và cách sử dụng miễn phí
    View 299 - Rating ★★★★☆

    TechSmith Camtasia Studio Vesion 2018 hướng dẫn cài đặt và cách sử dụng miễn phí

    Mô tả: Camtasia Studio là phần mềm quay video với chất lượng hình ảnh và âm thanh khá tốt, tạo video đầu ra với nhiều định dạng khác nhau. Camtasia Studio còn cung cấp nhiều công cụ chỉnh sửa và tùy biến video, tăng khả năng sáng tạo với các video, chia sẻ video dễ dàng qua YouTube, Google Drive hoặc trang web được tích hợp.

    loading Đang tải...