第7週


オブジェクト指向 / セキュリティ対策

先週の宿題

setcookie関数の第7引数について

第7引数に関してをTRUEにすることによって、HTTPCookeiが有効になり、
HTTP経由でのみアクセス可能となる。
よって、JavaScript?経由ではアクセスできない。
※ただし、すべてのブラウザがこの設定をサポートしているというわけではありません。

PHP:Manual setcookie

例. サンプル1

pdo 接続 / 接続の管理

PHP Manual - 接続、および接続の管理

bindValueとbindParamの使い分け

bindValueはコマンドが発行される都度SQL文に値がセットされるのに対して、
bindParamは参照で値が渡され、execute実行時に初めて値に変換される。

例. サンプル2


beginTransaction()を2回発行すると…?

結論:エラーが出ます。

例. サンプル3

サーバーが2台あるときのSESSIONについて

  • SESSIONのレプリケーション機能(セッション専用のWEBサーバでの共有)
  • SESSIONに対応したロードバランサを利用
     →SESSION機能を維持するロードバランサーであれば、
      同じ利用者からのリクエストを同じサーバーに飛ばせば矛盾は起きない
  • PeXの場合は、memchachedとDBの両方を使用

PeXではPeXのページにアクセスすることに

lib/filter/sfRememberFilter.class.php

というファイルにアクセスする。
そこで「memchached」にそのユーザーのセッションIDがあるか検索。
存在するならばそれを使うし、存在しない場合は

UserRememberKey

というDBにアクセスしてセッションIDを探す。

クラス

クラスの定義

class クラス名 {
    …
}

プロパティ

クラスの中で定義された変数のこと。
メンバ変数と呼ばれることもある。
ただ、classブロックの中で定義すればいいわけではなく、
そのクラスというカテゴリに関連する情報を表すための変数でなければならない。

また、プロパティを変数として定義する場合、アクセス修飾子を頭に付けなければならない。

アクセス修飾子概要
publicどこからでもアクセス可能
protected現在のクラスとサブクラスでのみアクセス可能
private現在のクラスでのみアクセス可能

ただし、プロパティに与えられる初期値はリテラルのみで、
式や関数の結果を設定することはできない。


メッソド

クラスで管理する値を処理するための関数で、メンバ関数と呼ぶこともある。
こちらも頭にアクセス修飾子を設定しなければならない

コンストラクタ

インスタンスのタイミングで実行される特別なメソッド。
インスタンスのタイミングで実行されるという性質上、
プロパティの初期値やクラスの内部で利用する外部リソースの初期化といった処理を書くのが一般的。
初期化処理が不要である場合には、省略することが可能。

なお、コンストラクタの名前は__constructに固定されている

※PHP4ではコンストラクタはクラス名と同名のメッソドとして表される。
 PHP5でも互換性を保つために、__constructメソッドが存在しない場合にはクラス名と同名のメソッドを検索して実行するので、
 注意が必要。

デストラクタ

オブジェクトが破棄されるタイミングで実行される。
クラスの中で使用したリソースを破棄するなど終了するときの処理を記述するのが一般的。
なお、デストラクタは引数も受け取らなければ、戻り値も返さない(※返してはならない)。
また、アクセス修飾子はかならずpublicにする

※PHPではリソースのほとんどが終了したタイミングで自動的に破棄されるので、
 あえてデストラクタを利用しなければならないケースはほとんどない

静的メソッド

インスタンスを生成しなくてもクラスから直接呼び出せるメッソド。
メソッド定義にstaticをつけるだけ。

また静的メソッドを呼び出すためには、「::」演算子を使用すればよい。

使い方としては、「クラス名::静的メソッド名」

クラス内定数

classブロック内で定義された定数。
constを使って定義して、「::」演算子を使って利用する。


カプセル化

クラス機能のうち、使い手に必要の無いものをブラックボックス化すること。

アクセサメソッド

private $hogehoge;

public function getHogehoge() {
    return $this->hogehoge;
}

public function setHogehoge($hogehoge) {
    $this->hogehoge = $hogehoge;
}

プロパティのアクセス修飾子をprivateに変更したことにより、外部から勝手にプロパティにアクセスできないようにする。(プロパティの隠蔽)
さらに、プロパティを読み書きするためのメソッド(アクセスメソッド)を用意して、プロパティの出入り口しを制限し、
プロパティをより安全に、簡単にコントロール(操作)する。

継承

