【vte.cx応用】16. セキュリティについて

今日はセキュリティについて説明します。

## セキュリティの基本的な考え方

セキュリティ対策は完璧にできる保証はないというスタンスが大切です。
一つ一つ現実的な対応をしっかりして安全性を確保していくしかありません。

vte.cxにおける基本的な考え方は「安全、使いやすさ、標準」の３つです。
優先順位は「安全>使いやすさ>標準」といったところでしょうか。

セキュリティを強化するあまり使い勝手が悪くなってもよくないし、使いやすさを優先するあまり脆弱になってしまってもいけません。手軽でかつ標準的なものがあればそれに越したことはないでしょう。

## 独自のログイン認証について

vte.cxはWebアプリケーションを提供するわけですからWebセキュリティの考慮が必要になります。

特に、ログイン認証については考慮点が多くて悩みます。

そもそも、独自ログイン認証を持つということが大変なリスクであって、できることなら持ちたくないというのが本音です。

セキュリティ専門家から「独自ログイン認証をやっているサイトから税金を取ったらいい」というような話も聞いたことがあります。

しかし、一般的なWebシステム開発の世界ではログイン認証の要求は依然として高く、ソーシャルログインだけで済む世界はまだ先のような気がしています。
また、独自ログインはリスクが高いという理由で見積もり金額を上げようものなら受託開発の世界ではまず生き残ってはいけないでしょう。

Fintechにおける銀行口座のパスワード管理の現状をご存知でしょうか？
独自ログイン認証でさえハッシュ化して生のパスワードを持たないなど苦労しているのに、一方で銀行アカウントの生パスワードを保存するような危ない管理がまかり通っている現状があります。

さすがに特定のサービスの危険を煽るようなセキュリティ専門家はいませんが、税金を取るとか脅すのではなく、まずはこのような現状を認識するべきではないでしょうか。（だからといって脆弱性を容認するわけではありませんが）その上で具体的な対応についてご提案いただきたいものです。

## ログイン認証のセキュリティ対策

vte.cxではログインフォームを用意しており、vtecxblankプロジェクトのログインフォームをカスタマイズして使えます。

独自ログインフォームを提供するわけですから十分なセキュリティ対策が必要です。

