+4

XSS vulnerabilities - Lỗ hổng XSS (Phần 3)

II. Phân tích, phòng chống các lỗ hổng Reflected XSS và Stored XSS (tiếp)

Ở phần trước, hàm htmlspecialchars() đã bảo vệ trang web trước các ký tự nhạy cảm trong lỗ hổng XSS như <, >, ", ... Nhưng liệu nó đã thực sự an toàn?

Xét tình huống một trang web cho phép người dùng để lại tên tác giả, lời chúc cùng link contact được gán trong tên tác giả. Mã nguồn như sau:

import mysql.connector
import html
from flask import Flask, request, redirect

app = Flask(__name__)

# Connect to MySQL database
cnx = mysql.connector.connect(user='root', password='password', database='mydatabase')
cursor = cnx.cursor()

@app.route('/')
def index():
    # Retrieve all the data from the database
    cursor.execute("SELECT * FROM hpny")
    datas = cursor.fetchall()

    # Build the HTML for the datas
    html = '<h1>Happy new year!</h1>'
    for data in datas:
        html += f'<p>Wishes from <a href="{data[3]}">{data[1]}<a>: {data[2]}</p><br>'

    html += '''
        <form action="/submit" method="post">
            Name: <input type="text" name="name"><br><br>
            Wishes: <textarea name="wishes"></textarea><br><br>
            Website: <input type="text" name="website"><br>
            <input type="submit" value="Submit">
        </form>
    '''

    return html

@app.route('/submit', methods=['POST'])
def submit():
    # Get the user's data from the request
    # prevent XSS attack with html.escape()
    name = html.escape(request.form['name'])
    wishes = html.escape(request.form['wishes'])
    website = html.escape(request.form['website'])

    # Insert the wishes into the database
    cursor.execute("INSERT INTO hpny (name, wishes, website) VALUES (%s, %s, %s)", (name, wishes, website))
    cnx.commit()

    return redirect('/')

if __name__ == '__main__':
    app.run(host = '0.0.0.0', port = 9999)

Trang web đã sử dụng hàm html.escape() trong Python - có chức năng tương tự hàm htmlspecialchars() thực hiện ngăn chặn lỗ hổng XSS:

image.png

Chúng ta quan sát cách trang web gán đường link contact:

html += f'<p>Wishes from <a href="{data[3]}">{data[1]}<a>: {data[2]}</p><br>'

Chú ý rằng đoạn code trên trực tiếp ghép giá trị tham số website vào thuộc tính href, nên chúng ta vẫn có thể tạo payload tấn công XSS bằng pseudo-protocol javascript như sau (tham số website):

javascript:alert('XSS')

Kết quả khi người dùng click vào link <a href="javascript:alert(&#x27;XSS&#x27;)">hacker<a> sẽ kích hoạt hộp thoại alert:

image.png

Với tình huống này các bạn đọc có thể luyện tập thêm tại các bài lab:

Để khắc phục lỗ hổng XSS tại tình huống này chúng ta có thể yêu cầu người dùng nhập đúng định dạng một link website bình thường bằng Regular expression (biểu thức chính quy). Ví dụ sử dụng hàm match() trong thư viện re:

import re

website = request.form['website']

if not re.match(r"^(http:|https:)//[0-9a-zA-Z]+$", website):
    raise ValueError("Invalid website")

III. Phân tích, phòng chống các lỗ hổng DOM-based XSS

1. Document Object Model (DOM) - Mô hình đối tượng Document

Theo định nghĩa từ w3schools:

The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a document.

Chúng ta có thể hiểu đơn giản DOM giúp một trang web truy nhập, thay đổi nội dung một cách dynamic (động) phần source code trang web (HTML) từ đó thay đổi nội dung hiển thị, tùy vào từng thao tác người dùng hoặc cách hoạt động từ trang web.

Một HTML DOM tree của Object có dạng như sau:

