Hi,

I prepared a patch to check the Set-Cookie domain values for being Public 
Suffices using libpsl. This is mainly for detecting and preventing 
'Supercookies' being set by 'bad' web servers.

Here are some references for more detailed information:
https://publicsuffix.org/
https://github.com/publicsuffix/list
https://github.com/rockdaboot/libpsl

The patch is missing a test case - it was not obvious for me how to prevent 
such a test being performed when libpsl is not compiled in.
I added 'has_psl' to test/runtests.pl but here I am stuck.
If you could give me a hint on that (please with a test number), I'll make up 
a test case.

On Debian, Fedora, Arch and maybe some other distros libpsl has already been 
packaged (Debian: libpsl-dev, libpsl0:amd64, libpsl0-dbg:amd64, psl).

Please review / test the patch.

Regards, Tim
>From ee2fc8d2f571c620f4c97e575c00b98e289a611d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20R=C3=BChsen?= <[email protected]>
Date: Tue, 29 Sep 2015 11:33:01 +0200
Subject: [PATCH] Add support for Mozilla's Publix Suffix List

Use libpsl to check the domain value of Set-Cookie headers
(and cookie jar entries) for not being a Publix Suffix.

Ref: https://publicsuffix.org/
Ref: https://github.com/publicsuffix/list
Ref: https://github.com/rockdaboot/libpsl
---
 configure.ac      | 14 ++++++++++++++
 lib/cookie.c      | 21 +++++++++++++++++++++
 lib/version.c     |  9 +++++++++
 src/tool_help.c   |  3 +++
 tests/runtests.pl | 18 +++++++++++++++++-
 5 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 26d77eb..771deac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,6 +166,7 @@ curl_verbose_msg="enabled (--disable-verbose)"
    curl_rtsp_msg="no      (--enable-rtsp)"
    curl_rtmp_msg="no      (--with-librtmp)"
   curl_mtlnk_msg="no      (--with-libmetalink)"
+    curl_psl_msg="no      (--with-libpsl)"
 
     init_ssl_msg=${curl_ssl_msg}
 
@@ -2314,6 +2315,18 @@ dnl **********************************************************************
 CURL_CHECK_CA_BUNDLE
 
 dnl **********************************************************************
+dnl Check for libpsl
+dnl **********************************************************************
+
+AC_ARG_WITH(libpsl, AS_HELP_STRING([--without-libpsl], [disable support for libpsl cookie checking]), with_libpsl=$withval, with_libpsl=yes)
+if test $with_libpsl != "no"; then
+  AC_SEARCH_LIBS(psl_builtin, psl,
+    [curl_psl_msg="yes"; AC_DEFINE([USE_LIBPSL], [1], [PSL support enabled])],
+    [curl_psl_msg="no      (libpsl not found)"; AC_MSG_WARN(*** libpsl was not found. Supercookie vulnerability possible.)])
+fi
+AM_CONDITIONAL([USE_LIBPSL], [test "$curl_psl_msg" = "yes"])
+
+dnl **********************************************************************
 dnl Check for libmetalink
 dnl **********************************************************************
 
@@ -3741,6 +3754,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl:
   RTSP support:     ${curl_rtsp_msg}
   RTMP support:     ${curl_rtmp_msg}
   metalink support: ${curl_mtlnk_msg}
+  PSL support:      ${curl_psl_msg}
   HTTP2 support:    ${curl_h2_msg}
   Protocols:        ${SUPPORT_PROTOCOLS}
 ])
diff --git a/lib/cookie.c b/lib/cookie.c
index 22730cf..e09cea1 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -84,6 +84,10 @@ Example set of cookies:
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
 
+#ifdef USE_LIBPSL
+# include <libpsl.h>
+#endif
+
 #include "curl_printf.h"
 #include "urldata.h"
 #include "cookie.h"
