【PHP】フォルダにアクセス制限をかけたい

解決済

回答 4

投稿

  • 評価
  • クリップ 2
  • VIEW 3,356

nnahito

score 1816

 やりたいこと

イメージ説明

上図の青色の枠の中ように、
HTML,CSS,JavaScript,画像等で構成された一つのWebページが一つのフォルダに入っております。

この、青色の枠の中は、会員登録を行ったユーザかつ、その中でも認証を行ったユーザのみしか閲覧されたくありません。

このアクセス制限の方法を考えているのですが、一向に手段が思い浮かばず、お知恵を貸していただきたいと存じます。

 行ったこと

ルーティング
Laravelのmod_rewrite処理を書いた.htaccessを青色の枠のフォルダ内におき、
access.phpのようなPHPファイルを別途作成し、そこにアクセスを転送させ、
SESSIONなどで認証を行っているかをaccess.phpで確認ができたらリダイレクトを行う。

まあ、もちろん無限ループになりました。


action
以下のような処理を書いた.htaccessを青色の枠のフォルダ内におき、
access.phpのようなPHPファイルを別途作成し、そこにアクセスを転送させ、
SESSIONなどで認証を行っているかをaccess.phpで確認ができたらリダイレクトを行う。
Action text/html /青枠のフォルダまでのパス/access.php

無限ループになりました。


後は、旧式の考えではありますが、フォルダにBASIC認証をかけようと思ったのですが、
ユーザには一度ログインを行ってもらっているので、再度BASIC認証で情報を入力してもらうのは良くなく、
そもそも、動的にユーザ情報を出力するのは難しそうなので躊躇しています。

PHP側で、BASIC認証用のヘッダを作成し、水色の枠の「メンバーページ」にログインしていたらBASIC認証を素通りでき、していなければこちらが用意した独自のログイン画面に遷移させ、
BASIC認証とは異なるログインをおこない、それがOKであればBASIC認証を行ったとすることは可能でしょうか?


ご存知の方がいらっしゃいましたら、やり方、ご意見等のお知恵を貸していただけますと幸いです。
よろしくお願いいたします。

 環境

PHP:7.2.3
Apache:2.4.6 (CentOS)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • nnahito

    2018/04/15 13:28

    どうしても知りたいです

    キャンセル

  • nnahito

    2018/04/16 11:16

    そろそろ、luckerさんのご回答を見てみたいです

    キャンセル

回答 4

+2

Laravel使ってるのになんでこんな無駄なことを…。
Laravel使うなら素のPHPでのやり方の発想はほとんど捨てる。
隠したいファイルをpublicに置いてるのが間違い。
html置いてるのも意味が分からないけどそういえばここではそんな質問も多かった…。
根本的な発想がずれてるとどうにもならない。

ガチガチに制限したいなら全ファイルLaravelを通して表示させる。
/member/{file}のルーティングに対して
コントローラーからはファイルを返す。

return response()->file('secret/' . $file);


member/style.cssならsecret/style.css
secret/style.cssを直接表示はできずLaravelの認証を通ってないと不可なようにする。

現実的にはそこまでやる必要もなくページに対して制限すれば十分。
それならLaravelの普通の認証機能の範囲。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/15 18:15

    > te2jiさん
    >> 要件としては、「青色の枠」のファイル群(相対パスで各種リンクが記述された1サイト分のデータ)をリンクの変更なしに認証を通したセキュアなアクセスを提供したいってことですかね?

    そうですね、そのとおりのことを行いたいです。

    キャンセル

  • 2018/04/15 18:32

    > mpywさん
    >> 特にLaravel入れちゃう場合はブーティング処理が重たいのでスケーラビリティ最悪だと思います。

    なるほど、この点を考慮するとsuzukisさんのようなチェック方式のほうが確実ですが、Cookieを使ったほうがいい感じなんですね!

    キャンセル

  • 2018/04/17 00:57

    すいません、kawaxさんのやり方ですと、例えば青枠のデータ一式をviewsフォルダなどに入れて、外部からアクセスできないようにするのはわかりますが、

    > ガチガチに制限したいなら全ファイルLaravelを通して表示させる。
    > /member/{file}のルーティングに対して
    > コントローラーからはファイルを返す。

    この方法はどのように実現するのでしょうか?
    例えば、青枠フォルダの中のindex.htmlで呼ばれているCssやJSはどのようにアクセスが起こり、
    その際にはどのようにそのファイルが指定されているかを見極めるのでしょうか?

    キャンセル

