⚙️

マッシュアッパーのためのwebAPI入門

2021/08/06に公開

概要

「webAPIを使ったツール/サービスを作ってみたい」「なんとなくwebAPIを使ってるけど、言われた通りにURL叩いているだけです」といった方(自分含む)向けに、webAPIをもうちょっとだけ理解できるようになる記事を書いてみました。

(あくまで大まかな流れにフォーカスするので、RESTにはノータッチで行きます。)

そもそもなんのためにあるの?

そもそもwebAPIってなんのためにあるの?というモチベーション部分から押さえておきます。
webAPIのモチベーションは、異なるシステム間の情報(リソース)や機能を共有することにあります。言い換えれば、

  • システムAがシステムBの中の情報を使って何らかの処理をする
  • システムAがシステムBに何かをさせる

ために必要なものということになります。

API = Application Programming Interfaceは、その字が表す通りインターフェース、つまり接続点であり、webAPIとは外部からウェブサービスを操るためのコントローラーとでも認識しておけば大丈夫でしょう。

一番簡単なシステム間連携

さて、モチベーションは上記の通りなのですが、webAPIをなんとなく触ったことある人ならば「なんでこんな単純なことのために、いろいろと面倒な呪文を設定しなきゃならんのだ」と思っていることだと思います。この疑問を、超簡単なwebAPIの仕様を出発点にして紐どいていくことにします。

聞かれたら返すだけのAPI(http)

webAPIは基本的にはhttpを用いて実装されています。
ここで,httpの基礎的な内容をまとめておきます。

httpの仕様

まず,http(hypertext transfer protocol)とはその名称が示す通り,HTMLやXMLといったハイパーテキストを転送することを目的とした転送プロトコルです。ただし,webAPIで受け渡しをするjsonのようなハイパーテキストではないもの(ハイパーメディアではある?)も転送することができます。good
httpは下記のようなメッセージ構成を取っています。このように「型」を決めているので,送信側と受信側でコンセンサスが取れるわけですね。

サーバーから情報を貰う連携

サーバーから情報を貰う連携では,requestメッセージにほしいリソースの条件を入れ込み,送信します。
結果として,要求した情報を(主にJSON形式で)BODYに含んだresponseメッセージが返されます。

request
POST http://**** HTTP/1.1
Content-Type: application/json
Host: ****
etc: ****
↑必要なヘッダ情報

{
  "filter": {
    "key": "value",
    "key": "value",
    "key": "value"
  }
}
↑ほしい情報の細かい条件とか
response
HTTP/1.1 200 OK
DATE: ****
Content-Type: application/json
etc: ****
↑必要なヘッダ情報

{
  "key": "value",
  "key": {
    "key": "value",
    "key": "value"
  }
}
↑ほしい情報

サーバー側の処理を促す連携

サーバー側の処理を促す連携としてわかりやすいのは,サーバー側のDBのデータを更新させる処理です。
先ほどの処理がDBのselectだとすれば,こちらはinsertやupdate等です。

request
POST http://**** HTTP/1.1
Content-Type: application/json
Host: ****
etc: ****
↑必要なヘッダ情報

{
  "0": {
    "key": "value",
    "key": "value",
    "key": "value"
  },
  "1": {
    "key": "value",
    "key": "value",
    "key": "value"
  }
}
↑insertするレコードの情報とか
response
HTTP/1.1 200 OK
DATE: ****
Content-Type: application/json
etc: ****
↑必要なヘッダ情報

(BODYはなかったり,書き込み情報をオウム返ししたり)

セキュリティに問題あり

上記のような仕組みがあれば,機能としては十分。おわりです。
ただしここにはセキュリティ上の問題があります。想像がつくかと思いますが,誰がAPIを叩いても処理が実行されてしまうのです。
自分のGoogleアカウントの個人情報を誰でも引っ張ってこれてしまったら困りますよね。
ここから先は,上記の単純なhttpのwebAPIに対してセキュリティを担保するいくつかの仕組みを解説していきます。これによって,みなさんが日々使うwebAPIの仕様になります。

セキュアにwebAPIを使うための認証方式

特定の人にしかAPI操作を許さないようにするため,「カギ」をかけます。webAPIに用いるカギの仕様にはいくつかバリエーションがありますが,下記の中でもBearer認証,OAuth認証が一般的に使われます。

Basic認証

サーバーが記憶しているユーザーIDとパスワードの組み合わせ情報をカギとする方法です。
httpリクエストのリクエストヘッダに

Authorization: Basic dGVzdHVzZXI6dGVzdHRlc3Q=

のように設定します。
ここで,Basicの後の文字列は"ID:pass"という平文をBase64エンコードしたものです。
上記の例は"testuser:testtest"という文字列のエンコードです。
非常に簡易に実装できますが,盗聴の問題があるので脆弱と言わざるを得ません。(AuthorizationのvalueをBase64デコードすればID/Passが逆算できてしまうので)

Digest認証

Digest認証はBasic認証の発展版です。
httpリクエストのリクエストヘッダに

Authorization: Digest username="ユーザーID",
		nounce="ランダム文字列",
		response="パスワードとnounceをつなげてハッシュ関数に通した文字列"

のように設定します。
仮に盗聴されたとしても,responseがハッシュ化されているためパスワードを逆算することは実質的に不可能である点においてBasic認証よりもちょっぴりセキュアです。が,まだ脆弱です。

Bearer認証

Bearer認証は,サーバーが発行するアクセストークンをカギとする方法です。
最後のOAuth認証の規格の一部ですが,これ単体でも切り離して使えるものになります。
httpリクエストのリクエストヘッダに

Authorization: Bearer アクセストークン

のように設定します。
ここでアクセストークンは事前にサーバーから発行され,クライアントが知っている必要があります。どのような発行手段でも成立します。
(例えば,サーバーにアクセストークン発行用ページがあり,クライアントからの操作で新規アクセストークンを発行するなど)

  • アクセストークンごとに操作権限レベルを設定する
  • アクセストークンに有効期限を設ける

などの工夫で,漏洩に対するダメージを最小化することができます。

OAuth認証

Bearer認証において,アクセストークンの要求から応答までひっくるめて規格化したものがOAuth認証になります。

トークンの発行を担う認可サーバーなる登場人物がでてきます。

  • クライアント(リソースサーバーのデータを使いたいシステム)から認可サーバーへトークン発行リクエスト
  • 認可サーバーからリソースオーナー(≒ユーザー)にトークン発行確認
  • ユーザーはリソースサーバー上のアカウントを以てトークン発行を許可
  • 認可サーバーからクライアントにアクセストークンが発行される
  • あとはトークンを使ってBearer認証APIをたたけます

以上

Discussion