Web開発現場を渡り歩くための技術的関心 2019

#この記事は
ジーズアカデミーアドベントカレンダー12日目 Side A

Side B はこちら

メンタルハック！　心を壊さず人より働く50の技術
https://note.com/moooooooooooooon/n/n50a660f7f20a

Dev10期卒の三宅です。たまにチューターで出入りしています。
曜日限定のインフラエンジニアと、フリーのWebエンジニアと、バーテンダーをやっています。

最近、個人でWeb開発プロジェクトに参加している私です。

Web開発ってプログラムを書ければよいのかと思いきや、領域を飛び越えてなんとかしなきゃならないことが多々あって、休みが全くないのが目下の悩み事です。

先日、打ち合わせでクライアントが話している内容が全く入ってこなくて、あれ？これ病気かなと思ったんですが、次の瞬間には口が動いてて意外にまともな説明になってて、あ、これは多分職業病なんだと思いました。

そんな中で、やはりまだまだ知らないことは多く直面して初めて焦りを感じることも多いのですが、その中でもこれは知っておいたほうがいいなと思って重点的に勉強しようと思った技術トピックを紹介していきます。

Web開発の中で立ち位置がある程度のレンジにまたがる、広く浅く系の人向けの内容だと思います。

#トピックのランク付け
そうでもない：☆
間違いなくそう：☆☆☆☆☆
##みんな知ってる度
業界的にどれくらい当たり前に知っているかです。
みんな知っているということは誰かに任せることができますが、誰も説明してくれないということでもあります。少なくとも不自由ない程度には知っておきたいという種類のものです。
##後がヤバい度
知らないで進めてしまうことによって後で壊滅的な被害を出しかねないものです。セキュリティホールができたりデータを吹っ飛ばしたりして改修に追われそうなやつです。
##武器になりそう度
お客さんが気にしていたり、知っておくと今後業界トレンド的に有利な仕事ができるのではないかと思われるものです。
　

#トピック
1. AWS: AWSは使えますよね？え、VMってなんです？
2. クロスオリジン: MDNが強調するほどヤバい割に浸透していないやつ
3. Googleクローラ: 真相は誰も知らないけど、知らないとも言えない雰囲気

#AWS
みんな知ってる度：☆☆☆☆☆
後がヤバい度：☆☆☆
武器になりそう度：☆☆
##AWSは使えますよね？え、VMってなんです？
AWSスキルって表現すると先進的な印象がありますが、大手企業のサーバーがだんだんAWSへアウトソースされていると言われると「そうだよね」ってなると思います。
保守会社さんもAWSで運用するところが多くて、VM触るよりAWSを扱うほうが得意だという人も割と見かける印象があります。

というかVMって言って伝わらないことすらあるので、もうVMの時代じゃないです。VMでは必須だけどAWSでは要らない知識も結構あるので、VMの知識はもう教養くらいに考えたほうがよさそうです。[^1]

[^1]: VM = 仮想マシン。実サーバーではないけどクラウドではないあれ。

ちなみにGCPはまだそんなに広がってないらしいです。当面AWSの1強か。え、Azure…？[^2]

[^2]: Azureは優れたツールだと思いますが、BtoB色が強く話題になりにくいですね。

##アカウントとIAM
いきなりAWSがとっつきにくい原因のアレ。
普通クラウドサービスと言えばアカウントでログインして利用する印象ですが、AWSのアカウントでログインするのはrootで端末を触っているような概念だと考えられているらしく、機能を制限したIAMと呼ばれるものを役割に応じて作ることになっています。

アカウントは企業と考えると分かりやすく、例えば
・使用するリソースを増やしたり削除したりするための権限を持ったIAM(責任者)
・予算管理や現在のコストをチェックするだけの権限を持ったIAM(経理メンバー)
・特定インスタンスをメンテナンスできる権限を持ったIAM(保守・開発メンバー)
といった形でIAMを作ることができます。

