Web制作者に送る、APIキーの取り扱い説明と注意ポイント

私は普段**「web制作」**と呼ばれる部類の仕事をしているのですが、この範囲においては直接APIキーと触れる機会は多くはありません。

普段web制作をされている方が実際にAPIキーを扱う場合は以下のような場合があるでしょう。

- 勉強でwebアプリの作り方を学んでいる
- webアプリ開発のプロジェクトにアサインされる

このような場合においてソースコード管理にはGitを使う場合が多いと思いますが、何も知らないと恐ろしいことになりかねないので、

- APIキーとはなにか
- 漏洩すると何がまずいのか
- 対策はどうするか

をセットで解説していきます。

## APIって何ぞ

めちゃ省略して言うと、
`あるアプリケーションの機能を第三者と共有する為の窓口`です。

例えば`「今日の天気予報で雨の場合、毎日自動で朝7時に通知してくれる」アプリ`を作る場合に、気象観測し情報を取得し、天候を判断するプログラムを自分で作成するのはひどくめんどくさそうです。

しかしそれらを提供してくれるプログラムが利用できれば楽ですよね？

そして実際に提供してくれています。

>[天気予報API](https://tenkiapi.jp/)

そして、これらを自分のプロジェクトで利用する際に必要になるものの一つが、**APIキー**になります。

## APIキーとは

APIを利用する場合は、通常`「API利用登録」`を行い、キーを発行します。

そしてそのキーを自分のプログラムに埋め込むことでAPIを利用することができます。

APIキーを取得することで、ユーザーを認証し、ある一定の条件をクリアしたものと見なされるわけです。

## API利用具体例

例えば、YouTubeの登録者数と再生数を表示させるプログラムを書くとすると、以下のようになります。

>
使用API：YouTube Data API 
言語：Ruby

```ruby:youtube.rb
require 'net/http'
require 'json'

CHANNEL_ID = 'UCdMzoB8z-zUwNOS9ZC4FsAQ'
API_KEY = 'hogehogehogehogehoge' #APIキーを直接書くわけにはいかないのでサンプル
YOUTUBE_URL = "https://www.googleapis.com/youtube/v3/channels?part=statistics&id=#{CHANNEL_ID}&key=#{API_KEY}"

def add_commas(number)
  number.to_s.reverse.scan(/\d{3}|.+/).join(',').reverse
end

def get_stats
  response = Net::HTTP.get(URI(YOUTUBE_URL))
  data = JSON.parse(response)

  {
    subscriber_count: add_commas(data['items'][0]['statistics']['subscriberCount']),
    view_count: add_commas(data['items'][0]['statistics']['viewCount'])
  }
end

stats = get_stats
puts "#{stats[:subscriber_count]} subs"
puts "#{stats[:view_count]} views"
```

この場合、

`https://www.googleapis.com/youtube/v3/channels?part=statistics&id=#{CHANNEL_ID}&key=#{API_KEY}`
というのが、エンドポイント（エントリーポイント）と呼ばれる部分になります。

ここにアクセスすることで、YouTube Data APIの場合はjson形式でデータを返してきます。
>ちなみに理由は後述ですが、今のAPIキーそのままでgithubに上げると終わります、その意味で上記は問題があるコードです（これはqiitaにあげるためAPIキーは誤魔化してますが）

`以下弊YouTubeチャンネルの情報です`

```json

{
  "kind": "youtube#channelListResponse",
  "pageInfo": {
    "resultsPerPage": 1
  },
  "items": [
    {
      "kind": "youtube#channel",
      "etag": "sample",
      "id": "sample",
      "statistics": {
        "viewCount": "242761",
        "commentCount": "0",
        "subscriberCount": "4270",
        "hiddenSubscriberCount": false,
        "videoCount": "46"
      }
    }
  ]
}
```

あとはここから`subscriberCount`と`viewCount`を取得できればOKです。

こんな感じで、APIからデータを取得（get）するのが一番わかり易いかもしれません。

## APIキーの取り扱い

さて、今回一番伝えたいことになります。

**APIキーは漏洩させてはなりません**

漏洩するパターンとして、一番ありえるのが以下２パターンになります。

- 個人開発
- レビュアーがいない（または気づかない）チームでのアプリ開発

## ①個人開発

もし、Githubなどでソースコードを管理していて、かつそのリポジトリがpublicである場合は、即刻秘匿するべきだと思います（privateでもよくないとされています）

結構やられてる方多いように思います。

秘匿方法としては、環境変数に格納するという方法が一番メジャーです。

以下は`firebaseのAPI情報`の例です（値は適当です）

```env:.env

FIREBASE_API_KEY='samplesamplesample123456789'
FIREBASE_AUTH_DOMAIN='samplesamplesample.com'
FIREBASE_DATABASE_URL='samplesample@sample.com'
FIREBASE_PROJECT_ID='1.samplesamplesample'
FIREBASE_STORAGE_BUCKET='sample.appspot.com'
FIREBASE_MESSAGING_SENDER_ID='111111111111'
FIREBASE_APP_ID='1:samplesamplesample.8'
```
.envで環境変数にAPI情報を格納します。.envはgitignoreされているため、共有されません。



## ②レビュアーがいない（または気づかない）チーム開発

Githubなどでチーム開発をする場合に、レビュアーがいないケースは稀かもしれませんが、気づかずにAPI情報がパブリックにプッシュされる可能性は排除できません。

これによる損害が実際に発生しています。

## APIキー流出での実害

以下が例になります。

>[【実録】アクセスキー流出、攻撃者のとった行動とその対策](https://dev.classmethod.jp/articles/accesskey-leak/)

昨今は使用量に応じて課金がされる「従量課金」サービスがふえてきました。

AWSやfirebaseのようなものです。

APIキーが漏洩すると、そうしたサービスを無断で使われて仮想通貨のマイニングなどが行われることが多いようです。

**絶対にpublicなリポジトリにAPIキーをプッシュしてはいけません**

## 補足：チーム開発でのAPIキーの共有はどうするの？

gitignoreされている.envをチームメンバーで共有しないと、環境変数を用いている部分で読み込めずエラーを吐きます。

これを解決するには最新の.envをみんなで共有しないといけないのですが、Githubは使えません（privateリポジトリでもセキュリティ的に不安）

どうするのか。

私が対応したプロジェクトではSlackのシークレットルーム（二段階認証）で共有していましたが、実際みなさんどのように秘匿情報をやり取りされているのでしょうか？

もしよろしければお教えください〜(｡>﹏<｡)

### 参考になりそうなリファレンス

>[APIキーやその他のクレデンシャルを含むシークレットを管理・保存するためのベストプラクティス[2020年版]](https://itnews.org/news_contents/secrets-api-management)