まとメモ

29才でエンジニアに転職したエンジニアのメモ

DOMについて

JavaScriptの処理の中で出てくる、DOMについて調べました。

DOMとは?

DOMとは、XML文書やHTML文書を構成する要素をコンピュータプログラムで参照したり操作したりするための取り決め(API)の一つ。
引用元:http://e-words.jp/w/DOM.html


DOM(Document Object Model)とは、プログラムやスクリプトで使って(X)HTML・XML文書の構造やノードに動的にアクセスためのAPIです。 JavaScriptでは(X)HTML・XML文書をオブジェクトとして扱えます。 プロパティやメソッドで各要素にアクセスすれば、要素の情報を取得したり、その情報を書き換えることができる。 引用:http://phpjavascriptroom.com/?t=js&p=dom

DOM(Document Object Model)とは、xmlやhtmlの各要素にアクセスする仕組みのこと。 このDOMを操作することによって、要素の値をダイレクトに操作できる。 例えば<p>の中身のテキストを変更したり、<img src="sample.jpg">のsrcの中身を変更して別の画像に差し替えるといったことができる。


補足

HTML(エイチティーエムエル、HyperText Markup Language)は、ウェブページを作成するために開発された言語です。 現在、インターネット上で公開されてるウェブページのほとんどは、HTMLで作成されています。
引用元:http://www.htmq.com/htmlkihon/001.shtml

HyperText:ハイパーリンクを埋め込むことができるテキスト(ハイパーリンクというのは、ウェブページで下線の付いたテキストなどをクリックすると別ページへ移動するリンクのこと。) ハイパーテキストでは、WEBページから別のウェブページにリンクをはったり、 WEBページ内に画像・動画・音声などのデータファイルをリンクで埋め込むことができる。

Markup:文字にタグという印をつけていくことでそれぞれ意味づけをし、コンピューターが正しく認識できるようにする。

XMLとはExtensible Markup Language(エクステンシブル マークアップ ランゲージ)の略語であり、文書やデータの意味、構造を記述するためのマークアップ言語の一つです。 引用元:http://xml.prognavi.com/?p=7


DOMはブラウザがWebページを解釈したもの

  • ブラウザによる HTML ファイルの解釈方法と表示方法は HTML と CSS の仕様で規定されている
    (仕様はウェブに関する標準化団体「W3CWorld Wide Web Consortium)」が管理)
  • ブラウザの主要コンポーネント
    1 ユーザー インターフェース
    2 ブラウザ エンジン
    3 レンダリング エンジン
    4 ネットワーキング
    5 UI バックエンド
    6 JavaScript インタープリタ
    7 データ ストレージ

引用:https://www.html5rocks.com/ja/tutorials/internals/howbrowserswork/

(ブラウザごとに使用されているレンダリングエンジンは異なる)

レンダリングエンジンの処理

1 HTMLをDOMツリーと呼ばれる構造体に変換
2 レンダーツリーを構成
3 レンダーツリーをレイアウト
4 レンダーツリーを描画

DOMツリー
  • DOMでは、HTMLの中にあるすべてを「ノード」という単位で区切る
  • <html>、<body>、<h1>、<p>といったHTMLタグや、コメント、属性、テキストすべてがノード
  • (documentオブジェクトの)ツリーの最上階はdocument。documentとはこのHTML全体を表す。 f:id:aki_photo_blog:20190305001504p:plain
DOMは「WEBページとプログラミング言語を繋ぐ役割を持つ」
  • JavaScriptによって、DOMツリーのノードを操作することができる。

まとめ

DOMとは、ブラウザに実装されているレンダリングエンジンを使い、HTML文書をツリー構造にしたもの。DOMはJavaScriptで操作できる。

参考