IAMの権限はKey:value形式で管理されていてkey毎に設定することもできますが、一般的によく使うであろう権限のセットが用意されているので、権限のセットを登録していく形で組み立てることができます。

基本は標準の権限セットでいいと思いますが、標準で用意されている権限のセットは自身のIAMのパスワードを変更する権限が付いていないようです。なんだこの罠仕様…。

##Amazon Linux
EC2が標準サポートしているOSです。標準サポートなので保守がアウトソースだと大体OSはAmazon Linuxになるようです。
パッケージマネージャーはyum、シェルはBashです。私の場合はとある保守会社にいきなり「CentOSは用意できないです」ってだけ言われたので若干ビビりましたが、この辺はCentOSと同じなので大したことではないです。


##EC2インスタンスを直接立てる
EC2っていうのがサーバー、あるいは仮想マシンみたいなものですね。
サーバーと呼ばずにインスタンスと呼ぶそうですが、これは設計をイメージとして保存して不要になったら消し去ることを標準的な運用と考えているのかもしれません。
インスタンスがスペック不足になればイメージからよりハイスペックなインスタンスを立ち上げて運用環境を切り替えるというのがVMとAWSでまず考え方が違うポイントだと思います。

設計書を保管して実体は作ったり壊したりするというのはコンテナも同じなので、AWSの考え方というよりは現代のスタンダードな気もしますね。

とにかく、EC2インスタンスのスペックを決めてOSイメージを選択するととりあえず環境が1つできます。これでいきなりアプリを動かそうというものでもないですが。

##セキュリティグループ
EC2インスタンスを立ち上げると自動的にネットワークみたいなものが立ち上がります。セキュリティグループという名前が付いていて、多分ネットワークなんだと思いますが妙なことにポートの解放設定機能が付いています。

EC2では個別のインスタンスでポート設定をするのではなく、セキュリティグループで管理するようになっています。多分、インスタンスをたくさん立てて機能ごとに分離するのを想定しているからなんでしょう。わざわざ全部のインスタンスでポート設定する手間は要りませんよ、という配慮だと思います。

ちなみにセキュリティグループは標準で「すべて無効」です。sshもつながらないですし、httpでアクセスすることもできません。AWSは基本的に運用を主眼に据えているのでしょう。[^3]

[^3]: sshぐらいあったほうが運用中便利そうですが、触る時だけ開けましょうというのがトレンド？

##キーペア
とはいえsshでログインできないというのは不便です。
多分AWSの事なので何とかする方法が用意されているのだとは思いますが、とりあえず触ってみるという意味ではsshを使うのが妥当でしょう。

しかしEC2インスタンスは初期状態で中に入る方法が…ない！？

中に入れないとなると鍵を置きに行けないので、そのためにキーペアの登録という手順が用意されています。キーペアは登録画面で作成するか、手元の環境でssh-keygenすればよいです。ただどうやら鍵の形式に制限があるようなので、とりあえず登録画面で作成してAWSの標準の鍵形式が何なのかチェックしたほうが楽かもしれません。[^4]

[^4]: rsaの2048桁だと通らず、rsaの1024桁で通りました。ご参考まで。

さて、このキーペアですがEC2インスタンスを立てる時に指定します。
…繰り返しますが、立てる時に指定します。

なので先ほど立てたEC2インスタンスはもう葬りましょう…なんだこの罠仕様…(2回目)。

「AWSってのはそうやって立てたり潰したりするものなんですよ」
ありがたいお言葉が聞こえたらそろそろAWSの思想に毒されています。私はそうです。
Yes, my father...[^5]

[^5]: 父なる神は厳しいものと相場が決まっております。

##RDS
データベースサーバーです。もちろんEC2を立ててデータベースをインストールして…という形でもデータベースを使ったアプリケーションの環境は作れますが、RDSを作ってEC2にくっつけるほうが立ち上げが非常に楽です。
しかもお値段もさほど変わらないので保守会社さんもこちらを好みます。ということは開発者もRDSの仕様くらいは理解しておいたほうがいいということですね。

