XST の攻撃手法#
XST のフルネームは Cross-Site Tracing であり、日本語では「クロスサイトトレース攻撃」と訳されます。具体的には、クライアントがサーバーに対して TRACE / TRACK リクエストを送信し、サーバーが標準的な方法で TRACE / TRACK レスポンスを実装している場合、レスポンスボディにはリクエストの完全なヘッダ情報が返されます。この方法により、クライアントは httpOnly の Cookie など、いくつかの機密のヘッダフィールドを取得することができます。
XST の攻撃原理は非常に単純であり、XST 攻撃によって Cookie 情報や他の機密情報を取得した後、攻撃者はこれらの情報を利用して XSS、CSRF、中間者攻撃などを行うことができます。XST 攻撃自体はサーバーに実質的な損害を与えることはありませんが、その真の影響は機密のヘッダデータを露呈することです。たとえば、httpOnly 属性を持つ Cookie は、フロントエンドの JavaScript からアクセスが禁止されており(document.cookie
など)、第三者に送信されることを防いでいますが、このような場合でも TRACE メソッドはこの保護を回避して Cookie にアクセスするために使用できます。そのため、XST は Trace 漏洩攻撃、Trace ヘッダ反射、Trace メソッドインジェクション(TMI)、Trace Header Cookie 攻撃(THC)とも呼ばれています。
XST 攻撃の条件:
- 対象の Web サーバーが Trace、Track メソッドのリクエストを受け入れる許可を与えている必要があります。
- クライアントが Trace、Track メソッドのリクエストを送信できる必要があります。(現在のブラウザ環境ではこの種のリクエストは防止されています)
以下に例を示します。ここでは、Express を使用してシンプルな Web サーバーを構築し、Trace メソッドのリクエストを受け入れます:
import express from 'express'
import cookieParser from 'cookie-parser'
const app = express()
app.use(cookieParser())
app.use('/', (req, res, next) => {
res.cookie('account', 'airing', { maxAge: 900000, httpOnly: true })
return res.json(req.headers)
})
app.listen(3000)
TRACE メソッドを使用して Cookie をリクエストに含めると、Cookie が送信されることがわかります(Chrome 24 環境下):
var xhr = new XMLHttpRequest();
xhr.open('TRACE', 'http://127.0.0.1:3000/', false);
xhr.withCredentials = true
xhr.setRequestHeader('Cookie', 'account=airingursb');
xhr.send(null);
if(200 == xhr.status) console.log(xhr.responseText);
XST の真の結果は、通常 JavaScript からアクセスできない HTTP ヘッダにアクセスできることです。httpOnly は JavaScript が Cookie を読み取り、サーバーに送信することを防ぐはずですが、XST は httpOnly の制限を回避して成功します。また、HTTP Basic 認証に使用される Authentication ヘッダは、ユーザー名とパスワードの Base64 エンコードであり、DOM の一部ではないため、直接 JavaScript から読み取ることはできませんが、XST を使用すると回避できます。これらの機密情報は、たった 1 つの Trace リクエストですべて公開されます。
XST の防御方法#
XST を防ぐには非常に簡単で、Web サーバーで Trace、Track メソッドのリクエストを制限すればよいです。また、現代のブラウザでは、XMLHTTPRequest による Trace と Track メソッドのリクエストはすでに防止されています(Chrome 25 以降、FireFox 19 以降)。Trace / Track メソッドのリクエストを試みると、SecurityError 例外がスローされ、XST 攻撃が根本的に防止されます。
var xhr = new XMLHttpRequest();
xhr.open('TRACE', 'http://localhost:3000/', false);
xhr.send(null);
if(200 == xhr.status) console.log(xhr.responseText);
また、FireFox 43 以降では、Cookie などの安全でないフィールドもリクエストヘッダに含めることができなくなりました。詳細は Forbidden header name | MSD を参照してください。
現代のブラウザはますます安全になっており、XST は過去のものとなりましたが、Web 開発者にはセキュリティと厳密さに注意するよう警告を与えています。