https://www.html5rocks.com/ja/tutorials/internals/howbrowserswork/
https://developer.mozilla.org/ja/docs/DOM/About_the_Document_Object_Model
http://jsstudy.hatenablog.com/entry/dom-document_object_model
https://app.codegrid.net/entry/2017-newer-dom-1
https://gigazine.net/news/20180323-rendering-engine/
http://piyo-js.com/05/dom.html
https://blog.codecamp.jp/javascript_dom01
https://www.atmarkit.co.jp/ait/articles/0803/12/news149.html
https://eng-entrance.com/what-is-dom
https://kuroeveryday.blogspot.com/2018/11/difference-between-dom-and-node-and-element.html
https://techacademy.jp/magazine/5638

JavaScript 記述場所・実行順

JavaScriptの記述


記述する場所
  • head要素の中
  • body要素の中
  • bodyタグの閉じタグの直前
HTMLへのスクリプトの埋め込み
  • <script></script>の間に記述する … インライン スクリプト

    • HTML5の場合はデフォルトのtype属性がJavaScriptなのでtype属性 (type="text/javascript")を特別記載する必要はない
  • bodyタグの閉じタグの直前にscriptタグを記述するのが一般的

    • すべてのブラウザではJavaScriptを読み込んで処理している間は他のレンダリング(HTML要素の読み込み)を中断するという処理になっているから
<script>
  // ここにスクリプトを記述
</script>
  • <script>のsrc属性に指定して、外部ファイルから読み込む … 外部スクリプト
    • インラインの時と同じようにbodyタグの閉じタグの直前に書くというのが一般的
<script src="./sample.js"></script>
<a href="javascript:(ここにスクリプトを記述)">クリック</a>

<input type="button" value="Click!" onclick="ソース記入">
- 直接 外部
メリット 読み込みが早い HTMLとJavaScriptが分離され再利用しやすい、管理しやすい
デメリット HTMLとJavaScriptが混在しコードが乱雑になる、管理しにくい ファイルが増えると、読み込みが遅くなる
記述する場所によってエラーになる
<head>
<script>
    var memo = document.getElementById(‘memo’);
    memo.textContent = ‘こんにちは!’;
</script>
</head>
<body>
    <p id=”memo”></p>
</body>

上記のコードは「pタグ」が存在していないのに文字列を代入しようとしているためエラーとなる。

JavaScriptの実行


すべてのDOMツリー構造及びCSS・画像などの関連リソースが読み込まれたあとにJavaScriptが実行されるようにする方法
window.onload = function() {
    // 実行したい処理 
}
  • head要素内でDOMを扱うプログラムを書いてもエラーにはならない
    ※ 複数の「onloadイベント」書いてしまうと上書きされてしまい、最後に書いたイベントだけが実行される →複数人でプログラムを書いている場合に誤って「onloadイベント」を上書きしてしまうリスクがあるので注意が必要
window.addEventListener('load', function() {
   // 実行したい処理
})

jquery

$(window).on('load', function() {
    //実行したい処理
});
  • この書き方だと複数の「onloadイベント」を登録してもすべて実行される
DOMの「ツリー構造」が完了した時点で実行される方法
window.addEventListener('DOMContentLoaded', function() {
    // 実行したい処理
})

jquery

$(document).ready(function(){
    // 実行したい処理
});

$().ready(function(){
    // 実行したい処理
});

$(function(){
    // 実行したい処理
});

まとめ

  • 記述する場所に気をつける
  • JavaScriptの実行順を考える
  • window.onloadは上書きされる

参考

【JavaScript基礎】JavaScriptの実行順序について - KDE BLOG

JavaScriptの記述場所 | JavaScript入門編 - ウェブプログラミングポータル

【JavaScript】記述方法別の実行タイミングについて - Qiita

JavaScriptの記入場所-JavaScript入門

ブラウザのアドレスバーからJavaScriptのコードを実行する方法 (JavaScript疑似プロトコル)

【備忘録】ページの各読み込みタイミングにスクリプトを実行する方法まとめ【javascript】 - Qiita

ページ読み込み時のJavaScriptの実行タイミング - ばしぶろ

なぜhead要素内で外部JavaScriptファイルを読み込むのが良くないのか?

jQueryの読込み「ready」と「load」と「function」の順番について | web-wizardry

