RAKUS Developers Blog

株式会社ラクスのエンジニアブログ

yum installで学ぶ! yum の仕組み

はじめに

エンジニアのnorthmkyです。 ラクスに新卒で入社し、今年で2年目になります。
業務ではシステムの運用保守チームに所属しているので断然サーバ周りの作業が多いということで今回はその中でもyumコマンドについてまとめてみました。

おそらくこれを読めば

  • yumrpmとの違いって?とりあえずyum使ってるけど...
  • yum install [package]って打つだけでなんでDL&Installできるの?

という疑問は少し解消されるかと思います。
まだまだ浅い知識なので間違っているところがあれば指摘いただけると嬉しいです。

yumとは

まずものすごく大雑把にいいますとyumは下記になります。

  1. パッケージ管理システム
  2. rpmというパッケージ管理システムをラッパーしている
    • yum = rpm + 「リポジトリ」による自動更新機能 + 依存関係の管理(検出だけじゃない)

yumRedHatディストリビューションのパッケージ管理システムです。
パッケージというのは「ソフトウェアを構成するファイルらをまとめたもの」で、設定ファイルやドキュメント、プログラム本体、プログラム本体が動くためのライブラリなどがそれにあたります。1

Linuxでは「パッケージ読み解き、ソフトウェアを正しく動作させるようにする」「パッケージの情報を管理する」ことでソフトウェアを使える/管理する仕組みを採用していて、今回取り上げるyumLinuxディストリビューションのなかでRedHat系のパッケージ管理システムとなります。

このyumですが実際裏側ではrpmというパッケージ管理システムを使っています。
rpmではできなかった点をyumができるようにしている」という立ち位置になっています。

この出来なかった点が冒頭に述べた

  1. リポジトリ」による自動更新機能
  2. 依存関係の管理(検出だけじゃない)

です。

リポジトリとは

