Hi,

Arslan Kabeer (on the Internet) made me aware of clickjacking being done on
my site using OpenBSD httpd.  This following patch implements a RFC 7034
protection called "noiframe" which disallows other sites (but not the same
site) to add an iframe to my site.

The config change is like this:

----->
        location "/" {
                directory index index.html
                noiframe
        }
<-----

The header that is added is the same that google.com adds and it is:

X-Frame-Options: SAMEORIGIN

but only if noiframe is set.

The small patch is against 7.2 openhttpd.

Best Regards,
-peter


Index: httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.161
diff -u -p -u -r1.161 httpd.h
--- httpd.h     15 Aug 2022 12:29:17 -0000      1.161
+++ httpd.h     7 Feb 2023 08:57:40 -0000
@@ -544,6 +544,8 @@ struct server_config {
        int                      fcgistrip;
        char                     errdocroot[HTTPD_ERRDOCROOT_MAX];
 
+       int                     noiframe;
+
        TAILQ_ENTRY(server_config) entry;
 };
 TAILQ_HEAD(serverhosts, server_config);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
retrieving revision 1.128
diff -u -p -u -r1.128 parse.y
--- parse.y     27 Feb 2022 20:30:30 -0000      1.128
+++ parse.y     7 Feb 2023 08:57:40 -0000
@@ -140,7 +140,7 @@ typedef struct {
 %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET
 %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
 %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
-%token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
+%token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT NOIFRAME
 %token ERRDOCS GZIPSTATIC
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
@@ -685,6 +685,7 @@ serveroptsl : LISTEN ON STRING opttls po
                        }
                        srv->srv_conf.flags |= SRVFLAG_SERVER_HSTS;
                }
+               | noiframe
                ;
 
 optfound       : /* empty */   { $$ = 0; }
@@ -697,6 +698,7 @@ hsts                : HSTS '{' optnl hstsflags_l '}'
                | HSTS
                ;
 
+
 hstsflags_l    : hstsflags optcommanl hstsflags_l
                | hstsflags optnl
                ;
@@ -716,6 +718,11 @@ hstsflags  : MAXAGE NUMBER         {
                }
                ;
 
+noiframe       : NOIFRAME              {
+                       srv_conf->noiframe = 1;
+               }
+               ;
+
 fastcgi                : NO FCGI               {
                        srv_conf->flags &= ~SRVFLAG_FCGI;
                        srv_conf->flags |= SRVFLAG_NO_FCGI;
@@ -1466,6 +1473,7 @@ lookup(char *s)
                { "max-age",            MAXAGE },
                { "no",                 NO },
                { "nodelay",            NODELAY },
+               { "noiframe",           NOIFRAME },
                { "not",                NOT },
                { "ocsp",               OCSP },
                { "on",                 ON },
Index: server_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
retrieving revision 1.153
diff -u -p -u -r1.153 server_http.c
--- server_http.c       21 Sep 2022 05:55:18 -0000      1.153
+++ server_http.c       7 Feb 2023 08:57:40 -0000
@@ -1557,6 +1557,17 @@ server_response_http(struct client *clt,
        if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
                return (-1);
 
+       /*
+        * X-Frame-Options header to prevent iframes/clickjacking
+        * As per RFC 7034 (Informational)
+        */
+
+       if (srv_conf->noiframe) {
+               if (kv_add(&resp->http_headers, "X-Frame-Options", 
+                               "SAMEORIGIN") == NULL)
+                       return (-1);
+       }
+
        /* Is it a persistent connection? */
        if (clt->clt_persist) {
                if (kv_add(&resp->http_headers,

Reply via email to