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 73cc3e5..d5a3876 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 ($) {