GASでハッシュ値(SHA-256)を
計算する方法|computeDigest

ハッシュ値(入力から作る固定長の指紋のような値)は、データの変更検知・重複判定・改ざんチェックに使えます。GASのUtilities.computeDigestでハッシュを計算し、実務で使える形に整える方法を動くコードで解説します。

|対象: GAS / Utilities / ハッシュ・HMAC

Table of Contents

ハッシュ値とは何か・何に使えるか

ハッシュ値とは、任意の長さの入力から作られる固定長の値です。同じ入力からは必ず同じ値になり、内容が1文字でも変われば全く別の値になります。そして元の入力に戻すことはできない一方向の変換です。この性質を使うと、次のような処理が手軽に書けます。

変更検知(差分チェック)

前回のハッシュと比べ、値が違えば内容が更新されたと判断する

重複判定のキー

長い文字列や複数列の組み合わせを、短い固定長のキーに変換する

改ざん・整合性チェック

ファイルやデータが途中で書き換えられていないかを確認する

署名検証(HMAC)

秘密鍵を使い、Webhookの送信元が正当かを確かめる

ハッシュは「元に戻さない」変換なので、後で復号したい暗号化とは目的が違う点に注意してください。GASではUtilities.computeDigest(ハッシュ計算のメソッド)が標準で用意されており、追加ライブラリなしで使えます。

computeDigestでSHA-256ハッシュを計算する

基本の使い方です。第1引数にアルゴリズム、第2引数に対象の文字列、第3引数に文字コードを渡します。第3引数を省略すると環境によって結果がずれることがあるため、Utilities.Charset.UTF_8を明示するのがおすすめです。

function sha256Hex(text) {
  // SHA-256でハッシュ化。文字コードは UTF_8 を明示する
  const bytes = Utilities.computeDigest(
    Utilities.DigestAlgorithm.SHA_256,
    text,
    Utilities.Charset.UTF_8
  );
  return bytesToHex(bytes);
}

// 動作確認
function testHash() {
  Logger.log(sha256Hex("hello"));
  // 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
}

戻り値はそのまま表示できる文字列ではなく、バイト配列(数値の配列)です。次のセクションで、扱いやすい16進文字列に変換します。

バイト配列を16進文字列に変換する

ここが最初のつまずきポイントです。GASのバイトはJavaと同じ符号付き(-128〜127)で返るため、そのまま16進に直すと値が壊れます。負の値には256を足して0〜255に戻し、2桁でゼロ埋めしてから連結します。

function bytesToHex(bytes) {
  // computeDigest が返すバイトは -128〜127 の符号付き。
  // 負の値は 256 を足して 0〜255 に戻し、2桁の16進にそろえる
  return bytes
    .map((b) => (b < 0 ? b + 256 : b).toString(16).padStart(2, "0"))
    .join("");
}

このbytesToHexは一度書けば使い回せます。SHA-256なら64文字、MD5なら32文字の16進文字列になります。

MD5・SHA-1に切り替える

アルゴリズムを変えたいときはDigestAlgorithmの指定を差し替えるだけです。MD5・SHA_1・SHA_256・SHA_512などが使えます。

function md5Hex(text) {
  const bytes = Utilities.computeDigest(
    Utilities.DigestAlgorithm.MD5,
    text,
    Utilities.Charset.UTF_8
  );
  return bytesToHex(bytes);
}

// SHA-1 を使いたい場合は DigestAlgorithm.SHA_1 に変えるだけ

MD5は高速ですが、別々の入力から同じ値を作る「衝突」が現実的に可能なため、改ざん検知やセキュリティ用途には向きません。単なる重複判定や変更検知のキー用途なら実用上問題ありませんが、迷ったらSHA-256を選べば安全です。

ハッシュでデータの変更を検知する

ハッシュの定番の使い道が「前回と同じか」の判定です。内容全体を保存して比較する代わりに、短いハッシュだけをPropertiesService(設定値を保存する領域)に残しておき、次回のハッシュと比べます。値が違えば内容が更新されたと分かります。

// 前回と内容が変わったときだけ true を返す(初回も true)
function hasChanged(key, currentText) {
  const props = PropertiesService.getScriptProperties();
  const prevHash = props.getProperty(key);
  const currentHash = sha256Hex(currentText);

  if (prevHash === currentHash) {
    return false; // 変更なし
  }
  props.setProperty(key, currentHash); // 最新のハッシュを保存
  return true;
}

// 使用例: 外部ページの内容が更新されたときだけ通知する
function checkPageUpdate() {
  const html = UrlFetchApp.fetch("https://example.com/news").getContentText();
  if (hasChanged("news-page", html)) {
    MailApp.sendEmail("you@example.com", "ページが更新されました", "内容を確認してください");
  }
}

この仕組みは、外部ページの更新監視、スプレッドシートの内容が変わったときだけ通知する処理、同じ内容の再送信を無視する処理などに応用できます。

HMACでWebhookの署名を検証する

署名検証には、ただのハッシュではなく秘密鍵を組み込んだHMACを使います。GASではUtilities.computeHmacSignatureで計算し、送られてきた署名と一致するかを比べます。署名の形式はサービスごとに異なり、LINEはBase64、GitHubは16進文字列です。

// Webフォームや外部サービスのWebhook署名を検証する
function verifySignature(body, signature, secret) {
  const bytes = Utilities.computeHmacSignature(
    Utilities.MacAlgorithm.HMAC_SHA_256,
    body,
    secret,
    Utilities.Charset.UTF_8
  );

  // LINEなど署名がBase64の場合
  const expected = Utilities.base64Encode(bytes);
  return expected === signature;

  // GitHubなどhex形式の場合は次のように比較する
  // return bytesToHex(bytes) === signature;
}

// doPost内で受信データが正当か確認してから処理する
function doPost(e) {
  const body = e.postData.contents;
  const signature = e.parameter.signature; // 実際は署名の受け取り方に合わせる
  const secret = PropertiesService.getScriptProperties().getProperty("WEBHOOK_SECRET");

  if (!verifySignature(body, signature, secret)) {
    return ContentService.createTextOutput("invalid signature");
  }
  // ここから正当なリクエストの処理
  return ContentService.createTextOutput("ok");
}

秘密鍵はコードに直書きせず、PropertiesServiceに保存して読み出します。署名が一致しないリクエストは処理せず弾くことで、なりすましの投稿を防げます。

スプレッドシートの行から重複判定キーを作る

複数列の組み合わせで重複を判定したいとき、列の値をそのまま連結するとキーが長くなりがちです。連結した文字列をハッシュ化すれば、どんなに列が多くても固定長の短いキーにまとまり、Setでの照合もすっきりします。

// 指定した列を連結してハッシュ化し、行の重複判定キーにする
function rowHash(row, keyColumns) {
  const source = keyColumns
    .map((i) => String(row[i]).trim())
    .join("|");
  return sha256Hex(source);
}

// 使用例: 氏名(0列)とメール(2列)が同じ行を重複として弾く
function dedupeByHash() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("受付データ");
  const data = sheet.getDataRange().getValues();
  const header = data[0];
  const rows = data.slice(1);

  const seen = new Set();
  const uniqueRows = rows.filter((row) => {
    const key = rowHash(row, [0, 2]);
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });

  sheet.clearContents();
  sheet.getRange(1, 1, 1, header.length).setValues([header]);
  if (uniqueRows.length > 0) {
    sheet.getRange(2, 1, uniqueRows.length, header.length).setValues(uniqueRows);
  }
}

連結時は列と列の間に区切り文字を入れるのがコツです。区切りがないと「AB」+「C」と「A」+「BC」が同じキーになり、別データを重複と誤判定してしまいます。

実務での注意点

1. 文字コードは必ず明示する

第3引数を省略すると、日本語を含む文字列でハッシュがずれることがあります。UTF_8を明示し、比較する相手側の文字コードともそろえてください。

2. バイトの符号に注意する

バイトが負の値で返ることを忘れると、16進変換で桁が欠けたり値が化けたりします。負の値に256を足す処理を必ず入れましょう。

3. ハッシュは元に戻せない

ハッシュは一方向の変換です。元データの保管が必要な用途では、ハッシュとは別に元データも保存してください。パスワード保存など機微な用途では、ソルトや専用の仕組みが別途必要になります。

まとめ

GASのUtilities.computeDigestは、バイト配列を16進文字列に変換する関数さえ用意すれば、変更検知・重複判定・整合性チェックに幅広く使えます。署名検証にはcomputeHmacSignatureを使い、秘密鍵はPropertiesServiceに保存します。文字コードの明示とバイトの符号処理という2つの落とし穴だけ押さえれば、追加ライブラリなしで安全なハッシュ処理を実装できます。

よくある質問

Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, text, Utilities.Charset.UTF_8) を使います。戻り値はバイト配列(Byte[])なので、そのままでは扱いにくく、通常は16進数の文字列に変換して使います。第3引数の文字コードを省略するとShift_JIS由来の環境で結果がずれることがあるため、UTF_8を明示するのがおすすめです。

GASのバイトはJavaのbyte型と同じで、-128〜127の符号付きで表現されるためです。0xFF(255)は-1のように負の値として返ります。16進文字列に直すときは、負の値に256を足して0〜255に戻してから、toString(16)で2桁ゼロ埋めするのが定番です。

同じ入力なら必ず同じ値になり、少しでも内容が変わると全く別の値になる性質を使い、データの変更検知(前回と同じかの差分チェック)、重複判定用の短いキー作成、ファイルやテキストの改ざんチェックなどに使えます。ハッシュは元に戻せない一方向の変換なので、暗号化(後で復号する用途)とは目的が異なります。

署名検証にはハッシュではなくHMACを使います。GASではUtilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256, body, secret, Utilities.Charset.UTF_8)で計算し、送られてきた署名と一致するか比べます。LINEなど署名がBase64の場合はUtilities.base64Encode、GitHubなどhex形式の場合は16進文字列に変換して比較します。

改ざん検知やセキュリティが関わる場面ではSHA-256を使ってください。MD5は衝突(別々の入力から同じ値が出る)が現実的に作れてしまうため、セキュリティ用途には非推奨です。単なる重複判定や変更検知のキーとしては速いMD5でも実用上問題ありませんが、迷ったらSHA-256を選べば安全です。

GAS開発・業務Webシステムを
相談する。

ハッシュを使った変更検知やWebhook連携、フォームの署名検証など、外部サービスと安全につなぐGAS開発をご相談いただけます。

GAS Webシステム開発を見る