our $sessiondb_user = "itkacl-web";
our $sessiondb_pass = undef;
+# Pick any random, secret string. E.g., the output of:
+# dd if=/dev/urandom bs=32 count=1 | hexdump
+our $hmac_key = undef;
+
# Local configuration overrides defaults.
eval {
require 'config.local.pm';
use Apache::Session::Postgres;
use Encode;
use HTML::Entities;
+use Digest::HMAC_SHA1;
use locale;
use utf8;
our $dbh;
our $last_modified = '$Date: 2011-11-19 11:08:01 $';
our %session;
+our $csrf_token;
+our $masked_csrf_token;
sub init {
$cgi = new CGI;
$dbh->{pg_enable_utf8} = 1;
$last_modified = '$Date: 2011-11-19 11:08:01 $';
%session = ();
+
+ if (defined($ENV{'REMOTE_USER'})) {
+ $csrf_token = Digest::HMAC_SHA1::hmac_sha1($ENV{'REMOTE_USER'}, $itkaclcommon::hmac_key);
+
+ # Mask the CSRF token to avoid the BREACH attack.
+ my @hmac_bytes = map { ord($_) } (split //, $csrf_token);
+ my @random_bytes = map { int(rand(256)) } (0..$#hmac_bytes);
+ my @masked_bytes = map { $hmac_bytes[$_] ^ $random_bytes[$_] } (0..$#hmac_bytes);
+
+ my $random_bytes_string = join('', map { chr($_) } (@random_bytes));
+ my $masked_bytes_string = join('', map { chr($_) } (@masked_bytes));
+ $masked_csrf_token = unpack('H*', $random_bytes_string) . '_' . unpack("H*", $masked_bytes_string);
+ } else {
+ $csrf_token = '';
+ $masked_csrf_token = '';
+ }
+}
+
+sub check_csrf_token {
+ if ($csrf_token eq '') {
+ # Not logged in, so always fine.
+ return 1;
+ }
+
+ my $candidate_csrf_token = $cgi->param('csrftoken');
+ if ($candidate_csrf_token !~ /^([0-9a-f]+)_([0-9a-f]+)$/) {
+ die "Invalid CSRF token!";
+ }
+
+ my ($random_bytes_string, $masked_bytes_string) = ($1, $2);
+ if (length($random_bytes_string) != length($masked_bytes_string)) {
+ die "Length mismatch in CSRF token!";
+ }
+
+ my @random_bytes = map { ord($_) } (split //, pack('H*', $random_bytes_string));
+ my @masked_bytes = map { ord($_) } (split //, pack('H*', $masked_bytes_string));
+ my @hmac_bytes = map { $masked_bytes[$_] ^ $random_bytes[$_] } (0..$#masked_bytes);
+ my $hmac_string = join('', map { chr($_) } (@hmac_bytes));
+
+ die "CSRF token mismatch!" if ($hmac_string ne $csrf_token);
}
sub print_header {
use itkaclcommon;
itkaclcommon::init();
+itkaclcommon::check_csrf_token();
my $allow = $itkaclcommon::cgi->param('allow');
my $entry = $itkaclcommon::cgi->param('entry');
use itkaclcommon;
itkaclcommon::init();
+itkaclcommon::check_csrf_token();
my $parent = $itkaclcommon::cgi->param('parent');
my $name = $itkaclcommon::cgi->param('name');
use itkaclcommon;
itkaclcommon::init();
+itkaclcommon::check_csrf_token();
my $entry = $itkaclcommon::cgi->param('entry');
my $entity = $itkaclcommon::cgi->param('entity');
use itkaclcommon;
itkaclcommon::init();
+itkaclcommon::check_csrf_token();
my $entry = $itkaclcommon::cgi->param('entry');
my $entity = $itkaclcommon::cgi->param('entity');
use itkaclcommon;
itkaclcommon::init();
+itkaclcommon::check_csrf_token();
my $entry = $itkaclcommon::cgi->param('entry');
'entry': td.getAttributeNS('http://acl.samfundet.no/', 'entry'),
'entity_type': td.getAttributeNS('http://acl.samfundet.no/', 'entity-type'),
'entity': td.getAttributeNS('http://acl.samfundet.no/', 'entity'),
+ 'csrftoken': td.getAttributeNS('http://acl.samfundet.no/', 'csrftoken'),
'comment': newComment
}
}).fail(function() { alert("Klarte ikke å endre kommentaren"); });
<td>$et_text</td>
<td>$e_text</td>
<td style="text-align: center;">
- <a href="/delete.pl?entry=$entry&entity_type=$entity_type&entity=$e_text">
+ <a href="/delete.pl?entry=$entry&entity_type=$entity_type&entity=$e_text&csrftoken=$itkaclcommon::masked_csrf_token">
<img src="/img/delete.png" alt="Slett" />
</a>
</td>
- <td ondblclick="enableEdit(this);" itkacl:entry="$entry" itkacl:entity-type="$entity_type" itkacl:entity="$e_text">$c_text</td>
+ <td ondblclick="enableEdit(this);" itkacl:entry="$entry" itkacl:entity-type="$entity_type" itkacl:entity="$e_text" itkacl:csrftoken="$itkaclcommon::masked_csrf_token">$c_text</td>
</tr>
EOF
}
<p>Den spesielle gruppen "<everyone>" inneholder alle brukere.</p>
<form method="post" action="add.pl">
+ <input type="hidden" name="csrftoken" value="$itkaclcommon::masked_csrf_token" />
<input type="hidden" name="entry" value="$entry" />
<table>
<tr style="text-align: left;">
er case-sensitive) samt tall og bindestrek.</p>
<form method="post" action="addnode.pl">
+ <input type="hidden" name="csrftoken" value="$itkaclcommon::masked_csrf_token" />
<input type="hidden" name="parent" value="$entry" />
<table>
<tr style="text-align: left;">
feile, så sjekk grundig før du sletter det at det ikke fortsatt er i bruk.</p>
<form method="post" action="deletenode.pl">
+ <input type="hidden" name="csrftoken" value="$itkaclcommon::masked_csrf_token" />
<input type="hidden" name="entry" value="$entry" />
<p><input type="submit" value="Slett dette området" /></p>
</form>