| 1 |
3 |
ahitrov@rambler.ru |
package Utils::Spam::SecretForm; |
| 2 |
|
|
|
| 3 |
|
|
use strict; |
| 4 |
|
|
use Digest::MD5; |
| 5 |
|
|
use Contenido::Globals; |
| 6 |
|
|
use Scalar::Util qw(blessed); |
| 7 |
|
|
|
| 8 |
|
|
# ��������� ������ ��� ������� � hidden-���� ����� |
| 9 |
|
|
# ��� ������������ �������� ������������. |
| 10 |
|
|
# extra - �������������� �������� ��� ��������� ������ |
| 11 |
|
|
# (� �������, ���� ������� ���������, ����� ���������� ��� �����) |
| 12 |
|
|
# �� ������ ���������� ������ �������� ��� ���������. |
| 13 |
|
|
sub generate { |
| 14 |
|
|
my %opts = @_; |
| 15 |
|
|
|
| 16 |
|
|
my ($start_time, $secret_code) = &get_secret_code(allow_generate_code => 1, memd => $opts{'memd'}); |
| 17 |
|
|
return unless $start_time && $secret_code; |
| 18 |
|
|
|
| 19 |
|
|
my $random = &get_random_string(5); |
| 20 |
|
|
# start secret code time | generate time | hash |
| 21 |
|
|
return $start_time.'|'.time().'|'.$random.'|'.Digest::MD5::md5_hex($start_time.$secret_code.$random.$opts{'extra'}); |
| 22 |
|
|
} |
| 23 |
|
|
|
| 24 |
|
|
# ��������� �������� hidden-���� ����� |
| 25 |
|
|
# secret - ���, ��� �������� |
| 26 |
|
|
# ttl - ����� ����� ��������� ���� |
| 27 |
|
|
# check_count - true �������� ���������� �� ������� ���������� ������������� |
| 28 |
|
|
sub validate { |
| 29 |
|
|
my %opts = @_; |
| 30 |
|
|
|
| 31 |
|
|
my $user_secret = $opts{'secret'}; |
| 32 |
|
|
my $ttl = $opts{'ttl'} || 3600; |
| 33 |
|
|
my $extra = $opts{'extra'}; |
| 34 |
|
|
my $check_count = $opts{'check_count'}; |
| 35 |
|
|
my $result = { is_valid => 1, is_expired => 0, count => 1 }; |
| 36 |
|
|
my $memd = blessed($opts{'memd'}) ? $opts{'memd'} : $keeper->MEMD(); |
| 37 |
|
|
|
| 38 |
|
|
return $result unless blessed($memd); |
| 39 |
|
|
|
| 40 |
|
|
# ���������� �� ������������ ������ |
| 41 |
|
|
my ($user_start_time, $user_generate_time, $user_random, $user_hash) = split(/\|/, $user_secret); |
| 42 |
|
|
|
| 43 |
|
|
# ������ � ��������� ������ |
| 44 |
|
|
my ($start_time, $secret_code) = &get_secret_code(time => $user_start_time, memd => $memd); |
| 45 |
|
|
|
| 46 |
|
|
# ���� ��� �� �������� ��������� ����� ��������� |
| 47 |
|
|
return $result if !defined($start_time) && !defined($secret_code); |
| 48 |
|
|
|
| 49 |
|
|
if (Digest::MD5::md5_hex($start_time.$secret_code.$user_random.$extra) ne $user_hash) { |
| 50 |
|
|
$result->{'is_valid'} = 0; |
| 51 |
|
|
} |
| 52 |
|
|
|
| 53 |
|
|
if ($result->{'is_valid'} && (($user_generate_time-$start_time > 3600) |
| 54 |
|
|
|| (time()-$user_generate_time > $ttl)) |
| 55 |
|
|
) { |
| 56 |
|
|
$result->{'is_expired'} = 1; |
| 57 |
|
|
} |
| 58 |
|
|
|
| 59 |
|
|
# ���� ���������� �������� �� ��������� ������������� |
| 60 |
|
|
# ������ � ���������� ������������� ���������� ��������� � ���� |
| 61 |
|
|
if ($result->{'is_valid'} && !$result->{'is_expired'} && $check_count) { |
| 62 |
|
|
|
| 63 |
|
|
$result->{'count'} = $memd->incr('usersecret|'.$user_secret, 1) if $memd; |
| 64 |
|
|
|
| 65 |
|
|
unless ($result->{'count'}) { |
| 66 |
|
|
$memd->add('usersecret|'.$user_secret, 1, $ttl) if $memd; |
| 67 |
|
|
$result->{'count'} = 1; |
| 68 |
|
|
} |
| 69 |
|
|
} |
| 70 |
|
|
|
| 71 |
|
|
return $result; |
| 72 |
|
|
} |
| 73 |
|
|
|
| 74 |
|
|
# ���������, ������� ���������� true ��� false � ����������� �� ����������, �������������� |
| 75 |
|
|
# � ���������� ������������� |
| 76 |
|
|
sub is_valid_secret { |
| 77 |
|
|
my %opts = @_; |
| 78 |
|
|
|
| 79 |
|
|
my $validate = &validate(%opts); |
| 80 |
|
|
|
| 81 |
|
|
if ($validate->{'is_valid'} && !$validate->{'is_expired'} |
| 82 |
|
|
&& (!$opts{'check_count'} || ($opts{'check_count'} && $validate->{'count'} == 1))) |
| 83 |
|
|
{ |
| 84 |
|
|
return 1; |
| 85 |
|
|
} |
| 86 |
|
|
|
| 87 |
|
|
return undef; |
| 88 |
|
|
} |
| 89 |
|
|
|
| 90 |
|
|
# ��������� ��������� � ��������� ��� ������������� |
| 91 |
|
|
# ���������� ����. ��������� ���� ����������� � ������� �����. |
| 92 |
|
|
# time - ��� ���������� ������� ������ ���������� �� ��� ������ ��� |
| 93 |
|
|
# allow_generate_code - ��������� ������������ ���, ���� �� �� ������ |
| 94 |
|
|
sub get_secret_code { |
| 95 |
|
|
my %opts = @_; |
| 96 |
|
|
|
| 97 |
|
|
# ������� ������� memcached �������� ������������ |
| 98 |
|
|
# �������� ����������������� |
| 99 |
|
|
my $memd = blessed($opts{'memd'}) ? $opts{'memd'} : $keeper->MEMD(); |
| 100 |
|
|
return unless blessed($memd); |
| 101 |
|
|
|
| 102 |
|
|
my $time = abs(int($opts{'time'})); |
| 103 |
|
|
my $now_time = time(); |
| 104 |
|
|
|
| 105 |
|
|
# ����� � ����������� �� ������ ���� |
| 106 |
|
|
unless ($time) { |
| 107 |
|
|
$time = $now_time; |
| 108 |
|
|
$time = $time - ($time % 3600); |
| 109 |
|
|
} |
| 110 |
|
|
|
| 111 |
|
|
my $cache_key = 'secret_code|'.$time; |
| 112 |
|
|
|
| 113 |
|
|
my $secret_code = $memd->get($cache_key); |
| 114 |
|
|
return ($time, $secret_code) if $secret_code; |
| 115 |
|
|
|
| 116 |
|
|
if ($opts{'allow_generate_code'}) { |
| 117 |
|
|
$secret_code = &get_random_string(10); |
| 118 |
|
|
$memd->set($cache_key, $secret_code); |
| 119 |
|
|
} |
| 120 |
|
|
|
| 121 |
|
|
return ($time, $secret_code); |
| 122 |
|
|
} |
| 123 |
|
|
|
| 124 |
|
|
|
| 125 |
|
|
# ��������� ��������� ������ |
| 126 |
|
|
# length - ����� ������ |
| 127 |
|
|
sub get_random_string { |
| 128 |
|
|
my $length = shift; |
| 129 |
|
|
$length = 10 unless $length && $length =~ /^\d+$/; |
| 130 |
|
|
|
| 131 |
|
|
my $random_chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; |
| 132 |
|
|
my $random_chars_length = length($random_chars); |
| 133 |
|
|
|
| 134 |
|
|
my $string = ''; |
| 135 |
|
|
for (1..$length) { |
| 136 |
|
|
$string .= substr($random_chars, int(rand($random_chars_length)), 1); |
| 137 |
|
|
} |
| 138 |
|
|
|
| 139 |
|
|
return $string; |
| 140 |
|
|
} |
| 141 |
|
|
|
| 142 |
|
|
|
| 143 |
|
|
1; |
| 144 |
|
|
__END__ |
| 145 |
|
|
|
| 146 |
|
|
=head1 NAME |
| 147 |
|
|
|
| 148 |
|
|
Utils::Spam::SecretForm - ������� ��������� � �������� ��������� ������ ��� web-���� |
| 149 |
|
|
|
| 150 |
|
|
=head1 SYNOPSIS |
| 151 |
|
|
|
| 152 |
|
|
���������: |
| 153 |
|
|
<input type="hidden" name="secret" value="<% Utils::Spam::SecretForm::generate() %>"> |
| 154 |
|
|
|
| 155 |
|
|
��������: |
| 156 |
|
|
my $validate = Utils::Spam::SecretForm::validate( secret => $ARGS{'secret'}, check_count => 0|1 ); |
| 157 |
|
|
if ($validate->{'is_valid'} && !$validate->{'is_expired'}) { |
| 158 |
|
|
allowed method |
| 159 |
|
|
} |
| 160 |
|
|
|
| 161 |
|
|
|
| 162 |
|
|
=head1 DESCRIPTION |
| 163 |
|
|
|
| 164 |
|
|
� ������� javascript ���������� ������ �������� http-������� get � post �������. |
| 165 |
|
|
����� �������� a.html ��������: |
| 166 |
|
|
<form method=post action=http://www.rambler.ru/post.html name="b"> |
| 167 |
|
|
<input type="text" name="text"> |
| 168 |
|
|
<input name="submit" type="submit" value="submit"> |
| 169 |
|
|
</form> |
| 170 |
|
|
<script> |
| 171 |
|
|
document.b.submit.click(); |
| 172 |
|
|
</script> |
| 173 |
|
|
|
| 174 |
|
|
����� �������, �������, �������� �� �������� a.html, �������� ������ �����. |
| 175 |
|
|
��� ������ � ������ ����� ���� ������� ������������ ������ ������. |
| 176 |
|
|
|
| 177 |
|
|
������� ������: ��� � ��� ������������ ��������� ��������� ������, ������� �������� � ���� �� ����� secret_code|�����_���������. |
| 178 |
|
|
���� ��� �� ��������, ��������� �������� ������� ��� ������ ���� ��������. |
| 179 |
|
|
������������ ��� ��������� ����� �������� ����� ��� � hidden ����, ������� ������� �� ���� ������: |
| 180 |
|
|
1) ����� ��������� ��������� ������ |
| 181 |
|
|
2) ����� ������ ������ ������������ |
| 182 |
|
|
3) ��������� ������ |
| 183 |
|
|
4) md5_hex( ����� ������ ������ ������������ . ��������� ������ . ��������� ������) |
| 184 |
|
|
��� ����������� ����������� hidden-��������� ���������� ��������� ��������� ������ �� ���� secret_code|�����_���������, ��������� md5_hex(������� . ���������� ������) � �������� ������� ������� ��������� ���� � �������� �������. |
| 185 |
|
|
����� ������� �������� ������ �� ������������������� ��������. ��� ������ �� ���������� ������������� ���� ���������� ������������ �������� check_count, � ����������� �� �������� � ���������� ����������� �������� ���������� ������������� ���� (����� ������� ������������� count = 1). |
| 186 |
|
|
��� ��������� ������ ���������� ����������� ���������� extra ��������� ��� ��������� hidden-����, �������� ��� ������������ ������������, ��� ����� ���� ����� ��� ������. �� ���������� �� �������� ���������� ���� �������� �� ����� ���������. |
| 187 |
|
|
|