turutani.com

Webサイトを公開する前に最低限やっておきたいセキュリティ対策まとめ

更新日:2019.06.01

アイキャッチ画像

 ホームページや個人ブログなど,Webサイト運営をしている人に向けて,SQLインジェクションやクロスサイトスクリプティング等の攻撃を受けないための最低限のセキュリティ対策まとめ

出力テキストに対するスクリプトの実行・クロスサイトスクリプティング(XSS)

 Webページ内にユーザ入力に応じて出力が変化する箇所がある場合,意図していないHTMLタグやスクリプトが実行されてしまったり,クロスサイトスクリプティング(XSS)の脆弱性になりうる可能性があります.


 クロスサイトスクリプティングとは,簡単に説明するとユーザが入力できる箇所に不正なスクリプトを挿入しそれを実行させることによる攻撃手法です.

 HTMLタグや,スクリプトが実行されてしまう仕組みとして,以下のようなプログラムを例に考えます.

<?php
    $a=$_GET['a'];
    echo $a;
?>

 このような$aの値を出力するプログラムにおいて,$aの値がユーザから入力されたものを保持している場合,

$a="<hr><hr><hr>"

となるように指定されると,echoにより表示されるのは<hr><hr><hr>ではなく,HTMLにおける<hr>タグ(水平線を表示するタグ)が実行され,





が表示されてしまいます.


これは,<hr>を文字列としてでなく,HTMLタグとして処理してしまうために起こります.


 また,$aの値が,

$a="<script>alert('scriptの実行');</script>"

となるよう指定されてしまうと,echoによってそのままスクリプトが実行され画面上にアラートが表示されてしまいます.


 このHTMLタグやスクリプトが実行されてしまう脆弱性をそのままにしていると,画面を書き換えられたり,クロスサイトスクリプティングに使われてしまう危険性があります.



解決法



 この問題のメジャーな解決方法としては,ユーザからの入力を表示する際にはhtmlspecialchars関数を利用するというものがあります.

 htmlspecialchars関数を使うことで,もしHTMLタグやスクリプトが入力された場合でもそれを文字列として処理することができます.


 さきほどのプログラムにhtmlspecialchars関数を組み込むと次のようになります.

<?php
    $a=$_GET['a'];
    echo htmlspecialchars($a, ENT_QUOTES, 'UTF-8');
?>

 htmlspecialcharsは第一引数の値をエスケープさせ,文字列として表示させることができるようになります.

 そのため,先ほどのような,

$a="<hr><hr><hr>"

$a="<script>alert('scriptの実行');</script>"

などが$aの値として指定された場合でも,出力はそれぞれ,

<hr><hr><hr>

<script>alert('scriptの実行');</script>

となり,HTMLタグやスクリプトがそのまま文字列として出力されます.


SQLインジェクション対策

 WebページにおいてSQL文を実行する際は,SQLインジェクションの脆弱性を考える必要があります.

 SQLインジェクションとは,SQLでデータベースを操作する箇所において,外部入力を元にSQL文を生成する場合,そこに不正なSQLを挿入することによってデータベースの情報を漏洩,改ざんさせるという攻撃手法です.


 SQLインジェクションの仕組みの説明として,以下のようなプログラムでSQLを実行する場合を考えます.

<?php
    $a=$_GET['a'];
    $stmt=$db->query("SELECT * FROM user_info WHERE user_name='$a'");
?>

 ここでは,テーブル名user_infoのデータベースに対し$aの値と一致するuser_nameを探すというSQLを実行しています.

 このような設計では,$aの値がユーザ入力によって決められる場合,不正なSQLが実行されてしまう可能性があります.


 例えば,$aの値に,

';DELETE FROM user_info;

が指定されてしまうと,SQL生成の際,

SELECT * FROM user_info WHERE user_name='';DELETE FROM user_info;'

という文が構築されてしまいます.

 これはSELECT文を';で終了させ,その後にDELETE文が挿入されており,結果的にSELECT文,DELETE文の両方が実行されるので,user_infoのテーブル情報は全て削除されてしまいます.


 この脆弱性を利用すればデータベースの情報を盗み出したり,改ざんを行うことができてしまいます.



解決法



 この脆弱性の対策として,静的プレースホルダを利用してSQLを組み立てるというものがあります.

 静的プレースホルダでSQL文中の変数の値を指定することで,悪意のあるSQLの実行を防ぐことができます.


 静的プレースホルダを利用するにはまず,データベースとPDO接続した際にsetAttributePDO::ATTR_EMULATE_PREPARESfalseにします.(trueにすると動的プレースホルダ)

<?php
    $db = new PDO('mysql:host=○○○○;dbname=○○○;charset=utf8mb4','', '');
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
?>


 SQL文中に値を指定する方法は2種類あり,1つは疑問符プレースホルダを用いて実行する方法です.

$a=$_GET['a'];
$stmt=$db->prepare('SELECT * FROM user_info WHERE user_name=?');
$stmt->bindvalue(1,$a);
$stmt->execute();

 これはSQL文中において,外部入力による値となる部分にを置き,その後bindValue関数を使って変数$aをバインドしています.


 もう1つは名前付けされたプレースホルダを用いて実行する方法です.

$a=$_GET['a'];
$stmt=$db->prepare('SELECT * FROM user_info WHERE user_name=:names');
$stmt->bindvalue(':names',$a);
$stmt->execute();

 これは,外部入力による値となる部分に任意で名前を付けておき(:names),その後bindValue関数で付けた名前に対して変数をバインドしています.


 これら静的プレースホルダを使ってSQLを実行することでSQLインジェクションを防ぐことができます.


エラーメッセージを表示しない

 PHPを使用しているページで,エラーメッセージの表示をOnにしていると,表示されたエラーメッセージの内容から,ディレクトリ構成やデータベースの構造などの情報を盗み出されてしまう可能性があります.

 そのため開発が終わって,サーバーにphpファイルをアップロードした際はphp.iniのdisplay_errorsをオフにしたほうが良いです.

php.ini
display_errors = Off

 こうすることによって,エラー内容がブラウザ上に表示されなくなります.


公開ディレクトリに重要なファイルを置かない

 パスワードを記録してあるファイルなど,重要なファイルを公開フォルダにアップしていると,そのファイルに誰でもアクセスできるため,閲覧されてしまう危険性があります.


解決法



 もし,レンタルサーバーを使ってる場合で,非公開ディレクトリが利用できる場合はそれを利用することでそのファイルを非公開にすることができます.

 レンタルサーバーに非公開ディレクトリがない場合は.htaccessを使って特定のファイルへのアクセスを拒否することができます.


 例えばpassword.txtというファイルを非公開にしたい場合.htaccessファイルに

.htaccess
<Files "password.txt">
  deny from all
</Files>

を加えることでpassword.txtを閲覧させないようにすることができます.


プロフィール

プロフィール画像(かぼちゃの絵)

こんにちわ.弦谷(つるたに)です.

Webサイト運用に関する記事をメインであげていきます.

福岡県在住

コメントフォーム


ページTOPへ