C# Tips | セキュリティ:Hashを比較する

C# C#
スポンサーリンク
スポンサーリンク

Hashを比較することは「改ざん検知・認証・整合性チェックの中心技術」です

業務システムを開発する読者のみなさんにとって、 ハッシュ値を正しく比較することは、セキュリティの基礎でありながら非常に重要な技術です。

ハッシュ比較は次のような場面で使われます。

  • ファイルが改ざんされていないか確認する
  • パスワードの検証(高速ハッシュは非推奨だが仕組みは同じ)
  • API署名の検証
  • データの整合性チェック
  • キャッシュキーの一致確認

ここでは、初心者でも理解できるように、 実務で使える C# の「ハッシュ比較ユーティリティ」を ステップバイステップで丁寧に解説します。

ハッシュ比較の基本原理

ハッシュは「指紋」である

ハッシュ値は、入力データから計算される一方向の指紋です。

  • 同じ入力 → 同じハッシュ
  • 少しでも違う入力 → 全く違うハッシュ
  • ハッシュから元のデータを復元することはできない

この性質を利用して「同じデータかどうか」を比較します。

ハッシュ比較で重要なポイント(深掘り)

1. 大文字・小文字の違いに注意

Hex形式のハッシュ値は、 ABCDEFabcdef は同じ意味です。

比較時は 大文字・小文字を区別しない比較 を使います。

2. 文字列比較ではなく「固定時間比較」が必要な場合がある

セキュリティ用途では、 通常の == 比較はタイミング攻撃に弱いです。

攻撃者は「比較にかかる時間の差」から 一致している部分を推測できてしまいます。

そのため、 CryptographicOperations.FixedTimeEquals を使うことが推奨されます。

3. ハッシュアルゴリズムが異なると比較できない

SHA-256 と SHA-512 は別物です。

  • SHA-256 → 64桁のHex
  • SHA-512 → 128桁のHex

アルゴリズムが違うと比較できません。

実務で使えるハッシュ比較ユーティリティ(テンプレート)

using System;
using System.Security.Cryptography;
using System.Text;

public static class HashCompareUtility
{
    /// <summary>
    /// Hex形式のハッシュ値を固定時間比較で検証します。
    /// </summary>
    public static bool CompareHex(string expectedHex, string actualHex)
    {
        // 大文字・小文字を統一
        string normalizedExpected = expectedHex.ToLower();
        string normalizedActual = actualHex.ToLower();

        byte[] expectedBytes = Encoding.UTF8.GetBytes(normalizedExpected);
        byte[] actualBytes = Encoding.UTF8.GetBytes(normalizedActual);

        return CryptographicOperations.FixedTimeEquals(expectedBytes, actualBytes);
    }

    /// <summary>
    /// Base64形式のハッシュ値を固定時間比較で検証します。
    /// </summary>
    public static bool CompareBase64(string expectedBase64, string actualBase64)
    {
        byte[] expectedBytes = Encoding.UTF8.GetBytes(expectedBase64);
        byte[] actualBytes = Encoding.UTF8.GetBytes(actualBase64);

        return CryptographicOperations.FixedTimeEquals(expectedBytes, actualBytes);
    }
}
C#

ハッシュ比較の使い方(例題)

例1:SHA-256ハッシュを比較する

string expected = "9f2c4a..."; // 保存していたハッシュ値
string actual = FileHashUtility.ComputeSha256Hex("sample.txt");

bool match = HashCompareUtility.CompareHex(expected, actual);

if (match)
{
    Console.WriteLine("ファイルは正しい状態です。");
}
else
{
    Console.WriteLine("ファイルが改ざんされている可能性があります。");
}
C#

例2:API署名の比較(Base64)

string expectedSignature = request.Headers["X-Signature"];
string actualSignature = HmacUtility.GenerateHmacSha256Base64(message, secretKey);

if (!HashCompareUtility.CompareBase64(expectedSignature, actualSignature))
{
    throw new SecurityException("署名が一致しません");
}
C#

固定時間比較の深掘り(重要)

なぜ固定時間比較が必要なのか

通常の文字列比較は、 一致している部分が多いほど比較時間が短くなる傾向があります。

攻撃者はこの「時間差」を利用して、 署名やハッシュの一部を推測することができます。

固定時間比較は、 一致していてもしていなくても、比較にかかる時間が同じ になるように設計されています。

これにより、 タイミング攻撃を防ぐことができます。

ハッシュ比較で絶対にやってはいけないこと

  • 大文字・小文字を区別して比較する
  • 通常の == 比較を使う(セキュリティ用途では危険)
  • アルゴリズムが違うハッシュを比較する
  • ハッシュ値をログにそのまま出力する
  • ハッシュ値を「暗号化」と誤解する

これらはセキュリティ事故の原因になります。

実務的ベストプラクティス

  • Hex形式のハッシュは小文字に統一して比較する
  • セキュリティ用途では必ず固定時間比較を使う
  • ハッシュ値は安全な場所に保存する
  • ハッシュ値を扱うコードはログに出力しない
  • ハッシュアルゴリズムを統一する(SHA-256ならSHA-256で揃える)

まとめ:ハッシュ比較は「改ざん検知の最後の砦」

ハッシュ比較の本質は次の3つです。

  • 同じハッシュ値なら同じデータである
  • 少しでも違えば全く違うハッシュになる
  • セキュリティ用途では固定時間比較が必須

このユーティリティを使うことで、 業務システムの改ざん検知・署名検証・整合性チェックを 安全かつ確実に行えるようになります。

関連トピック(Guided Links)

  • SHA-256ハッシュ生成
  • SHA-512ハッシュ生成
  • HMAC署名の検証
  • ファイルハッシュ計算

タイトルとURLをコピーしました