【JavaScript】window と document の違い

【JavaScript入門】onloadイベントの使い方とハマりやすい注意点とは | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト

【超初心者向け】JavaScriptの基本的な書き方講座

&lt;script&gt; タグに async / defer を付けた場合のタイミング - Qiita

httpsとは?

httpsとは「Hypertext Transfer Protocol Secure」の略称で、SSL/TLSプロトコルにより暗号化されたhttp通信の事

  • 「http」から始まっている場合は、通常のhttp通信であり、データの送信は平文で行われている。
  • 一方で、「https」から始まっている場合は、SSL/TLSプロトコルを利用した、暗号化通信が行われている。
  • SSL暗号化通信では、データは暗号化されてやりとりされるため、複合化ができない第3者からは、内容を読みとくことができない。
  • 個人情報や認証情報、機密情報等のやりとりが必要なサイトやページで導入することで、盗聴・なりすまし・中間者攻撃・情報漏洩等の対策として活用されている。

httpsの仕組み

SSL(SSLサーバ証明書)を用いたhttps暗号化通信は、「共通鍵暗号方式」と「公開鍵暗号方式」の両方を用いた「ハイブリッド方式」とも呼ばれる仕組みで行われる。

  1. HTTPSリクエス
  2. SSLサーバー証明書と公開鍵を送る
  3. SSLサーバー証明書は 3 または 4階層からできていて、その最上位の階層にあるのがルート証明書
  4. ルート証明書Webブラウザにもあらかじめ情報が登録されていて、サーバーから送られてくる証明書と照合する

    ハッシュ関数というアルゴリズムを用いて「証明書が改竄されていないか」といったことを確認します。 照合した結果、ルート証明書にある認証局の署名が一致すれば、信頼できる証明書と判断します。 ブラウザに登録されるルート証明書は、ブラウザのバージョンアップなどに伴ってアップデートされていて、新たなルート証明書の追加や、安全性に疑いのある証明書の削除などが随時行われています。

  5. 証明書を確認(クライアントは、受け取った SSLサーバー証明書の階層を辿りながら、サーバー側のルート証明書とブラウザ自身に登録されているルート証明書を照合する)
  6. 共通鍵を生成
  7. 共通鍵を公開鍵で暗号化してサーバーに送る
  8. 秘密鍵で公開鍵を復号し、共通鍵を取り出す→サーバーとクライアントの両方が安全に共通鍵を持つことができた
  9. SSL暗号化通信
  10. 共通鍵を使って暗号化通信をする

SSL/TLSとは?


SSLは"Secure Sockets Layer"の略称で、通信の暗号化、通信相手の認証、通信内容の改ざん検知の機能を有した、安全性の高いインターネット通信を行うためのプロトコルである。 現在仕組みとしての「SSL」は使われていない。 TLSは"Transport Layer Security"の略称で、SSLの後継として作成された。 実際に現在「情報を安全にやりとりするための仕組み」として使われているのが「TLS」である。 SSLの名称が広く普及しているため、SSLTLSを総省して、「SSL」と呼ばれることも多い。

  • 通信の暗号化(盗聴を防ぐ)
    • SSL証明書を利用したSSL暗号化通信では、通信内容は判読が困難な乱数に変換・暗号化される。
  • サーバの正当性の確認(なりすましを防ぐ)
    • SSL証明書を正当性の確認のために利用する。
  • メッセージ認証(改ざんを防ぐ)
    • 送信側のデータと受信側のデータが同一であるかを確認するために、一方向ハッシュ関数で確認する。
SSL」 は仕組みとしては使われていないけど、「情報を安全にやりとりする」という意味の言葉として使われている
TLS」 は「情報を安全にやりとりする」ために実際に使われている仕組み

SSL証明書とは?


