解明!password_hash関数で生成される文字列の正体

こんにちは、CTOの山岡(@hiro_y)です。

(この記事は、来る2022年4月9日から開催されるPHPerKaigi 2022登壇応募したものの選出されなかった題材をブログに書くことで供養しようという試みです。)

Webシステムでパスワードを保存するとき、そのままの値(平文)で保存してはいけません。データベースの中身が何かしらのインシデントで漏洩してしまった場合、パスワードの内容が明らかになってしまうからです(漏洩の時点でもっと酷い事態になっていそうではありますが…)。では、どのような対策を行えばよいのでしょうか。

パスワードはハッシュ化しよう

一つ目の対策は、パスワードを秘密鍵を使って暗号化、保存する方法です。

その場合、それぞれの暗号化に共通の秘密鍵を使わないことが大切です。また、初期化ベクトル(IV)としてそれぞれ異なるものを用意、ブロック暗号化モードを利用して暗号化した結果が同じパスワードでも異なるように工夫する必要があります。パスワードの検証をするときは、暗号化されたパスワードを復号して比較することになります。

…こう書いているだけでちょっと面倒ですね。実際、正しい手順で暗号化されていないばかりに不正アクセスからの漏洩事故が過去に何度か発生しています。あとは単純に、昨今簡単に手に入るようになったマシンパワーで解読してしまえるという話もあります。

そこで、現在は二つ目の方法、ソルトと呼ばれる文字列を付けてハッシュ化を行い、ストレッチングを行うことでより強い仕組みを作る手法が主流になってきています。パスワードに適当な文字列(ソルトと呼ばれる)を付けてハッシュ化した上で、できあがった文字列をさらに何度も繰り返しハッシュ化する(ストレッチングと呼ばれる)という仕組みです。検証の際には、同じ方式でハッシュ化を行い、保存しておいたハッシュ値と同値になることを確かめます。

続きを読む

TypeScriptのUtilityTypesと使い方

こんにちは。エンジニアのujitaです。

弊社の「MediaDX」というサービスでは独自のCMSであるOpen Media Suite(以下OMS)を提供しています。 OMSのフロントエンドはTypeScriptを使用して開発しています。

開発を続けていくと、似たような型定義が増えていくことがあると思います。 そのような場合にTypeScriptが提供しているUtilityTypesを利用すると、既存の型から別の型に変換することができます。 今回はOMSで使っているUtilityTypesと使い方についてご紹介します。

続きを読む

失敗する練習と準備

こんにちは、CTOの山岡(@hiro_y)です。

エンジニアをやっている皆さんなら、プログラミングはバグが付きものであることがおわかりかと思います。バグがゼロであることはあり得ないし、もしゼロという結果が出たなら、その結果の方を疑ってかかった方がよいとされているぐらいです(全くないとは言いませんが、極めてまれです…)。

これは言ってみれば、失敗を最初から想定し、許容する態度だとも言えます。必ず失敗するので、失敗に気が付ける仕組みを最初から用意しておく。そのために各種テストプロセスがあります。単体テスト、結合テスト、システムテスト。その他にもプロセスが用意されていることも少なくありません。

続きを読む

Webエンジニアとして駆け出したあなたにやってほしいこと

こんにちは、CTOの山岡(@hiro_y)です。

以前「Webエンジニアとして駆け出そうとしているあなたに」という記事を書きました。その中で「学習の高速道路」について触れましたが、その「高速道路」は最初からあったものなのでしょうか。また、「高速道路」の部分は通り過ぎたまま、先に向かってしまってよいものなのでしょうか。

tech.innovator.jp.net

続きを読む

nginxをあれこれ設定してWebサーバを少し理解した

こんにちは、Webエンジニアの小野寺です。 最近はVPSを契約したのでWebサーバ周りの設定などを楽しんでいます。 そこで直近の2ヶ月間ぐらいにWebサーバでやってみたことを3つほど書いてみます。

使っているWebサーバはnginx、OSはCentOS7です。

413 Request Entity Too Largeのエラー対応

複数枚の画像を一度にアップロードするアプリケーションをLaravelで作ったのですが、413 Request Entity Too Largeエラーが出ました。画像が大きすぎるからですね。 php.iniを設定するだけでエラーが消えると思っていたのですがWebサーバも変更しないといけないようです。 解決方法は以下です。

例えば20Mの画像をアップロードしたい場合、nginxは以下のdefault.confの中身を変更します。

# /etc/nginx/conf.d/default.conf

default.confはもしかしたら環境によって違うかもしれません。その場合は ***.confを変更してください。

# sudo vi default.conf

でファイルを開くとデフォルトはこんな記述になってるかと思います。

server {
  listen 80;
  server_name example.com;
  root /var/www/html/hoge;
  index index.php index.html;
}