意味のあるまとまりでパッケージを複数格納している場所のことです。
この場所には下記が格納されています。

  • 複数のパッケージ(./*.rpm)
  • そのリポジトリのメタ情報ら(./repodata)

パッケージが複数存在してもその場所はリポジトリとは言えません。メタ情報があってリポジトリとなります。2
yumではこのリポジトリの情報を元にパッケージを検索したり、installを行います。

yum/rpm/リポジトリの関係性

yumrpmリポジトリの配置場所との関係性は下記のようになっています。

f:id:northmky:20171213093542j:plain

yum/etc/yum.repos.d/*.repoに記載されているリポジトリ場所にあるパッケージらに対してrpm経由でDLしたり、インストールしたり、必要であればインストール時に依存関係のあるパッケージを検出して一緒にインストールしたりします。
逆をいえば、/etc/yum.repos.d/*.repo以外のレポジトリは情報がないのでyumは取得することができませんので注意してください。

では、実際によく打つコマンドを例にしてどのようになっているか見てみます。

yum installを見てみる

「このコマンド(ソフトウェア)、インストールしてないからインストールしよう」というのはよくあると思うので
今回はyum isntall [package]を通してどんなことが行われているかを見ていきたいと思います。

f:id:northmky:20171213100704j:plain

大枠の流れは上記のようになっています。

今回はphpをインストールしてみたいと思います。 (OS:CentOS6)

[root@localhost ~]# yum install php

こちらを実行すると、下記のようによく見るインストールしますか?という対話モードになります。 この中身を見ていきましょう。

[root@localhost ~]# yum install php
読み込んだプラグイン:fastestmirror, security
インストール処理の設定をしています
Loading mirror speeds from cached hostfile /* 1.ミラーサイトの中で一番地理的に近いミラーサーバを各レポジトリごとに探す */
 * base: ftp.jaist.ac.jp
 * epel: ftp.jaist.ac.jp
 * extras: ftp.jaist.ac.jp
 * remi-safe: mirrors.mediatemple.net
 * updates: ftp.jaist.ac.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> Package php.x86_64 0:5.3.3-49.el6 will be インストール
--> 依存性の処理をしています: php-common(x86-64) = 5.3.3-49.el6 のパッケージ: php-5.3.3-49.el6.x86_64
--> 依存性の処理をしています: php-cli(x86-64) = 5.3.3-49.el6 のパッケージ: php-5.3.3-49.el6.x86_64
--> トランザクションの確認を実行しています。
---> Package php-cli.x86_64 0:5.3.3-49.el6 will be インストール
---> Package php-common.x86_64 0:5.3.3-49.el6 will be インストール
--> 依存性解決を終了しました。

依存性を解決しました  /* 2.必要なパッケージ情報を取得する */
=============================================================================================================================
 パッケージ                     アーキテクチャ             バージョン                         リポジトリー              容量
=============================================================================================================================
インストールしています:
 php                            x86_64                     5.3.3-49.el6                       base                     1.1 M
依存性関連でのインストールをします。:
 php-cli                        x86_64                     5.3.3-49.el6                       base                     2.2 M
 php-common                     x86_64                     5.3.3-49.el6                       base                     530 k

トランザクションの要約 
=============================================================================================================================
インストール         3 パッケージ

総ダウンロード容量: 3.8 M
インストール済み容量: 13 M
これでいいですか? [y/N]

1. ミラーサイトの中で一番地理的に近いミラーサーバを各レポジトリごとに探す

結果としてリポジトリの場所(URL)のほとんどが.jpドメインつきなため、一番地理的に近いミラーサイトをレスポンスを計測して選んだというのがわかります。

これはyumが、前述した/etc/yum.repos.d/*.repoリポジトリの情報からインストールするリポジトリの場所を決定しています。ではphpのパッケージが存在する 「base」というリポジトリの情報が記載されているCentOS-Base.repoを見てみます。

CentOS-Base.repo
  1 # CentOS-Base.repo
  2 #
  3 # The mirror system uses the connecting IP address of the client and the
  4 # update status of each mirror to pick mirrors that are updated to and
  5 # geographically close to the client.  You should use this for CentOS updates
  6 # unless you are manually picking other mirrors.
  7 #
  8 # If the mirrorlist= does not work for you, as a fall back you can try the 
  9 # remarked out baseurl= line instead.
 10 #
 11 #
 12 
 13 [base] /* 1.リポジトリ名 */
 14 name=CentOS-$releasever - Base
 15 mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra /* 2.ミラーサイトリスト */
 16 #baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
 17 gpgcheck=1
 18 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
 19 
 20 #released updates 
 21 [updates]
 22 name=CentOS-$releasever - Updates
 23 mirrorlist=http://mirrorlist.centos.org/?
 ...
 ...

*.repoの中には基本的にはリポジトリ情報が複数記載されています。
mirrorlistに設定されているURLを実際に叩くと、

[root@localhost ~]# curl 'http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os&infra='
http://ftp.yz.yamagata-u.ac.jp/pub/linux/centos/6.9/os/x86_64/
http://ftp.iij.ad.jp/pub/linux/centos/6.9/os/x86_64/
http://mirror.fairway.ne.jp/centos/6.9/os/x86_64/
http://ftp.tsukuba.wide.ad.jp/Linux/centos/6.9/os/x86_64/
http://ftp.riken.jp/Linux/centos/6.9/os/x86_64/
http://ftp.nara.wide.ad.jp/pub/Linux/centos/6.9/os/x86_64/
http://ftp.jaist.ac.jp/pub/Linux/CentOS/6.9/os/x86_64/
http://www.ftp.ne.jp/Linux/packages/CentOS/6.9/os/x86_64/
http://mirror.0x.sg/centos/6.9/os/x86_64/
http://mirror.nus.edu.sg/centos/6.9/os/x86_64/
[root@localhost ~]

ミラーサイトのリストが返ってきます。
このリストからyumは一番近い場所を選定して、リポジトリ内のパッケージを取得する、ということをしているようです。 今回はftp.jaist.ac.jpでした。

2. 必要なパッケージ情報を取得する

phpパッケージを対象にしただけですが、実際には依存してる他パッケージもインストールの準備をしています。 パッケージが依存しているソフトウェアは、パッケージ(.rpm)のSPECファイルというパッケージのメタ情報(ソースバージョンなど)を記載したファイルに記載してあります3 この情報をRPMデータベース(/var/lib/rpm)4と呼ばれるパッケージの情報を保存しておくDBに登録し、install前に検索をかけ、依存関係の有無を見ています。

このような処理が走ったあとでDL&installが行われます。

おわりに

yumについてまとめてみました。
yumとはに記載した

  1. パッケージ管理システム
  2. rpmというパッケージ管理システムをラッパーしている

が伝えることができていれば幸いです。

ネットではチートシートや「rpmよりyumをまずは使うべし」などのハウツーの記事は多いのですが、
改めてどういった仕組み、処理でインストールが行われているかの記事はあまり見なかったので試行錯誤しながら執筆しました。
少しでも知識の助けになれば幸いです。(そして私自身の正しい知識の定着のためにもご指摘頂けると非常に助かります...!!)

GoogleHomeアプリを開発しよう!Dialogflowチュートリアル

こんにちは、 west-c です。

スマートスピーカー、国内でも各社から販売され盛り上がっていますね。 私も弊社開発チーム内での GoogleHome モニター選考に当選し*1、自宅で使い方を模索中です。

GoogleHome(厳密には GoogleHome 内蔵のGoogleアシスタント)は、ユーザが自由にアプリを開発したり公開したりすることができます。 簡単な対話アプリであればノンプログラミングで作成することも可能です。 今回は、自分で作成したスクリプトと組み合わせたアプリの作成手順を説明したいと思います。

作成するアプリの説明

今回は「指定した路線の遅延有無を教えてくれるアプリ」を題材に説明します。以下のような会話が行えることを目標としましょう。

ユーザ:「OK Google, XX線の遅延情報を教えて」
GoogleHome:
(遅延が発生している場合)「XX線で遅延発生中です。」
(遅延が発生していない場合)「現在XX線では遅延は発生していません。」

このアプリの流れを図にすると以下のようになります。 f:id:west-c:20171128171848p:plain

図内に登場する単語を簡単に説明します。

  • Action on GoogleGoogle アシスタント対応のアプリ開発を行えるプラットフォームです。Action on Googleで作成するアプリの単位をプロジェクトと呼びます。
  • Dialogflow:自然言語対話のプラットフォームです。Dialogflowを使うことで、GUIで簡単に会話形アプリを作成することができます。Dialogflowで作成するアプリの単位をエージェントと呼びます。
  • 遅延情報取得プログラム:今回作成するスクリプトです。遅延情報の取得処理はこのスクリプトで行います。Dialogflow 上でFulfillmentとして設定することで Dialogflow と連携することができます。

以下から詳細な手順を説明します。

Action on Googleでプロジェクトを作成する

GoogleHomeと連携しているGoogleアカウントでAction on Googleのコンソールにアクセスし、Add/import project から新しいプロジェクト TrainDelayInfo を作成しましょう。
作成したプロジェクトをクリックし、ADD ACTIONSから Dialogflow のBUILDを選択します。 f:id:west-c:20171127160038p:plain

CREATE ACTIONS ON DIALOGFLOWをクリックすると、Dialogflowのコンソールに遷移します。

Dialogflowでエージェントを作成する

ここからDialogflow上での設定になります。 コンソールには以下のような画面が表示されるので、CREATEをクリックします。 f:id:west-c:20171127161851p:plain

今回 Dialogflow で設定することは大きく以下の3点です。 順番に設定していきましょう。

  • Entitiesの作成
  • Intentsの作成
  • Fulfillmentの実装

Entitiesを作成する

Entitiesでは、ユーザからの入力として受け付ける単語を定義します。例えば、Dialogflowで提供しているEntityに@sys.colorがありますが、これは色名の単語(赤色・青色・黄色など)が定義されています。 「赤」という入力を「赤色」と判断するなど、単語の揺れを補正することも可能です。

今回は電車の路線名を入力として受け取る必要があるため、路線名を定義する @train-route というEntityを新しく作成します。 Entityの作成は Entities> CREATE ENTITYから行います。

f:id:west-c:20171127170046p:plain

左側(reference value)には「パラメータの単語」を、右側(synonym)には「その単語の同義語」を入力します。 日本語の場合、ひらがなで認識される可能性もあるため synonym にひらがなも入力すると良いでしょう。 上記の場合、ユーザが「おだきゅうせん」や「小田急」と発言しても、「小田急線」として認識されます。

作成が完了したらSAVEで保存しましょう。

Intentsを作成する

Intentsではユーザの会話によってどの処理を実行するのかを定義します。

今回は「路線名の遅延情報を教えて」という会話に反応するIntentを作成するため、Intents > Default Welcome Intentで以下のように編集しました。

f:id:west-c:20171127172330p:plain

  • User says:このIntentとして認識される例文を入力します。追加で「路線名は遅延している?」という呼びかけでも認識するようにしました。黄色背景部分(路線名)はパラメータとなる部分です。
  • Action:上のテキストボックスにはアクション名を指定します。後述のFulfillmentの実装で利用します。2つ目のテーブルではパラメータを指定します。
    • REQUIRED:必須有無を選択できます。必須の場合、このパラメータが入力されないと次の Intent には遷移しません。
    • PARAMETER NAME:パラメータ名です。Fulfillmentにてパラメータを識別するために利用します。
    • ENTITY:このパラメータのEntityです。今回は先ほど作成したEntityの@train-routeを指定しています。
    • IS LIST:複数の値を受け取る場合に指定します。
    • PROMPTS:パラメータの入力を促す文章を定義します。REQUIREDにチェックしたパラメータについて、ユーザからの入力が無かった場合やEntityに存在しない単語を入力された場合に使われます。
  • Response:このIntentでのユーザへの返答を定義します。今回はFulfillmentを使って返答するため、デフォルトで設定されているものは削除します。

作成が完了したらSAVEで保存しましょう。

Fulfillmentを実装する

IntentとEntityを使って路線名は取得できましたので、いよいよFulfillmentで遅延情報を確認するスクリプトを書いていきましょう。

今回は、Fulfillmentの実装に Firebase というサービスを利用します。 DialogflowはFirebaseと連携しているため、Dialogflow上でFulfillmentの実装・デプロイをすることができます。

Fulfillment > Inline Editor > ENABLED で表示されるエディタにスクリプトを記述しましょう。 f:id:west-c:20171127175826p:plain

今回実装したコードは以下のようなものです。 遅延情報を取得する処理は割愛しますが、API等を利用するなどして遅延有無をisDelayフラグにセットする想定です。

'use strict';

process.env.DEBUG = 'actions-on-google:*';
const App = require('actions-on-google').DialogflowApp;
const functions = require('firebase-functions');

// Intentのアクション名を指定
const NAME_ACTION = 'confirm_delay';

// パラメータのPARAMETER NAMEを指定
const ROUTE_ARGUMENT = 'train-route';

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
    const app = new App({request, response});

    function confirmDelay (app) {
        // 路線名を取得する
        let route = app.getArgument(ROUTE_ARGUMENT);

        let isDelay = false;

        /* 指定した路線の電車遅延情報を取得する処理をここに書く */

        if (isDelay) {
            app.tell(route + 'で遅延発生中です。');
        } else {            
            app.tell('現在' + route + 'では遅延は発生していません。');
        }
    }
    let actionMap = new Map();
    actionMap.set(NAME_ACTION, confirmDelay);

    app.handleRequest(actionMap);
});

下部のDEPLOYボタンを押せばFirebaseへのデプロイが完了します。

IntentからFulfillmentを呼び出すためには、Intents > Default Welcome Intent > Fulfillment > Use webhook にチェックを付けてください。 f:id:west-c:20171127180755p:plain

動作確認をする

これで設定は概ね完了したので、動作確認をしてみます。 右側のテキストエリアに会話文を入力することで、Dialogflowでの動作確認を行えます。 早速「おだきゅうの遅延情報を教えて」と入力してみましょう。

f:id:west-c:20171127181406p:plain

USER SAYSにはユーザが入力した文章が表示されます。 作成したEntity@train-routeにて、「おだきゅう」は「小田急線」の同義語と定義したため、パラメータtrain-routeには小田急線がセットされています。 このパラメータがセットされた状態でFulfillmentが呼び出され、レスポンスとして「現在小田急線では遅延は発生していません」という文章が返ってきました。

GoogleHome実機でのテストは、Integrations > Google Assistant > TESTGoogleアシスタントと連携することで実施できます。

おわりに

以上でGoogleHome上で動作するアプリを作成することができました。 Dialogflow自体はSlackやTwitterとも連携しているため、今回説明した内容を応用すればアプリ開発Bot開発の幅が広がりそうですね。 ほぼすべての設定をWeb上で実施でき敷居も低いと思いますので、皆さんもぜひお試しください。

お知らせ

ラクスでは去年に引き続き、ラクス Advent Calendar 2017を実施いたします! Qiitaにカレンダーを公開していますのでお楽しみに。 qiita.com

参考

*1:選考方法:じゃんけん

オトナのフェス「Japan IT Week」に行ってきた

id:radiocat です。楽楽精算の大阪開発チームのリーダーを担当しています。 11月8日、Japan IT Weekが開催された幕張メッセに行ってきました。

f:id:radiocat:20171108103300j:plain:w600

Japan IT Weekとは

Japan IT Weekは様々なIT技術を持った出展企業とソリューションを求めるビジネスマンが商談を交わす日本最大級のIT専門展です。BtoBサービスを展開する我々にとってはスーパー重要なイベントです。東京ビックサイト、幕張メッセインテックス大阪の3箇所で時期を分けて開催されています。今回は数々のバンドが伝説を作りサカナクションアルクアラウンドした幕張メッセにスーツを身にまとったビジネスマンが集結し列を作りました。毎年多くの人が熱狂するこの場所をビジネスマンが埋め尽くす超ビックなオトナのフェスなのです。

Japan IT Week秋@幕張メッセ

11/8〜10の3日間、幕張メッセで開催されました。今回私は各業界の動向をウォッチしたり弊社のサービスとの機能連携の可能性を考えてみたりなど、今後の製品開発の参考にすることを目的にそれぞれのブースを回ってきました。会場は10種類の展示区画に分かれています。

www.japan-it.jp

f:id:radiocat:20171108105305j:plain:w600

中でもビックデータ、IoT/M2M、AI・業務自動化は近年とても注目されている分野ということもあり、多くの人で溢れかえっていました。それぞれ独立した分野というよりも、センサーを活用してビックデータを集め、AIを活用して業務を分析、改善するような、それぞれの分野を融合させた製品が多数出展されていました。まだまだ発展途上の分野でもあり、今後も注目され続けそうな熱気を感じることができました。

f:id:radiocat:20171108171032j:plain:w600

通販ソリューション展は弊社製品のメールディーラー/チャットディーラー、配配メール、クルメルが出展していました。そしてクラウドコンピューティングEXPOには私も開発に携わっている楽楽精算と働くDBが出展していました。どちらも大変盛況で主に営業チームのメンバーが休む間もなく対応していました。一言ぐらい激励を…と思い近づこうとしたものの多忙そうで入る隙間もなく、社員なのにコンパニオンさんに勧誘されそうになってこれはまずいと思い立ち去りました。。

f:id:radiocat:20171108170928j:plain:w600

自分が開発に関わっている製品が多くの人達に支えられて、さらに多くのユーザーに届けられようとしているその瞬間を見られることはとても貴重なことであり良い体験になりました。

f:id:radiocat:20171108135342j:plain:w600

総務・人事・経理ワールド@インテックス大阪

幕張メッセとの関連展示会として11/15〜17に大阪でも総務・人事・経理ワールドという展示会が開催されました。こちらは私も関係者の1人として楽楽精算の出展のお手伝いをしてきました。

f:id:radiocat:20171115114321j:plain:w600

来訪頂いた人にコンパニオンさんが簡単な説明を行い、興味をもって頂いた場合はスタッフがデモをしました。僭越ながら私もスタッフの1人としてデモしました。中小企業の経理部門が抱えている課題は会社によって様々なので、こうして少しだけデモのお手伝いをするだけでも様々なご意見が聞けてとても参考になります。

f:id:radiocat:20171115173952j:plain:w600

ちなみに、私が開発に関わった機能の1つに ICリーダーアプリ がありますが、コンパニオンさんが手に持っているタブレット端末ではこのアプリを使った説明をされていました。自分が開発に関わったアプリをお姉さまたちが手にとってコンパニオン活動をされているのを見るだけでも、慣れないスタッフ作業の疲れが吹き飛ぶほど価値ある経験でした。

まとめ

以上のように来訪者側とスタッフ側の両方を体験して私のこの秋のフェスシーズンは幕を閉じました。しかし年明けにはまたインテックス大阪で、そして春には東京ビックサイトで次の展示会が予定されているようです。ビジネスマンの活動は既に次に向けて動き出しているのです。

おわりに

なお、ラクスでは一緒に働く社員やパートナー企業の方を募集しています。このような経験を一緒に堪能してみたいと感じられたかたがいましたらぜひお声がけください。Web技術だけでなくiOSAndroidといったモバイル技術やAIなどの先進的な技術を持ったエンジニアのかたも大歓迎です。

株式会社ラクス|採用情報

要注意!新人エンジニアが発生させた2大脆弱性

はじめに

記事をご覧のみなさん、はじめまして。新卒1年目エンジニアのkasuke18と申します。ブラウザは圧倒的にChrome派です。

今回の記事では私が作ってしまった2大脆弱性XSSSQLインジェクションについて、ソース例を踏まえて原因を追及します。なお、ソースの言語についてはPHPを利用しています。

この記事が初めてのブログ投稿ですので、「この書き方はヘンだな」と感じるときがあると思いますが、そこは温かい目で見守ってくださると幸いです。。

もくじ

この記事の想定する読者

新人エンジニアの方々

「2大脆弱性は知ってるけど、具体的にダメな実装例が実感できない」という方が読まれた際に、理解の手助けとなれば幸いです。

つきましては「XSSとは」「SQLインジェクションとは」ということは今回はさらっと流します。それらをお探しの方は他のサイトをご覧ください。IPAのサイトは国の機関なので信頼できると思われます。

「こんなパターンで脆弱性が発生するのか」や「ここの実装するときは気を付けないと!」などと感じていただくのが目的です。とはいっても実際のソースは大人の事情で載せられないので、実際のソースとは少しズレてしまいますが、そこはご容赦ください。。

XSS

XSSとは

いきなりですが、新人エンジニアの私から見てもわかりやすくまとまっていると感じた記事があるので引用します。「XSSとは何か」ということをお探しの方はこちらをご確認ください。

XSS(Cross Site Scripting)は、あるWebページにアクセスした標的のブラウザ上で、攻撃者が任意のコードを実行し得るバグ、あるいはそれを用いた攻撃手法のこと

XSSが発生したソース例

XSSが発生した原因などは次で説明するとして、まずはXSSが発生してしまったソース例を示します。

<!DOCTYPE>
<html>
  <head>
  </head>
  <body>
    <form action="" method="post">
      <!-- ↓ここでXSSが発生 -->
      <input name="hoge" type="hidden" value="<?php echo $_POST['hoge']; ?>">
    </form>
  </body>
</html>

この時実現したかったことは、フォームから入力値を受け取り、その入力値をパラメータにセットすることです。

なぜXSSが発生したのか

ソース例を見ていただければわかるかと思いますが、直接の原因は単純にエスケープが漏れていたことです。言い方は悪いですが半ば思考停止気味に「とりあえずエスケープしておこう」で防ぐことはできたミスです。

ではなぜエスケープが漏れてしまったのかと言い訳をしますと、単純に注意不足でエスケープをしなかったことに加えて、「入力値検証をしっかりと行っているから大丈夫」という無意識のうちに安心感を持っていたことです。

むしろ今回の件では見事にその意識の甘さが脆弱性を生み出しました。どういうことかと申しますと、具体的には以下の流れで発生していました。

  1. Chromeのdeveloperツールでパラメータを変更しスクリプトを仕込み、確定する
  2. サーバは入力値検証を行い、エラーと入力値を返す
  3. 戻った画面では受け取った入力値をセットする
  4. XSSが発生!!

今回XSSを発生させてしまったのは<input>type="hidden"パラメータでした。これは通常の画面操作からは直接変更できませんが、developerツールではできてしまいます。

それでは好き放題に変更された入力値を受け入れてしまうので、普通は入力値検証を行い、決められた値以外は許可しないようにします。

また、ユーザの使いやすさを考えると、エラー時に戻った画面ですでに入力されていた内容をセットしておくことも必要です。(入力内容を1か所間違えただけで全部やり直しというのはあまりに不親切ですので。)

今回の件でもそれに乗っ取り入力値検証を行い、数値以外は許可しないようにしていました。また、エラー時に入力値をセットするということもしていました。XSSを発生させる原因となった処理はこの「エラー時に入力値をセットする」という処理で、この入力値を出力する際にエスケープしなかったためにXSSが発生しました。

実施した対処

今回の件ではエスケープが漏れていたことが原因なので、エスケープを実施して対処しました。PHPではhtmlspecialchars()という関数を利用することでエスケープできます。

以下が修正後のソース例となります。

<!DOCTYPE>
<html>
  <head>
  </head>
  <body>
    <form action="" method="post">
      <!-- ↓ htmlspecialchars() を使用 -->
      <input name="hoge" type="hidden" value="<?php echo htmlspecialchars($_POST['hoge']); ?>">
    </form>
  </body>
</html>

この件を通して感じたこと

このXSS脆弱性は被害という意味ではほぼ問題ないと考えています。その理由は、

  1. 入力値検証ではじかれるため、サーバがスクリプトを許容していない

  2. 1を考慮すると、スクリプトが実行されるのはスクリプトを埋め込もうとした攻撃者のみである

以上の2点から被害はほぼないと考えました。

しかし、エスケープが漏れてしまっていたことは問題なので、今後は忘れないように十分に注意します。

SQLインジェクション

SQLインジェクションとは

XSS同様にSQLインジェクションも詳しい説明は省略させていただきます。詳しくはIPAの資料をご覧ください。

SQLインジェクションが発生したソース例

SQLインジェクションが発生した原因などは次で説明するとして、まずはSQLインジェクションが発生してしまったソース例を示します。

<?php
$id = $_POST['id'];
$status = $_POST['status'];
$conditions = '';
$isFirst = true;
if($id !== null){
  if($isFirst){ 
    $conditions .= ' WHERE ';
    $isFirst = false;
  } else { 
    $conditions .= ' AND ';
  }
  $conditions .= 'id = :id';
}
if($status !== null){
  if ($isFirst) { 
    $conditions .= ' WHERE ';
    $isFirst = false;
  } else { 
    $conditions .= ' AND ';
  }
  // ここでSQLインジェクションが発生
  $conditions .= 'status = ' . $status;
} 
$sql = 'SELECT is, name, status FROM table'. $conditions;
$sth = $dbh->prepare($sql);
$sth->bindValue(':id', $id);
$sth->execute();
?>

この時実現したかったことは、フォームから入力値を受け取り、その入力値によりDB検索を行うことです。また、フォームで入力されるパラメータは毎回すべて入力されるわけではないので、SQLのWHERE句は動的に組み立てる必要があります。

なぜSQLインジェクションが発生したのか

上記のソース例を見ていただければ一目でわかりますが、パラメータidは正しくプリペアードステートメントが使用されていますが、パラメータstatusは単なる文字列結合となってしまっています。このことがSQLインジェクションを発生させていました。

また間接的な原因として、パラメータstatusについての入力値検証が全く行われていなかったことがあります。ただの言い訳でしかありませんが、入力値検証を行わなかった理由はパラメータstatusの入力方法がプルダウンメニューであり、「プルダウンならプログラムが用意した値以外は送られてこない」という誤った認識をもってしまっていたからです。すでに上記XSSの項でも述べていますが、Chromeなどのdeveloperツールを利用すれば簡単に値を変更できることを失念していました。

実施した対処

理想論でいえば、本来は保険的な対策でしかない入力値検証だけで対処するのではなく、適切にプリペアードステートメントを利用することが必要です。しかし今回の件では諸事情により根本的な原因であるSQLの組み立て部分を変更することはできませんでした。よって入力値検証で数値以外は許容しないようにして対処しました。

XSSと同様、修正後のソース例を書こうと考えましたが、大人の事情で書くことができません。 代わりに、理想的な対処法であるプリペアードステートメントを適切に利用して対処したソース例を以下に示しますので、ご容赦ください。

<?php
$id = $_POST['id'];
$status = $_POST['status'];
$conditions = '';
$isFirst = true;
if($id !== null){
  if($isFirst){ 
    $conditions .= ' WHERE ';
    $isFirst = false;
  } else { 
    $conditions .= ' AND ';
  }
  $conditions .= 'id = :id';
}
if($status !== null){
  if ($isFirst) { 
    $conditions .= ' WHERE ';
    $isFirst = false;
  } else { 
    $conditions .= ' AND ';
  }
  // プレースホルダを使用
  $conditions .= 'status = :status';
} 
$sql = 'SELECT is, name, status FROM table'. $conditions;
$sth = $dbh->prepare($sql);
$sth->bindValue(':id', $id);
// 値をパラメータにバインドする
$sth->bindValue(':status', $status);
$sth->execute();
?>

この件を通して感じたこと

今回の件では「プルダウンなら入力値検証を行わくてもよい」という完全に誤った認識が露呈しました。プルダウンだけではなく、XSSの項でも挙げている<input>type="hidden"パラメータも同様で、「通常の画面操作から直接変更できないパラメータこそ入力値検証が必要」と感じました。

おわりに

以上が、私が実装してしまった2大脆弱性です。この記事の目的の通り、「こんなパターンで脆弱性が発生するのか」と把握していただけたでしょうか。実際のソースが載せられないため、正直よくあるソース例になってしまった感が否めません。。

ちなみにと言っては何ですが、今回ご紹介した脆弱性はどちらも単体テストで発見・修正しているので、大事には至っておりません。

最後までお読みいただきありがとうございました。

参考文献

失敗しない Laravel 導入方法

はじめに

はじめまして、ラクス新卒1年目のMasaKuと申します。

PHPの勉強を開始した当初は「とにかく動かせること」「思い通りに動くこと」だけで満足していました。
しかし、勉強を進めていくうちに「もっと綺麗にできないものか」と思うようになり、フレームワークの勉強を開始しました。

フレームワークは、使い方を覚えるまでは時間がかかるものですが、要領が分かってくると、たった数行書くだけでいろんな機能を実現してくれるため、Webアプリ開発を強力にサポートしてくれます。

LaravelではComposerというシステムを利用することで簡単に導入することができるため、これからフレームワークを勉強しようとしている方にもおすすめのフレームワークであると考えます。

本記事は、生のPHPは書いたことがあるけれど、フレームワークは使ったことがない、という方に対して、導入の一歩をお手伝いできるよおうな記事になれれば幸いです。
なお、以下はWindowsで導入する際の手順となります。
macOSをお使いの方は、同じように進められない可能性がありますのでご了承ください。

PHPフレームワークとは

フレームワークとは、「開発で多様される様々な機能や仕組みを持ったソフトウェア」です。
Webアプリ制作で最低限必要となる機能(ログイン画面など)は大抵のアプリである程度共通化しています。
そのため、そういったお決まりの機能の開発はフレームワークに任せてしまおうといった思想のもと生まれました。
PHPフレームワークで有名なものは以下の通りです。

書店に行くと上記のいずれかの参考書を目にしたことがあるのではないでしょうか。
特にCakePHPの本はどの書店に行っても置いているという印象で、日本で最も人気のPHPフレームワークなのではないでしょうか。

Laravelとは

私が大人気のCakePHPを差し置いて、Laravelの勉強をしようと思った理由は以下の通りです。

  • 低い学習コスト
  • 楽に導入できる
  • GitHubで人気急上昇中

フレームワーク導入でつまづいてしまうと、一気にやる気を失ってしまうと感じたため、スムーズに開発できる段階に移行できるものがいいなと感じました。
また、現在GitHubで注目されているというのもポイントでした。
以下はGitHub上でのスターなどの比較です。

f:id:MasaKu:20171112005637p:plain
GitHubでの注目度比較 (2017/11/11 時点)

フレームワーク開発に携わる人が多いということは、これからも進化し続ける可能性があるということです。
また、そういった風潮を受けてか、書店では出版日が比較的若い本が販売されていたことも魅力の一つだと思いました。

Laravelのインストール

さて、前置きが長くなりましたが、さっそくLaravelの導入です。
今回は、Laravelの画面が表示できるところまでを解説させていただきます。

準備するもの

Laravelを導入に必要なものは以下の通りです。

  • XAMPP
  • Composer

「あれ、Laravelの導入なのにLaravelは用意しなくてもいいの?」と感じる方もいらっしゃるかもしれません。
Laravelでは、Composerというプログラムを利用することで、Laravelを利用するために必要なライブラリなどを自動で入手することができます。
コマンド入力が必要となりますが、そこさえ間違えなければ、導入で失敗することはありません。

XAMPPのインストール

まずはXAMPPのインストールです。
XAMPPとはPHPの実行環境を簡単に構築できるApacheディストリビューションのことです。
以下のページからXAMPPをダウンロードしてください。
Composerを利用するためにXAMPPのPHPを利用したいだけなので、php.iniなどの設定ファイルは触らずに、インストールだけ完了させておいてください。

www.apachefriends.org

Composerのインストール

次はComposerのインストールです。
Composerは上述の通り、PHPフレームワークを導入する上で必要となるライブラリなどを自動で入手してくれるプログラムです。
これを利用することで、簡単にLaravelを導入ることができます。

では、Composerのインストーラーを以下のページからダウンロードしてください。
getComposer.org

インストーラーをダウンロードするリンクがわかりにくいと感じたので、画像を掲載しておきます。
よければ参考にしてください。

ダウンロード手順

f:id:MasaKu:20171112121035p:plain
Download をクリック
f:id:MasaKu:20171112121040p:plain
Composer-Setup.exe をクリック

Composerのインストーラーがダウンロードできたら、次はインストールです。

インストール手順

f:id:MasaKu:20171112121958p:plain
Nextをクリック

f:id:MasaKu:20171112122002p:plain
XAMPPフォルダ内のPHPが選択されていることを確認しNextをクリック

f:id:MasaKu:20171112122006p:plain
プロキシサーバーを設定する画面ですが、今回は何も選択せずにNextをクリック

f:id:MasaKu:20171112122011p:plain
Installをクリック

f:id:MasaKu:20171112122011p:plain
Nextをクリック

f:id:MasaKu:20171112125423p:plain
Finishをクリック

これでComposerのインストールは完了です。

Laravelのインストール

いよいよLaravelのインストールです。
Laravelのインストールでは、先ほどインストールしたComposerを利用します。
Composerを利用するには、コマンドプロンプトを利用します。

「Windodsキー」 + 「R」のショートカットで「ファイル名を指定して実行」を表示し、「cmd」と入力することでコマンドプロンプトを起動できます。

コマンドプロンプトが起動できたら、以下のコマンドを実行してLaravelのインストーラーをダウンロードします。

Composer global require "laravel/installer=~1.1"

ダウンロードには少々時間がかかりますがUpdating dependencies(including require-dev)までが表示されていれば、コマンドは成功していますので、気長に待っていてください。

しばらくすると、ダウンロードが開始してGenerating autoload filesが表示されればLaravelのダウンロードは成功です。

f:id:MasaKu:20171112153327p:plain
Laravelのダウンロードに成功した際の表示

これで一通りは完了なのですが、最後にLaravelを利用するため環境変数PATHを設定する作業があります。

コントロールパネル→システムとセキュリティ→システム→システムの詳細設定の順で開き、システムのプロパティを開きます。

f:id:MasaKu:20171112131158p:plain
システムのプロパティ画面

ウィンドウ下部に「環境変数」というボタンがありますので、クリックします。

環境変数ウィンドウ下部のシステム環境変数のリストの中に「Path」という項目があると思います。
この項目を選択して「編集」をクリックします。

f:id:MasaKu:20171112154054p:plain
システム環境変数のPathを選択して編集をクリック

環境変数名の編集が表示されたら「新規」をクリックして以下のパスを追加します。
C:\Users\ここには各ユーザの名前が入ります\AppData\Roaming\Composer\vendor\bin

f:id:MasaKu:20171112154601p:plain
新規をクリックしてパスを追加する

Pathの追加が完了したら各画面をOKで閉じていきます。
ここまでの作業が完了したらLaravelプロジェクトを作成する準備が完了です。

Laravelプロジェクトの作成

それでは、いよいよLaravelプロジェクトを作成して、画面を表示していきましょう。
Laravelプロジェクトを作成する場所はどこでも構いませんが、今回はわかりやすいようにデスクトップに作成しましょう。