SSL証明書とは、SSL/TLSの暗号化通信を行うのに必要な、電子証明書です。 SSL証明書にはドメイン認証(DV)、組織認証(OV)、EV認証(EV)の3段階の認証レベルがあります。 認証レベルによって、SSL/TLS暗号化通信の機能や強度に違いはありません。 しかしながら、認証レベルにより、 * 取得可能な対象 * 認証局による確認項目 が異なるため、発行されるSSL証明書の信頼性に大きな違いがあります。 * ドメイン認証タイプ(Domain Validation) * ドメインの所有権を確認するシンプルなSSLサーバ証明書 * 企業認証タイプ(Organization Validation) * ドメインの所有権に加えて、企業の実在性を確認するSSLサーバ証明書 * 企業認証タイプ(Extended Validation) * 標準化された業界基準により、厳格な認証プロセスを経て発行するSSLサーバ証明書

Q.SSL証明書の確認方法は?
A,証明書情報のプロファイルを確認する

[GeoTrust] 証明書の階層構造について

SSLに関してよくある10個の質問 | DigiCert & Symantec

中間証明書(SecureCoreドメイン認証SSL用)|SSLボックス

5分でわかるSSL通信 SHA-1、SHA-2の違いとは? | geechs magazine

SSL証明書の内容と確認する方法|GMOグローバルサイン【公式】

SSLサーバ証明書の認証レベル | 基礎から学ぶSSL入門ガイド | CSP SSL
SSL証明書について簡単にご紹介! | 技術情報ブログ | マネージドホスティングのディーネット

今さら聞けないSSL証明書とは、DV、OV、EVとは、常時SSLについて | レンタルサーバーのCPIスタッフブログ

SSLサーバ証明書の種類と比較 | DigiCert & Symantec

SSLサーバー証明書 各証明書の見え方|Zenlogic - ファーストサーバ株式会社のレンタルサーバー

httpsとは?httpとの違いとSSL暗号化通信の仕組み

誰でもわかる SSL (HTTPS) 通信の仕組み [図解]

SSLとは? | 基礎から学ぶSSL入門ガイド | CSP SSL

HTTPS と SSL と TLS:その違いを5分でわかりやすく解説! – キュービストブログ

第1回 HTTPS(HTTP over SSL/TLS)とは

SSL/TLS サーバー証明書の認証レベルとは?|DigiCert SSL/TLS 証明書|DigiCert

TLS1.2への移行の必要性~TLS1.2への有効化が始まる現状の動きとは | GMOグローバルサイン

無名関数

無名関数

無名関数はクロージャとも呼ばれ、 関数名を指定せずに関数を作成できるようにするものです

変数を引数で渡す

function method() {
    $hello = 'hello';
    $closure = function($greeting) {
        echo $greeting." world", PHP_EOL;
    };
    $closure($hello);
}
method();

変数をuseを使って引き継ぐ(値渡し)

function method2() {
    $hello = 'hello';
    $closure = function() use ($hello){
        $hello = 'goodby';
        echo $hello." world",  PHP_EOL;
    };
    $closure();
    echo $hello;
}
method2();

変数をuseを使って引き継ぐ(参照渡し)

function method3() {
    $hello = 'hello';
    $closure = function() use (&$hello){
        $hello = 'goodby';
        echo $hello." world",  PHP_EOL;
    };
    $closure();
    echo $hello;
}
method3();

クロージャとは関数の中の関数である

function outer(){
    $x = 1;
    return function () use (&$x){ 
        echo $x,PHP_EOL;
          $x = $x + 1;
    };
}

$f =  outer(); 
$f();  
$f();  
$f();  

クロージャを使うと、このように「状態を保持する関数」を作ることができる

JavaScriptでは、あるスコープ内で指定された変数が見つからない時、自動的に外側のスコープへ探しに行きます。

function outer(){
    var x = 1;
    return function (){
      console.log(x);
        x = x + 1;
    };

}

var f =  outer(); 
f();  // 1
f();  // 2
f();  // 3

クロージャは何の役に立つのか?

$(function(){
  var isClicked = false;
  $('#form').submit(function(){
        if (isClicked) {
            alert('すでにクリック済みです。');
            return false;
        }
        isClicked = true;
    });

});

パーフェクトPHPのクロージャの説明が全然わからなかった - blog @kimromi
JavaScriptとPHPの無名関数内での変数の扱い - せかいろぐ
なぜクロージャ(Closure)と言うのか? - Qiita
私が今までクロージャを理解できなかった理由 - 主にプログラムを勉強するブログ
無名関数/クロージャー基礎
phpのクロージャ・無名関数の使いどころについて考えてみた - Qiita

PHP URLの存在確認

URLの存在確認

  • 下記コードは、httpのリクエストを送信してURLにアクセス可能かどうか確認している。
  • 確認する方法はいくつかある

    • file_get_contents
    • fopen
    • get_headers
  • 現状のコード

## URLのチェック
$text = "チェックするURL"
public static function validation_site_url($text)
{
  // プロトコルがない場合
  if(!preg_match('/^https?:\/\//', $text)) $text = 'http://'.$text;
  if($fp = @fopen($text, 'r')){
    fclose($fp);
    return true;
  }
  else
  {
    return false;
  }
}

参考 【php】 URLが存在するかどうか確認する at softelメモ

fopen()の返り値

成功した場合はファイルポインタを返します。失敗した場合はFALSEを返し、E_WARNINGレベルでエラーを発します。エラー制御演算子(@)が使用可能です。通常はこのファイルポインタを用いて、ファイル操作を行います。 PHP関数講座:fopen | そふぃのphp入門

ブラウザではアクセスできるのに、上記のコードでfalseが返ってくるURLがある


対策その1
  • fopen()ではない処理を試す

get_headersを使ってみる

get_headersの返り値

数値添字配列あるいは連想配列でヘッダを返します。 失敗した場合は FALSE を返します。 PHP関数 - HTTPヘッダーを取得 - get_headers() - PHP入門 - Webkaru

問題のURLで試してみる

$url = "問題のURL";
$http_header = get_headers($url);
var_dump($http_header);

array(6) {
  [0]=>
  string(22) "HTTP/1.1 403 Forbidden"
  [1]=>
  string(35) "Date: Mon, 24 Dec 2018 17:03:33 GMT"
  [2]=>
  string(14) "Server: Apache"
  [3]=>
  string(19) "Content-Length: 328"
  [4]=>
  string(17) "Connection: close"
  [5]=>
  string(43) "Content-Type: text/html; charset=iso-8859-1"
}

HTTPステータスコード403が返って来た

なぜブラウザでは200が返って来るのに、get_headersでは403が返ってくるのか

原因

fopenget_headersではUser-Agentヘッダーが送信されていないので、User-Agentヘッダーをチェックしているサイトでは期待する値を取得できない

対策

User-Agentヘッダーを送信する

User-Agentヘッダーとは

HTTPではUser-Agentヘッダーが定義されている。 クライアントはサーバーにリクエストを送る際に、ユーザーエージェントの情報をUser-Agentヘッダーとして送信する。User-Agentヘッダーには、アプリケーション名、バージョン、ホストオペレーティングシステムや言語といった情報が含まれる。 ユーザーエージェント - Wikipedia

取得してみる

var_dump($_SERVER['HTTP_USER_AGENT'])

string(120) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"

このUser-Agentヘッダーをfopenget_headersの前にini_setでセットする

ini_set ('user_agent', $_SERVER['HTTP_USER_AGENT']); 

現状のコードを修正する

## URLのチェック
public static function validation_site_url($text)
{
  // プロトコルがない場合
  if(!preg_match('/^https?:\/\//', $text)) $text = 'http://'.$text;
  ini_set ('user_agent', Input::server('HTTP_USER_AGENT'));  //追記コード
  if($fp = @fopen($text, 'r')){
    fclose($fp);
    return true;
  }
  else
  {
    return false;
  }
}

fopenステータスコード1xx,4xx,5xxではfalseを返す

PHP: fopen - Manual

参考 get headers - PHP - get_headers returns "400 Bad Request" and "403 Forbidden" for valid URLs? - Stack Overflow

ファイルのオープンとクローズ(fopen, fclose) - ファイル関数 - PHP関数

PHPにおいてファイルの入出力 - Qiita

[メモ] PHPのfile_get_contentsを、HTTPリクエストに使うときのTIPS ::ハブろぐ

404エラーとは〜今さら聞けない基礎知識と原因の対処方法を解説|ferret [フェレット]

PHP、URLの存在チェックを行うついでに「get_headers()」関数で遊んでみる。|マコトのおもちゃ箱 ~ぼへぼへ自営業者の技術メモ~

ユーザーエージェント とは 意味/解説/説明 【User Agent, UA】 | Web担当者Forum

UserAgentからOS/ブラウザなどの調べかたのまとめ - Qiita

PHPでファイルのアップロード

Ajaxでjpg画像をS3にアップロードしたい

ファイルアップロードの流れ

  1. ファイルアップロードフォームでアップロード
  2. サーバーの一時フォルダに一旦保管
  3. move_uploaded_file()で指定のパスに移動

アップロードその1
- Ajaxを使わずにアップロードする方法

ファイルアップロード用フォーム
HTMLでファイルアップロードを実現するには以下がポイント

formタグのenctypeにmultipart/form-dataを設定

<form action=”upload.php” method=”post” enctype=”multipart/form-data”>

input typeにはfileを指定

<input type=”file” name=”upload”>
// ファイルの保存先
$uploadfile = '/var/www/files/test.jpg';
// アップロードされたファイルに、パスとファイル名を設定して保存
move_uploaded_file($_FILES['upload']['tmp_name'], $uploadfile);

$_FILESの中身は以下のような連想配列になっている

Array(
[name] => test.jpg
[type] => img/jpg
[tmp_name] => /var/tmp/php7UNOJY
[error] => 0
[size] => 45
)

配列で取得した内容

項目 内容
name 元ファイル名
type ファイルタイプ
tmp_name 一時保管されたファイル名
error エラーコード
size ファイルのバイト数

エラーコードは0ならアップロード成功で、1〜4、6〜8は以下のようなエラーになる

コード エラー定数 説明
0 UPLOAD_ERR_OK エラーなし
1 UPLOAD_ERR_INI_SIZE php.iniのupload_max_filesizeのサイズを超えている
2 UPLOAD_ERR_FORM_SIZE HTMLフォームで指定された MAX_FILE_SIZE を超えている
3 UPLOAD_ERR_PARTIAL 一部のみしかアップロードされていない
4 UPLOAD_ERR_NO_FILE アップロードされなかった
6 UPLOAD_ERR_NO_TMP_DIR サーバー一時保管フォルダがない
7 UPLOAD_ERR_CANT_WRITE ディスクへの書き込みに失敗
8 UPLOAD_ERR_EXTENSION PHPの拡張モジュールがアップロードを中止した

アップロードその2
- Ajaxでアップロード

サンプル

<form id="foo">
    <input id="file" name="file" type="file" />
    <input id="send" type="submit" />
</form>

<script>
$(function(){
    $('#foo').submit(function(){
        var fd = new FormData($('#foo').get(0));
        $.ajax({
            url: "test.php",
            type: "POST",
            data: fd,
            processData: false,
            contentType: false,
            dataType: 'json'
        })
        .done(function( data ) {
            $('#result').text(data.width + "x" + data.height);
        });
        return false;
    });
});
</script>
  • ポイント
    • type="file"を含むinput要素は、FormDataオブジェクトで取得
    • data:にはFormDataオブジェクトを設定
    • processData:とcontentType:をfalseにする

processDataは、data:に指定したオブジェクトをGETメソッドのクエリ文字への変換有無を設定する項目で、ファイルを送信する場合にはPOSTメソッドのまま送信する必要があるため、必ずfalseを設定します。

contentType:はデータ送信時のcontent-typeヘッダの値になりますが、FormDataオブジェクトの場合は適切なcontentTypeが設定されるので、同じくfalseを設定します。