ここのserver内にclient_max_body_size 20mを追記します。httpsの場合は443の箇所にも同様の追記が必要です。

server {
  listen 80;
  server_name example.com;
  root /var/www/html/hoge;
  index index.php index.html;
  client_max_body_size 20M;
}

設定が終わったらnginxを再起動します。

sudo systemctl restart nginx

以上でnginxの設定は終わり。 あとはphp.ini側でpost_max_sizeとupload_max_filesizeを設定すれば20Mまでアップロードできるはず。

HTTPS化

セキュリティ、見た目どちらにしてもHTTPS化はしておいたほうが良いですよね。(このサイトは安全ではありません。って出したくない) 無料のLet's EncryptでSSL化を行うためにCertbotを使います。 Certbotは無料かつ自動でSSL証明書を発行できるツールで、CSRとKEYファイルの作成からWebサーバー設定まで自動で行ってくれます。 ちなみに僕が以前使っていたsakuraのレンタルサーバは、コンソール画面で無料SSLボタンをポチッとすれば次の日にはHTTPS化が完了しています。 nginxに自力で設定する場合は少なからず知識は必要ですが、30分ぐらいでHTTPS化が完了します。

//certbotインストール
# sudo yum install certbot

//nginx停止
# sudo systemctl stop nginx

//SSL証明書の取得(たぶんメールアドレスとか色々聞かれるので回答します)
# sudo certbot certonly

//nginx起動
# sudo systemctl start nginx

以上でhttps化が完了します。 なお、Let's Encryptの証明書は3ヶ月で有効期限が切れるので、crontabで自動更新処理を書いておくと良いと思います。

特定ディレクトリをBasic認証

管理者以外に見せたくないディレクトリがあったので突貫工事的ですが取り急ぎBasic認証を行いました。 ApacheのBasic認証で利用するファイル「.htpasswd」を使います。nginxとApacheにはファイル互換性があるので.htpasswdをそのまま使えるので便利です。

まずはApacheのコマンドツールをインストール。 CentOSを使っているので以下(Ubuntuは別のコマンド)

# yum install -y httpd-tools

htpasswdコマンドを利用して.htpasswdを作成します。

#htpasswd -c /etc/nginx/.htpasswd [username]
New password: [パスワードを入力]
Re-type new password: [パスワードを入力]
Adding password for user username

最後にnginxの設定をします。例えばhogeディレクトリの場合は

server {
    listen       80;
    server_name  localhost;
    ................
    ................

    location / {
      root   /usr/share/nginx/html;  
      index  index.html index.htm; 
    }

    #Basic認証
    location /hoge {
      root   /usr/share/nginx/html; 
      index  index.html index.htm; 
      auth_basic "Input username and pass"; 
      auth_basic_user_file /etc/nginx/conf.d/.htpasswd;  # Basic認証用のファイル
    }

設定が終わったらnginxを再起動します。

sudo systemctl restart nginx

Basic認証をかけたいディレクトリを定義して、その中にBasic認証ファイルディレクトリを記述します。 これで/hoge にアクセスしたときはBasic認証が求められ、それ以外のディレクトリはBasic認証が求められません。

ちなみBasic認証でログインに成功するとその後はキャッシュにより認証を求められなくなります。 ログアウトしたい場合はhttp://me@hoge.co.jpのようにme@をつけてアクセスすれば再度Basic認証が求められるようになります。

参考:Nginx BASIC認証通過後に 404 エラーになる | ハックノート

参考:Nginxにてベーシック(Basic)認証を有効にする手順 | りんか ネット

最近のWebサーバ周りでやったことでした。

頼りにするのと依存するのは違うという話

こんにちは、CTOの山岡(@hiro_y)です。このエントリーは「イノベーター・ジャパンAdvent Calendar 2021」の24日目の記事です。

あなたの会社に「頼りにできるエンジニア」はいるでしょうか。業務に必要なドメイン知識を持っていて、技術的にも複数領域携われる力があるような、そういう存在。

非常にありがたい存在なのですが、彼らに対して私たちはどうしても依存しがちです。この人に聞けば答えてくれる、安心感。それはいつしか依存に変わります。いつの間にか、その人なしではプロジェクトがまわらないようになっていたりしないでしょうか。その人がいるから他にエンジニアを入れなくていい、と判断してしまうこともあるかもしれません。

続きを読む

JavaScriptでイミュータブルな変数を定義する

こんにちは、エンジニアのたべたつ(@ttabtt3)です。このエントリーは「イノベーター・ジャパンAdvent Calendar 2021」の22日目の記事です。

今回は、勘違いされがちなJavaScriptのconstの挙動とイミュータブルな変数の定義の方法について書こうと思います。

続きを読む