Как использовать хэш для проверки целостности загруженных частей файла
Что проверяют
Умеете ли вы построить схему проверки, а не только вызвать SHA256. Важно, различаете ли вы случайную порчу и подмену данных и считаете ли хэш потоково. Следом часто спрашивают: а если злоумышленник подменит и файл, и хэш?
Как отвечать
Схема для загрузки по частям:
- клиент режет файл на чанки, считает хэш каждого и всего файла, шлёт хэш чанка вместе с ним, например в заголовке
Content-Digestиз RFC 9530; - сервер считает хэш по мере чтения тела, не буферизуя его целиком, и при расхождении отвечает ошибкой. Клиент перезаливает только этот чанк;
- после сборки сервер сверяет итоговый хэш, чтобы поймать ошибку в порядке или склейке частей.
Инструменты .NET:
SHA256.HashData: статический метод без создания объекта, для потока естьSHA256.HashDataAsync(Stream);IncrementalHash:CreateHash(HashAlgorithmName.SHA256), затемAppendDataна каждый буфер иGetHashAndResetв конце. Удобно копить хэш файла по мере прихода чанков;Convert.ToHexString: hex безBitConverterиReplace;CryptographicOperations.FixedTimeEquals: сравнение за постоянное время, когда значение работает как секрет;HMACSHA256: защита от подмены, ключ знают только клиент и сервер.
Против одних сетевых сбоев хватит CRC32 или xxHash из пакета System.IO.Hashing, они быстрее. MD5 и SHA-1 для безопасности не годятся: коллизии для них строятся на практике.
Где спотыкаются
Читают файл через File.ReadAllBytes и только потом хэшируют. На гигабайтной загрузке это лишняя память, а поток хэшируется кусками.
Называют хэш защитой от атакующего. Если хэш едет тем же каналом, что и данные, подменить оба ничего не стоит: нужен HMAC, подпись или хэш из доверенного источника.
Сравнивают строки, не договорившись о формате: hex в разном регистре, Base64 против hex. Надёжнее сравнивать байты, а не их текстовое представление.