KiSAKU

サーバー・セキュリティの用語

攻撃から守る仕組みと、使っているソフトウェアを安全に保つための言葉。

それぞれ「なぜそれがあるのか」と「つまずきやすい点」まで書いています。実際にこのサイトを作る中で出てきた具体例も入れました。

依存関係(いぞんかんけい)

あるプログラムが動くために必要な、他のプログラムのこと。連鎖的に増えていく。

自分のプログラムが動くために必要な、外部のプログラムのことです。そしてその外部のプログラムにも、また別の依存があります。

連鎖する

直接指定したのが10個でも、実際にインストールされるのは数百個ということが普通に起こります。自分が選んでいないものが、大量に入っている状態です。

知っておくべき性質

同じ名前のパッケージが、違うバージョンで同時に入ることがあります。AがBの1.0を要求し、CがBの2.0を要求する場合、両方を満たすために入れ子にして共存させます。

この性質のため、自分が直接指定したものを更新しても、他のパッケージが内側に抱えている古い版は残ります。「上げたのに脆弱性の警告が消えない」という現象は、たいていこれが原因です。

関連記事: 依存の中の依存

環境変数(かんきょうへんすう)

プログラムの外側から渡す設定値。パスワードやAPIキーをコードに書かないために使う。

プログラムの外側から渡す設定値です。接続先のURLやパスワード、APIキーなどを、コードに直接書かずに済ませるために使います。

なぜコードに書いてはいけないのか

コードはリポジトリに保存され、履歴として残り続けます。一度書いてしまうと、あとから消してもコミット履歴には残ります。公開リポジトリなら世界中から読めますし、非公開でも共有範囲が広がります。

もうひとつの利点

開発環境と本番環境で違う値を使い分けられます。同じコードのまま、接続先だけを切り替えられるわけです。

フロントエンドでの注意

Next.jsでは、NEXT_PUBLIC_ という接頭辞が付いた環境変数はブラウザに送られます。つまり誰でも読めます。秘密の値にこの接頭辞を付けてはいけません。

「環境変数だから安全」ではなく、どこまで届くのかを理解して使い分ける必要があります。

関連記事: ローカルのサイトを本番公開するまでにハマった話

セマンティックバージョニング(せまんてぃっくばーじょにんぐ)

バージョン番号を「1.2.3」の3つに分け、どこが変わったかで互換性を示す取り決め。

バージョン番号を「メジャー.マイナー.パッチ」の3つに分け、それぞれの意味を決めた取り決めです。SemVer とも書きます。

位置 上がるとき 影響
1.2.3 パッチ 不具合の修正 そのまま上げてよい
1.2.3 マイナー 機能の追加 基本は安全
1.2.3 メジャー 互換性のない変更 移行作業が必要

実務でどう効くのか

更新の提案が来たとき、どこの数字が変わったかを見るだけで危険度が判断できます。パッチ更新はそのまま入れてよく、メジャー更新は移行作業として扱う。ボタンの見た目は同じでも、やっていることがまったく違います。

ただしこれは取り決めであって強制ではありません。守っていないパッケージもあるので、重要なものは変更内容を確認する価値があります。

関連記事: 上げる先が、ひとつしかなかった

脆弱性(ぜいじゃくせい)

悪用されると被害につながる、ソフトウェアの弱点。修正版が出たら更新して塞ぐ。

ソフトウェアに含まれる「悪用されると被害につながる弱点」のことです。バグの一種ですが、特にセキュリティに関わるものを指します。

なぜ次々に見つかるのか

ソフトウェアは膨大な組み合わせで動くため、作った時点では想定できない使われ方が後から見つかります。世界中の研究者が探しているので、有名なソフトほど多く報告されます。

報告が多いことは、必ずしも品質が低いことを意味しません。見られている量が多いとも言えます。

実務での付き合い方

警告の件数に圧倒されないことが大事です。件数と、必要な作業の数は一致しません。1つのパッケージに対する報告が積み上がっているだけ、というケースがよくあります。

また、開発時にしか動かないもの(開発用の依存)は、公開されるサイトには含まれません。同じ「重要度:高」でも、緊急度は変わります。

関連記事: 依存の中の依存 / 公開したあとの話 — 脆弱性検知と監視の仕組みを作る

ハニーポット(はにーぽっと)

人には見えない入力欄を置き、そこに何か書き込まれたら機械による送信だと判断する仕掛け。

フォームに、画面の外へ飛ばした入力欄をひとつ足しておきます。人間には見えないので空のままですが、フォームの中身を機械的に読んで全部埋めるプログラムは、そこにも書き込みます。埋まっていたら機械、という判定です。

利用者に負担をかけない

画像を選ばせたり文字を読ませたりする対策は、正しく使っている人の手間も増やします。ハニーポットは見えない欄を無視するだけなので、人間の側には何も起きません。

弾いたときに「あなたはボットです」と返さず、成功したように見せるのが定石です。理由を教えると、次はその欄を避けて送ってきます。

これだけでは足りない

そのフォーム専用に作られた送信プログラムには効きません。見えない欄の名前を知っていれば、避けて送るだけです。

費用がほとんどかからないので最初に入れる価値はありますが、これ一本に頼る設計にはしないほうが安全です。送信の間隔や回数の制限と組み合わせます。

関連記事: 届かない問い合わせ

レート制限(れーとせいげん)

同じ相手からの送信回数を、一定時間あたり何回までに抑える仕組み。

「10分のあいだに3回まで」のように、回数そのものに上限を付けます。1件ずつ見れば正しい送信でも、短い時間に何十件も来るなら機械だと判断できます。

中身を見ないで判定できる

書かれている内容が正しいかどうかとは関係なく効くところが利点です。文面をいくら変えても、回数は変えられません。

数え方は、送信元ごとに「いつ送ってきたか」を覚えておき、古いものを捨てながら数える形が基本です。上限を超えたときは429という専用のステータスコードを返します。

つまずきやすい点

記録をどこに置くかで挙動が変わります。サーバーの中に持つと、サーバーが複数あったり作り直されたりしたときに数がばらけます。厳密にやるなら外部の保存先が必要です。

ただし、機械による大量送信を鈍らせるだけなら、ばらけても効き目はあります。完全さを求めて何も入れないより、荒くても入れるほうが効きます。

ロックファイル(ろっくふぁいる)

実際にインストールされた全パッケージのバージョンを記録したファイル。環境を再現するために使う。

package-lock.json のような、「実際に何が、どのバージョンで入ったか」を全部記録したファイルです。

なぜ必要なのか

設定ファイル(package.json)には「1.2以上」のような幅を持った指定を書きます。この幅があると、インストールする時期によって違うバージョンが入ります。

それでは「自分の環境では動くが、本番では動かない」が起こります。そこで、実際に入った正確なバージョンを記録しておき、他の環境でも同じ組み合わせを再現できるようにします。

実務での扱い

ロックファイルは必ずリポジトリに含めます。「自動生成されるファイルだから」と除外すると、環境の再現性が失われます。

また、依存の実態を調べたいときは、このファイルを見るのが確実です。入れ子になった古いバージョンも、ここには正確に記録されています。

関連記事: 依存の中の依存

EOL(イーオーエル)

End of Life。そのバージョンへのサポートが終了し、脆弱性が見つかっても修正されなくなること。

End of Life の略。そのバージョンの提供が終わり、以後は修正が出なくなることを指します。

なぜ重要なのか

EOLを迎えたバージョンは、新しい脆弱性が見つかっても修正されません。使い続けている限り、危険は増える一方になります。

「動いているから問題ない」と思いがちですが、動くことと安全であることは別です。

作業前に調べる価値がある

更新作業の前にEOLを確認すると、「上げる先」が判断できます。実際にこのサイトでは、手元のバージョンがすでに最終版で、上げる余地が存在しないことが分かりました。調べずに作業していたら、何も起きないコマンドを実行するところでした。

あわせて、次のバージョンのサポート期限も見ておくと、「2か月後にまた同じ作業をする」ことを避けられます。

関連記事: 上げる先が、ひとつしかなかった

CAPTCHA(キャプチャ)

人間かどうかを判定するために出す課題。文字入力や画像選択、行動の観察など。

歪んだ文字を読ませる、写真の中から該当するものを選ばせる、といった課題を出す仕組みです。最近のものは課題を出さず、操作の様子から判断する形が主流になっています。

効き目と引き換えに減るもの

強い対策ですが、正しく使っている人の手間が増えます。読み取りづらい文字は、目の見えづらい人や、その言語に慣れていない人には大きな壁になります。

問い合わせフォームは、そもそも送信の数が多くありません。届かなくなる送信が1件ある損と、迷惑な送信を完全に止める得を、数で比べて決める話になります。

入れる順番

手間の少ない対策から順に入れて、それで足りないと分かってから足すのが穏当です。見えない入力欄や送信回数の制限は利用者に何の負担もかけないので、先に試せます。

外部のサービスを使う場合、判定のために利用者の情報がその会社へ渡ります。何を渡しているかは、プライバシーポリシーに書く必要が出てきます。

XSS(クロスサイトスクリプティング)

サイトに悪意のあるスクリプトを埋め込み、閲覧者のブラウザで実行させる攻撃。

Cross-Site Scripting の略。投稿欄などから悪意のあるプログラムを送り込み、それを見た人のブラウザで実行させる攻撃です。

何が起きるのか

実行されると、その人のログイン情報を盗んだり、意図しない操作を行わせたりできます。攻撃されるのはサイトではなく、サイトを見に来た人という点が特徴です。

なぜ起きるのか

受け取った文字列を、そのままHTMLとして出力してしまうと起こります。<script> という文字列が、文字ではなく命令として解釈されるためです。

防ぎ方

外部から来た文字列を出力するときは、記号を「ただの文字」に変換します。これをエスケープといいます。

構造化データのようにスクリプトタグの中へ文字列を出す場合も同じで、< をユニコード表記に置き換えるといった対処が必要になります。自分で書いた文章しか入らない場所でも、塞いでおくコストは低いです。

CORS(コルス)

ブラウザが、別のドメインへの通信を既定で制限する仕組み。許可はサーバー側が出す。

Cross-Origin Resource Sharing の略。ブラウザ上のプログラムが、別のドメインのサーバーと通信することを制限する仕組みです。

なぜ制限するのか

もし自由に通信できると、悪意のあるサイトを開いただけで、あなたがログイン中の別のサイトに勝手に操作を送れてしまいます。それを防ぐため、ブラウザは既定で他ドメインへの通信をブロックします。

誰が許可を出すのか

重要な点として、許可を出すのは通信される側のサーバーです。呼び出す側でいくら書いても解決しません。サーバーが「このドメインからの通信は許可します」という応答ヘッダーを返して、初めて通ります。

そのため「自分のコードを直しても直らない」ことがよくあります。直す場所が自分の手元にないのが、この仕組みの分かりにくさです。

補足

サーバー同士の通信には、この制限はありません。ブラウザの中でだけ働くルールです。

関連記事: 書いた記事をWordPressに届けるまで — CORS・nonce・CSSの壁

CSRF(シーサーフ)

ログイン中のユーザーに、意図しない操作を実行させる攻撃。nonceなどで防ぐ。

Cross-Site Request Forgery の略。日本語では「クロスサイトリクエストフォージェリ」、俗に「リクエスト強要」とも呼ばれます。

どういう攻撃か

あなたが銀行のサイトにログインしたまま、別のタブで悪意のあるページを開いたとします。そのページが裏で「送金する」という要求を銀行に送ると、ブラウザはログイン情報を自動で付けて送ってしまいます。銀行から見れば、本人からの正規の要求に見えます。

なぜ成立するのか

原因は、ブラウザがログイン情報を自動的に付けるという仕様にあります。便利さのための仕組みが、そのまま攻撃の入口になっています。

防ぎ方

「正規の画面を開いた人にしか分からない情報」を操作に添えさせます。nonceがその代表です。外部サイトはその値を知り得ないため、偽の要求を作れなくなります。

Dependabot(ディペンダボット)

GitHubの機能。依存パッケージの脆弱性を検知し、更新のプルリクエストを自動で作る。

GitHubに組み込まれている仕組みで、使っているパッケージに脆弱性が見つかると知らせ、更新用のプルリクエストを自動で作ってくれます。

便利だが、そのまま入れてはいけない

自動で作られたプルリクエストには、危険度のまったく違うものが混ざっています。パッチ更新もあれば、メジャーバージョンを2つ跨ぐものもあります。

そしてブラウザ上でマージすると、手元で動作確認する機会が飛びます。通るかどうかは本番のデプロイが動いてから分かる、という状態になります。パッチ更新なら許容できますが、メジャー更新でこれをやるのは賭けです。

使いこなし方

バージョン番号の変化を見て、そのまま入れてよいものと、移行作業として扱うものに分けるのが基本です。後者は手元にブランチを作り、ビルドと動作確認を挟んでから入れます。

関連記事: 依存の中の依存 / 公開したあとの話 — 脆弱性検知と監視の仕組みを作る

nonce(ナンス)

一度きりの使い捨ての文字列。その操作が正規の画面から行われたことを確かめるために使う。

number used once の略で、一度だけ使う使い捨ての文字列のことです。WordPressをはじめ、多くのシステムで使われています。

何のためにあるのか

ログイン中のユーザーが、悪意のあるサイトを開いてしまったとします。そのサイトが「記事を削除する」という要求を裏で送ったら、ブラウザはログイン情報を自動的に付けて送ってしまいます。これが成立すると、本人の意図しない操作が実行されます。

そこで、正規の画面を開いたときにだけ発行される文字列を、操作のたびに一緒に送らせます。外部のサイトはこの文字列を知り得ないので、なりすましを防げます。

実務で出会う場面

WordPressのREST APIをプログラムから叩くとき、ログインしているだけでは足りず、nonceも必要になることがあります。「認証は通っているのに403が返る」場合、ここを疑う価値があります。

関連記事: 書いた記事をWordPressに届けるまで — CORS・nonce・CSSの壁

WAF(ワフ)

Webサイトへの通信を手前で見張り、攻撃らしいものを遮断する仕組み。

Web Application Firewall の略。サイトに届く前の段階で、怪しい通信を止める仕組みです。レンタルサーバーでは契約時から有効になっていることが多いです。

なぜあるのか

Webサイトは誰でもアクセスできる場所にあります。入力欄に不正な文字列を送り込んでデータベースを操作しようとしたり、管理画面のパスワードを総当たりで試したりする通信が、常に混ざってきます。

これをサイト側で1つずつ防ぐのは大変なので、手前で機械的に弾く役割を専門の仕組みに任せます。

つまずきやすい点

WAFは「攻撃らしいもの」を機械的に判定するため、正しい操作なのに止められることがあります。これを誤検知といいます。

このサイトでも起きました。記事をプログラム経由で投稿しようとしたら403で拒否され、原因は記事本文にプログラムのコードが含まれていたことでした。WAFから見ると、コードが送り込まれているように見えたわけです。

厄介なのは、止められた側に理由が表示されないことです。「なぜか失敗する」としか分からないので、原因にたどり着くまで時間がかかります。

関連記事: 自分のブログに記事が投稿できない — WAFの誤検知と、渡し方を変える解決

← 用語集の一覧へ戻る