基になるクラスの機能(メソッド)を引き継ぎながら、新たな機能を追加したり、
元の機能の一部だけを修正すること。

継承元となるクラスのことをスーパークラス(親クラス基底クラス)といい、
継承してできたクラスのことをサブクラス(子クラス派生クラス)という。

継承を行うにはクラス定義の際にextendsキーワードで親クラスを指定する

class サブクラス名 extends スーパークラス名 {
    …

継承した子クラスでは、親クラスのメソッドが定義なしに使える。

親クラスで定義されたメソッドを使用する場合には、「parent::メソッド名(引数)」の形を使用する。

※正確には、子クラスで呼び出されたメソッドが見つからない場合には、
 指定された親クラスのメソッドを検索する

PHPでは一つのクラスが同時に複数のクラスを親に持つこと(多重継承)を認めていない。

※上記の多重継承に関しては、C++などでは認めている

※継承は、子クラス is a 親クラスの関係が成り立つ場合、
 子クラスが親クラスを全て含んでいる場合に使用することがよい。

オーバーライド

親クラスで定義されたメソッドを、子クラスで上書きすること。
メソッドの再定義。

final修飾子

オーバーライドを明示的に禁止させる修飾子。
このい修飾子をつけたメソッドを子クラスでオーバーライドしようとすると、エラーが出る。

このような制限を付けるのは、子クラスを定義する人間が、必ずしも親クラスの構造を理解しているとは限らないから。
親クラスの構造を理解していない人間でも安全に仕様できるように設計しておくのがクラス設計のあるべき姿なので、
オーバーライドしたためにクラスの全体、または一部に不具合動が起きないようにするための修飾子。


ポリモーフィズム(多態性)

複数のクラスの同名のメソッドで異なる挙動を実現するための仕組み

抽象メソッド

中身を持たない空のメソッド
子クラスでオーバーライドされることを強制するメソッド。

この抽象メソッドを含んだクラスを抽象クラスという。

この抽象クラスを継承したクラスは、全ての抽象メソッドをオーバーライドしなければならない
オーバーライドしていない場合には、エラーになる。

また、抽象クラス、抽象メソッドを定義するにはabstract修飾子を使用する

abstrsct class クラス名 {
    …
    アクセス修飾子 abstract function メソッド名 (引数…);
}

インターフェイス

PHPでは多重継承が認められていないため、複数のクラスの機能を同時に継承することは出来ない。
そのため、ポリモーフィズムを実現したい全てのメソッドを一つの抽象クラスにまとめなければならないが、
その場合は必ずしもサブクラスが必要としない機能(メソッド)をオーバーライドしなければならないかもしれない。

そこで、多重継承を実現するために、インターフェイスを使う

interface インターフェイス名 {
    …抽象メソッド、定数の定義…
}

以下、インターフェイスの特徴

  • 定義できるのは、抽象メソッドと定数のみ
  • 配下のメソッドが抽象メソッドなのは明らかなので、abstractは指定してはいけない
  • アクセス修飾子もしてしない。
     piblicは指定してもかまわないが、通常省略する。
  • (規則ではないが)インターフェイスであることが分かりやすいように、クラス名に接頭辞/接尾辞を指定する

なお、インターフェイスを受け継ぐことは「実装する」といい、実装したクラスを実装クラスという。

class 実装クラス名 implements インターフェイス名, インターフェイス名, …{
    // クラス本体
}

instanceof演算子

変数名 instanceof 型名

型名には判定したいインターフェイス、あるいはクラス名を指定しする。
instancof演算子は変数が指定された次のいずれかの方の場合にtrueを返す。

  • 直接のインスタンス
  • 実装クラスのインスタンス
  • サブクラスのインスタンス

オブジェクトの操作

PHPは、変数は値渡しが基本だが、オブジェクトは参照渡しが基本。
オブジェクトを値渡ししたい場合には、clone命令を使う

例.

$val2 = clone $val1

オブジェクトの比較

演算子等しいとみなす条件
==同じクラスのインスタンスであること、同じプロパティと値をもつこと
===同じクラスのインスタンス

IteratorAggregate?

タイプヒディング

メソッドの引数に明示的に型を明示すること

例.

アクセス修飾子 function 関数名 (class名 オブジェクト名)

この場合、指定したclass以外のオブジェクトを入れてもエラーになる。
ただし、タイプヒディングが対応しているのはオブジェクト、または配列のみで、
例えば、intやdoubleのような型を指定することはできない。

例外処理(try〜catch)

あらかじめ補足したいエラーを想定しておき、そのエラーが発生したタイミングで行うべき処理。

一般的なアプリケーションはチェック項目が多岐にわたっており、
それらを全てif文でチェックしようとした場合、コードが読みにくくなる可能性がある。

しかし、try〜catchでエラー処理専用のブロックを作ることで以下の効果が期待できる

