フロントエンド開発のためのセキュリティ入門

第3章 HTTP基礎

TCP/IPは通信プロトコル群の総称。TCP/IPは4つの階層に分かれている。
アプリケーション層(レイヤー4)
アプリケーションに応じた通信
トランスポート層(レイヤー3)
- インターネット層から受け取ったデータをどのアプリケーション層に届けるか
- データに誤りはないかを検知する
インターネット層(レイヤー2)
- どのコンピューターに届けるかを決定する
データリンク層(レイヤー1)
- 電気信号を相手に届ける
- 電気信号の制御や誤りを検知する

そもそも通信プロトコルとは?

異なるデバイスやOSで通信を行うために定められたルール

リクエストでは各層でヘッダを加えながら下位層のプロトコルへデータを渡していく
レスポンスでは各層でヘッダを取り出しながら上位層のプロトコルへデータを渡していく

HTTPヘッダはボディの付随的な情報をやデータのやり取りに使われる
リクエストで使われるヘッダ
フィールド名 | 概要 |
---|---|
Host | リクエスト先のサーバーのホスト名とポート番号を指定する |
User-Agent | リクエストもとの情報を伝える |
Refer | アクセス元のWebアプリのURLをサーバーに伝える |
レスポンスで使われるヘッダ
フィールド | 概要 |
---|---|
server | レスポンスに使われたサーバーのソフトウェアに関する情報を伝える |
Location | リクエスト先のURLを指定する |
エンティティヘッダ
リクエスト・レスポンスどちらも使える
フィールド | 概要 |
---|---|
Content-Length | リソースの大きさをバイト単位で示す |
Content-Type | リソースのメディア種別を示す |

Cookie
ブラウザとサーバー間で状態を維持するために、サーバーとやり取りをした情報をブラウザに保存しておく
Cookieをブラウザに保存するためにはレスポンスにSet-Cookieヘッダ
を加える

ブラウザからAPIへリクエストを送信する
fetch
関数を使ってブラウザから/api
のパスにリクエストを出す。
const response = await fetch("http://localhost:3000/api/")
await response.json();
> { message: 'Hello' }

次はfetch
関数を使ってPOST
リクエストを出す。
await fetch("http://localhost:3000/api/", {
method: "POST",
body: JSON.stringify({ message: "こんにちは" }),
headers: { "Content-type": "application/json" }
});
> Response {type: 'basic', url: 'http://localhost:3000/api/', redirected: false, status: 200, ok: true, …}
サーバーを実行しているNode.js
を確認
> Sever running at: http://localhost:3000
{ message: 'こんにちは' }
リクエストだせてるー!面白い!

3.3 安全な通信のためのHTTPS
HTTPSの弱点
- 通信データの盗聴ができる(ブラウザとサーバーのHTTPでのやり取りが見れちゃう)
- 通信相手が本物かわからない(通信先のサーバーが本物か判断できない)
- 通信内容の改ざん(ブラウザとサーバー間でのやりとりを書き換えることができる)

これらの問題点を補うためにHTTPSを使う。HTTPSではTLSという通信プロトコルを使っている。TLSハンドシェイクという手順をHTTP通信の前に行うことで、暗号通信を確立することができる。
TLSハンドシェイクによってできる暗号化は以下の3つ
- 通信データの暗号化
- 通信相手の検証
- 通信データの改ざんチェック

通信データの暗号化
TLSではデータを送信する前に暗号化する。暗号化されたデータを受け取った側は暗号文を平文に復元する。
これを復元するには秘密鍵がなければ暗号を復元することはできない。
秘密鍵はTLS通信ごと(つまりHTTP送信ごと)に生成され、通信が終わると廃棄される。だからサーバーに不正に侵入しても秘密鍵は廃棄されてるので情報を盗むことはできない

通信相手の検証
TLSでは電子証明書を使って通信相手が本物かを判断する。電子証明書は認証局と呼ばれる社会的に信用されている機関によって発行される。
サーバーから送信された電子証明書はブラウザによって正しいか判断され、ブラウザとOSに組み込まれている電子証明書と照合される

通信データ改ざんのチェック
暗号化されていても通信データを改ざんすることはできる(!)。
TLSではデータを暗号化する時に認証タグを生成する。データを受け取った側は認証タグを使って、データが改ざんされていないかを確認する。もしデータを改ざんされていたらそのデータは使われず通信エラーになる。
認証タグを使ってどうやって改善されているのかを確認するんだ??

Mixed Contents対策
HTTPSで実装されてwebアプリケーションでもHTTP通信でリソースを受け取っていることがある。その場合リソースを改ざんすることができる。
HTMLやCSSが書き換えられても損害は少ない(たぶん)が、JavaScriptを書き換えられるとログインや決済などユーザーの個人情報に関わるやり取りをするときに、データを盗まれたり、悪用される可能性がある。

ユーザーにHTTPSを強制させる
HSTS(HTTP Strict Transport Security)という仕組みを使えばHTTPS通信を強制することができる。
HSTSを使うにはレスポンスヘッダにStrict- Transport-Security
ヘッダを追加する。
ブラウザがStrict- Transport-Security
ヘッダを受け取ると、それ以降の通信はHTTPSでリクエストを行うようになる

HSTSはディレクティブ
と呼ばれる設定値によって動作を変更することができる
-
max-age
: HSTSで必須のディレクティブ。HSTSを適用する時間を秒数で指定 -
preload
: 初回アクセス時からHTTPS通信を有効化する

HSTSはレスポンスヘッダで有効になるため、初回アクセス時にはHTTPS通信は行えない。
preload
を使うことで、ブラウザはHSTS Preloadリスト
の一覧を参照して、アクセスしようとしているドメイン名がリストにあればHTTPSでアクセスする

ここから第4章
オリジンによるWebアプリケーション間のアクセス制限

ブラウザには同一オリジンポリシー
というWebアプリケーション間でのアクセス制限の仕組みが作られている。
ブラウザは異なるwebアプリケーション間でオリジン
という境界を設けている。
オリジンは[スキーム名, ホスト名, ポート番号]
の組み合わせで構成される。
> https://example.com:443/path/to/index.html
↑のポート番号までがオリジン