開発にとって恐らく一番大きいのは各種DBの最新版には対応していないということです。ですからRDSと聞いた瞬間に仕様と設計を一度確認したほうがいいかもしれないません。[^6]

[^6]: 現在サポートの中心になっているのはMySQLだそうです。postgresqlは若干アップデート遅い？。

##Elastic beanstalkとかFargateとか
今研究中の分野です。標準的な使用方法はEC2を直で立てるパターンだと思いますが、Elastic beanstalkを使えばEC2+RDSの環境を丸ごと立てたり、環境ごとアップデートして古い環境を捨てたりするのが楽に行えます。

またFargateのようなコンテナ単位でリリースできるサービスもあり、AWSだけでも色々なデプロイパターンがあるので、これらに対応できるようになっておくと大小さまざまなプロジェクトで役割を取って行けそうです。[^7]

[^7]: が、知っていてもインフラ役になってコード書く割合が減ると嫌なのでアピールはしません。

#クロスオリジン
みんな知ってる度：☆
後がヤバい度：☆☆☆☆☆
武器になりそう度：☆
##MDNが強調するほどヤバい割に浸透していないやつ
G's関係者の皆様は我らが山崎大先生がセッション管理とCORSを授業で触れているのでご存知だと思いますし、私も一応「へー、そうなんだ」ぐらいには知っていました。
しかし、いざ自分で設計レベルから考えると厄介なことに気が付きます。

まず何が厄介かというと、CORSのセキュリティの仕組みはブラウザによる制限に頼っているのでブラウザ側にセキュリティホールがあると簡単に破られるということ。

それでいてデータベースの中身を引き抜かれたり書き換えられるリスクをコントロールしている非常にヤバい部分。
安全と思われる方法は、サーバーサイドでsession認証するか[^8]、もしフロントエンドフレームワーク+APIの構成にするならフロントとサーバーの両エンジニアが共通仕様を理解してヘッダを設計すること。

[^8]: ということで、g'sの授業で作られたphpアプリは安全なのであります。

我が敬拝するMDNも「全員知っているべきことだよ！」と太字で書いております。[^9]

[^9]: フロント担当に「こっちでやること無いですよね？」って言われたので「はい」って答えました。それが現実…。

##いきなり私も理解していないことから話しますが
そもそもサーバーに対してhttpリクエストを投げる方法って結構あるんですよね。
ブラウザ上でaタグのリンクをクリックしたりフォームのボタンを押したりするとGETが、フォームがPOST方式になっていればPOSTでリクエストが飛びますし、POSTMANみたいな開発ツールを使えば容易にGET、POST、DELETE辺りを投げることができます。[^10]

[^10]: POSTMAN: https://www.getpostman.com/ APIの挙動確認にすごく便利です。

それ以外にもUNIXで使えるwgetやcurlコマンドでも送ることができるほか、エクセルマクロでおなじみのVBAでも送れるのでブラウザからのアクセスに対してだけ対応すればいいというものでもないはずです。
実際のところ、wgetをブロックする仕組みとかを実装しているケースもあるらしいので、突き詰めてセキュリティを考え出すと結構大変な気がします。正直この辺は全く理解が及んでいないです。

それでも、少なくともブラウザからのアクセスにで送られるリクエストに関してはまず対処しましょうというのがここからの話です。

##Simple Request
ブラウザから送られてくる「単純なリクエスト」です。と言っても意味が分からないと思います。私もこの呼び方は意味不明だなと思います。

これは歴史的にブラウザが画面遷移を伴ったリクエストしかできなかった時代から持っているリクエスト方法で、ユーザー視点で見ればリンクをクリックしたりフォームを送信するようなものです。

技術的な視点でいえば
・GET, POST, HEADのいずれかである
・決められたヘッダオプション以外にヘッダオプションが付けられていない
・content-typeが決められた3タイプのどれか
であると、ブラウザはクロスオリジンへのアクセスに制限を設けません。