基本的には、[Web API認証について](http://blog.virtual-tech.net/2014/01/web-api.html)で紹介した「WSSEをハッシュ化して送信する方法」を採用しています。そのまま保存してしまうとハッシュ化パスが事実上のパスワードになってしまうため、さらにハッシュ化（または暗号化）したものを保存しています。
　生パスワードを知らないので漏れて悪用される心配もありません。つまり、同じパスワードを使って他のシステムに侵入するパスワードリスト攻撃のような悪用を防げます。
　また、初回だけWSSEを送って認証に成功したらサービス側で有効なトークン(セッションID)を発行していますので毎回パスワードを入力しなくてもよくなります。
また、リピート攻撃に耐えうるようにWSSEをワンタイム化しています。
　さらに、パスワードを３回間違えるとCaptchaが現れます。これはDDoSやリピート攻撃に対しても有効です。
ただし、パスワードの強度はクライアント側のJavaScriptでチェックする必要があります。
vtecxblankプロジェクトのユーザ登録画面ではパスワードを「8文字以上、かつ数字・英字・記号を最低1文字含む」条件でチェックしています。

その正規表現については、こちらの[Qiita](http://qiita.com/KENJU/items/d281049303f7d1d97998#comment-75533fe332f43dfdfd40)の記事が参考になります。

また、ログイン履歴やリスクベース認証（通常と異なる端末からのアクセスをメールして確認する）機能が欲しくなることもあるでしょう。
ログイン時(?_login)には、サーバサイドでlogin.jsが起動しますので、これを使って実装することも可能です。

２段階認証は今のところできません。

## 安全性確保のために犠牲にしていること

ときに、使いやすさを犠牲にしてまでも安全性を確保したいことがあります。
vte.cxでは安全性を確保するために、JSONを直接ブラウザに表示することを禁止しています。

つまり、JSONを取得できるのはXHRだけであり、リクエストヘッダに「X-Requested-With: XMLHttpRequest」が付与されていなければエラーを返却します。

一時期、JSONPなどのテクニックが流行しましたが、これはデータの提供元が信頼できないと危険です。
私たちは提供元を信頼できる仕組みをつくることはできないと判断して全面的に使用禁止にしました。
データをブラウザで確認したいときはXMLで表示してください。

また、CSRF対策でCookieのCSRFトークンを使用していましたが、使い勝手が悪かったため今は廃止しています。その代わり、[XMLHttpRequestを使ったCSRF対策](http://d.hatena.ne.jp/hasegawayosuke/20130302/p1)を施しています。
セキュリティのためならFORMのSubmitも廃止して**データの入出力はXHR通信のみ**という斬新な仕様にしています。

## 利便性のために犠牲にしていること

実は利便性のためにセキュリティを犠牲にしていることが一つだけあります。
それは、cookieのsecure属性を付けていないことです。

vte.cxはhttpでもhttpsでもアクセスできますが、開発時はlocalhostのgulp webserverを利用しますのでhttpでのアクセスになります。
つまり、開発時にhttpで使いたいのでcookieにsecure属性を付けられないのです。（もしかしたら、httpsでproxyする方法があるかもしれません）

本番運用では必ずhttpsでアクセスするようにしてください。
（将来的に本番運用か開発中かのサービスステータスでhttp/httpsの選択をできるようにするかもしれません。現在検討中です）

## サーバサイドにおけるチェックとバリデーション

クライアントでどんなに頑張ってチェックしたところで、サーバではデータを無条件に受け付けるわけにはいきません。例えば、商品金額のマスターチェックを回避するなどの不正をフロントエンドだけでは防げません。金額を正確にチェックするにはサーバ側でマスター参照する必要があるはずです。
また、IDなどのシーケンス番号の採番もサーバ側で実行する必要があるでしょう。

vte.cxではスキーマにバリデーションを記述することで受け入れ可能なデータの条件を指定できます。また、サーバサイドJavaScriptによりマスターチェックを実行することができます。
サーバサイドJavaScriptについては２１日目で詳しく説明します。

## 権限グループとACL

vte.cxのフォルダにACLを設定できることはこれまでも説明してきました。
contributorタグに以下を設定することでフォルダやその配下のアクセスコントロールが可能です。
uidで特定のユーザ、*で全てのユーザ、+でログインしているユーザ、グループなどを設定できます。

詳しくは、[アクセスコントロール](http://reflexworks.jp/documentation.html#taggingservice.html#C)を参照してください。

```
<contributor>
    <uri>urn:vte.cx:acl:{uid|*|+|-|GroupKey},{C|R|U|D|E|.|/}</uri>
</contributor>
```

vte.cxは第一階層を`/@{サービス名}`にして、サービス管理者しか権限を与えないようにすることでマルチテナントを実現しています。

### 管理権限

システムがデフォルトで持っている権限グループには以下の３つがあります。

 - サービス管理権限(`/_group/$admin`)
 - ユーザ管理権限(`/_group/$useradmin`)
 - コンテンツ管理権限(`/_group/$content`)

管理権限はサービスを作成した人にはサービス管理権限(`/_group/$admin`)が付きます。
これは上記のACLを設定できる権限でもあります。つまり、`<contributor>`タグの操作ができます。

ユーザ管理権限はユーザを追加・削除したりできる権限です。

コンテンツ管理権限はHTMLやJavaScriptなどのコンテンツを登録できる権限です。
この権限がなければcontentタグの操作はできません。
一般のユーザがコンテンツ登録できるとXSSの脆弱性につながりますので、コンテンツ管理権限は管理者だけに与えるようにしてください。

### 開発者が考慮すべきその他のセキュリティ対策

vte.cxではこれまで述べたような様々なセキュリティ対策がなされています。
基本的に開発者はセキュリティを意識しなくても大丈夫なようにしていますが、１点だけ、XSSだけは開発者が対策するようにしてください。

XSS対策は入力した文字列を表示するときにエスケープすればOKです。
[参考](http://www.todesking.com/blog/2015-02-05-html-escape-with-innertext-and-innerhtml-is-not-enough/)

これで本日は以上になります。
お疲れ様でした。