  • 逐一if文でチェックする必要がないので、コードが短くなる
  • try〜catchは例外処理専用の命令文なので、汎用的な命令文であるif文と違って本来の処理に埋もれにくい。
     したがってコードが読みやすくなる
  • メソッドの戻り値をエラー通知のために利用しなくて済む

throw

例外を自分で発生させるための命令。例外をスローするという。

throw 例外オブジェクト

Exceptionクラス

発生させたエラーを補足するためにExceptionクラスを使用する。
Exceptionクラスは全ての例外クラスの親クラスでもある。
つまり、全ての例外クラスは、このExceptionクラスを継承している。

new Exception($message, $code = 0, $prev)
    $message:エラーメッセージ
    $code:エラーコード
    $prev:原因となった例外(※PHP5.3〜)

例外クラスの拡張

例外クラスは拡張することが可能。
Exceptionクラスは全てのク例外クラスの親クラスなので、
Exceptionクラスを継承し、自作の例外クラスを定義して、適当ところで自作した例外を発生させると、より処理が分かりやすくなる。

例.

class NumberFormatException extends Exception { }
class ZeroDivisionException extends Exception { }

また、例外を補足するためにcatchブロックを続けて記述していくが、
その場合はExceptionクラスは一番最後にするのが鉄則。

エラー情報の例外への変換

PHPで例外処理が導入されたのはPHP5から。
それまではエラーを深刻度レベルで管理し通知するエラー報告を利用する。

正確にはエラーと例外は異なるもので、エラー報告によって通知されたエラーはそのままではtry〜catchブロックでは処理できない。

そこでset_error_hondler関数を利用する

mixed set_error_handler(callback $handler [, int $types = E_ALL | E_STRICT])

マジックメソッド

__construct, __destruct, __call, __callStatic, __get, __set, __isset, __unset などは、PHP クラスにおける特殊関数の名前で、
これらの関数に関連する特別な機能を使用する場合を除き、
クラス内にこれらの名前を有する関数を作成してはいけない。

__construct, __destruct

__construct
インスタンスのタイミングで実行される特別なメソッド。
__destruct
オブジェクトが破棄されるタイミングで実行される。

その他は省略。

__call, __callStatic

mixed __call(string $name, array $args)
アクセス不能メソッドが呼び出された場合の挙動を定義するためのメソッド。~

 それ自体はなんら実装を持たない名前だけ予約されたメソッドで、必要に応じて中身を実装する必要がある。

mixed __callStatic(string $name, array $args)
アクセス不能メソッドを静的コンテキストで実行したときに起動する。

PHP Manual -オーバーロード

__get, __set

mixed __set(mixed $name)
アクセス不能プロパティへデータを書き込む際に実行される
void __get(string $name, mixed $value)
アクセス不能プロパティからデータを読み込む際に使用される

__isset, __unset

bool __isset(string $name)
isset() or empty()をアクセス不能プロパティに対して実行したときに起動する
void __unset(string $name)
unset()をアクセス不能プロパティに対して実行したときに起動する

__toString

オブジェクトが文字列に変換された場合に、戻り値としてオブジェクトの文字列を返すメソッド

__invoke (PHP5.3〜)

オブジェクトが関数の形式で呼び出された場合にコールされる

_clone

クラスの自動ローディング

__autoload関数

名前空間(PHP5.3〜)

組み込み関数や、自作関数、クラスをたくさん定義していった場合、
どこかで名前の衝突が起こる可能性がある。

そこで名前空間を利用する。
名前空間が別ならば、同じ名前の関数が定義されても衝突することはない。

namespace 名前空間名

以下、名前空間を使用する際に気をつけること

  • 名前空間はファイルの先頭で定義する
  • フォルダ構造は名前空間の構造に準ずること

例.

wings\selfphp\chap10 名前空間に属するMyClass ⇒ /wings/selfphp/chap10 のフォルダに配置
  • ひとつのファイルには、ひとつの名前空間
     ※これは必須ではない。
      実際中カッコで区切れば、いくつも名前空間を定義できるが、コードが読みづらくなる。

名前空間のインポート

名前空間が導入されても、
結局呼び出すときに長い名前空間名を書かなければならないのであれば意味がない。

そこで、use命令を使って名前空間にエイリアスをつけることができる

use 名前空間 / クラス名 as 別名

また、「as 別名」を省略することも可能で、その場合は一番下の階層がエイリアスと認識される。

セキュリティ対策

XSS(クロスサイトスクリプティング)

