В действительности вам нужна не простая хеш-функция, а код аутентификации сообщения , например HMAC . Поскольку вы говорите, что хотите использовать SHA-256, вам может понравиться HMAC_SHA256, который доступен в Perl через модуль Digest :: SHA :
use Digest::SHA qw(hmac_sha256_base64);
my $mac = hmac_sha256_base64( $string, $key );
Здесь $key
- произвольный ключ, который вы должны хранить в секрете, а $string
содержит данные, которые вы хотите подписать. Чтобы применить это к более сложной структуре данных (такой как хэш пар ключей и значений), сначала необходимо преобразовать ее в строку. Есть несколько способов сделать это; например, вы можете использовать Storable :
use Storable qw(freeze);
sub pairs_to_string {
local $Storable::canonical = 1;
my %hash = @_;
return freeze( \%hash );
}
Вы также можете кодировать URL, как , предложенное Дэвидом Шварцем . Важно то, что какой бы метод вы ни использовали, он всегда должен возвращать одну и ту же строку, если для него задан тот же хэш, что и для ввода.
Затем, перед отправкой данных пользователю, вы рассчитываете MAC для них и включаете его в качестве дополнительного поля в данные. Когда вы получаете данные обратно, вы удаляете поле MAC (и сохраняете его значение), пересчитываете MAC для оставшихся полей и сравниваете его с полученным значением. Если они не совпадают, кто-то (или что-то) подделал данные. Как это:
my $key = "secret";
sub mac { hmac_sha256_base64( pairs_to_string(@_), $key ) }
# before sending data to client:
my %data = (foo => "something", bar => "whatever");
$data{mac} = mac( %data );
# after receiving %data back from client:
my $mac = delete $data{mac};
die "MAC mismatch" if $mac ne mac( %data );
Обратите внимание, что есть некоторые потенциальные уловки, которые эта техника не предотвращает автоматически, такие как атаки воспроизведения : как только вы отправите данные и MAC пользователю, они узнают MAC, соответствующий конкретному набор данных, и может потенциально заменить поля в более поздней форме значениями, сохраненными из более ранней формы. Чтобы защитить себя от таких атак, вы должны включить достаточное количество идентифицирующей информации в данные, защищенные MAC, чтобы вы могли обнаружить любые потенциально опасные повторы. В идеале вы должны включить уникальный идентификатор в каждую форму и убедиться, что ни один идентификатор никогда не отправляется дважды, но это не всегда удобно. В противном случае может быть хорошей идеей добавить идентификатор пользователя (чтобы злоумышленник не мог обмануть кого-то другого в отправке своих данных) и идентификатор формы (чтобы пользователь не мог копировать данные из одной формы в другую). ) и, возможно, отметку времени и / или идентификатор сеанса (чтобы можно было отклонить старые данные) в форме (и в расчете MAC).