[vlc-devel] [PATCH 1/2] httpd: mitigate CRSF attack by checking request Origin

Pierre Lamot pierre at videolabs.io
Wed Jan 31 18:38:01 CET 2018


---
 src/network/httpd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/src/network/httpd.c b/src/network/httpd.c
index d9237ebb9c..cfd947ad94 100644
--- a/src/network/httpd.c
+++ b/src/network/httpd.c
@@ -81,6 +81,7 @@ struct httpd_host_t
     int         *fds;
     unsigned     nfd;
     unsigned     port;
+    char        *psz_origin;
 
     vlc_thread_t thread;
     vlc_mutex_t lock;
@@ -971,6 +972,7 @@ static httpd_host_t *httpd_HostCreate(vlc_object_t *p_this,
     host->i_client = 0;
     host->client   = NULL;
     host->p_tls    = p_tls;
+    host->psz_origin =  url.psz_host ? strdup( url.psz_host ) : NULL;
 
     /* create the thread */
     if (vlc_clone(&host->thread, httpd_HostThread, host,
@@ -1040,6 +1042,8 @@ void httpd_HostDelete(httpd_host_t *host)
     net_ListenClose(host->fds);
     vlc_cond_destroy(&host->wait);
     vlc_mutex_destroy(&host->lock);
+    if ( host->psz_origin )
+        free( host->psz_origin );
     vlc_object_release(host);
     vlc_mutex_unlock(&httpd.mutex);
 }
@@ -1687,6 +1691,41 @@ auth_failed:
     return false;
 }
 
+//https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Verifying_Same_Origin_with_Standard_Headers
+static bool httpdOriginOk( const httpd_host_t *p_host, const httpd_message_t *p_query )
+{
+    char* psz_source_origin = NULL;
+    char* psz_target_origin = NULL;
+
+    const char* psz_origin = NULL;
+    const char* psz_referer = NULL;
+    if ( ( psz_origin = httpd_MsgGet( p_query, "Origin") ) != NULL )
+        psz_source_origin = strdup( psz_origin );
+    else if ( ( psz_referer = httpd_MsgGet( p_query, "Referer" ) ) != NULL ) {
+        vlc_url_t referer_url;
+        vlc_UrlParse( &referer_url, psz_referer );
+        psz_source_origin = strdup( referer_url.psz_host );
+        vlc_UrlClean( &referer_url );
+    } else //unknowned source origin
+        return true;
+
+    const char* psz_host = NULL;
+    if ( p_host->psz_origin ) {
+        psz_target_origin = strdup( p_host->psz_origin );
+    } else if ( ( psz_host = httpd_MsgGet( p_query, "Host" ) ) != NULL ) {
+        psz_target_origin = strndup( psz_host, strcspn(psz_host, ":") );
+    } else { //unknowned target origin
+        free( psz_source_origin );
+        return true;
+    }
+
+    bool ret = (strcmp( psz_source_origin, psz_target_origin ) == 0);
+    free( psz_source_origin );
+    free( psz_target_origin );
+    return ret;
+}
+
+
 static void httpdLoop(httpd_host_t *host)
 {
     struct pollfd ufd[host->nfd + host->i_client];
@@ -1821,6 +1860,7 @@ static void httpdLoop(httpd_host_t *host)
                     default: {
                         int i_msg = query->i_type;
                         bool b_auth_failed = false;
+                        bool b_crsf_failed = false;
 
                         /* Search the url and trigger callbacks */
                         for (int i = 0; i < host->i_url; i++) {
@@ -1835,8 +1875,17 @@ static void httpdLoop(httpd_host_t *host)
                                 b_auth_failed = !httpdAuthOk(url->psz_user,
                                    url->psz_password,
                                    httpd_MsgGet(query, "Authorization")); /* BASIC id */
+
                                 if (b_auth_failed)
                                    break;
+
+                                if ( query->i_proto == HTTPD_PROTO_HTTP )
+                                {
+                                    b_crsf_failed = !httpdOriginOk( host, query );
+
+                                    if ( b_crsf_failed )
+                                       break;
+                                }
                             }
 
                             if (url->catch[i_msg].cb(url->catch[i_msg].p_sys, cl, answer, query))
@@ -1858,7 +1907,9 @@ static void httpdLoop(httpd_host_t *host)
                             answer->i_type   = HTTPD_MSG_ANSWER;
                             answer->i_version= 0;
 
-                           if (b_auth_failed) {
+                           if ( b_crsf_failed ) {
+                               answer->i_status = 403;
+                           } else if ( b_auth_failed ) {
                                 httpd_MsgAdd(answer, "WWW-Authenticate",
                                         "Basic realm=\"VLC stream\"");
                                 answer->i_status = 401;
-- 
2.14.1



More information about the vlc-devel mailing list