Open21

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

ryo_tsukadaryo_tsukada

TCP/IPは通信プロトコル群の総称。TCP/IPは4つの階層に分かれている。

アプリケーション層(レイヤー4)

アプリケーションに応じた通信

トランスポート層(レイヤー3)

  • インターネット層から受け取ったデータをどのアプリケーション層に届けるか
  • データに誤りはないかを検知する

インターネット層(レイヤー2)

  • どのコンピューターに届けるかを決定する

データリンク層(レイヤー1)

  • 電気信号を相手に届ける
  • 電気信号の制御や誤りを検知する
ryo_tsukadaryo_tsukada

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

ryo_tsukadaryo_tsukada

HTTPヘッダはボディの付随的な情報をやデータのやり取りに使われる

リクエストで使われるヘッダ

フィールド名 概要
Host リクエスト先のサーバーのホスト名とポート番号を指定する
User-Agent リクエストもとの情報を伝える
Refer アクセス元のWebアプリのURLをサーバーに伝える

レスポンスで使われるヘッダ

フィールド 概要
server レスポンスに使われたサーバーのソフトウェアに関する情報を伝える
Location リクエスト先のURLを指定する

エンティティヘッダ

リクエスト・レスポンスどちらも使える

フィールド 概要
Content-Length リソースの大きさをバイト単位で示す
Content-Type リソースのメディア種別を示す
ryo_tsukadaryo_tsukada

ブラウザとサーバー間で状態を維持するために、サーバーとやり取りをした情報をブラウザに保存しておく

Cookieをブラウザに保存するためにはレスポンスにSet-Cookieヘッダを加える

ryo_tsukadaryo_tsukada

ブラウザからAPIへリクエストを送信する

fetch関数を使ってブラウザから/apiのパスにリクエストを出す。

const response = await fetch("http://localhost:3000/api/")
await response.json();
> { message: 'Hello' }
ryo_tsukadaryo_tsukada

次は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: 'こんにちは' }

リクエストだせてるー!面白い!

ryo_tsukadaryo_tsukada

3.3 安全な通信のためのHTTPS

HTTPSの弱点

  1. 通信データの盗聴ができる(ブラウザとサーバーのHTTPでのやり取りが見れちゃう)
  2. 通信相手が本物かわからない(通信先のサーバーが本物か判断できない)
  3. 通信内容の改ざん(ブラウザとサーバー間でのやりとりを書き換えることができる)
ryo_tsukadaryo_tsukada

これらの問題点を補うためにHTTPSを使う。HTTPSではTLSという通信プロトコルを使っている。TLSハンドシェイクという手順をHTTP通信の前に行うことで、暗号通信を確立することができる。

TLSハンドシェイクによってできる暗号化は以下の3つ

  1. 通信データの暗号化
  2. 通信相手の検証
  3. 通信データの改ざんチェック
ryo_tsukadaryo_tsukada

通信データの暗号化

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

ryo_tsukadaryo_tsukada

通信相手の検証

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

ryo_tsukadaryo_tsukada

通信データ改ざんのチェック

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

認証タグを使ってどうやって改善されているのかを確認するんだ??

ryo_tsukadaryo_tsukada

Mixed Contents対策

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

ryo_tsukadaryo_tsukada

ユーザーにHTTPSを強制させる

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

ryo_tsukadaryo_tsukada

HSTSはディレクティブと呼ばれる設定値によって動作を変更することができる

  • max-age: HSTSで必須のディレクティブ。HSTSを適用する時間を秒数で指定
  • preload: 初回アクセス時からHTTPS通信を有効化する
ryo_tsukadaryo_tsukada

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

ryo_tsukadaryo_tsukada

ここから第4章

オリジンによるWebアプリケーション間のアクセス制限

ryo_tsukadaryo_tsukada

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