image.png (https://www.w3schools.com/js/jshtmldom.asp)

Chúng ta cùng so sánh với đoạn code html sau để dễ dàng hình dung hơn:

<html>
  <head>
    <title>This is title</title> 
  </head> 
  <body> 
    <h1>Viblo</h1> 
    <a href = "https://viblo.asia/">viblo.asia</a>
  </body> 
</html>

Các thẻ html được quản lý trong DOM:

  • Thẻ cao nhất là <html>
  • Tiếp theo phân thành 22 nhánh gồm thẻ <head><body>
  • Bên trong <head> chứa các thẻ <title>, <style>, ...
  • Bên trong <body> chứa các thẻ <a>, <h1>, <div>, ...
  • Và tiếp tục quá trình phân nhánh như trên ...

Sử dụng DOM, chúng ta có thể truy nhập tới từng node trong cây DOM trên, thực hiện các thao tác thêm, sửa, xóa.

2. DOM-based XSS

Các lỗ hổng DOM-based XSS xảy ra khi mã độc được chèn vào trang web bằng cách sử dụng các tài nguyên không được lưu trữ trên máy chủ, mà được tải từ máy chủ và xử lý trên trình duyệt của người dùng.

Để hiểu rõ hơn về dạng lỗ hổng này, chúng ta cùng xem xét một vài lab sau:

Kiểm tra chức năng Search với một chuỗi ngẫu nhiên:

image.png

Chú ý đoạn script xử lý chuỗi tìm kiếm:

  • Biến query lấy giá trị tham số search từ URL qua hàm URLSearchParams().
  • Nếu biến query khác rỗng thì gọi hàm trackSearch(), sử dụng hàm document.write() ghi nội dung:
'<img src="/resources/images/tracker.gif?searchTerms='+query+'">'

Do biến query chúng ta có thể thay đổi được nên đồng nghĩa với việc chúng ta có thể tác động vào giá trị thẻ <img>. Chẳng hạn, tận dụng thuộc tính onerror để kích hoạt sự kiện alert(). Chúng ta cần giá trị src trong thẻ <img> gặp lỗi. Xây dựng payload như sau:

abc" onerror="alert(1)

Khi đó document.write() ghi nội dung <img src="/resources/images/tracker.gif?searchTerms=abc" onerror="alert(1)">, giá trị src gặp lỗi nên sự kiện alert(1) thực hiện, bài lab hoàn thành.

image.png

Bạn đọc có thể làm bài lab tương tự DOM XSS in document.write sink using source location.search inside a select element, DOM XSS in innerHTML sink using source location.search

3. DOM XSS trong jQuery

Thư viện jQuery trong ngôn ngữ Javascript cũng có thể gây ra các lỗ hổng DOM XSS. Chẳng hạn hàm attr() - dùng để lấy hoặc thiết lập giá trị của một thuộc tính trên một phần tử HTML, ẩn chứa nguy cơ tạo ra lỗ hổng DOM XSS khi việc cài đặt chưa chặt chẽ. Xét tình huống trong lab DOM XSS in jQuery anchor href attribute sink using location.search source.

Trang web Submit feedback sử dụng thư viện jQuery. Chức năng Back gọi hàm attr() lấy giá trị tham số returnPath trong URL để thiết lập giá trị cho thuộc tính href:

image.png

image.png

Do giá trị tham số returnPath có thể thay đổi bởi người dùng nên kẻ tấn công có thể sửa tham số returnPath nhận giá trị javascript:alert('XSS') nhằm kích hoạt thông báo alert().

image.png

Payload hoàn thành bài lab: javascript:alert(document.cookie)

Một lab khác về lỗ hổng DOM XSS trong thư viện jQuery dành cho bạn đọc: DOM XSS in jQuery selector sink using a hashchange event

4. Phát hiện và khắc phục DOM XSS

Trong lỗ hổng DOM-based XSS, source là nguồn dữ liệu không được kiểm duyệt mà được chèn vào trang web, còn sink là nơi mà dữ liệu đó được hiển thị. Do đó, source và sink là hai yếu tố quan trọng trong việc phát hiện và khắc phục lỗ hổng DOM-based XSS.

Một số sinks có thể dẫn tới lỗ hổng:

document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent

Các hàm trong thư viện jQuery cũng có thể đóng vai trò sinks dẫn tới lỗ hổng:

add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()

Để khắc phục lỗ hổng này, chúng ta cần đảm bảo rằng dữ liệu đầu vào được kiểm duyệt kỹ trước khi được chèn vào trang web tại sink.

Các tài liệu tham khảo


©️ Tác giả: Lê Ngọc Hoa từ Viblo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí