chiark / gitweb /
blinding: Blind cookies and hidden form param
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Oct 2015 13:37:15 +0000 (13:37 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Oct 2015 13:37:15 +0000 (13:37 +0000)
Each time we generate a cookie or a hidden form parameter, generate
some random hex digits and xor them with the hex digits in the cookie
or parameter value.

Our cookies contain decimal digits, and punctuation, too.  The decimal
digits are simply blinded the same way (which is fine) and the
punctuation is left alone.  It's the actual values we care about.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
cgi-auth-flexible.pm

index 73cc3e5594bcb94b32e4432518a8ae468245b53a..d5a3876b644662b963dbb51ee5a030f6189f89d4 100644 (file)
@@ -791,7 +791,8 @@ sub _check_divert_core ($) {
                  Params => { } });
     }
 
-    my $cooks = $r->_ch('get_cookie');
+    my $cooksraw = $r->_ch('get_cookie');
+    my $cooks = $r->_unblind($cooksraw);
 
     if ($r->{S}{encrypted_only} && !$r->_ch('is_https')) {
         return ({ Kind => 'REDIRECT-HTTPS',
@@ -801,7 +802,8 @@ sub _check_divert_core ($) {
     }
 
     my $meth = $r->_ch('get_method');
-    my $parmh = $r->_rp('assoc_param_name');
+    my $parmhraw = $r->_rp('assoc_param_name');
+    my $parmh = $r->_unblind($parmhraw);
     my $cookh = defined $cooks ? $r->hash($cooks) : undef;
 
     my ($cookt,$cooku) = $r->_identify($cookh, $cooks);
@@ -913,7 +915,7 @@ sub _check_divert_core ($) {
         die unless $cookh eq $parmh;
     }
     $r->{ParmT} = $parmt;
-    $r->{AssocSecret} = $cooks;
+    $r->{AssocRaw} = $cooks;
     $r->{UserOK} = $cooku;
 #print STDERR "C-D-C OK\n";
     return undef;
@@ -1034,10 +1036,10 @@ sub check_divert ($) {
     $dbh->commit();
 
     my $cookraw = $r->{_CookieRaw};
-    $r->{CookieSecret} = $$cookraw;
+    $r->{CookieSecret} = $r->_blind($cookraw);
     if ($cookraw) {
        $r->{Params}{$r->{S}{assoc_param_name}} = [
-           $r->hash($cookraw)
+           $r->_blind($r->hash($cookraw))
            ];
     }
 
@@ -1159,6 +1161,39 @@ sub _random ($$) {
     return $out;
 }
 
+sub _blind_len ($$) {
+    my ($r, $str) = @_;
+    return length($str =~ y/0-9a-f//cdr);
+}
+
+sub _blind_combine ($$$) {
+    my ($r, $in, $mask) = @_;
+    my @mask = split //, $mask;
+    $in =~ s{[0-9a-f]}{
+        my $m = shift @mask;
+        sprintf "%x", hex($m) ^ hex($&);
+    }ge;
+    return $in;
+}
+
+sub _blind ($$) {
+    my ($r, $in) = @_;
+    return undef unless defined $in;
+    my $l = $r->_blind_len($in);
+    my $mask = $r->_random(($l+1)>>1);
+    $mask = substr $mask, 0, $l;
+    my $blound = $r->_blind_combine($in, $mask);
+    return "$blound/$mask";
+}
+
+sub _unblind ($$) {
+    my ($r, $in) = @_;
+    my ($blound,$mask) = ($in =~ m#^(.*)/([0-9a-f]+)$#) or die "$in ?";
+    my $l = $r->_blind_len($blound);
+    $l == length($mask) or die "$in ?";
+    return $r->_blind_combine($blound, $mask);
+}
+
 sub _random_key ($) {
     my ($r) = @_;
 #print STDERR "_random_key\n";
@@ -1340,13 +1375,13 @@ sub check_nonpage ($$) {
 sub secret_cookie_val ($) {
     my ($r) = @_;
     $r->_assert_checked();
-    return defined $r->{AssocSecret} ? $r->{AssocSecret} : '';
+    return defined $r->{AssocRaw} ? $r->_blind($r->{AssocRaw}) : '';
 }
 
 sub secret_hidden_val ($) {
     my ($r) = @_;
     $r->_assert_checked();
-    return defined $r->{AssocSecret} ? $r->hash($r->{AssocSecret}) : '';
+    return defined $r->{AssocRaw} ? $r->_blind($r->hash($r->{AssocRaw})) : '';
 }
 
 sub secret_hidden_html ($) {