ざっくりいえばこれがsimple requestです。詳細はこちら。
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Examples_of_access_control_scenarios

ここで大事なのは、フォーム送信とかurlパラメータとかで受け取る部分にセキュリティは一切かからないので、手始めにバリデーションはしっかりしましょうということですね。

##XMLHttpRequest
Ajaxでのリクエストの場合は、リクエストヘッダーに'X-Requested-With': 'XMLHttpRequest'の値が付きます。javascriptで規定されたXMLHttpRequestと呼ばれる規格です。
javascriptの規格でXMLHttpRequestインスタンスは'X-Requested-With': 'XMLHttpRequest'のヘッダを持つことになっており、ヘッダーの書き換えを制限する仕組みになっているようです。

このヘッダーを持っているとsimple requestの要件に当てはまらなくなる為、ブラウザによってクロスオリジンへのアクセスに制限が設けられます。これが原因でアクセスできないというのが一般にCORS問題と言われる話で、大体の場合は「この制限を突破するにはどうしたらよいか？」が課題と捉えられているのですが、それは単にセキュリティに穴をあける方法だったりします。

本来エンジニアが作るべきは必要なリクエストには応じ、それ以外はブロックする仕組みですからもう少し詳しく考える必要があります。

##プリフライト
ブラウザはsimple requestでない場合、urlに対して2回アクセスを行います。1回目のアクセスはプリフライトと呼ばれ、実際にアクセスを試みてよいか先にサーバーへ問い合わせるようになっています。

プリフライトで拒否された場合は2回目のアクセスを行わずにエラーを返します。

##OPTIONSメソッド
プリフライトの時に設定されているメソッド名です。仮にAjaxの設定でリクエストメソッドをGETにしていてもプリフライトはOPTIONSで飛びます。

なので、許可するメソッドをGET, POSTのみとかにしているとAjaxは全部弾かれます。

##Allow-Originの意味
サーバー側で規定するヘッダーにAllow-Originというものがあります。
これは特定のドメイン名をオリジンに持つソースからのアクセスを許可するというものですが、厳密には「特定のドメイン名を持つオリジンに持つソースに対しては、レスポンス内容を読み取る許可を与える」という仕様になっています。

つまり、許可していないオリジンのソースはエラーレスポンスを受け取るのですが、サーバー側では受け取ったパラメータを使った処理が中断されないということです。
データベースの改竄とかDoS攻撃は通ってしまうんですね…。

Allow-Originはヘッダーを付けて返すだけなので処理が軽量なのだとは思いますが、ヘッダーを読んでOriginを検査してExitさせるようにすればアクセス自体をシャットアウトできます。

##originは偽造可能らしい
よし、じゃあOriginで弾けば安全なんだ！

と思いきや、Originを書き換える方法があるそうです。[^11]ダメじゃないですか！

[^11]: curlでヘッダーをイチから書けるそうです。結構初歩的な技術で破られてしまうんですね。

##ベストプラクティス？
私が関わっている範囲ではそこまでパフォーマンスにシビアなシステムに当たっていませんが、場合によってはセキュリティチェックがパフォーマンスのネックになることもあるみたいです。

例えばGETを拾ってSELECTするだけのバックエンドで、かつアクセス先が公開情報しか載せていないデータベースなら、極論セキュリティは不要という判断もありじゃないかと思います。

万能薬のような方法があるというよりは、リスク評価が問われる問題ということですね。

##守る以外のセキュリティ
最近、これも大事だと思っているのが監視サービスです。監視サービスというとNagiosとかが保守部隊のPCで常駐しているイメージがありますが、新しいものは比べ物にならないほど高性能で使いやすくなっていて、開発であっても手を伸ばす価値があるなあと思います。[^12]

[^12]: 先日、NewRelicのハンズオンに行ってきました。ベンダーのハンズオンですが体感するには十分。

最近の監視サービスではデータベースがおかしな動きをした場合に、そのトリガーとなったアクセスがどこから飛んできたのか数秒で調べることができますし、ついでにパフォーマンスチェックもできるので一石二鳥な雰囲気がします。

個人的に、今の案件が落ち着いたら真っ先に深彫りしようとしている分野です。

#Googleクローラ
みんな知ってる度：☆(☆☆☆)
後がヤバい度：☆☆
武器になりそう度：☆☆☆☆

みんな知ってる度の☆☆☆は知ってるつもりで昔の話をする人が多いせい。
##真相は誰も知らないけど、知らないとも言えない雰囲気
やっぱりSEOってお客さん気にしますよね。SEO特化の会社さんも多くって、旧来の小手先的なテクニックを売っている会社さんもまだ多いですし、コンテンツマーケティングなんていう分野も広がっていて、魑魅魍魎[^13]の世界だなあと思っているのですが、実際ビジネスへのインパクトがあるのは否定できません。

[^13]: 効果のない施策を売り続けている会社があったり、これ知人が勤務してたので事実…。

Googleさんが小手先でSEO対策されるのを嫌っていて、明確なことは分からないというのは周知のことだと思いますが、Webを戦場にする以上知らないとは言えない雰囲気があります。

##クローラが基本的にできること
SEOの戦略的な話はマーケティング部隊がいればそちらにお任せしたいものですが、そこに工数が付くかどうかはケースバイケースなので[^14]、少なくとも設計上のヘマをしないようにクローラの仕様を調べてみました。

[^14]: 本来はサイトマップを書きましょうということなのですが、プロジェクトの目的や規模によりますね。

SEOはクローラに見つけてもらうことが始まりになりますし、クローラにとって動きにくいサイト構成になっているとスコアが下がるということはよく言われますからね。[^15]

[^15]: しかし公式ドキュメントで見つからなかったので真偽不明。

クローラの基本的な動きはhtmlのソースを読んでリンクやフォームを解析し、あたかもリンクをクリックしたかのようにリンク先のソースを読むというもの。ページ遷移を伴うブラウジングは人間同等に行っていると思ってよさそうです。

##最近のクローラができるようになったこと
従来のクローラはchromeと異なるソフトウェアを積んでおり、人間のブラウジングを再現できていない部分が少なくありませんでした。例えばPOSTのフォームでページ遷移できなかったり、ES6のjavascript文法があると無視されるようなことがあったようですが、2019年の5月にクローラのエンジンがchromium最新版互換になったことでかなり人間に近いブラウジングを模倣できるようになっています。
https://webmasters.googleblog.com/2019/05/the-new-evergreen-googlebot.html

ざっくりまとめると、今のクローラは
・htmlを読む
・javascriptを解釈する（ES6まで対応）
・GET, POSTのフォームを送る
といった機能を持っています。

ちなみにですが、GET, POSTは「実際に送る」らしく、なるべく送らないようにしているという記事が2008年のものでありました。そして技術的には値を入れて送ることが可能とのことです。

既に11年前の話ですから、今はどうなっているんでしょうね。

#終わりに
つい先日、友人の結婚式で式場に向かう途中、電車を降りてから普段使う出口を目指している私がいました。後から聞いたら式場にもっと近い出口があったそうで、そちらから出れば1,2分くらい早く着いたみたいです。

迷わないように安全な方法を取るとか、まあ1,2分なんて気にしたらいけないとかそういう話もあるかもしれませんが、脳の中で「これは知っていること」と処理してしまってより良い方法を調べなかったというのに気が付いて「あっ、脳が老化してるな…」と思いました。

最近歳を重ねるごとに無茶が利かないことも増えてきている自覚があるので、老いって無いわけではないんだなと実感しています。
若い人に「その考え古いですよ」と言われないでいつまでも仕事を続けられるように頑張ろうと思います。