@@ -379,6 +383,10 @@ Curl_cookie_add(struct SessionHandle *data,
   bool replace_old = FALSE;
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
 
+#ifdef USE_LIBPSL
+  const psl_ctx_t *psl;
+#endif
+
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
 #endif
@@ -777,6 +785,19 @@ Curl_cookie_add(struct SessionHandle *data,
   /* at first, remove expired cookies */
   remove_expired(c);
 
+#ifdef USE_LIBPSL
+  /* Check if the domain is a Public Suffix and if yes, ignore the cookie.
+     This needs a libpsl compiled with builtin data. */
+  if(co->domain && !isip(co->domain) && (psl = psl_builtin()) != NULL) {
+    if(psl_is_public_suffix(psl, co->domain)) {
+		/* infof("cookie '%s' dropped, domain '%s' is a public suffix\n", co->name, co->domain); */
+		fprintf(stderr,"cookie '%s' dropped, domain '%s' is a public suffix\n", co->name, co->domain);
+      freecookie(co);
+      return NULL;
+    }
+  }
+#endif
+
   clist = c->cookies;
   replace_old = FALSE;
   while(clist) {
diff --git a/lib/version.c b/lib/version.c
index 1727c5a..8784c2b 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -40,6 +40,10 @@
 #include <stringprep.h>
 #endif
 
+#ifdef USE_LIBPSL
+#include <libpsl.h>
+#endif
+
 #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
 #include <iconv.h>
 #endif
@@ -100,6 +104,11 @@ char *curl_version(void)
     ptr += len;
   }
 #endif
+#ifdef USE_LIBPSL
+  len = snprintf(ptr, left, " libpsl/%s", psl_get_version());
+  left -= len;
+  ptr += len;
+#endif
 #ifdef USE_WIN32_IDN
   len = snprintf(ptr, left, " WinIDN");
   left -= len;
diff --git a/src/tool_help.c b/src/tool_help.c
index 355fe7d..4f569cd 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -317,6 +317,9 @@ void tool_version_info(void)
 #ifdef USE_METALINK
     printf("Metalink ");
 #endif
+#ifdef USE_LIBPSL
+    printf("PSL ");
+#endif
     puts(""); /* newline */
   }
 }
diff --git a/tests/runtests.pl b/tests/runtests.pl
index 377d733..6e9f4a1 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -224,6 +224,7 @@ my $has_http2;      # set if libcurl is built with HTTP2 support
 my $has_crypto;     # set if libcurl is built with cryptographic support
 my $has_cares;      # set if built with c-ares
 my $has_threadedres;# set if built with threaded resolver
+my $has_psl;        # set if libcurl is built with PSL support
 
 # this version is decided by the particular nghttp2 library that is being used
 my $h2cver = "h2c";
@@ -2474,6 +2475,10 @@ sub checksystem {
                 # Metalink enabled
                 $has_metalink=1;
             }
+            if($feat =~ /PSL/i) {
+                # PSL enabled
+                $has_psl=1;
+            }
             if($feat =~ /AsynchDNS/i) {
                 if(!$has_cares) {
                     # this means threaded resolver
@@ -2599,8 +2604,9 @@ sub checksystem {
     logmsg sprintf("* HTTP Unix     %s\n", $http_unix?"ON ":"OFF");
     logmsg sprintf("* FTP IPv6      %8s", $ftp_ipv6?"ON ":"OFF");
     logmsg sprintf("  Libtool lib:  %s\n", $libtool?"ON ":"OFF");
-    logmsg sprintf("* Shared build:      %-3s", $has_shared);
+    logmsg sprintf("* PSL:          %8s", $has_psl?"ON ":"OFF");
     logmsg sprintf("  Resolver:     %s\n", $resolver);
+
     if($ssl_version) {
         logmsg sprintf("* SSL library: %13s\n", $ssllib);
     }
@@ -2981,6 +2987,11 @@ sub singletest {
                     next;
                 }
             }
+            elsif($1 eq "PSL") {
+                if($has_psl) {
+                    next;
+                }
+            }
             elsif($1 eq "socks") {
                 next;
             }
@@ -3117,6 +3128,11 @@ sub singletest {
                         next;
                     }
                 }
+                elsif($1 eq "PSL") {
+                    if(!$has_psl) {
+                        next;
+                    }
+                }
                 else {
                     next;
                 }
-- 
2.5.3

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to