クロスサイト・リクエストフォージェリ(CSRF)

クロスサイト・リクエストフォージェリ(CSRF)

・概要  サービスの利用者に意図しないHTTPリクエストを送信させ、利用者の意図しない処理をサービスに実行させる攻撃 →「利用者の意図したリクエストである」という確認が抜けていると、罠のサイト等を閲覧しただけで、利用者のブラウザから何らかの処理を実行させられる場合がある

〜例〜
・利用者のアカウントによる物品の購入 ・利用者の退会処理 ・利用者のアカウントによるSNSや問い合わせフォームなどへの書き込み ・利用者のパスワードやメールアドレスの変更

CSRF脆弱性

・上記のような「重要な処理」の悪用に限られる ・被害者である利用者の個人情報などを盗むことは基本的にはできない (パスワードを勝手に変更させられる場合は、パスワードを用いて個人情報をなどを盗み出せる場合がある)

CSRF攻撃の例 1. Aさんがexample.jpにログインしている(ログインのセッション情報が残っている) 2. 攻撃者が罠のサイトを用意する 3. Aさんが罠のサイトを閲覧する 4. 罠のJavaScriptにより、Aさんのブラウザ上でexample.jpに対し、新しいパスワードが送信される 5. 勝手にパスワードが変更される → パスワードを勝手に変更されると、攻撃者は変更後のパスワードを知っているため、それを利用して被害者の情報を盗むことができる

CSRFはログイン済みのユーザに、意図しない操作を強制的に実行させてしまう攻撃であるといえる

入力フォームに確認画面がある場合のCSRF攻撃

  • hiddenパラメータで受け渡ししている場合
  • 入力画面 → POSTで送る
  • 確認画面 → hiddenパラメータで送る
  • 実行画面

この場合は確認画面がない場合と同じで、実行画面がHTTPリクエストとして値を受け取っているため、上記のように攻撃される

  • セッション変数でパラメータを受け渡している場合
  • 入力画面 → POSTで送る
  • 確認画面 → 値をセッション変数に保存
  • 実行画面 → セッション変数から値を取り出す

この場合は2段階の攻撃が必要になる
1. 確認画面に対して値をPOSTしてセッション変数に値をセットする 2. その後実行画面を呼び出す

脆弱性が生まれる原因

  1. form要素のaction属性にはどのドメインのURLでも指定できる → 罠サイトからでも攻撃対象サイトにリクエストを送信できる
  2. クッキーに保管されたセッションIDは、対象サイトに自動的に送信される → 罠経由のリクエストに対しても、セッションIDのクッキー値が送信されるので、認証された状態で攻撃リクエストが送信される

対策

CSRF対策の必要なページを区別する → ECサイトにおける物品購入や、パスワード変更、個人情報編集等の確定画面等

・正規利用者の意図したリクエストを確認できるようにする → 具体的な方法として、以下の3種類が知られている

  1. パスワードの再入力
  2. +重要な処理の確定前に、ユーザがパスワードを入力することで、意図したリクエストであることを確認できる
  3. -ユーザの操作が増える

  4. Refereのチェック

  5.  Refereとは、リクエスト元のページのURLを示すHTTPヘッダである
  6.  +Refereをチェックすることで、正規のページからのリクエストか確認できる
  7.  -ファイアウォールやブラウザの設定でRefereを抑止している利用者もいる

  8. トークンの埋め込み

  9. リクエストが正しいものか判断するための文字列をリクエストの中に仕込む
  10. +第三者に予測不能トークンを要求することで、CSRF攻撃を防ぐ
  11. +Refereとは違いヘッダではなくパラメータなので、ユーザ依存で失敗することがない

・保険的対策として、重要な処理の実行後に、対象利用者の登録済みメールアドレスに、処理内容の通知メールを送信することも効果的である → 攻撃自体を防ぐことは出来ないが、もし攻撃を受けた際に利用者がすぐに気づくことで、被害を最小限に抑えることができる