+2

単純で汎用的な方法は、認証処理を含んだプログラム経由でコンテンツをサーブすることです。PHPならこんな感じで。

<?php
    $path = $_GET["path"];

    // $pathが不正なものでないかチェック

    // 認証および認可の処理

    header('Content-Type: ' + 適切な MIME type);
    readfile($path);
?>

http://example.jp/example.php?path=contents.html でアクセスします。

任意のパスが指定可能にならないよう、パラメータは必ずチェックしてください。


Webサーバが「認証済みかどうか」という「アプリケーション側の情報」を利用して動作を変えるのは基本難しいです。

アプリケーション側の「認証済み」という情報をアプリケーションを介さずに安全にWebサーバに伝えるのはとても困難です。単純に思いつくような方法(CookieにIDとか秘密の文字列のような何かの情報を載せるとか)は単純に突破可能なのでそんなことやるぐらいなら無条件で公開しても変わりません。

HTTP認証であればそれはWebサーバ側の情報になるので、それによって動作を変えることはある程度できます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/15 16:37

    ご回答有り難うございます。

    この手法だと、htmlタグ内で呼び出しているCSSやJSは読み出せないような気がします。。。

    キャンセル

  • 2018/04/15 17:28

    <link rel="stylesheet" href="example.php?path=hoge.css">などとすればいいです。

    キャンセル

  • 2018/04/15 17:31

    ご返信有難うございます。

    やはりそうなりますよね……
    他コメントでも記載しましたが、
    今回、何故ワザワザデータを一つのフォルダとして、publicフォルダに配置したかと言うと、
    そのHTML,CSS,JSは、ディラのスクリプト( https://tyrano.jp/ )というゲームエンジンで吐き出されたものだからです。
    なので、エンジン内で作られたHTMLをすべて修正するのは困難であると判断し、このような手法を取っております。

    キャンセル

  • 2018/04/15 17:46

    /public/hoge.css→/example.php?path=hoge.cssというようなrewriteをHTTPサーバ側に仕込めばよいでしょう

    キャンセル

checkベストアンサー

+1

Basic 認証の情報が漏洩するぐらいなら

Apache のみで Cookie によるアクセス制御をかける

<VirtualHost *:80>
    ServerName www.sourcewalker.com
    DocumentRoot "/var/www/localhost/htdocs"
    SetEnvIf Cookie password=\x22?pass\x22? site_password
    <Location />
        Order deny,allow
        deny from all
        Allow from env=site_password
    </Location>
    <Files "/var/www/localhost/htdocs/auth.html">
        Order allow,deny
        Allow from all
    </Files>
</VirtualHost>

のようにすればいいと思います。

SetEnvIf にある Cookie password=\x22?pass\x22? は任意に変更してください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/15 15:14

    asahina先生、何いってんのかわかりません。ユーザーごとにみられるファイルが違う場合、どうなるんですかっ?

    キャンセル

  • 2018/04/15 15:50

    lucker あなたのお望みはこんなのですか?

    ※ mod_rewrite でうまく偽装する部分は省いてあります。

    キャンセル

  • 2018/04/15 15:50 編集

    <DirectoryMatch "/var/www/html/test/(.*)/css/(.*)">
    RewriteEngine ON
    RewriteCond %{HTTP_COOKIE} !UUID=%1
    RewriteRule - - [F]
    </DirectoryMatch>

    こっちになると SetEnvIf の手じゃないが

    キャンセル

0

静的な画像ファイル等へのリンクを出力する際

<img src="https://user:password@example.com/secret.jpg" alt="">

のようにすれば認証素通りできると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/15 14:09

    これ、getで送るのか… https://user:password@example.com/secret.jpg

    キャンセル

  • 2018/04/15 14:10

    ご返信ありがとうございます!


    > あるいはLaravelを使っているのであればミドルウェアを挟むのもあり

    こちらなのですが、今後、青枠のフォルダーが増えていくので、ページのHTMLもpublicフォルダに入れており、
    bladeでobjectタグを使って呼び出しています。

    この場合でも、ミドルウェアは利用できるのでしょうか?

    キャンセル

  • 2018/04/15 17:09 編集

    レンダリングされたHTMLを書き換えるだけなのでどんな場合でもできますよ(ただ手法としてはあんまりきれいじゃない)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる