手続き型音楽の日常

関数型音楽に乗り換えたい

MUSECA 名古屋交流会に参加してきた話

まさか2回連続 MUSECA の話題でブログ書くことになるとは誰が思っただろうか。私も思ってなかったよ。

でもこれは流石に書かずにはいられない。正直ここ1ヶ月で、控えめに言って最高の1日だったと思います。

というわけで、書きます。いいですか、書きますよ。

>> #Trashで踊るな <<

MUSECA 名古屋交流会に参加してきました

f:id:yuzutan_hnk:20180418024727j:plain

先日 4月14日、名古屋のレジャーランドささしま店で開催された、 MUSECA 名古屋交流会に参加してきました。

前回の記事でも書いた打鍵舞踏廻に引き続き、実に2回目となるゲームイベントへの参加でした。

なんか、たった2ヶ月空いただけなのに、なんだか懐かしいというか、なんというか。

こういう雰囲気、久しぶりだなぁという感覚でした。

こんな日に限って寝坊するとか無いわ〜、ありえないわ〜…

とりわけ私早めに行きたいなぁと思って、というか朝から開店凸ってもいいなぁとか思いつつ。

地元勢だしばっちりリハーサルも兼ねて出かけようかなぁとか思ってたんですよね。気持ちだけは。

というわけで当日の私のツイートをペタリ。

もうこれどうしようもねぇな。

一応、会自体は14時からなので、 間に合ってます 間に合ってません。

いやこれめっちゃ急いで支度して出ないとほんとに間に合わないなと思いつつ、家を飛び出し…。

なんとか直前に会場入り。みんな集まってる、というかめっちゃ人多いな!?みたいな感じでめっちゃ挙動不審してました。

そして打鍵以来のしゃーさんに名札をもらい、メカコさんに記念品(?)のアクリルキーホルダーを貰い。

打鍵舞踏廻のときにも、仔猫吸引さんがアクリルキーホルダーを作ってきてくださって、めっちゃ感動したんですけど。

今回もまた超クオリティなものを頂いてもう感謝感激…。いやいや勿体無くて使えない。でもずっと眺めてたい。

こう、ユーザ参加型のゲームなだけあって、キュレーターの中にコンテンツ提供者がいるっていうちょっと不思議な感覚ではあるんですけど。

実際にクリエイターから直接もらえるって、めちゃくちゃ嬉しい。いや今度の JB は参加したいよ。めっちゃ行きたい。前回行けなくてごめんなさい。

久々にロカマチ!

いやぁ交流会ということで、久々に筐体が4台並ぶところを拝見いたしました。拝み。写真は神様を写すということに値するかもしれないのでなし。

普段は1人でしかやらないのでどちらかといえばマイペースに別機種交えながらやるんですが。

今回はみなさんとロカマチしながら楽しくワイワイ…ワイワイ?

多分、現場にいた皆さんから見えてた私って、こんな感じだと思うんですよね。

私「アッ、アッ、えーっと、うん、アッ」

絶賛コミュ障発揮してるーーーッ!!!

あーなんでこんなコミュ障なんだろネット弁慶極めてるとかホント自慢にならない…

ほんっとなんで自分こんなに人前で緊張しちゃうんだろう、せっかく話しかけてくださった方々と気軽に話せない。うーん。

と思いつつ、何度かいろいろな方とロカマチさせていただきました。

f:id:yuzutan_hnk:20180418015247j:plain:w300 f:id:yuzutan_hnk:20180418015319j:plain:w300 f:id:yuzutan_hnk:20180418015344j:plain:w300 f:id:yuzutan_hnk:20180418015429j:plain:w300 f:id:yuzutan_hnk:20180418015457j:plain:w300 f:id:yuzutan_hnk:20180418015532j:plain:w300 f:id:yuzutan_hnk:20180418015601j:plain:w300 f:id:yuzutan_hnk:20180418015629j:plain:w300 f:id:yuzutan_hnk:20180418015658j:plain:w300 f:id:yuzutan_hnk:20180418015729j:plain:w300 f:id:yuzutan_hnk:20180418015755j:plain:w300 f:id:yuzutan_hnk:20180418015824j:plain:w300 f:id:yuzutan_hnk:20180418015849j:plain:w300 f:id:yuzutan_hnk:20180418015918j:plain:w300 f:id:yuzutan_hnk:20180418015944j:plain:w300 f:id:yuzutan_hnk:20180418020011j:plain:w300

計4回かな?いやめちゃくちゃ楽しかったですよ!

みなさんほんと上手いし、何より楽しそう。というか、 MUSECA ってやっぱ楽しいよね。何度も思う。

いつも全然やってる人を見ないので、本当に自分だけの空間みたいになっちゃうんですけど。

いろんなひとが MUSECA で楽しんでいるところを見ると、ホッとしますね。色々思うところはあります。

最後に

やっぱり MUSECA 楽しいです。

私自身、どちらかといえばエンジョイ勢に寄っているのでこれまであまり突っ込んで活動はしてこなかったのですが。

こうして交流会だったり、大会だったり、いろいろなイベントに足を運んでみると、また違った世界が見えてきます。

純粋に音楽を楽しみたいがために始めた音ゲーが、自分の中でこうも大きな存在になっているのかと改めて実感もしましたし、

色んな人がいろんな思いで一つのことに夢中になれる、本当に素晴らしいゲームなんだなと感じたりもしました。

本当に、楽しかった。

あの場にいた人全員に、感謝しています。ありがとうございました。

打鍵舞踏廻に参加してきたお話

f:id:yuzutan_hnk:20180220020802j:plain:w600

初めて、コンピュータ関係以外の記事を書く気がする。

打鍵舞踏廻に行ってきました。

先日 2月17日、ラウンドワン府中本町駅前店で開催された MUSECA 非公式全国大会、打鍵舞踏廻というイベントに参加してきました。

https://e63s3neu.wixsite.com/mscchampionship

全国のキュレーターが参加できる大会で、去年の暮れからオンライン上で予選を行い、最終決戦が府中が行われました。

私は楽曲プレー部門でエントリーし、29人中10位という成績で最終戦に進出しました。ほかにも、解放ミッション部門とフリースタイル部門がありましたが、そちらには参加しませんでした。

私の MUSECA レベル

勉強会記事とかでも毎回この部分は、私がイベントの趣旨に対してどれだけ経験があるかっていうことをまとめているので今回も。

MUSECA というゲームを知ったのが、実はたまたまゲーセンに行ったらロケテをやっていた、ということでして。

初めて見たとき、SDVX の衝撃がよみがえってきたというか、『あ、このゲームは面白そうだ』と感動したんですよね。

今でこそ SDVX は当時の面影を残さず (BOOTH も FLOOR も) 、様々な進化を遂げて一つのジャンルを築いてきたと思いますが、MUSECA はそれをさらにこじらせたような、なんというか個性の塊というか、魅力を感じました。

時間的に1回?2回やったかな?ロケテをやってみて、「なんだこのゲーム、めちゃくちゃ面白いじゃん」という感覚に襲われ、本稼働してすぐにやりこむようになりました。

というわけで、実はロケテ勢、もっと言えばここ2年本当にやりこんでいる (自分の中では) ゲームなんです。

もう MUSECA レベル…キュレーターレベルは 20 MAXです。はい。何の参考にもならないって?

まず結果から行こうか

というわけで、結果を発表いたしますね。

1回戦敗退 でした。それも、ブロックで最下位。

実力をしっかり発揮できれば、もうあと1,2上を目指せたかなとは思います。後から悔やんでも仕方のないことですが、いろいろと反省しています。

実は、この1~2週間の間 MUSECA やるのサボっていて、全然調整することなく本番を迎えていたんですね。これが一番大きな要因かなと思っています。

当日になって「そういえば左手黄色スピナが入りにくい癖があったんだっけ…」とか「精度とる練習怠ってたな…」とかいろいろ思い返すあたりには 何もやってない っていう。

仕事のせいにするのもちょっと気が引けますが、実際本職が本当に忙しくて、ゲーセンに寄って帰る時間だったり MUSECA する気力だったり全部無くなってしまったっていうのが、正直なところ。

更に体調も微妙な感じ (ちょっと風邪気味、喉が痛い) だったし、当日新幹線で移動するので昼まで練習できないとか、朝ごはん食べれていないとか。

総合的に、計画性の無さ、準備の足りなさ、そして仕事を溜めすぎたっていうのが敗因ですかね。 ごめんなさい最後無かったことにして

皆さん上手すぎる件

とりわけ当日不調だ不調だって散々言いましたけど、調子が良ければ勝てたのかと言われれば 圧倒的に無理 なわけでして。

1回戦の次がもう準決勝だったのですが、その時点で遥かにうまい人しか残っていませんでしたはい。

Lv.15 (最高難易度) の曲が課題曲だったのですが、パーフェクト 100万点 がMAX値のうち、軽々 99万点 出してくるような戦いでして (私95万くらいしかいかない…)

見ていて圧巻というか、唖然というか、レベルが違うってこういうことなんだなぁと実感させられました。

行って良かったと心から思った

とはいえ、最終戦に出場できただけでも嬉しいですし、結果がどうであれその場にいることができたのが本当に幸せです。

本当は予選終了間際まで、出られるか出られないかわからない順位でした。ちょうど真ん中あたり (14位くらい) をうろうろしていたので、予選を通らなかったら仕事忙しいし東京なんて行かないんだろうなぁと思っていました。

でもこうして最終戦に呼んでいただき、東京まで足を運んで、こんなに熱をもって MUSECA をやっているキュレーターの皆さんに出会えて。

私がまだ知らないような世界がそこに広がっていて、ランカーの凄さだけでなくその熱量、なによりその場にいた全員の MUSECA への愛。

普段決して感じることがないような…。言葉が思い当たらないんですが。

MUSECA に出会えて、MUSECA を続けてこれたことが、こんなにうれしいと思える日が来るとは夢にも思っていませんでした。

最後に

普段から日記を書いたり、何か文章に気持ちを書き下ろしたりすることが滅多にないのでなかなかうまく伝えられない部分がありますが。

今までゲームをしてきた中で一番うれしかった1日でした。こんなに嬉しいことがあるんだなって、心から思いました。

当日見に来てくださった皆さん、一緒にプレイしてくださったみなさん、そしてこのイベントを主催してくださったお二方。

本当にありがとうございました。そして、お疲れさまでした。

MVVM 初心者なので、 .NET Standard 2.0 + Xamarin.Forms で Messaging クラスを実装してみた

昨今のお技術についていけていない私は、もちろん MVVM も初心者です。もっぱら Windows Forms に生きてる人なのです。

この間 Xamarin 勉強会に出かけたし、本業でも少し Xamarin を触ることになったので、 WPF 含め MVVM を色々と調べていたのですが。

やっぱり実装する方々それぞれ、いろいろなお作法で実現されていまして。

  • View -> ViewModel の機能呼び出しは ICommand 実装のクラス
  • ViewModel -> View の機能呼び出しは Messaging 機構

というのが現在の流行だという事を知りました。

早速実装してみる。

準備するもの

1. Xamarin.Forms でソリューションを作る

Xamarin.Forms を使ったソリューションを作成。とりあえず PCL で作っておく。

f:id:yuzutan_hnk:20171122014755p:plain:w600

f:id:yuzutan_hnk:20171122015100p:plain:w600

UWP のバージョン指定をしろと言ってくるので、最小バージョンを Fall Creators Update にする。

ここでキャンセルをクリックすると、 UWP とおさらばできる。スクショ撮ってて今知った。

f:id:yuzutan_hnk:20171122015344p:plain:w600

2. .NET Standard 2.0 化する

共有プロジェクトを無理くり .NET Standard 化する。

VS2015 のときは PCL プロジェクトをそのまま .NET Standard 化できていたけれど、 VS2017 ではできない。そこでまず、ソリューションに .NET Standard プロジェクトを追加する。名前は後々役立つように、 PCL プロジェクト名 + Standard にしておく。

f:id:yuzutan_hnk:20171122015937p:plain:w600

VS 15.4 なら大丈夫だと思うけど、念のためプロパティからターゲットを .NET Standard 2.0 にしておく。

f:id:yuzutan_hnk:20171122020310p:plain:w600

ソリューションの NuGet パッケージマネージャで、ほかのプロジェクトの Xamarin.Forms のバージョンを確認する。この画面からではたぶん .NET Standard プロジェクトに Xamarin.Forms を導入できないので、プロジェクト側の NuGet パッケージマネージャでバージョンに気を付けながら導入する。

ついでに、 PCL プロジェクト以外のプロジェクトに NETStandard.Library を導入。 .NET Standard プロジェクトのターゲットを .NET Standard 2.0 にしたので、自動的に NETStandard.Library のバージョンが 2.0.0 に固定される。 2.0.1 入れるとどうなるんだろう…。

f:id:yuzutan_hnk:20171122020627p:plain:w600

f:id:yuzutan_hnk:20171122020846p:plain:w600

PCL 側からソースファイルを全部コピー。ドラッグアンドドロップでおk。

f:id:yuzutan_hnk:20171122021319p:plain:w300

PCL プロジェクトを削除して、各プラットフォーム向けのプロジェクトの参照を .NET Standard のプロジェクトに張り替える。

最後に、ソリューションエクスプローラー上で .NET Standard プロジェクトの名前から「standard」を消す。

これで PCL プロジェクトを完全に置き換えたような形になる。

もっときれいにしたいときは、いったん Visual Studio を閉じ、エクスプローラー上でプロジェクトフォルダの配置や名前を変更、 sln ファイルの中身を弄って正しい配置にする。

3. Messaging クラスを実装する

本題の Messaging クラスです。

Messaging クラスの役割は、コーディング時に呼び出し先が用意する機能を直接参照せずに呼び出すという機能です。

というわけで、相手を見ずに機能を特定する方法を考えます。 いや考えるのが非常にめんどくさいので 文字列を使って特定することにします。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Xamarin_SelfMessaging
{
    /// <summary>
    /// メッセージ機構を実現するクラス
    /// </summary>
    public class Messaging
    {
        #region Private Class

        /// <summary>
        /// 接続先一覧を表すクラス
        /// </summary>
        public class MessagingNetwork : Dictionary<object, MessagingPeer> { }

        /// <summary>
        /// 接続先を表すクラス
        /// </summary>
        public class MessagingPeer : Dictionary<string, Action<object>> { }

        #endregion

        #region Variable / Const

        /// <summary> 既に接続されている </summary>
        private const string EXMSG_CONNECTING = "Already connecting.";

        /// <summary> まだ接続されていない </summary>
        private const string EXMSG_NOTCONNECTED = "Not connected yet.";

        /// <summary> 既に購読されている </summary>
        private const string EXMSG_LISTNING = "Already listening.";

        /// <summary> まだ接続されていない </summary>
        private const string EXMSG_NOTLISTNED = "Not listened yet.";

        /// <summary> 接続先一覧 </summary>
        private MessagingNetwork _network = new MessagingNetwork();

        #endregion

        #region Public Property

        /// <summary>
        /// 現在の接続数 を取得します。
        /// </summary>
        public int ConnectionCount => _network.Count;

        #endregion

        #region Public Method

        /// <summary>
        /// メッセージングネットワークに接続します。
        /// </summary>
        /// <param name="target">接続するオブジェクト</param>
        public void Connect(object target)
        {
            if (target == null) throw new ArgumentNullException(nameof(target));
            if (_network.ContainsKey(target)) throw new InvalidOperationException(EXMSG_CONNECTING);

            _network.Add(target, new MessagingPeer());
        }

        /// <summary>
        /// メッセージングネットワークから切断します。
        /// </summary>
        /// <param name="target">切断するオブジェクト</param>
        public void Disconnect(object target)
        {
            if (target == null) throw new ArgumentNullException(nameof(target));
            if (!_network.ContainsKey(target)) throw new InvalidOperationException(EXMSG_NOTCONNECTED);

            _network.Remove(target);
        }

        /// <summary>
        /// メッセージを購読します。
        /// </summary>
        /// <param name="target">購読するオブジェクト</param>
        /// <param name="key">購読するイベント名</param>
        /// <param name="action">イベントの引数</param>
        public void Listen(object target, string key, Action<object> action)
        {
            if (target == null) throw new ArgumentNullException(nameof(target));
            if (key == null) throw new ArgumentNullException(nameof(key));
            if (!_network.ContainsKey(target)) throw new InvalidOperationException(EXMSG_NOTCONNECTED);
            if (_network[target].ContainsKey(key)) throw new InvalidOperationException(EXMSG_LISTNING);

            _network[target].Add(key, action);
        }

        /// <summary>
        /// メッセージの購読を停止します。
        /// </summary>
        /// <param name="target">購読しているオブジェクト</param>
        /// <param name="key">停止するイベント名</param>
        public void Unlisten(object target, string key)
        {
            if (target == null) throw new ArgumentNullException(nameof(target));
            if (key == null) throw new ArgumentNullException(nameof(key));
            if (!_network.ContainsKey(target)) throw new InvalidOperationException(EXMSG_NOTCONNECTED);
            if (!_network[target].ContainsKey(key)) throw new InvalidOperationException(EXMSG_NOTLISTNED);

            _network[target].Remove(key);
        }

        /// <summary>
        /// メッセージを送信します。
        /// </summary>
        /// <param name="target">送信元オブジェクト</param>
        /// <param name="key">イベント名</param>
        /// <param name="arg">引数</param>
        public void Post(object target, string key, object arg)
        {
            var actionList = _network
                .Where((item) => item.Key != target)
                .Select((item) => item.Value.Where((item2) => item2.Key == key))
                .Where((item) => item.Count() > 0)
                .Select((item) => item.First().Value);

            foreach (var action in actionList)
                action?.Invoke(arg);
        }

        /// <summary>
        /// メッセージを送信します。
        /// </summary>
        /// <param name="target">送信元オブジェクト</param>
        /// <param name="key">イベント名</param>
        public void Post(object target, string key)
            => Post(target, key, null);

        #endregion
    }
}

使うイメージ的には、イベントを購読するクラスを Connect し、購読するイベント名を Listen 。メッセージを発行する側はイベント名を Post する。一通り何かの通信のような感覚で使えるようにしたつもり。

ただ一つ、 宛先を指定できない (=ブロードキャスト状態) という難点があり、ネットワークごとにインスタンスを分ける必要がある…。

今回はめんどくさいので ViewModel にインスタンスを持たせて、 View が BindableContext直接参照で ViewModel をインスタンス化するときにコンストラクタ内でこっそり登録する方針で行きます。

4. DelegateCommand を実装する

Messaging ついでにボタンに登録するコマンドも実装します。

フレームワークには System.Windows.Input.ICommand インターフェイスしか用意しておらず、自前で実装するしかないというちょっと微妙な感覚。

というわけで汎用性を高めるよう、 delegate で処理を指定できるようにする。

using System;
using System.Windows.Input;

namespace Xamarin_SelfMessaging
{
    /// <summary>
    /// 任意の処理を実行可能なコマンド
    /// </summary>
    public class DelegateCommand : ICommand
    {
        #region Variable

        private Action<object> _command;
        private Func<object, bool> _canExecute;

        #endregion

        #region Public Event

        /// <summary>
        /// 実行可能かどうかを取得する必要がある時に発生します。
        /// </summary>
        public event EventHandler CanExecuteChanged;

        #endregion

        #region ctor

        private DelegateCommand() { }

        /// <summary>
        /// 任意の処理を実行可能なコマンドをインスタンス化します。
        /// </summary>
        /// <param name="command">コマンド実行時の処理</param>
        /// <param name="canExecute">実行可能かどうかを返す処理</param>
        public DelegateCommand(Action<object> command, Func<object, bool> canExecute)
        {
            _command = command;
            _canExecute = canExecute;
        }

        #endregion

        #region Public Method

        /// <summary>
        /// コマンドが実行可能かどうかを取得します。
        /// </summary>
        /// <param name="parameter">パラメータ</param>
        /// <returns>実行可能かどうか</returns>
        public bool CanExecute(object parameter) => _canExecute?.Invoke(parameter) ?? false;

        /// <summary>
        /// コマンドを実行します。
        /// </summary>
        /// <param name="parameter">パラメータ</param>
        public void Execute(object parameter) => _command?.Invoke(parameter);

        /// <summary>
        /// <see cref="CanExecuteChanged"/> イベントを発生させます。
        /// </summary>
        public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());

        #endregion
    }
}

System.Windows.Input.ICommand インターフェイスExecute メソッドと CanExecute メソッド、 CanExecuteChanged イベントを定義しています。

特に引数を必要としないのでデリゲートのほうは引数をなくしてもいいのですが、とりあえず純粋にスルーするだけにしてみます。

指定されたデリゲートが null だったりしたら不通に例外出したほうがもしかしたら安全かも?

5. ViewModelBase を実装してちょっとだけコーディングを楽にする。

すべての ViewModel でいちいち System.ComponentModel.INotifyPropertyChanged を実装したり MessagingConnect するのがめんどくさいので、基底クラスを作っていしまいます。

あとは継承するだけ。使うだけ。って状態にしてみます。

using System.ComponentModel;

namespace Xamarin_SelfMessaging
{
    /// <summary>
    /// ViewModelのためのテンプレート
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region Public Property

        /// <summary>
        /// メッセージネットワーク
        /// </summary>
        public Messaging Messaging { get; }

        #endregion

        #region Public Event

        /// <summary>
        /// バインドプロパティが変更されたときに発生します。
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region ctor

        public ViewModelBase()
        {
            Messaging = new Messaging();
            Messaging.Connect(this);
        }

        #endregion

        #region PrivateMethod

        /// <summary>
        /// バインドプロパティを変更したときに呼び出します。
        /// </summary>
        /// <param name="name">変更したプロパティ名</param>
        private void OnPropertyChanged(string name)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

        #endregion
    }
}

本当はプロパティだけ用意すれば勝手にバインドしてくれるジェネリックな型を作ってみたい。 ReactiveProperty みたいな。

6. View ~ ViewModel を実装

あとは機能要件を作るのみ。今回はボタンを押したらカウントアップして、さらにダイアログを出すという単純な機能を作ってみます。

View

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:Xamarin_SelfMessaging"
             x:Class="Xamarin_SelfMessaging.MainPage">
    <ContentPage.Content>
        <StackLayout>
            <Button Text="{Binding Count}" Command="{Binding ButtonCommand}"
                    HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
using System;
using Xamarin.Forms;

namespace Xamarin_SelfMessaging
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            var viewModel = new MainPageViewModel() as ViewModelBase;

            viewModel.Messaging.Connect(this);
            viewModel.Messaging.Listen(
                this, "A",
                (arg) => DisplayAlert(
                    $"Do you have a watch???",
                    $"It's {(arg as DateTime?)}",
                    $"Awesome!!!")
                );

            BindingContext = viewModel;
        }
    }
}

ViewModel

using System;

namespace Xamarin_SelfMessaging
{
    class MainPageViewModel : ViewModelBase
    {
        private int _Count;
        public int Count
        {
            get { return _Count; }
            set
            {
                _Count = value;
                OnPropertyChanged(nameof(Count));
            }
        }

        private DelegateCommand _ButtonCommand;
        public DelegateCommand ButtonCommand
        {
            get { return _ButtonCommand; }
            set
            {
                _ButtonCommand = value;
                OnPropertyChanged(nameof(ButtonCommand));
            }
        }

        public MainPageViewModel()
        {
            ButtonCommand = InitialButtonCommand;
        }

        private DelegateCommand InitialButtonCommand
            => new DelegateCommand(
                (arg) =>
                {
                    Count++;
                    Messaging.Post(this, "A", DateTime.Now);
                },
                (arg) => true
                );
    }
}

7. 実行

あとは実行するのみ。今回は UWP で動かしてみる。

f:id:yuzutan_hnk:20171123230412p:plain:w600 f:id:yuzutan_hnk:20171123231034p:plain:w400 f:id:yuzutan_hnk:20171123231053p:plain:w600

以上。

IoTLT名古屋 vol.7 に参加してきた話

IoT ってなんだか楽しそう!いろんな端末がインターネットにつながるのって面白そう!やってみたい!

…という人が、ガチ IoT 勉強会に参加してきた世にも恐ろしい話…。

というわけではなく、比較的ラフな LT 大会というジャンルの勉強会に参加してきました。

iotlt.connpass.com

きっかけ

前回の OWASP Nagoya Local Chapter Meeting #1 に参加してから早 2 週間。

日々スプラトゥーンばかりやってて ちょっと退屈な日々でした。嘘。

で。次の勉強会 (?) の OWASP World Tour in Tokyo / Nagoya Satellite までちょっと間が開くなぁと思っていたところ、

友人やいつも追いかけている MSP の方々 が参加される勉強会というだけあって、ちょっと参加してみようと思いました。

最近、思いとどまるということを知らない気がするぞ…。

私の IoT レベル

7月あたり、ハンズオンセミナーで ESP8266 を使った簡単なプログラミング (兼ハンダ付け大会) に行ったこともあり、一応それっぽい知識はあります。

とはいえあれから1ヶ月2ヶ月放置して、全く使っていません…。もうそろそろ使わないと忘れちゃいそう…。

電子工学とか全くわからないし、 HDL とかほぼ組んだこと無いしハードウェアに密接に関わるような分野は難しいなぁと感じています。

でも、 IoT ってそれだけじゃない、はず、よね?

と信じてました。

私の LT レベル

LT ? 無理無理!まず LT 大会に参加したこともないよ!!

という超初見さん状態でした、まる

当日

Misoca さんという会社の会議室で行われました。ルーセントタワーの目の前…。

www.misoca.jp

f:id:yuzutan_hnk:20170926015019j:plain:w600

2011 年創業のスタートアップ企業だそうで、最近いろいろあって綺麗なオフィスを構えることができましたーとおっしゃっていました。

確かにとても清潔感のあるオフィスで、アットホームなスタートアップと言うよりかは、しっかり堅実なオフィスという感じでした。

一般参加 22 人という枠でしたが、席が全部埋まる大盛況でした。私は一番前に座ってエアコンの風に当たって最後のほうちょっと寒かったです。とはいえしっかり見れてよかった。

Twitter トレンド入りを果たそう」 という神の助言があったり connpass のバグがあったり、開始する前もワイワイと盛り上がる盛り上がる。

勉強会ってこういうところラフだなぁと思いながら、 15:35 からスタートしました。

まぐろ㌠ さん

www.slideshare.net

題名は「音のなるIoTデバイス

IoT らしい IoT といえば、音を使うデバイスでしょ!と初っ端ズキッとくる内容。

私もこういうの作りたいと思って IoT ハンズオン行ったんだっけなぁと2ヶ月前の記憶が蘇って来ました。

作られたデバイスDFPlayer miniESPr Developer という 2 種類のボードを使ったもので、その間に噛ませるボードを自作されたそう。

センサを取り付けたり Wi-Fi 越しに操作できるなんてまさに夢のようですね!

ネタ要素もたくさん取り入れられて面白かったし、内容もとても濃かった (というか私が興味あるだけ?) と思います。

@ueponx さん

www.slideshare.net

題名は「DragonBoard410cを使ったソーシャルTVリモコンの作成」

ネットからトレンドのテレビ番組を取得して自動でチャンネルを切り替えるというもの。

最近のテレビは高機能になってネットワークからチャンネル操作とかもできるようになっているので、 Wi-Fi を使って操作するものかなぁと思っていたのですが、実際には赤外線を使ったリモコンでした。

自宅のテレビの操作で検証されていましたが、コマンドをちょっと変えるだけで各社のテレビに対応できるのでとても実用性が高そう。

テレビの機能として実現するのではないので、まさに インターネット を駆使した IoT だなぁと考えさせられました。

更に声まで出せるという、なんともハイテクな機能もついているそうで。もはやスマートスピーカーと言えると思います。

ぶぁぶぁくん さん

題名は「太陽光発電を監視したい!」

connpass で題名見た時、一体どのレベルの話をされるんだろうと不思議に思ったのですが(屋根に太陽光載せる時には基本的に HEMS ってついてくると思うし)

発表を聞いてみたら、趣味の範囲で太陽光パネルを買い、趣味の範囲で HEMS を 1 から作ってらっしゃるという素晴らしい内容でした。もはや IoT じゃねぇ。

とはいえ、その発電量を手動で確認・集計するのは面倒という事で、センサから取得した情報を VPS に流して集計する、というシステムを考えられているみたいです。

将来的には発電量を自動的に視覚化したり、遠隔で負荷を接続・切断したりできるようになるという、私ら SIer 泣かせのシステムが完成するそう。

ほんとに趣味の世界って広いなぁ…。と思います。

ytsuboi さん

題名は「名古屋駅裏にLoRaがやってきた」

LoRa という Low-Power Wide-Area 通信の一種の共有ゲートウェイを、駅裏にあるオフィスに設置されたそう。

IP 通信ではないとか、SORACOM のゲートウェイ・ネットワークサーバなので現状 SORACOM のシールドでしか繋がらないとか制限はあるものの、とにかく省電力で運用できるものだそう。

実際に街を歩いてどこまで電波が取れるかと調べた結果、実測 500m ほど飛ぶそうで (オフィスが1階のため) 、円を描けば駅西もすこしの距離カバーできてるみたいです。

タッパーを持ち歩いている姿見たかったなぁ

IoT が注目されるに従って、こうした省電力な通信ってどんどん注目されてきている気がしますよね。これを広めていく方々、いわゆるフロンティアな方々は、本当に尊敬します。

もしかしたら将来 LoRa が一斉を風靡するようになるのかもしれませんね?

くぅ さん

題名は「」

出来れば Unicode 座標書いて欲しかった

Android Things 使ってみたよ!という紹介。そういえばそんなものもありましたね…。

Raspberry Pi など IoT 向けの Android ビルドで、 Java や Kotlin で開発できる非常にユーザフレンドリな OS らしいです。

インストールもネットからイメージを落としてきて SD カードに焼けば認識するみたい。非常にお手軽。

IoT なだけにピン操作が標準 API として用意されているそうです。

ところが、 GUI を扱えるがために通常の Android のアプリを動かせるかなぁとやってみると、簡単には動かず。本家 Android にはあって Things には無い API が多数存在したり、非推奨という名の非対応があったりするそう。

スペック的に追いつかないとか、そもそもフル Android 動かす必要がないとか理由はたくさんありそうですが、これだけ聞くとなかなか手が出せないですね…。

kaizen_nagoya さん

www.slideshare.net

題名は「IoT のサイバセキュリティ対策」

最初の方、 Q&A 形式でこんなの知ってますかーという質問が20問30問くらいあったのですが、全くわからず…。

というのも、セキュリティについての団体を作ろうという計画をされているそうで、それくらい知識がないと務まらないほど高度な作業のようです。

多くの方からシミュレータでいいじゃんなど突っ込まれていたのですが、真摯に

「オーバースペックな処理をしてマシンが燃えた時どうなるか、を検証しなければいけない」

と答えられていて、本当に高度すぎるお話ですありがとうございました。

私達の普段知らないところで、こうした超高度な方々が作業されているからこそ、私達が平和にプログラミングを組めているんだなと思います。本当に感謝です。

わみ さん

題名は「クラウドファンディングの話」

Nerfy というデバイスを作成されているそうで、その資金の調達をクラウドファンディングで行われたそうです。

codezine.jp

会社で別のデバイスクラウドファンディングが成功したので、これはいけるのでは?と挑戦されたのがきっかけだそう。

結果、無事大成功され生産決定されました。おめでとうございます!

ただ実際に当事者になってやってみると大変なことが多かったそうで、量産しなきゃとか、告知しなきゃとか色々と不安要素は多かったみたいです。

そう言われれば、私がこの間投資した Nintendo Switch 用のポータブル充電器を知ったのも、ネットのニュースサイトで取り上げられていたからで、ああいう場所で知らなければ全く気づかずにスルーしてたんだなぁと。

表では手軽で気楽なイメージですが、裏では必至に作業をされているんだなぁと感じました。

まとめ

初の LT 大会とだけあって、終わってみると他の勉強会よりヒアリング重視だったなぁと思います。要するにメモが少ない。

いろいろ笑いを交えながら思われたことを素直に発表されていて、みなさん本当に楽しまれているんだなぁと感じました。

これからどんどんデバイスが普及していって、もはや IoT と特別視されなくなっても、こうした体験が基礎として活きてくるのかもなぁと。

また一段と興味が湧いて来ました。本当にありがとうございました。そして、お疲れ様でした。

コレクション初期化子とオブジェクト初期化子はどちらが優先されるのか

ちょっと気になったのでメモ。

結論

オブジェクト初期化子のほうが優先される

実験

No.1

まず、普通にオブジェクト初期化子を書く。

using System.Collections.Generic;

namespace ClassInheritedListSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Hoge hoge = new Hoge { A = 1, C = 2 };
        }
    }

    class Hoge
    {
        public int A { get; set; }
        public string B { get; set; }
        public int C { get; set; }
    }
}

オブジェクト初期化子に違いない。

No.2

次に、 List<int> を継承してみる。

using System.Collections.Generic;

namespace ClassInheritedListSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Hoge hoge = new Hoge { A = 1, C = 2 };
        }
    }

    class Hoge : List<int>
    {
        public int A { get; set; }
        public string B { get; set; }
        public int C { get; set; }
    }
}

オブジェクト初期化子のままだ。

f:id:yuzutan_hnk:20170923022100p:plain:w600

No.3

次に、 Program クラス側に同様のプロパティを定義する。

using System.Collections.Generic;

namespace ClassInheritedListSample
{
    class Program
    {
        public static int A { get; set; }
        public static string B { get; set; }
        public static int C { get; set; }

        static void Main(string[] args)
        {
            Hoge hoge = new Hoge { A = 1, C = 2 };
        }
    }

    class Hoge : List<int>
    {
        public int A { get; set; }
        public string B { get; set; }
        public int C { get; set; }
    }
}

オブジェクト初期化子のままだ。

f:id:yuzutan_hnk:20170923022359p:plain:w600

No.4

Program に用意したプロパティの型を変えてみる。

using System.Collections.Generic;

namespace ClassInheritedListSample
{
    class Program
    {
        public static int A { get; set; }
        public static int B { get; set; }
        public static int C { get; set; }

        static void Main(string[] args)
        {
            Hoge hoge = new Hoge { A = 1, B = 2 };
        }
    }

    class Hoge : List<int>
    {
        public int A { get; set; }
        public string B { get; set; }
        public int C { get; set; }
    }
}

これもオブジェクト初期化子のまま。 Hoge.B の型が int じゃないと怒られる。

f:id:yuzutan_hnk:20170923022737p:plain:w600

No.5

かっこで括る。

using System.Collections.Generic;

namespace ClassInheritedListSample
{
    class Program
    {
        public static int A { get; set; }
        public static int B { get; set; }
        public static int C { get; set; }

        static void Main(string[] args)
        {
            Hoge hoge = new Hoge { (A = 1), (B = 2) };
        }
    }

    class Hoge : List<int>
    {
        public int A { get; set; }
        public string B { get; set; }
        public int C { get; set; }
    }
}

やっとコレクション初期化子になった。

f:id:yuzutan_hnk:20170923022932p:plain:w600

どうしてこうなるのか

C# 5.0 の言語仕様 7.6.10.3 項を見ると、書いてあります。

コレクション初期化子は、"{“ トークンと ”}“ トークン内のコンマで区切った要素初期化子のシーケンスから構成されます。各要素初期化子は、初期化対象のコレクション オブジェクトに追加する要素を指定し、”{“ トークンと ”}“ トークン内のコンマで区切った式のリストから構成されます。単一式の要素初期化子は、 かっこなしで作成することができますが、メンバー初期化子とのあいまい性を防ぐため、代入式にすることはできません 。non-assignment-expression の生成は 7.18 で定義されています。

ここでいうメンバー初期化子とは、たぶんオブジェクト初期化子で使用される A = B の形式のものだと思われます。明確な定義が見つけられないのですが、オブジェクト初期化子の説明にもメンバー初期化子という言葉が使われています。

オブジェクト初期化子では、メンバー初期化子の形式は次のようにあります。

オブジェクト初期化子は、"{“ トークンと ”}“ トークン内のコンマで区切った一連のメンバー初期化子から構成されます。各メンバー初期化子では、 初期化対象のオブジェクトのアクセス可能なフィールドまたはプロパティを指定し、その後に等号と式、またはオブジェクト初期化子かコレクション初期化子を指定する 必要があります。オブジェクト初期化子に、同じフィールドまたはプロパティに対する複数のメンバー初期化子を含めるのは誤りです。オブジェクト初期化子は、初期化対象の新しく作成したオブジェクトを参照することはできません。

上記二つから考えるに、コンパイラ的には

  • 名称 = から始まる要素が1つでもあれば、オブジェクト初期化子
  • のみで構成される要素しかなければ、コレクション初期化子

と分類している気がします。

dynamic なオブジェクトに IntelliSense を表示する

ネタです。ホントは出ちゃいけないんじゃないの?という記事。

Visual Studio 2015 で最初確認したんですが、家に帰ってきて 2017 でやってみても同じ結果でした。

Roslyn のせいなのかな?

コード

namespace dynamicIntelliSenseTest
{
    class Program
    {
        static void Main(string[] args)
        {
            (0 as dynamic) // この後ドットをつけると補完が出てしまう
        }
    }

    static class Hoge
    {
        public static void ホントは出ちゃいけないんじゃないの(this object hoge){
            return;
        }
    }
}

f:id:yuzutan_hnk:20170908012633p:plain:w600

dynamic の実態は object 型なので間違ってはいないのですが、入力した後は定義を紛失するようです。

f:id:yuzutan_hnk:20170908013007p:plain:w600

OWASP Nagoya Chapter Meeting 1st に参加してきた話

f:id:yuzutan_hnk:20170903144157j:plain:w300

よりによって普段セキュリティなどまったく気にしない私が、よりによってセキュリティの世界的コミュニティ OWASP の名古屋チャプター、よりによって設立後初の勉強会に、よりによって参加してきた話。

先日の Xamarin 勉強会の懇親会でお世話になったまるちゃんさんが宣伝していたり、前々から connpass で見ていたりして知ってはいましたが、直前まで参加するかどうかは悩んでいました。

でも、何事もやらなきゃはじまらないな、と思い立ち参加してきました。

私のセキュリティレベル

前の Xamarin の記事を読んでいただければわかると思いますが、ソフトウェアエンジニアやっていながらこういった問題に関しては全くの無知です。

CVE?とか監視してないし、 Java のアップデートとかセキュリティに特に重要になってくると思いますが、何か月前から放置してるし。

Xamarin の場合は、 Mono とか .NET とか前提知識があったので何とかついていけましたが、セキュリティに関しては本当にわからないことだらけ。というか何を勉強すればよいのかもわからない。

でも、せっかくの OWASP Nagoya Chapter 設立後初の勉強会だし、きっかけ作りとして行ってみてもいいかなと思って行ってみることにしました。

とりあえず前日の夜から CTF を少しやってみたんですけど、 SQL インジェクションできずに諦めて寝ました。朝6時に。

迎えた当日

会場は、名古屋駅からほど近い愛知大学名古屋キャンパスの 8 階の教室。

あの 109 シネマズの目の前にある大学で、設備がもはやオフィス並み。エスカレータはおろかエレベータまでついてる。というか 8 階まであるって、とんでもない大学ですね…

名古屋駅側から地上を歩いていくと、誘導係の方が数人。ちょっと陰になったところに入り口がありましたが、わかりやすい説明のもと迷わず行くことができました。

実は 100 人規模の勉強会だけあって、教室は超満員。ひろい講義室にプロジェクタの画面 3 つとでっかい BOSE のスピーカー。

大学の講義を聴くような感覚ですが、なかなか面白そうな雰囲気で勉強会がはじまりました。

勉強会スタート

OWASP Nagoya Chapter Leader 坂梨 さん

まず初めに、 OWASP Nagoya Chapter の Chapter Leader を務めていらっしゃる、坂梨さんから OWASP についての簡単な説明がありました。

OWASP とは

OWASP - Open Web Application Security Project は、 セキュアなソフトウェア開発を促進する技術、プロセスに関する情報を普及・啓発するオープンコミュニティ 。もっと詳しいことを話されてましたが、早すぎてメモれず…。

OWASP

コミュニティ内でのノウハウを集めたドキュメントや、ツールなどが無料で使えるというものらしいです。

世界各地に チャプター というローカルな活動拠点があり、その数 276 チャプターが現在あるそう。

さらに、 OWASP Project というプロジェクトがいくつもあり、代表的な

  • OWASP TOP 10
  • OWASP Zend Attack Proxy (ZAP)

をはじめ全部で 93 もあるそう。活発ですね。

OWASP Nagoya の使命

日本には OWASP Japan をはじめ、全部で 10 のチャプターがあり、 OWASP Nagoya はその 記念すべき 10 番目。

世界中で議論されているセキュリティ情報を名古屋から広め、名古屋から世界に向けて新たな情報を発信していくことが OWASP Nagoya Chapter の使命だそうです。

Nagoya といえど名古屋に限らず、東海地区を中心に活動していくんだそうです。確かにこの辺りにセキュリティ関連の団体ってなかなかないですよねー、って思ったんですけど、

  • 名古屋情報セキュリティ勉強会
  • ISACA 名古屋支部
  • CISSP 東海コミュニティ

と、案外セキュリティに関する団体はあるみたいで、連携を取りながら活動をしていきたいそう。

OWASP Kansai Chapter とのテレビ通話

OWASP Kansai も同日に勉強会が開催されていたそうで、ビデオ通話で会場を繋げました。

どこかのカフェなのか、おしゃれな丸テーブルが並び 4, 5 人グループになって座っているような形で、なかなか気楽なムードでした。

あちらも 100 人越えの規模で、熱気はどちらも劣らず。コミュニティってすごいなぁと思いました。

ただ、サブ画面でビールサーバからビールを注ぐ映像が淡々と流れていて、めっちゃラフな勉強会だな!?と驚いたりしたんですが、後々聞いてみたら大阪はいつもあんな感じらしいです。さすが大阪…。

感想とか

connpass で OWASP を初めて見たとき、セキュリティに関してだからすごく高度で、ちょっとおかたい雰囲気なのかなと早とちりしていたのですが、実際に来てみるとそうでもなくて、とても楽しそう。

肩の力が抜けたというか、何の変哲もないただの紹介のお話だったのに、どこか面白かった。

こういう空気もいいなぁ、と思いました。

OWASP Nagoya Chapter Leader 岡田さん

株式会社 アスタリスク・リサーチ 代表取締役。 OWASP Japan Chapter Leader でもあるすごい人。

2012 年 3 月に OWASP Japan ができる前、 OWASP Tokyo なるものがあり、そこで OWASP Developer Guide を翻訳したりしていたらしいです。もはや大御所ですね…。

スペアリブ美味しそう。

OWASP Japan への思い

OWASP Tokyo ができる少し前、1年ほどかけていろんなサイトのセキュリティに関しての対策を、サイトの設立者のもとまで足を運んてヒアリングして回ったことがあるそう。

その結果、パスワードをグループで使いまわすシステムだとか、 HTTPS に対応していなかったりだとか、システムを停止させたくないのでアップデートをしないだとか、そうしたセキュリティへのおざなりな姿勢が浮き彫りになったそうです。

もっと気軽にセキュリティに対して興味を持ってもらえる環境を作っていきたいと思っていた矢先、 OWASP Tokyo が設立からわずか 3 ヶ月で解散してしまいます (もともと企業絡みだったため) 。

そこで、日本全国に門戸を開こうと、 OWASP Japan Chapter を設立 (再設) されたそうです。

現在では全国に 9 つのローカル Chapter が存在していますが、 OWASP Japan ではそうした Chapter がない場所でも積極的に活動を行っていく方針だそうです。

聴いていて、心にグッとくる内容でした。

OWASP について

坂梨さんが説明されていましたが、もっと詳しく説明をされました。

Who is OWASP

「OWASP が~~と言っているから」とネット上に書き込んでいる人がいるみたいだそうですが、コミュニティの名前であって、人の名前ではない。

OWASP のメンバー

米国にいる中心メンバー数人以外は、全員ボランティア。

ボランティアだからこそ、プライスレスに活動ができることも多々あるそう。スポンサーがついてくれるということでしょうか?

OWASP’s DNA

OWASP のモットーは、「 やってから謝る 」こと。

いつかの APSEC というカンファレンスで Facebook の CIO がこんな発言をしたそうで。

最善のセキュリティを尽くせないのであれば、ほかのことをやれ

たとえば Facebook のユーザの 1/3 は、端末が SHA-1 ハッシュ化しか対応しておらず、高度な暗号技術を利用できない状態にあるのですが、それをセキュリティを重視するからといって切り捨ててしまうのはおかしい。

つまりセキュリティ管理者は、そうした 最善のセキュリティを尽くせないユーザ に対応するため、 プランB を考えなければならない。

たとえ先進国では最善の策を講じるとしても、ほかの地域では強制的に対応することはせず、ほかの認証や技術によってそれを補う形でセキュリティを担保する。

こうしたときに重要になってくるのは、 いろんなやり方を否定しない ことであり、発言したり実行したりした後から「この問題は考えていませんでした」というパターンも当然ありうるそう。

だから、 やってから謝る 。なんだかこのあたりは終始考えさせられる内容でした。

OWASP の活動

OWASP Japan だけでも Chapter Leader はたくさんいるし、世界ではもっとたくさんいるそう。 Leader がたくさんいるということは、他のメンバーもたくさんいるわけで。

世界中で様々な議論がされ、その成果物が無料でネット上にアップされているそう。ちょっとわからないことがあれば OWASP で検索すればなんでも出てくる、というレベルで。

基本的に英語で書かれている (英語で議論された) ものですが、日本のメンバーによって翻訳されているものがいくつもあるので、 (チートシート、 IoT プロジェクトのドキュメントなど) どんどん活用していってほしいそうです。

さらに今回のような勉強会で集まれば、同じ興味を持った仲間の顔が見れるからいいね、とおっしゃっていました。やっぱこうして集まるといいですね。

すごい!飲み会

すごい!飲み会

セキュリティへの 3 つの視点と、シフトレフト

このセクションの冒頭前後、異常な腹痛に襲われてしまい席を外していたので、当時の TL と戻ってきてからの話でちょっとだけ推測して書きます。間違ってたら容赦なくご指摘ください。

Shift Left とは

セキュリティを考えるうえでまず思い立つものといえば、一般的に 何が盗まれたか、何が壊されたか 。しかし、セキュリティはそんなに甘くはない。

顧客のクレジットカード番号が漏洩した、という問題について、それはなぜ起きたのかを考える必要がある。これは、どうして漏れたのか、すなわち どんな準備が不足したから問題が起こったのか という、問題が起こる前のことを考えるということ。

さらに言えば、 なぜ不足してしまったのか という根本的なことも考えていく必要がある。

そうした、時系列にして前に々にと考えていく (一般的に時系列は左から右に進むため、その逆である 左に進む ) ことを シフトレフト というらしい。

そして、シフトレフトを考えるうえで重要な 3 つの視点について解説してくださった(この部分が一番わからない、完全なる予想)

Attack Surface

単純に、 どこから攻められるか 。アプリケーションで言えばどの画面から攻められるか、システム的に考えればどの機能から攻め込まれるか。

日本語で言えば 攻撃面 。穴が露出していればそこから入ってきてしまうということですね。きっと。

攻撃側はそうした 攻撃面の調査 、それを踏まえた 脆弱性の発見 を売買するエコシステムを成立させていて、一度見つけられてもすぐには利用されない。いつかどこかでその情報を買った人が、自分が作ったウイルスに組み込んで使う、ということが一般的だそう。

(ここら辺から復帰)

つまり根本的には、脆弱性の情報が売られないため、攻撃面 (弱い面) を見つけられないということが重要だそうです。

攻撃面を意識すれば、おのずと脆弱性は防がれ、攻撃されない、という根本的解決につながる。これがシフトレフト的視点。

OWASP には Attack Surface脆弱性、それによって盗まれる可能性のあるデータが関連付けられて掲示されているみたいです。気になったときには調べてみたい。

IoT Attack Surface Areas - OWASP

コンポーネント

昨今では、エンジニアが製作するシステムのうち、 OSS の割合がほとんどを占めていて、実際にエンジニアが作成しているシステムはほんの一部になっている。

つまり、自分で書いたプログラムやシステム以外の場所に脆弱性がある可能性が非常に高く、実際にそれらを知らずに使うことが多いそうです。

天才がプログラムを書けば 10000 行につき 2,3 個のエラーで済むものの、普通のプログラマが書けば 1000 行に 1 個の割合でエラーが含まれるそうで、そう考えると OSS脆弱性がある可能性ってものすごく高いんですね。

自分ですべての責任を持っているプログラムを出荷しているプログラマって、本当に少ないそう。

使うコンポーネントはしっかりと選ぼう、ということでした。

例として挙げられていたのは、とある超有名な OSS のソースの中に、 パスワードが入力されていなければ ××× にする というロジックが含まれているのを見たことがあるらしい。つまり、パスワードがばれているようなもの。

恐ろしいことに、これが脆弱性として報告されていない (正規のプログラムとみなされている) んだそうです。

こうした問題を許せるようなプロダクトであればいいのですが、そうでないプロダクトの場合は言語道断でしょうし、しっかりと調べたうえで使わなければいけないさそうですね。

プロセス

名古屋では有名なかんばん方式、これはプログラムには当てはまらない。なぜなら、プログラミング自体が設計に値するから。

けれど、プログラムを作るにも設計は必要。スケジュールとか納期とかそういったものだけではなく、セキュリティに対しても重要だそうです。

OWASP TOP 10OWASP Proactive Controls のようなドキュメントには、 どうすれば脆弱性が止まるか というベストプラクティスが書かれている。日常生活で言えば、手洗いやうがいにあたるらしい。そう考えると、たしかに簡単な予防を続けることで、大きな事故にならなくて済むということは、よくありますね。

システムを作る初期の段階から、運用を見据えて設計していき、脆弱性を潰していく。常に前段階でユニットテストを行い、盤石なシステムを築いていくということが大事。

OWASP で公開されている Open SAMM を使うと、プロジェクトの成熟度を定量的に測ることができ、どこに力を入れているのか、そしてどこが弱いのかを視覚的に表せるため、おすすめだそう。

www.opensamm.org

まとめ

岡田さんの SHIFT LEFT やセキュリティへの熱い思いがとても伝わってきました。

OWASP Nagoya で初めてだからなのかとても概念的な話が多かったのですが、 OWASP がどういう方向性で、セキュリティを考えるとはどういうことかという、とても基礎的なものが学べたと思います。

学校でも仕事でも、これまで具体的な技術とか攻撃の方法だけとか、いわゆる 即戦力 になる知識しか得てこなかったのですが、ちょっと視点を変えるだけでセキュリティに対してこんなにも熱くなれるんだという、 経験力 を見ることができて、幸せです。

なかなかこういう機会、私は持ち合わせていないので新鮮…。

OWASP Japan Advisory Board 徳丸さん

徳丸浩のWebセキュリティ教室(日経BP Next ICT選書)

徳丸浩のWebセキュリティ教室(日経BP Next ICT選書)

とてもすごい人だそうです。お名前だけは伺っております。

先のお二方とは違い、格段にレベルの高い実践的なお話をしていただきました。

脆弱性とは

脆弱性、と一言で言っても多種多様。たとえば、

  • パスワードを推測され、 認証を突破される
  • マルウェアによって 認証を突破される
  • 基盤ソフトの 潜在的な弱みを突かれる
  • 自分で書いたプログラムの 弱みを突かれる

簡単に言えば、そうした脆弱性というのは 悪用されるバグ のことであって、 バグを減らせばセキュリティ向上がある程度見込める のだそう。

国際的な分類

脆弱性の情報を国際的な基準で分類する仕組みがある。

  • CVE
    • Common Vulnerabilities and Exposures
    • ソフトウェア個別の脆弱性情報
    • 米国政府の支援を受けた MITRE 社が採番
    • 既知の脆弱性を対策するということは、 CVE を参考にすることが多いらしい
  • CWE
    • Common Weakness Enumeration
    • 汎用的な脆弱瀬瑛を識別する
    • 体系化されている

信頼境界とは

Java セキュアコーディングスタンダードの例を解説されていました。

分類番号 IDS00-J は、もともと「境界を越えたデータを信頼しない、無害化しなければならない」という意味のコードだったそう。

ここでいう境界とは 信頼境界 と呼ばれるもので、システムの外側との境目、つまりシステム設計時に不明な領域との境目ことらしい。つまり外側の領域は、簡単に言えばユーザからの入力やディスク環境。

解説ではデータベースのやり取りにおいて、信頼境界外から受け取ったデータをデータベースと連携して利用するときは、必ず無害なデータに変換しなければならない(フィルタにかける)としているそう。

この説明を聞いて、誰もが システムの外側 (ユーザからの入力など) を自身が実装しているシステムの信頼境界で無害化し利用する必要がある と解釈するだろう、と徳丸さんは言う。

そんなこと本当にできるの?と徳丸さんは続ける。

実際、無害かどうかはそれを解釈する側の実装や仕様による。つまりデータベース側の実装によって無害かどうかの基準が変わってくるということだ。このことは Java セキュアコーディングスタンダードも把握して書かれているようで、 解析器側に無害化アルゴリズムが存在しているのであればそれを使うのが望ましい と解説されているそうだ。

多くのデータベース (またはそのやり取りを担保するフレームワーク) には、 プレースホルダ という無害化する実装がある。 SQL を穴あきの状態にしておき、そこにデータを埋め込む作業をデータベース側が行うというものだ。 ※動的プレースホルダについては割愛

もはや、 システムの信頼境界を考えるのは無意味だったのだ 。というか、データベース側の信頼境界をそのまま流用しているような気がする (私たちのコード自体が信頼境界外)。

この話のオチは、 Java セキュアコーディングスタンダードの IDS00-J につけられたタイトルが「 SQLインジェクションを防ぐ 」になったこと。解説にももはや信頼境界などという言葉は出てこないそう。

でも、徳丸さんはこれもセキュリティの進化の結果だと捉えているそうだ。こうしてセキュリティは進化していくんだなぁ…? (わかってない)

信頼されるデータとは

IPA が公開している「安全なウェブサイトの作り方」にも、信頼境界という言葉は出てこないけれど、概念自体は登場するそう。

というか、自分たちにとって信頼が必要なデータは何かを考えることが大事だそうだ。

例えば、

  • プログラムコードそのもの
  • SQL 文、 eval 文
  • 設定ファイル名
  • 正規表現
  • オブジェクト

といったものは、プログラムが動いていくうえで信頼されていなければならない。こうしたものを、いわゆる信頼境界の外側、 外部から入力できないようにする ということが重要。

どうしてもこれらを外から指定しなければならないとき (掲示板で HTML の装飾タグを使いたいとか) は、フィルタを使って無害化を行う。

  • ログイン済みユーザ名 (認証)
  • 管理者が入力できるようにした SQL (認可)
  • HTML タグを制限 (フィルタリング)
  • 外部からのファイル名 (basename)

上記のように、信頼するしかないデータ、信頼できなければ無害化すれば良いデータ、はじめの方に出てきた信頼しなくても良いデータ (プレースホルダに入れる場合など) と、データの意味を理解してセキュリティ対策を行う必要がある。なるほど深い。

よくわかるPHPの教科書

たにぐちまこと著、『よくわかるPHPの教科書』という本を参考に、セキュリティ攻撃の実践を行ってくださいました。

さて、皆さんお待ちかねの時間ですね。誰だ祭りだなんて言ったのは。

SQL インジェクション攻撃

セキュリティ攻撃の代表格とも言える、 SQL インジェクション。サーバサイドプログラミングに多少の実装差異や漏れがあると、悪用されてしまう。

たとえば $id に 「 88-1 」という文字列が入っていたとする。

  • UESR_NUMBER = sprintf('%d', $id) とすると USER_NUMBER = 88 と解釈される
  • UESR_NUMBER = $id とすると USER_NUMBER = 88-1 となり USER_NUMBER = 87 と解釈される

と、ほんの些細な実装差異によって、本来意図した挙動を示さなくなります。

この脆弱性を利用して、簡単な掲示板サイトで SQL インジェクション攻撃を実演されました。記事を削除するときにユーザ ID を偽装し、いともたやすく他人の投稿を消すことができてしまいました。

このようにエスケープ処理を施さず SQL 文に入力文字列を直接連結してしまうのは大いに危険だと言います。

応用的な SQL インジェクション攻撃として、 ブラインド SQL インジェクション も紹介されました。これは、 SQL が副問い合わせに対応していることを悪用し、 ANY(SELECT USER_NUMBER FROM T_USER) などと入力して攻撃を行うことだそう。これが恐ろしいのは、たった一つのデータではなくすべてのデータがヒットしてしまうということ。

実演として、たった20行足らずのプログラムで実際にデータベースの中身をすべてかっさらっていかれました。ユーザ名とパスワードのハッシュ値が駄々洩れの状態に。

世間にはこうした SQL インジェクションを行いやすくする、通称 SQL 注入工具というものが出回っているそうで、中にはセキュリティ企業が販売しているものもあるそう。誰でも簡単に行えるようになっているみたいです。

ますます SQL インジェクションが恐ろしいものだということがわかってきました。ちゃんとプレースホルダを使おう、文字コードを指定して文字化け攻撃を食らわないようにしよう、ということでした。

CSRF 攻撃

日本でもこの手口を用いて、なりすまし犯行予告事件が起きました。

細工されたサイト…具体的には iframe が埋め込まれたサイトを用意して、その中に action 属性に爆撃先サイトを指定した form タグを配置します。 iframe の高さを 0 にしておけば、見た目はわかりません。

そうすると、それを開いたブラウザが iframe の中身を解釈し、そこにある任意のコードを実行してしまいます。実行するのは閲覧者のブラウザですので、完全になりすましができてしまいます。

このような攻撃への対策としては、セッション毎にハッシュ値トークンを比較して認証を行うことで、不正に CGI へコマンドを送っても処理しないようにする、という対策が有効だそうです。

XSS (クロスサイトスクリプティング)

ブラウザで見ているドメイン (オリジン) 上の他のサイトで任意の javascript を実行できる、という脆弱性を活かした攻撃。

ウイルスではないとされているそうですが、ワームには分類されるそう。

少し前までは (学校で習ったような内容としては) 、プログラム文字列が掲示板に登録されてしまいそれが潜在的にブラウザに残り、別のサイトを閲覧中に発動してしまう、ということが多かったそうですが、最近はもっと手口が多くなっているそう。

今回紹介されていたのは、掲示板におけるアイコンファイルの細工。アップロード時に画像ファイルかどうか判別するためにファイル名の下 3 桁をチェックしていましたが、ピリオドまではチェックしていないため、拡張子なしのファイルがアップロードできてしまいました。

サーバ設定によっては拡張子なしのファイルを text/html とみなして実行することができるそうで (規定では OFF になっているけど) 、アイコンとして表示しているにもかかわらずブラウザ上では通常のサイトと同じ状態で解釈し、 javascript を実行してしまいます。

ブラウザ上で実行されるだけでなく、二重拡張子を使うなどしてサーバ上で実行可能なプログラムがアップロードされると、サーバサイドがそもそも危険にさらされることになります。とくに実演では webshell というブラウザからサーバ上で UNIX コマンドを実行できるという チートな プログラムをアップロードし、サーバを完全に乗っ取っていました。本当に怖い。

感想など

実演や時折笑いを交えながらわかりやすく解説され、セキュリティの重要性や危険性が身に染みてわかりました。

数々の脆弱性は局所的な対策の積み重ねで食い止めることができる、と最後におっしゃっていたのですが、私のようにセキュリティに疎いとその重大さに気づいていないから、おざなりな姿勢になってしまうのかなと思いました。

中途半端な憶測や推測をせず、しっかりと地道に対策すれば、セキュアなシステムは実現できる。改めて実感しました。

OWASP Nagoya Chapter Leader 村井さん

勉強会の最後に、 OWASP Nagoya のこれからの活動について紹介してくださいました。

OWASP Nagoya Local Chapter Meeting / OWASP Day

スクール形式の勉強会や、外部講師を招待しての講演、 OWASP で公開しているドキュメントの紹介など、 至って真面目な イベントのようです。とはいえ今回のムードからしてそこまでお堅くはなさそう。

直近では、 11月に OWASP Nagoya Local Chapter Meeting #2 が開催されるそう。行かなくちゃ!

OWASP Nagoya Hands-On

ハンズオン形式でのセミナー、 OWASP で公開しているツールの紹介など、 至って真面目な イベントのようです。座学だけではわからないことも、ここでしっかりと理解できそう。

直近では、 2018年 3月に OWASP Nagoya Hands-On #1 が開催されるそう。行かなくちゃ!

OWASP Night in Nagoya

すごい!飲み会

すごい!飲み会

セミナーや、 LT で行う カジュアルな イベントのようです。わいわいと盛り上がりながら、セキュリティへの意欲を高めていくのだそう。

直近では、 2018年 1月に新年会も兼ねた OWASP Night in Nagoya #1 が開催されるそう。行かなくちゃ!

OWASP World Tour 2017 Tokyo / Nagoya Satellite

一般募集だと思った?残念、来場特典でした!

2017 OWASP World Tour Tokyo - OWASP

9月 30日に行われる OWASP World Tour 2017 の東京講演を名古屋で視聴できるサテライトイベント。今回の勉強会のまさにその場で connpass に公開していただき、真っ先に応募することができました。

会場は今回と同じ愛知大学で最大 40人 のところ、公開直後すぐ満席状態になってしまいました。私はとりあえず確保できました。

OWASP の Wiki を見ると会場変更されるかも?定員増えるかも?と示唆されているので、応募すればもしかしたら優先的に確保してもらえるかも。行かなくちゃ!!

懇親会に参加してみて

f:id:yuzutan_hnk:20170903144159j:plain:w300

勉強会終了後、懇親会も行ってきました。

まともに飲み会も懇親会も行ったことがない中この規模に終始圧倒されていましたが、いろいろな話ができて面白かったです。

隣に座っていた某すごい方が岡田さんと対等 (?) に話をされていたのがとてもうらやましい。というか、自分の力不足さにとても失望した。もっと頑張らなければ、と改めて自覚しました。

おわりに

今回の勉強会は、初めは軽い気持ちで参加したけれど、振り返ってみると参加してよかったなぁと感じます。

セキュリティに対する関心を持てましたし、これからプログラムを作っていくうえでどれだけセキュリティが重要かを再確認できた気がします。

信頼境界のくだりは最近自分でも考えていたテーマで、ユーザをどこまで信用するか、どこで信用度チェックをするのか、という問いにひとまず結論がついたように思えます。たぶんすべてではないのですが。

自分の中で多くのきっかけができました。本当にありがとうございました。

最後になりましたが、長々と最後までお読みいただきありがとうございました。そして、お疲れ様でした。