  • 内容:エンドユーザからの入力値に悪意ある値が入っていて、
        開発者が予期していなかった挙動を起こしてしまう虚弱性
  • 対策:動的に生成される全ての値に対してエスケープ処理を施す

SQLインジェクション

  • 内容:SQLに不正なパラメータに引き渡すことで、
        開発者が意図していなかったSQL命令が生成・実行されてしまう虚弱性
  • 対策:SQLエスケープ
        シングルクオート(')をダブルクオート(")にする・プレイスホルダの使用

OSコマンドインジェクション

PHPではスクリプトからOSコマンドを実行できる。
そのため、悪意ある値を入力されると予期せぬ挙動を取ることがある。

例.

sendmailコマンドを利用してメール送信をする処理の場合

本来なら、メールアドレスのみを入力する欄に、以下のように入力すると…

  メアドhogehoge; rm -rf /

ちゃんとした処理を施しておかないとまずい!

対策としては、以下のような方法が考えられる

  • そもそも、OSコマンド(外部プログラム)を呼ばない
  • サニタイズ
     汚染された入力データを綺麗にする。
     この脆弱性で危険性の高い文字は、; , [ ,] ,| ,< ,> ,\などで、
     これらの文字が含まれていたらエラーにしてしまう。
  • Webサーバの実行ユーザーの権限の設定
  • 入力値チェック

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

  • 内容:Webサイトにスクリプトや自動転送を仕込むことによって、
        エンドユーザに意図せず別のWebサイト上で何らかの操作を行なわせる手法。
        これによってユーザの個人情報が漏れる危険性がある。
  • 対策:CSRFを防ぐには、サイト外からリクエストの受信を拒否する必要がある。
        ヘッダに含まれる情報を元に参照元が正規のページかどうかをチェックしたり、
        フォームの一部にランダムな数値を隠しておいてアクセスの一貫性をチェック(ワンタイムトークン)したり、
        CPが読み取れないよう画像として表示したチェックコードの入力をユーザに要求するなどの手法があり、
        これらを組み合わせて対策を講じる。

ディレクトリパストラバーサル

  • 内容:アプリケーション経由でファイルシステム上のファイルを操作するという処理において、
        そのファイル名指定の処理に不備があった場合、本来公開することを意図していないディレクトリのファイルに対して、
        不正にアクセスできる危険性がある
  • 対策:「../」や「/」などのパス名として識別される文字列のチェックを適切に行っていないことが原因になるので、
        ファイル名を指定する際の入力値を必ずチェックする。

セッションハイジェック

  • 内容:成り済ましの一種でクライアントとサーバの正規セッションに割り込んで、
        セッションを奪い取る行為。
        これらの攻撃は3つの手法に分けられる。
        1. 2つのホスト間の通信を横取りする攻撃手法     2. 2つのホスト間の通信にコマンドなどを挿入するブラインドハイジャックと呼ばれる手法
        3. 新しいセッションを作成するか以前のセッションを盗用する方法
  • 対策:上記の攻撃方法はそれぞれ以下のような対策方法がある
        1.OSおよびアプリケーションに最新のパッチを適用
        2.SSLなどでパケットの暗号化を行う。
        3.WebサーバのURL Rewriting機能を無効にする
          →URL Rewriting機能:
           Cookieが使用できない場合、URLのパラメータとして
           GETメソッドでセッションIDを引き渡す機能

ファイルアップロード攻撃

  • 内容:不正なファイルをアップロードすることによって、
        任意のスクリプトを実行可能にする攻撃方法
  • 対策:ファイルのアップロード先を、公開フォルダの外に設定する

eavl攻撃

mixed eval (string $code_str)
$code_str で与えられた文字列をPHPコードとして評価する

PHP Manual -eval

  • 内容:eval関数は与えられた文字列をPHPコードとして処理するので、
        悪意ある引数が渡されたときは危険
  • 対策:そもそもeval関数を使わない。
        どうしても入力する場合には、エンドユーザーから入力された値をeval関数の
        引数にしない

参考資料

  • 独習PHP 第2版