Hướng dẫn chính xác về XSS

Hướng dẫn các cuộc tấn công kịch bản trên nhiều trang web. Họ làm việc như thế nào? Làm thế nào bạn có thể ngăn chặn chúng?

XSS, hay còn gọi là Cross Site Scripting là gì?

XSS là thuật ngữ chúng tôi sử dụng để định nghĩa một loại tấn công cụ thể trong đó một trang web (trang web của bạn, nếu bạn không chú ý) có thể được sử dụng như một vectơ để tấn công người dùng của nó, do người dùng nhập dữ liệu vào không an toàn.

Về cơ bản, một tác nhân xấu (kẻ tấn công) có thể đưa JavaScript, bằng cách này hay cách khác, vào trang web của chúng tôi, bằng cách tận dụng lỗ hổng mà chúng tôi để lại trong mã của mình.

Sử dụng lỗ hổng này, chúng có thể đánh cắp thông tin của người dùng.

Dựa trên cách lỗ hổng XSS được khai thác, chúng tôi có 3 loại tấn công XSS chính:

  • XSS liên tục
  • XSS phản ánh
  • XSS dựa trên DOM

Tại sao XSS lại nguy hiểm?

Hãy tưởng tượng bạn có một trang web. Kẻ tấn công bằng cách nào đó có thể đưa mã JavaScript được cung cấp bởi trang web của bạn và nó được thực thi - không theo ý muốn của bạn và bạn không biết về nó - bởi trình duyệt của người dùng của bạn.

Điều này rất nguy hiểm.

Do sơ suất của bạn trong việc sửa lỗ hổng XSS, trang web của bạn có thể được sử dụng làm vectơ tấn công và thông tin người dùng của bạn có thể gặp rủi ro.

Đặc biệt, khi bất kỳ ai có thể đưa JavaScript vào một trang, họ có thể có quyền truy cập vào cookie của người dùng được liên kết với trang web và đọc bất kỳ thông tin nào có trong đó. Và gửi cái này đến máy chủ của riêng họ. Họ có thể lắng nghe các sự kiện bàn phím và có quyền truy cập vào bất kỳ ai mà người dùng nhập vào trang và gửi nó đến máy chủ của kẻ tấn công bằng cách sử dụng tìm nạp hoặc XHR. Ví dụ: tên người dùng và mật khẩu. Họ cũng có thể thao túng DOM và với sức mạnh này, họ có thể thực hiện rất nhiều điều tồi tệ.

XSS có phải là vấn đề giao diện người dùng hay phần phụ trợ không?

Đó là cả hai. Đó là một vấn đề về kiến trúc trang web liên quan đến cả giao diện người dùng và phụ trợ.

Ví dụ về tấn công XSS

Về cơ bản, XSS được kích hoạt khi bạn cho phép người dùng nhập thông tin mà bạn lưu trữ (trong phần phụ trợ của bạn) và sau đó trình bày trở lại.

Giả sử bạn có một blog và bạn cho phép người dùng nhận xét trong blog. Nếu bạn chấp nhận một cách mù quáng bất kỳ nội dung nào mà người dùng nhập vào, thì một người dùng độc hại có thể cố gắng nhập một đoạn mã JavaScript, ở dạng cơ bản nhất của nó được bao gồm<script></script>. Ví dụ<script>alert('test')</script>.

Bạn có thể lưu trữ nhận xét này trong cơ sở dữ liệu của mình và khi trang được tải lại - một lần nữa, nếu bạn không có bất kỳ biện pháp ngăn chặn nào - tất cả người dùng tải trang đó sẽ chạy đoạn mã JavaScript đó.

Tôi đã sử dụng một đơn giảnalert()gọi để tạo một ví dụ, nhưng như được liệt kê ở trên, người dùng có thể nhập bất kỳ loại tập lệnh nào. Tại thời điểm này, trang web đã bị xâm phạm.

XSS liên tục là gì?

XSS liên tục là một trong 3 loại XSS mà chúng tôi tìm thấy trong tự nhiên. Đó là cái tôi đã mô tả ở trên trong ví dụ bài đăng trên blog.

Trong trường hợp này, mã cho lỗ hổng bảo mật được lưu trữ trong cơ sở dữ liệu hoặc vào một số nguồn khác do chính bạn lưu trữ.

Khi ai đó có thể nhập đoạn mã JavaScript, đoạn mã này sẽ được trang web của bạn tự động phân phát mà không cần thực hiện bất kỳ hành động nào khác.

