Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?

posted at

updated at

40%の確率で失敗するコード

この記事は、上智大学エレクトロニクス研究部Advent Calendar第6日目の記事です。

まえがき

今日のお題は確率的に発生するバグです。入力を受け付けたり、ランダムに値を生成するプログラムを作っていると、手元では動いたのに別環境にデプロイした後バグが発覚する事例があります。この記事では実際に僕が実装した例を紹介いたします。

どんなものを作っていたか

個人サイトのアプリケーションでLambda(とDynamoDB)を使ってセッション管理をしようとしていました。普段であれば、FlaskなどのWebフレームワークを使っているのでセッション管理もライブラリを使っていますが、今回はLambda上の実行ということで、極力外部モジュールを使わず自力で実装しました。
そこで、NodeJSの標準モジュールである cryptorandomBytes メソッドを使いランダムなバイト列を作り、それをURL安全な形にするために base64 でエンコードすることにしました。
最初に書いたコードは以下の通りです。

import {APIGatewayProxyHandler} from "aws-lambda";
import * as crypto from "crypto";

export const hello: APIGatewayProxyHandler = async (_event, _context) => {
  const sessionId = crypto.randomBytes(24).toString("base64");
  const setCookie = `sessionId=${sessionId}; HttpOnly; Secure`

  return {
    statusCode: 200,
    body: "hello, world!",
    headers: httpUtils.toKebabCase({setCookie})
  };
};

何が問題だったか

base64 で完璧にエスケープできていると思いこんでいたのが間違いだったのです。 base64 はバイト列を印字可能な文字列に変換するために、a-zA-Z0-9/+ の64種類の文字を使います。しかし、この中に1文字だけ Set-Cookie ヘッダの値にそのまま使うとまずい文字が紛れています。そう、+ が問題の文字です。NodeJS(に限らずサーバー)は値を処理するときに、 + を発見すると空白文字として処理してしまうのです。それを回避するには、+%2b に置き換えてあげる必要があったのです。

教訓

  • しっかりとエスケープを行う
  • 動作確認を何回も行う。テストケースを書く。

あとがき

最後になぜ40%の確率で失敗するのかを計算で示します。
上記のコードの sessionId は24バイトのものをbase64でエンコードしているので、 24 * 4 / 3 = 32(文字) となっています。32文字のうち1文字も + が含まれない確率は (63/64) ** 32 ~ 0.604 = 60%。逆に含まれてしまう確率は 40% であることがわかります。

この記事以外にも上智大学エレクトロニクス研究部の部員が面白い記事をたくさん書いているので、ぜひ読んでみてください!

上智大学エレクトロニクス研究部Advent Calendar
上智大学エレクトロニクス研究部の公式サイト

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?