XSSの決定的なガイド

クロスサイトスクリプティング攻撃のガイド。それらはどのように機能しますか?どうすればそれらを防ぐことができますか?

XSS、別名クロスサイトスクリプティングとは何ですか?

XSSは、ユーザー入力の安全でない処理のために、Webサイト(注意を払わない場合はWebサイト)がユーザーを攻撃するためのベクトルとして使用される可能性がある特定の種類の攻撃を定義するために使用する用語です。

基本的に、悪意のある攻撃者(攻撃者)は、コードに残された脆弱性を利用して、何らかの方法でJavaScriptをサイトに挿入できます。

この脆弱性を利用して、ユーザーの情報を盗むことができます。

XSSの脆弱性がどのように悪用されるかに基づいて、3つの主要な種類のXSS攻撃があります。

  • 永続的なXSS
  • 反映されたXSS
  • DOMベースのXSS

XSSが危険なのはなぜですか?

あなたがウェブサイトを持っていると想像してください。攻撃者はどういうわけかあなたのウェブサイトによって提供されるJavaScriptコードを挿入することができ、それはあなたの意志なしに、そしてあなたがそれについて知らなくても、あなたのユーザーのブラウザによって実行されます。

これは非常に危険です。

XSSの脆弱性の修正を怠ったため、サイトが攻撃ベクトルとして使用される可能性があり、ユーザー情報が危険にさらされています。

特に、誰もがページにJavaScriptを挿入できる場合、Webサイトに関連付けられているユーザーのCookieにアクセスし、そこに含まれている情報を読み取ることができます。そして、これを自分のサーバーに送信します。キーボードイベントをリッスンし、ユーザーがページに入力したすべてのユーザーにアクセスし、フェッチまたはXHRを使用して攻撃者のサーバーに送信できます。たとえば、ユーザー名とパスワード。また、DOMを操作することもでき、この能力を使用して、多くの悪いことを実行できます。

XSSはフロントエンドまたはバックエンドの問題ですか?

それは両方です。これは、フロントエンドとバックエンドの両方に関係するWebサイトのアーキテクチャ上の問題です。

XSS攻撃の例

XSSは基本的に、ユーザーが情報を入力できるようにすると有効になります。情報は(バックエンドに)保存してから表示します。

ブログがあり、ユーザーがブログにコメントできるようにするとします。ユーザーが入力するコンテンツをやみくもに受け入れると、悪意のあるユーザーは、JavaScriptスニペットを最も基本的な形式で入力しようとする可能性があります。<script></script>。例えば<script>alert('test')</script>

このコメントをデータベースに保存すると、ページが再読み込みされたときに(これも、防止策がない場合)、そのページを読み込んだすべてのユーザーがそのJavaScriptスニペットを実行します。

シンプルなalert()例を作成するために呼び出しますが、上記のように、ユーザーは任意の種類のスクリプトを入力できます。この時点で、サイトは危険にさらされています。

永続的なXSSとは何ですか?

永続的XSSは、私たちが野生で見つけた3種類のXSSの1つです。これは、上記のブログ投稿の例で説明したものです。

この場合、脆弱性のコードはデータベースまたは自分でホストされている他のソースに保存されます。

誰かがJavaScriptスニペットを入力できるようになると、他のアクションを必要とせずに、サイトによって自動的に提供されます。

反映されたXSSとは何ですか?

リフレクトXSSは、エンドユーザーにスクリプトを含むリンクを提供することにより、サイトの脆弱性をオンザフライで悪用する方法です。

このようにして、攻撃者は次のようなリンクを提供します

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: