web-dev-qa-db-ja.com

JSONP呼び出しからのコールバックパラメーターをサニタイズする必要がありますか?

JSONPを介してWebサービスを提供したいのですが、コールバックパラメーターの値をサニタイズする必要があるかどうか疑問に思いました。

私の現在のサーバーサイドスクリプトは現在次のようになっています(多かれ少なかれ。コードはPHPですが、実際には何でもかまいません)。

header("Content-type: application/json; charset=utf-8");
echo $_GET['callback'] . '(' . json_encode($data) . ')';

これは古典的なXSSの脆弱性です。

私がそれを消毒する必要がある場合、それではどうやって?コールバック文字列が許可される可能性があるものについての十分な情報を見つけることができませんでした。 ウィキペディア から引用します:

パディング(プレフィックス)は通常、ブラウザーの実行コンテキスト内で定義されるコールバック関数の名前ですが、変数の割り当て、ifステートメント、またはその他のJavascriptステートメントのプレフィックスの場合もあります。

18

はい、callbackが次のような場合

(function xss(x){evil()})

Phpからエコーバックすると、次のようになります

(function xss(x){evil()})(json)

関数xssが実行され、evil()はCookieを別の場所に送信するコードになる可能性があります。

したがって、有効な関数名のみにサニタイズします。たとえば、英数字に制限します。

10
YOU

コールバックが有効な識別子であり、英数字、アンダースコア、または$であることを確認する必要があります。また、予約語にすることもできません(念のため、undefinedNaN、またはInfinityではないことを確認します)。これは私が使用するテストです:

function valid_js_identifier( $callback ){
    return !preg_match( '/[^0-9a-zA-Z\$_]|^(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|delete|do|double|else|enum|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|null|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|true|try|typeof|var|volatile|void|while|with|NaN|Infinity|undefined)$/', $callback);
}

予約語の多くは無意味ですが、エラーや無限ループを引き起こす可能性のあるものもあります。

重要:文字を置き換えることによって入力をサニタイズするだけではありません。変更されたコールバックはエラーなしで実行され、返されたデータは適切に処理されません(または、間違った関数によって処理される可能性もあります)。入力が有効かどうかをテストし、有効でない場合はエラーをスローします。これにより、予期しない動作が回避され、別のコールバックが必要であることが開発者に通知されます。

注:これは、表現や改良を許可しない、より安全ですが制限されたバージョンのJSONPです。特にjQueryと$.getJSONを使用している場合は、ほとんどのアプリケーションでうまく機能することがわかりました。

11
Brett Wejrowski

はい。

@YOUで説明されているように、攻撃者は悪意のあるjavascript、またはさらに悪いことに 悪意のあるFlash に評価されるコールバックパラメータを作成する可能性があります。

コールバックが予約語ではなく、@ Brett-Wejrowskiによって説明されているように英数字であることを検証することは良いスタートです。

Google、Facebook、Githubは、jsonpコールバックの前に/ ** /な​​どの空のコメントを追加することで、RosettaFlashの脆弱性を軽減しています。

別のアプローチは、ExpressJSのように安全なjavascript式を返すことです。

typeof callbackstring === 'function' && callbackstring(.....);
4
Ryan

はい、コールバックパラメータをサニタイズする必要があります。

JSONPは、基本的には自発的なXSS攻撃です。別のホスト名へのURLを含むスクリプトタグを(一時的に)挿入し、ページ上のグローバル関数またはメソッドを呼び出せるようにする場合は、少なくとも、「コールバック」をコールバックにすぎないように制限するいくつかの予防措置を講じることが重要です。名前。

コールバック名は、構文的には識別子と同じくらい単純である必要があります。オブジェクトのプロパティを考慮に入れることができます。関数の呼び出しなどが可能になる可能性があるため、括弧を許可しないことをお勧めします。

以下は、JSONとJSONPの両方をサポートする基本的なAPIの例です。 PHP(MediaWikiのAPIから簡略化)で記述されていますが、他のプログラミング言語でも同様の構造を作成できます。

<?php

// Simulate the response data
$responseData = [
    'foo' => 'bar',
    'count' => ['one', 'two', 'three'],
    'total' => 3,
];

// Prepare to send the response
$prefix = '';
$suffix = '';
$ctype = 'application/json';

if (isset($_GET['callback'])) {
    $ctype = 'text/javascript';
    // Sanitize callback
    $callback = preg_replace("/[^][.\\'\\\"_A-Za-z0-9]/", '', $_GET['callback']);

    $prefix = $callback . '(';
    $suffix = ')';
}

// Send the response
header("Content-Type: $ctype; charset=UTF-8", true);
print $prefix . json_encode($responseData) . $suffix;
exit;
3
Timo Tijhof