それでは、コマンドプロンプト上でデスクトップに移動します。
デスクトップに移動するコマンドは以下の通りです。

cd Desktop

コマンドプロンプト上でデスクトップに移動できたら以下のコマンドを実行して、Laravelプロジェクトを作成してください。

laravel new hellolaravel

laravelコマンドにより、プロジェクトを構成する上で必要なパッケージをどんどん揃えてくれます。
ダウンロードには少々時間がかかりますので、気長に待ってください。

f:id:MasaKu:20171112140259p:plain
laravelコマンド実行後の画面

f:id:MasaKu:20171112140302p:plain
Application ready! Build something amazing.が表示されればインストール完了

もし、うまくいかない場合は、環境変数の設定が間違っている可能性がありますので、設定を見直していただくか、以下のコマンドでもLaravelプロジェクトの作成が可能です。

Composer create-project laravel/laravel hellolaravel --prefer-dist

プロジェクトの作成に成功すると、デスクトップに「hellolaravel」というディレクトリが作られているはずです。
では、プロジェクトがうまく作成できたか確認してみましょう。

以下のコマンドをコマンドプロンプトに入力してhellolaravelの場所に移動します。

cd hellolaravel

hellolaravelに移動できたら、以下のコマンドを実行してください。

php artisan serve

するとLaravel development server started: <http://127.0.0.1:8000>のような表示が現れます。
Laravel では 内部サーバを利用することができ、上記のコマンドで簡単に動作確認をすることができます。
内部サーバはPHP5.4以降に実装されたビルドインサーバー機能を利用しています。

さきほど実行した artisan というコマンドでは、ビルドインサーバを利用するだけでなく、Laravelで利用可能な様々な機能を実行することができます。
以下のコマンドで実行可能なコマンドを一覧で確認することができるので、ほかにどんなコマンドがあるか気になった方は是非調べてみてください。

php artisan list

さて、少し脱線しましたが、php artisan serveでビルドインサーバが起動できたら、ブラウザ上で動作確認をしてみましょう。
ブラウザを立ち上げてhttp://localhost:8000にアクセスしてみてください。

すると、Laravelのホーム画面が表示されているかと思います。
正しく表示されていたら、Laravelの導入が成功した証拠です。
おめでとうございます。

f:id:MasaKu:20171112155957p:plain
http://localhost:8000 にアクセスした際の表示

ちなみに、起動したビルドインサーバを停止させたい場合は、コマンドプロンプト「Ctrl」 + 「C」を入力します。

おわりに

以上が、Laravelの導入方法です。いかがでしたでしょうか。
私も初めて自分でフレームワークを導入してみましたが、特に失敗することなく導入することができました。
この手軽さが、Laravelが低コストで学習することができる所以であるかしれません。

Laravelの使い方については、参考書などで勉強することが効率的かと思いますが、いくつか紹介したい機能もありますので、またいつかの機会に紹介できたらなと思います。

以上です。長文失礼しました!

参考資料

PHPフレームワーク Laravel入門
http://www.shuwasystem.co.jp/products/7980html/5258.html

ソフトウェアフレームワーク
https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF

XAMPP
https://www.apachefriends.org/jp/index.html

XAMPPのインストール方法
https://techacademy.jp/magazine/1722

Composer
https://getcomposer.org/

Composer Wiki
https://ja.wikipedia.org/wiki/Composer

Laravel 5.3 インストール
https://readouble.com/laravel/5.3/ja/installation.html

社内勉強会「もくもく勉強会」のご紹介

ラクスエンジニアのstrongWhiteです。
過去に「WIP制限の大切さ」の記事を書いているので、興味がある方はそちらも参考にしてくださいませ。
さて、今回はラクス大阪本店で開催しているもくもく勉強会のご紹介をさせていただきます。

もくもく勉強会とは

「勉強会」と付いていますが、共通のテーマをもとに議論したりはしていません。
何らかの課題や目的をもつ人々が集まって、それぞれの目的のもとにそれぞれが自由に取り組むことを目的として活動しています。
そのため勉強の内容も参加者によってさまざまで、必ずしもITや技術に関係するトピックを扱っていません。

↓↓↓勉強内容はこんな感じです↓↓↓

  • 業務と関係のない言語やフレームワークの勉強をする
  • プライベートサービスの開発をする
  • 今後業務にぶっこんでやろうと思っている何かの予習をする
  • 積ん読を消化する
  • 資格の勉強をする
  • IoT的ななにか
  • ペアプロをする etc...

月イチで発表会も開催しており、勉強会の成果や、勉強会の活動とは全く関係なく発表したいことがある人が発表を行っています。
ここまで読んでいただいて分かる通り、割とゆるやか~な雰囲気で活動しております。

10月の発表会の様子

では実際に10月の発表会の様子を一部紹介したいと思います。

f:id:strongWhite:20171107185825j:plain:w500

f:id:strongWhite:20171108191402p:plain:w200 f:id:strongWhite:20171108191722p:plain:w200

写真はオフィスのカフェスペースにぶら下がってる電球をPhilips Hue v2に差し替えて、AWS IoT ボタンを押した際に電球の色を変えてみよーという試みを行っている様子です。
カフェスペースをいつもの白色から色鮮やかで華やかでスタイリッシュに変えてみようという感じです(笑)
AWS IoT ボタンの入力をローカルサーバで受け取り、Philips Hue v2と同期することで電球の色が変わります。

f:id:strongWhite:20171108184120j:plain:w400
f:id:strongWhite:20171108192431p:plain:w150 f:id:strongWhite:20171108192620j:plain:w300

次の写真はカフェスペースでいまいろんな意味で流行りのドローンを飛ばしてみた様子です。
制御自体はRaspberry Piで行っており、離着陸、旋回以外に一回転するなどのトリッキーな動きも実現しています。
写真の真ん中で紫色の光を放っているのがドローンです。今まさに一回転してます(笑)

もくもく勉強会のよいところ

私が参加して良いなと思うところは技術的興味の窓口(キッカケ)ができるところかなと思います。
他のエンジニアの人が行っている勉強内容から興味を持ち、自分も学んでみようというキモチが生まれるイメージです。
勉強会では他のエンジニアの方と和気あいあいと話しながら楽しく学べるので、普段は話さない人ともコミュニケーションが盛んになり、 同時に技術的知識を蓄えられるので一石二鳥かなと思います。

おわりに

ラクスでのもくもく勉強会を紹介しました。

エンジニアならば自由に技術の話題を見聞きするのは楽しいと思うはずです。
弊社ではこういった技術的勉強会に対してオープンなので、エンジニアとしては嬉しい限りです。
これからも続いていけるようにしていきます。

以上strongWhiteからのもくもく勉強会の紹介でした。

参考

JavaからPHPに乗り換えて感じたこと

はじめに

はじめまして、新卒一年目のd_shrと申します。
現在、業務ではPHPを用いて開発を行っています。業務に入る前は大学在学中の研究開発や入社後の新人研修でJavaを使っていました。
在学中にPHPを学習した経験はありましたが、業務で扱うことになると入出力のチェックなど セキュリティの観点には特に注意しなければいけないため、プログラミング言語の細かい仕様まで把握する必要があると思います。
そこで変数の扱いなどにPHP独特のものを感じ、Javaとは違う仕様に戸惑うことがありました。

本記事では、JavaからPHPに転向した際に戸惑ったことを中心に、主にJava経験者から見たPHPの特徴、注意点などをまとめていこうと思います。 PHPの学習を考えている方やPHP初心者の方に少しでも参考になれば幸いです。

目次

PHPを使い始めて戸惑ったこと

業務で実装をしていて1番戸惑ったことは、変数の扱いです。
セキュリティの観点から正しい値が格納されていることをチェックする実装することがありますが、その際にPHPの変数の扱いに戸惑いました。

PHPの変数の扱い

まず、PHPは変数の型がありません。
Javaと比較すると、PHPの大きな特徴であると思います。
変数に型がないPHPでは、1つの変数に数値と文字列を格納することができます。

<?php
  $hoge = 123;
  $hoge = "hogehoge"
?>

他にも...
以下のような書き方ができることにも最初はすごく違和感を感じました。

<?php
  $hoge = 1;
  $hoge = $hoge == true ? "true" : 0;
?>

PHP側で解釈してくれるので型の宣言をする必要がなく、記述量が減るメリットはあると思います。
(可読性を考えると、このように書くことはあまりないと思いますが)
しかし、PHPが勝手に型を合わせてしまうため、Javaのような型に厳密な言語を触った後では、変数の扱いに戸惑うことがよくありました。

暗黙的な型変換

暗黙的な型変換とは、PHPが変数の型を勝手に変換してしまうことです。
例えば、以下のような変数の比較。

<?php
  $a = 0;
  $b = "hoge";
  if ($a == $b) {
    // true
  }
?>

PHPで数値と文字を比較すると、文字を数値に変換しようとします。
文字列の最初の部分により値が決まり、有効な数値がない場合は0になるため、 このような結果になります。
PHPの仕様通りに変換され意図しない結果が得られることがあるため、 PHPでの条件分岐を作る際には、変数の扱いには注意が必要です。

  • 扱いに注意が必要な例
<?php
  if ( 0 == 0 )     // true
  if ( 0 == "0" )   // true
  if ( 0 == false ) // true
  if ( 0 == null )  // ture
?>

これらは、型が正しいかどうか厳密な比較を行う演算子"==="を使うことで解決できます。
しかし、厳密な比較を行わない、switch文も注意が必要です。

<?php
switch ($hoge) {
  case 0:
    // hogeが0, "0",false, null,""などで実行される
    break;
  case "0":
    // ここは実行されない
    break;
}

// 厳密な型変換を行う場合
switch (true) {
  case $hoge === 0:
    // hogeが数値の0のときだけ
    break;
  case $hoge === "0":
    // hogeが文字列の"0"のときだけ
    break;
}
?>

型に厳密なプログラミング言語の経験がある場合は、 変数の扱いで引っかかりやすいのではないかと思いました。
PHPで正しく変数の扱うためには、変数について仕様をしっかり把握し注意しないといけません。

変数のスコープ

PHPの変数の扱いで戸惑ったことは暗黙的な型変換だけでなく、 変数のスコープでも経験があります。
変数のスコープとは、変数の有効範囲のことです。
PHPでは、関数単位のスコープしかなく、 if文やループ中のみでしか使わないような変数を定義できません。

<?php
$flag = true;

if ($flag) {
  $value = "true";
} else {
  $value = "false";
}

Javaではif文の中で定義された変数は、if文のブロックの中だけで有効です。
PHPのスコープを把握していなかったときに、以下のようなソースコードを書いたことがあります。

<?php

$flag = true;
$value = "";
if ($flag) {
  $value = "true";
} else {
  $value = "false";
}

// $valueに空を入れたくなかったときはこっちで書いた
$flag = true;
$value = "true"
if (!$flag) {
  $value = "false";
}

スコープを正しく理解していないと可読性の低いソースコードになってしまうこともあります。
スコープもプログラミング言語で特徴があるので、 各言語ごとに把握しておかないといけないことだと思います。

その他、気になったこと

上記以外で、実装中に疑問に思って調べたことや違和感を感じたことです。

配列の値渡し

Javaのデフォルトは参照渡しですが、PHPのデフォルトは値渡しです。
PHPでも参照渡しはできます。

  • 値渡しの例
<?php
$array = [1,2,3];

$copy = $array;

$copy[1] = 5;

print_r($array);
print_r($copy);

$array: Array ( [0] => 1 [1] => 2 [2] => 3 )
$copy: Array ( [0] => 1 [1] => 5 [2] => 3 )

  • 参照渡しの例
<?php
$array = [1,2,3];

$copy = $array;
$copy2 = &$array;

$copy[1] = 5;
$copy2[1] = 5;

print_r($array);
print_r($copy);
?>

$array: Array ( [0] => 1 [1] => 5 [2] => 3 )
$copy: Array ( [0] => 1 [1] => 5 [2] => 3 )

まとめ

JavaからPHPを扱うようになって戸惑ったことや違和感についてまとめてみました。
当初はこの違和感に嫌気が差していましたが、今ではPHP洗脳され慣れてしまいました。
PHPを学び始めた方や、次の新卒で入社される方に参考になればと思います。
また、同じような境遇の方に共感いただければ幸いです。

Copyright © RAKUS Co., Ltd. All rights reserved.