XSS được phản ánh là gì?

XSS được phản ánh là một cách để khai thác một cách nhanh chóng lỗ hổng trong trang web của bạn bằng cách cung cấp cho người dùng cuối một liên kết có tập lệnh bên trong nó.

Bằng cách này, kẻ tấn công cung cấp một liên kết tương tự như

yoursite.com/?example=<script>alert('test')</script>

If your site uses the example GET variable to perform something and display it on the page, and you don’t check and sanitize its value, now that script will be executed by the user’s browser.

A typical example is a search form. It might live in the /search URL and you might accept the search term using the GET term variable.

You might display the You searched for <term> string when someone searches for it. Now, if you didn’t sanitize the value, you now have a problem.

Spam/phishing emails are a common medium for this XSS attack. Of course, the bigger and more important the site, the more frequently hackers will try to hack it.

What is DOM-based XSS?

With persistent XSS, the attacking code must be sent to the server, where it can be (and hopefully it is) sanitized. With reflected XSS, the same is true.

DOM-based XSS is a kind of XSS where the malicious code is never sent to the server. It’s common for this to happen by using the fragment part of a URL, or by referencing document.URL/document.location.href. Some examples you find online don’t really work any more because modern browsers automatically escape JS in the address bar for us. They only work if you unescape it, which is kind of scary (don’t do it!).

Here’s a simple working example. Say you have a page listening on http://127.0.0.1:8081/testxss.html. Your client-side JavaScript looks at the test variable passed in the fragment part of the URL:

http://127.0.0.1:8081/testxss.html#test=something

The #test=something value is never send to the server. It’s only local. Persistent/reflected XSS would not work. But say your script accesses that value using:

const pos = document.URL.indexOf("test=") + 5;
const value = document.URL.substring(document.URL.indexOf("test=") + 5, document.URL.length)

and you write it directly into the DOM:

document.write(value)

All is fine, until someone calls the URL like this:

http://127.0.0.1:8081/testxss.html#test=

Now, thanks to the automatic escaping that happens by referencing document.URL nothing should happen in this specific case.

You’d get

%3Cscript%3Ealert('x')%3C/script%3E

printed to the page. The value is escaped, so it’s not interpreted as HTML.

But if for some reason you unescape the document.URL value, you have a problem now, as the JavaScript is run. Any JS can be run on your users browsers.

On older browser, this was a much bigger problem, since they didn’t auto-escape JS put into the address bar.

Are static sites vulnerable to XSS?

Yes! Any kind of site, actually. Because being static does not mean there is no information loaded from other sources. For example you might roll your own form or comments, even without a database.

Or, we might have a search functionality that accepts input from an HTTP GET or POST variable. You are not immune just by not having a database.

How can we prevent XSS?

There are 3 techniques we can use:

  • encoding
  • validation
  • CSP

Encoding is done to escape the data. Doing so, the browser will not interpret the JavaScript because, for example, <script> will be encoded to %3Cscript%3E.

Encoding, as a general rule, should be always done.

Server-side frameworks commonly provide helper functions to provide this functionality to you.

In client-side JavaScript we use a different encoding mechanism depending on the use case.

If you need to add content to an HTML element, the best way is to assign the user-generated input to that element using the textContent property. The browser will do all the escaping for you:

document.querySelector('#myElement').textContent = theUserGeneratedInput

If you need to create an element use document.createTextNode():

const el = document.createTextNode(theUserGeneratedInput)

If you need to add content to an HTML attribute, use the setAttribute() method of the element:

document.querySelector('#myElement').setAttribute('attributeName', theUserGeneratedInput)

If you need to add content to the URL, use the window.encodeURIComponent() function:

window.location.href = window.location.href + '?test=' + window.encodeURIComponent(theUserGeneratedInput)

Validation is usually done when you cannot use escaping to filter the input. A common example is a CMS that lets the user define the content of the page in HTML. You can’t escape that.

You either use a blacklisting or whitelisting strategy for validation. The difference is that with blacklisting you decide which tags you want to disallow. With whitelisting you decide which tags you want to allow. Whitelisting is safer because blacklisting is prone to errors, complex and also not future-proof.

CSP means Content Security Policy. It’s a new standard implemented by browsers to enforce only executing JavaScript code coming from secure and trusted sources, and you can disallow running inline JavaScript in your code. The kind of JavaScript that allowed the above XSS exploits, for example.

CSP is enabled by the Web Server, by adding the Content‑Security‑Policy HTTP Header when serving the page.


More security tutorials: