- 投稿日:2020-07-28T22:19:12+09:00
PHPデバッグが捗るTips
この記事について
PHPのデバッグで「var_dump($test);exit;」しかしない人のために
手動デバッグで役に立ったことをまとめてみました。デバッグおすすめリスト
やりたいこと デバッグ方法 役立つ度 配列をコピペで変数代入できる状態で出力する 「var_dump()」ではなく「var_export()」を使用する ★★☆ var_dumpの「string(5)」みたいな出力をなくす 「print_r()」で出力する ★☆☆ 関数の呼び出し元の関数を特定する echo debug_backtrace()[1]['function'];
★★★ 呼び出し元のクラス名を特定する echo debug_backtrace()[1]['class'];
★★★ ログを指定したファイルに出力する error_logの第2引数に「3」
第3引数に出力させたいログパスを記載する
error_log($message, 3, '/var/log/php/test_log');★★★ var_dumpした値の文字化けを解消 chromeのテキストエンコーディングを入れる
https://chrome.google.com/webstore/detail/set-character-encoding/bpojelgakakmcfmjfilgdlmhefphglae?hl=ja
もしくはheader('Content-Type: text/html; charset=UTF-8');<br>var_dump(配列);
★☆☆ var_dump()を見やすく出力する echo '<pre>';var_dump($array);
★★★ MySQLのエラーを表示する echo mysql_error();
★☆☆ 「echo 111;exit;」を簡潔に書く(Laravel/CakePHPの場合) dd(111); ★★☆
- 投稿日:2020-07-28T19:05:58+09:00
React + Laravel 開発時のVS Code拡張まとめ
どちらにでも使える拡張
Bracket Pair Colorizer
メソッドや関数内で、ペアとなる括弧を色付けしてくれる拡張。どの関数内でどの処理が実行されるのか一目瞭然なので重宝しています。
Code Spell Checker
英語の表記誤りを指摘してくれる。キャメルケースやスネークケースにも対応。
ただ、サードパーティのメソッドもチェックしてくれてしまうので、うっかり直さないように注意。Regex Previewer
正規表現のプレビュー用拡張です。JSでもphpでも正規表現はよく使うので重宝しています。
Todo Tree
コメントで
//TODOとしたものを一覧で表示してくれます。プロジェクトのコード全体のTODOを見渡したい時にとても便利です。
JS/Reactに関する拡張
Auto Rename Tag
自動で対応する閉じタグを作ってくれ、その上、タグを変更した時に閉じタグの名前も変更してくれる拡張機能。
Auto Close Tagという同じ人が作った拡張もあるが、こちらの方が上位互換という印象。ESLint
コードを自動整形してくれる。プロジェクト内でのReactのコードを統一するために使っています。
JS Refactor
JSをリファクタリングする時に使用できる。変数名などを一括して変えたい時にとても便利。
TypeScript Import
TypeScript
のimport
を自動で保管してくれます。Reactを書いている時もとても良い感じに補完してくれるので便利です。PHPやLaravelで使える拡張
DotEnv
.envのシンタックスハイライトをしてくれる。
PHP Class Generator
Laravelの
artisan
コマンドで賄えないようなクラスを作る時に非常に重宝しています。ディレクトリを見てnamespace
まで自動で付与してくれる機能がとても強力です。php cs fixer
こちらはPHPソースの自動整形に使う拡張です。Laravelは
PSR2
に対応しているので、開発時も同様の規約でソースを書くことができます。PHP DocBlocker
作成したメソッドに合わせて
PHPDoc
を自動で生成してくれます。心地よいコード補完のために、PHPDoc
もストレスなく書きたいですね。PHP Intelephense
PHPのコード補完用の拡張です。非常に強力で個人的には、
PHP Intelesense
よりも補完機能が良かったと感じています。その他、Laravelに関する機能
こちらに集約しています。
最後に
VS Code
の拡張は種類も多く、どれを使ったら良いのか?と思うことが多かったのでまとめてみました。
社内のプロジェクトチーム内で話しても、いろいろな発見があったので試してみると良いと思います。
- 投稿日:2020-07-28T18:41:37+09:00
Laravelの認証(JWT)
前提条件
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っていますLaravelでデータベースを扱う準備をする
Laravelでテーブル作成
Laravelで初期データ投入
Laravelでデータベースを操作する(Eloquent編)
本記事は上記ので作成したデータベースとレコード、PHPファイルを使用します認証に必要なソース生成
コマンドラインで
cd sample
composer require tymon/jwt-auth
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押しますコマンドラインで
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"eclipseプロジェクトを右クリック→リフレッシュ
/sample/config/jwt.phpが現れますコマンドラインで
php artisan jwt:secret
eclipseプロジェクトを右クリック→リフレッシュ
/sample/.envにJWT_SECRETが記載されますModel修正
/sample/app/Models/User.php修正
(1) use文追記
use Tymon\JWTAuth\Contracts\JWTSubject;
追記
(2) implementsにJWTSubject追加
class User extends Authenticatable implements MustVerifyEmail , JWTSubject
(3) メソッド追加
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
auth.php修正
/sample/config/auth.php修正
guards->apiを修正auth.php‥‥ 'guards' => [ ‥‥ 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], ], ‥‥Controller
(1) AuthController作成
コマンドラインで
cd sample
php artisan make:controller AuthController
xdebugの設定をしているとeclipseが実行していいですかというプロンプトを出すのでOKを押します
eclipseプロジェクトを右クリック→リフレッシュ
/sample/app/Http/Controllers/AuthController.phpが現れます
/sample/app/Http/Controllers/AuthController.phpを下記に修正しますAuthController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class AuthController extends Controller { public function __construct() { $this->middleware('auth:api', ['except' => ['login']]); } public function login() { $credentials = request(['email', 'password']); if (! $token = auth('api')->attempt($credentials)) { return response()->json(['error' => 'メールアドレス、またはパスワードが間違っています'], 401); } return $this->respondWithToken($token); } public function me() { return response()->json(auth('api')->user()); } public function logout() { auth('api')->logout(); return response()->json(['message' => 'Successfully logged out']); } public function refresh() { return $this->respondWithToken(auth('api')->refresh()); } protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60 ]); } }jwt-authの公式ドキュメントとほとんど同じですが、違っている箇所があります。
auth()関数に引数'api'を渡しています
jwt-authの公式ドキュメントではauth.phpのdefaultsのguardをapiにしているので、auth()に引数を渡さなくてもjwtのguardが取れますが、今回はdefaultsのguardはwebのままにしますので、auth()関数に引数'api'を渡すようにします
また、コンストラクタでmiddlewareを指定しています。middlewareは/sample/routes/web.phpや/sample/routes/api.phpの中でRoute::getやRoute::postの戻り値に対して指定することもできますが、コンストラクタで指定することもできます。この場合$this->middleware('auth:api', ['except' => ['login']]);
なので、loginメソッドを除いて、メソッドにリクエストが来るとguard->apiの認証が必要になります(2) SampleController.php修正
/sample/app/Http/Controllers/SampleController.php修正
api1メソッド、api2メソッド追加SampleController.phppublic function api1() { return view('sample.api'); } public function api2(Request $request) { $data = [ 'a' => 'a_value', 'b' => 'b_value', 'c' => $request->input('c') ]; return $data; }(3) /sample/routes/api.php修正
下記を追記api.phpRoute::post('auth/login', 'AuthController@login'); Route::post('auth/logout', 'AuthController@logout'); Route::post('auth/refresh', 'AuthController@refresh'); Route::post('auth/me', 'AuthController@me'); Route::post('sample/api2', 'SampleController@api2')->middleware('auth:api');/sample/routes/api.phpにルーティングを書いた場合、app/Providers/RouteServiceProvider.php#mapApiRoutesによって自動的に/apiがURLの先頭につきます
AuthControllerの各メソッドはAuthControllerのコンストラクタ内で認証の要、不要が設定されていますが、SampleControllerのapi2はここで認証が必要なようにmiddlewareを付けました(4) /sample/routes/web.php修正
下記を追記
Route::get('sample/api1', 'SampleController@api1');
要ログインURLへ未認証ユーザーがアクセスした場合のエラーメッセージ修正
/sample/app/Http/Middleware/Authenticate.php修正
unauthenticatedメソッド追加protected function unauthenticated($request, array $guards) { throw new AuthenticationException( 'ログインしてください', $guards, $this->redirectTo($request) ); }view作成
/sample/resources/views/sample/api.blade.php
api.blade.php<html> <head> <title>sample</title> <script type="text/javascript"> function login(){ var form = document.getElementById("sampleForm1"); var reqData = {"email": null, "password": null}; reqData.email = form.email.value; reqData.password = form.password.value; var req = new XMLHttpRequest(); req.open(form.method, form.action); req.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); req.responseType = 'json'; req.send(JSON.stringify(reqData)); req.onload = function () { var json = req.response; if (json['error']) { alert("error:" + json['error']); } else { localStorage.setItem('access_token', json['access_token']); alert('ログイン'); } } } function ajax(){ var form = document.getElementById("sampleForm2"); var reqData = {"c": null}; reqData.c = form.c.value; var req = new XMLHttpRequest(); req.open(form.method, form.action); req.setRequestHeader('Authorization', 'Bearer ' + localStorage.getItem('access_token')); req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); req.setRequestHeader('Accept', 'application/json'); req.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); req.responseType = 'json'; req.send(JSON.stringify(reqData)); req.onload = function () { var json = req.response; if (json['message']) { alert("message:" + json['message']); } else { alert("a:" + json['a'] + "\n" + "b:" + json['b']+ "\n" + "c:" + json['c']); } } } function logout(){ var form = document.getElementById("sampleForm3"); var req = new XMLHttpRequest(); req.open(form.method, form.action); req.setRequestHeader('Authorization', 'Bearer ' + localStorage.getItem('access_token')); req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); req.setRequestHeader('Accept', 'application/json'); req.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); req.responseType = 'json'; req.send(); req.onload = function () { var json = req.response; alert("message:" + json['message']); } } </script> </head> <body> <form id="sampleForm1" action="{{ url('api/auth/login') }}" method="post" onsubmit="login(); return false;" style="border: #000000 solid 1px; padding: 10px;"> <div>email:<input type="text" name="email" ></div> <div>password:<input type="password" name="password" ></div> <input type="submit" value="ログイン"> </form> <br> <br> <form id="sampleForm2" action="{{ url('api/sample/api2') }}" method="post" onsubmit="ajax(); return false;" style="border: #000000 solid 1px; padding: 10px;"> <input type="text" name="c" > <input type="submit" value="要認証リクエスト"> </form> <br> <br> <form id="sampleForm3" action="{{ url('api/auth/logout') }}" method="post" onsubmit="logout(); return false;" style="border: #000000 solid 1px; padding: 10px;"> <input type="submit" value="ログアウト"> </form> </body> </html>動作確認
http://localhost/laravelSample/sample/api1
・要認証リクエストの左にあるテキストフィールドに何か入力し、要認証リクエストボタンをクリックします
ログインしてくださいとalertがでました
・メールアドレスとパスワードを入力してログインボタンをクリックします
ログインできました
・要認証リクエストの左にあるテキストフィールドに何か入力し、要認証リクエストボタンをクリックします
SampleController.php#api2のレスポンスが表示されました
・ログアウトボタンをクリックします
ログアウトしました
- 投稿日:2020-07-28T18:33:19+09:00
PHPでアクセスされているURLを取得する方法
現在のURLを取得する方法です。
必要なのは【プロトコル】【ホスト】【パス】の3つで、それぞれを組み合わせてURLを表示させます。【プロトコル】 (HTTP or HTTPS)の判定
HTTPでのアクセスか、HTTPSでのアクセスなのかを判定。
echo $_SERVER['HTTPS'];実行結果
'on'HTTPSでのアクセスの場合は'on'
HTTPでのアクセスの場合はNULLとなります。アクセスされているページの【プロトコル】を取得
httpやhttpsなどのプロトコルを取得します。
HTTPSではなかったら、$_SERVERのHTTPSは空になりhttpを表示、そうではなかったらhttpsを表示。echo (empty($_SERVER['HTTPS']) ? 'http://' : 'https://')実行結果
'https://'アクセスされているページの【ホスト】を取得
ホスト名(ドメイン部分)を取得します。
echo $_SERVER['HTTP_HOST'];実行結果
'localhost'アクセスされているページの【パス】を取得
httpやhttpsなどのプロトコル名やサーバーのドメイン名(ホスト名)を除いた、ページURLを取得します。
echo $_SERVER['REQUEST_URI'];実行結果
'/index.php'実際に現在のURLを取得する!
上記で書いた【プロトコル】【ホスト】【パス】がの組み合わせが現在のURLになるため、下記のように書くことで、URLを取得することができます。
echo (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];実行結果
'http://localhost/index.php'まとめ
複数ページのSNSシェア設定部分のテンプレ化をしたくてURLの取得をしてみました。
- 投稿日:2020-07-28T17:04:09+09:00
PHPのセキュリティ関係
この記事は以下の書籍のアウトプットとして執筆しました。
Webアプリケーションの入力は何をするか
入力処理では入力値に対して以下の処理を行う
a. 文字エンコーディングの妥当性検証
→文字エンコーディングを使った攻撃対策ため
b. 文字エンコーディングの変換
→HTTPメッセージとプログラム内部でも自演コーディグが異なるため
c. 入力値の妥当性検証
→セキュリティ上の保険的な対策文字エンコーディングの検証
PHPではmb_check_encoding関数が使える
文字エンコーディングの変換
PHPはphp.iniでの設定で自動変換と明示的な返還を選べる。
入力値検証
バイナリセーフとヌルバイト攻撃
バイナリセーフ
入力値がどんなバイト列であっても正しく扱えることを意味する。
典型亭には値ゼロのバイト(ヌルバイト、PHP言語では\0と表記)が現れても正しく処理することを指す。ヌルバイトが特別扱いされるのはC言語及びUnixやウィンドウズのAPIでは、ヌルバイトを文字列の終端とみなす取り決めがある。
C言語で開発されたPHPは塗るバイトを文字列の終端としてそれ以降を切り詰める関数がある。
このような関数をバイナリセーフでない関数という。eregの検査を回避
この関数は PHP 5.3.0 で 非推奨 となり、 PHP 7.0.0 で 削除 されました。
<body> <?php $p = $_GET['p']; if (ereg('^[0-9]+$', $p) === FALSE) { die('整数値を入力してください'); } echo $p; ?> </body>このコードに対して以下のようにアクセスするとeregを回避される。
?p=1%00<script>alert('XSS')</script>
回避される理由
URLの中に
%00
がある。これは値ゼロのバイトすなわちヌルバイトでereg関数はバイナリセーフの関数ではないため、塗るバイトがあるとそこで文字列が終わっていると判断してしまう。ヌルバイト対策はバイナリセーフの関数のみを用いてアプリを開発すればいいが、それは困難
ファイル名のように仕様上ヌルバイトを許容しないパラメータがあるから。
このため、アプリの入り口で倍ナチセーフを使って入力値の塗るバイトをチェックして、塗るバイトがあればエラーにする方法がある
制御文字のチェック
制御文字とは改行やタブ等通常表示されない文字のことでヌルバイトも含まれる。
文字数のチェック
すべてのパラメータで最大文字数をチェックスべき。
これをチェックしておくとセキュリティ上で保険になる。
攻撃は文字列が長いことが多いため。PHPの正規表現
入力値検証には正規表現が便利。
関数 説明 perg 文字エンコーディングがUTF-8の場合のみ日本語が使える mb_ereg 様々な文字エンコーディングに使える 1文字以上5文字以下の英数字をチェックする正規表現
preg_match('/A[a-z0-9]{1,5}\z/ui',$p);
名前 説明 u修飾子 UTF-8エンコーディングであることを示す。 i修飾子 大文字小文字を区別しない u修飾子は不要の場合があるが。正規表現の「.」なドアが意図しない結果になるため、常にu修飾子を指定しておくほうがいい
全体一致は\Aと\zで示す
データの先頭は
\A
データの末尾は\z
で示す。
^
と$
は「行の」先頭と末尾を示すものだから$
は改行にマッチする。
このため^
と$
をデータの先頭・末尾として使うと不具合が生じる場合がある。参考文献
- 投稿日:2020-07-28T17:04:09+09:00
入力処理とセキュリティ
書籍のアウトプットとして
Webアプリケーションの入力は何をするか
入力処理では入力値に対して以下の処理を行う
a. 文字エンコーディングの妥当性検証
→文字エンコーディングを使った攻撃対策ため
b. 文字エンコーディングの変換
→HTTPメッセージとプログラム内部でも自演コーディグが異なるため
c. 入力値の妥当性検証
→セキュリティ上の保険的な対策文字エンコーディングの検証
PHPではmb_check_dncoding関数が使える
構文mb_check_encoding ([ mixed $var = NULL [, string $encoding = mb_internal_encoding() ]] ) : bool文字エンコーディングの変換
PHPはphp.iniでの設定で自動変換と明示的な返還を選べる。
入力値検証
バイナリセーフとヌルバイト攻撃
バイナリセーフ
入力値がどんなバイト列であっても正しく扱えることを意味する。
典型亭には値ゼロのバイト(ヌルバイト、PHP言語では\0と表記)が現れても正しく処理することを指す。ヌルバイトが特別扱いされるのはC言語及びUnixやウィンドウズのAPIでは、ヌルバイトを文字列の終端とみなす取り決めがある。
C言語で開発されたPHPは塗るバイトを文字列の終端としてそれ以降を切り詰める関数がある。
このような関数をバイナリセーフでない関数という。eregの検査を回避
この関数は PHP 5.3.0 で 非推奨 となり、 PHP 7.0.0 で 削除 されました。
<body> <?php $p = $_GET['p']; if (ereg('^[0-9]+$', $p) === FALSE) { die('整数値を入力してください'); } echo $p; ?> </body>このコードに対して以下のようにアクセスするとeregを回避される。
?p=1%00<script>alert('XSS')</script>
回避される理由
URLの中に
%00
がある。これは値ゼロのバイトすなわちヌルバイトでereg関数はバイナリセーフの関数ではないため、塗るバイトがあるとそこで文字列が終わっていると判断してしまう。ヌルバイト対策はバイナリセーフの関数のみを用いてアプリを開発すればいいが、それは困難
ファイル名のように仕様上ヌルバイトを許容しないパラメータがあるから。
このため、アプリの入り口で倍ナチセーフを使って入力値の塗るバイトをチェックして、塗るバイトがあればエラーにする方法がある
制御文字のチェック
制御文字とは改行やタブ等通常表示されない文字のことでヌルバイトも含まれる。
文字数のチェック
すべてのパラメータで最大文字数をチェックスべき。
これをチェックしておくとセキュリティ上で保険になる。
攻撃は文字列が長いことが多いため。PHPの正規表現
入力値検証には正規表現が便利。
関数 説明 perg 文字エンコーディングがUTF-8の場合のみ日本語が使える mb_ereg 様々な文字エンコーディングに使える 1文字以上5文字以下の英数字をチェックする正規表現
preg_match('/A[a-z0-9]{1,5}\z/ui',$p);
名前 説明 u修飾子 UTF-8エンコーディングであることを示す。 i修飾子 大文字小文字を区別しない u修飾子は不要の場合があるが。正規表現の「.」なドアが意図しない結果になるため、常にu修飾子を指定しておくほうがいい
全体一致は\Aと\zで示す
データの先頭は
\A
データの末尾は\z
で示す。
^
と$
は「行の」先頭と末尾を示すものだから$
は改行にマッチする。
このため^
と$
をデータの先頭・末尾として使うと不具合が生じる場合がある。
- 投稿日:2020-07-28T14:58:56+09:00
CORS
この記事は以下の書籍を参考にして執筆しました。
CORS
異なるオリジンとの通信を可能にする。
Access-Control-Allow-Origin
クロスオリジンからの読み出しを居するための仕掛け。
アクセスされる側がHTTPレスポンスヘッダとして出力する。シンプルなリクエスト
特定の条件を見たすシンプルなリクエストの場合、XMLHttpRequestで異なるオリジンにHTTPリクエストを送ることが許可になしに可能。
http://example.js
からhttp://example.com
へのXMLHttptRequestを許可する場合は
http://example.com
が以下のようにHTTPレスポンスヘッダを送信する。Access-Control-Allow-Origin:http://example.jsプリフライトリクエスト
シンプルナリクエストでないクロスサイトオリジンアクセスでは、ブラウザはプリフライトリクエストというHTTPリクエストを送信する。
このリクエストを受けたサーバは以下のヘッダに応答する必要がある。
揚州の種類 リクエスト レスポンス メソッドに対する許可 Access-Control-Request-Method Access-Control-Allow-Method ヘッダに対する許可 Access-Control-Request-Headers Access-Control-Allow-Headers オリジンに対する許可 Orijin Access-Control-Allow-Orijin プリフライトリクエストの受け取り
if ($_SERVER['REQUEST_METHOD'] === "OPTIONS") { //プリフライトリクエスト受取時の処理 }elseif ($_SERVER['REQUEST_METHOD'] === "POST") { //ポスト処理 }プリフラを受け取って、ヘッダに返答したら次は正常のPOSTが送信されるから条件付を記載する。
その際にheader('Access-Control-Allow-Origin: URL');
を忘れないように。認証情報を含むリクエスト
デフォルトではクロスサイトオリジンに対するリクエストにはHTTP認証やクッキーなどの認証に用いられるリクエストヘッダは自動的に動診されない。
XMLHttpRequestのプロパティにwithCredentialsをセットする必要がある。
withCredentialsをセットする
req.open('GET', URL); req.withCredentials = true;withCredentialsをtrueにすると
Access-Control-Allow-Credentials: true'
というレスポンスヘッダを返す必要がある。まとめ
クッキー等認証用ヘッダを用いるクロスオリジンリクエストは書きを満たす必要がある。
- withCredentialsをtrueにする
- レスポンスヘッダとしてAccess-Control-Allow-Credentials: trueを返す
参考文献
- 投稿日:2020-07-28T14:33:07+09:00
php用のgRPCソースを生成するDockerfile
gRPCのプラグインをbrew等で入れることができなかったので、Dockerコマンド化しました.
ディレクトリ構成
├── Dockerfile ├── protos/ │ └── sample.proto └── gen/
- protos: protoファイルを置いておくディレクトリ
- gen: 生成されたコードが配置されるディレクトリ
Dockerfile
FROM php:7.2.32-cli WORKDIR /tmp RUN apt-get update -y && apt-get install -y wget zip git automake zlib1g-dev libtool # install protoc command # releases: https://github.com/protocolbuffers/protobuf/releases ENV proto_version 3.12.3 RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v${proto_version}/protoc-${proto_version}-linux-x86_64.zip \ && unzip -d protoc protoc-${proto_version}-linux-x86_64.zip \ && mv protoc/bin/* /usr/local/bin/ \ && mv protoc/include/* /usr/local/include/ # install grpc php plugin # releases: https://github.com/grpc/grpc/releases ENV grpc_version v1.30.2 WORKDIR /var/local RUN git clone -b ${grpc_version} https://github.com/grpc/grpc --depth=1 WORKDIR /var/local/grpc RUN git submodule update --init \ && make grpc_php_plugin \ && cp -p ./bins/opt/grpc_php_plugin /usr/local/bin/ WORKDIR /var/local RUN mkdir protos \ && mkdir gen ENTRYPOINT ["protoc", "--proto_path=/var/local/protos", "--php_out=/var/local/gen", "--grpc_out=/var/local/gen", "--plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin"] CMD ["hello.proto"]コード生成コマンド
- コンテナの中にボリュームマウントでprotoファイルを埋め込む
- コンテナ内でソースが生成される
- コンテナ内に生成されたファイルをボリュームマウントでローカルにコピーする
の流れです。
$ docker build -t grpc-php-gen -f docker/grpc-php-gen/Dockerfile . $ docker run --rm -v $(PWD)/protos:/var/local/protos -v $(PWD)/gen:/var/local/gen grpc-php-gen sample.proto
- 投稿日:2020-07-28T13:53:01+09:00
受動的攻撃と同一オリジンポリシー
この記事は以下の書籍を参考にして執筆しました。
ブラウザ側のセキュリティ
サンドボックス
サンドボックスの中ではプログラムができることが制限されいる。
- ローカルファイルへのアクセス禁止
- プリンタなどの資源の利用禁止(画面表示は可能)
- ネットワークアクセスの制限(同一オリジンポリシー)
同一オリジンポリシー
サイトをまたがったアクセスを禁止する
XMLHttpRequestでは相手の許可があれば同一オリジンでなくても通信できるCORSという規格が策定された。
アプリケーション脆弱性と受動的攻撃
XSS
iframeの外側のjavascriptで内側をアクセスすると同一オリジンポリシー違反だが
何らかの方法でiframeの内側にjavascriptを送り込んで実行させたらどうか内側ならポリシー違反にならないため、アクセスができる。
これがクロス・サイトスクリプティング(XSS)参考文献
- 投稿日:2020-07-28T13:36:11+09:00
【PHP】クッキーとセッション管理
この記事は以下の書籍を参考にして執筆しました。
クッキーとセッション管理
クッキー
クッキーはサーバ側からブラウザ側に「名前=変数」の組を覚えておくように指示する。
クッキーの発行
session_start()この画面を表示させるとブラウザに以下のようなレスポンスが返る。
レスポンスヘッダのSet-Cookieにより、サーバはブラウザにクッキー値を覚えるように指示する。
以降、同じサイトにリクエスト送信するときにはこの覚えたクッキーを送信する。
有効期限がないクッキーはブラウザを閉じるまで有効。セッションID
PHPSESSIDのクッキー値のこと
このセッションIDを
$session[名前]
に格納しておくクッキーは整理番号として使う
クッキーそのものに値を格納するは良くない。
セッションIDEAに求められる要件
要件1 第三者がセッションIDを推測できないこと
要件2 第三者からセッションIDを強制されないこと
要件3 第三者にセッションIDが漏洩しないこと
セッションID漏洩の原因
- クッキー発行の際の属性に不備がある。
- ネットワーク的に盗聴されてる。
- クロスサイトスクリプティングなどアプリの脆弱性で漏洩
- プラットフォームで漏洩
- Refererヘッダから漏洩
公衆無線LANは盗聴の可能性が高い。
セッションIDをネットワーク頭頂から保護するにはTLSによる暗号化が有効だがクッキーを発行する際の属性指定に注意がいる。クッキーの属性
先のクッキーの発行には「path=/」があったがこれも属性の1種
属性一覧
属性 意味 Domain ブラウザがクッキー値を送信するサーバのドメイン Path ブラウザがクッキーを送信するURLのディレクトリ Expires クッキー値の有効期限。 Secute HTTPSの場合のみクッキーを送信 HttpOnly この属性が指定されたクッキーはjavascriptからアクセスできない Domain属性
クッキーはデフォでクッキーをセットしたサーバのみに送信される。
でも複数のサーバに送信されるクッキーを生成したい場合がある時にDomain属性が使える。異なるドメインへのクッキー設定は出来ない
a.example.jpが
Set-Cookie
の際にDomain=example.com
としてもブラウザでは無視される。通常はDomain属性を指定しなものとおぼえておくといい
Secure属性
SecureをつけていないクッキーはHTTPS通信かどうかに関係なく常にサーバに送信される。
この属性はHTTPS送信を保証する目的で使用される。HttpOnly属性
クッキーとして格納されたセッションIDを盗み出す典型としてクロスサイトスクリプティングでjavascriptで抜き出すがこの属性を指定すればjavascriptが使えなくなる。
完全には防げないが難しくできる。これをつけていても悪影響はないためHttpOnly属性を杖kておくように知ればいい。
HttpOnly属性をつけるにはphp.iniで設定をする。
php.inisession.cookie_http_only = Onまとめ
- セッションの発行は
session_start()
でできる。これをするとブラウザのレスポンスとしてSet-Cookie
が設定される。- セッション発行には属性がある。とりあえずDomain属性はつけずHttpOnly属性を設定しておくようにすればいい
参考文献
- 投稿日:2020-07-28T07:55:38+09:00
phpのフレームワークLaravelを触ってみた。
環境構築
※ローカル上で環境構築可能ですが、今回はdocker上で動く様にしてみました。
dockerのディレクトリ、ファイル構成
.(任意の作業ディレクトリ) ├── docker │ ├── php │ │ └── Dockerfile │ └── web │ └── default.conf ├── docker-compose.yml ├── index.html ├── index.phpphpモジュールのビルド
- build
$ docker-compose buildLaravelのプロジェクト新規作成
以下コマンドを実行する。
$ cd (任意の作業ディレクトリ) $ laravel new sample-larabel※プロジェクト作成後のディレクトリ構成
.(任意の作業ディレクトリ) ├── docker │ ├── php │ │ └── Dockerfile │ └── web │ └── default.conf ├── docker-compose.yml ├── index.html ├── index.php ├── sample-larabelNginxの設定ファイル(default.conf)の修正
※rootディレクトリの修正
server { listen 80; root /var/www/html/my-laravel-app/public; index index.php index.html index.htm; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }コンテナ起動及び動作確認
- コンテナ起動
$ docker-compose up -d
- 起動確認
$ docker-compose ps※この様に表示されればOK。
Name Command State Ports ---------------------------------------------------------------------------------------------------------- docker-compose-laravel_app_1 docker-php-entrypoint php-fpm Up 9000/tcp docker-compose-laravel_mysql_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp docker-compose-laravel_web_1 nginx -g daemon off; Up 0.0.0.0:8000->80/tcp ```画面表示確認
- http://localhost:8000/にアクセスして、正常に画面が表示される事を確認します。
新規ページ作成
- 後日アップします。