Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Tag Manager include that passes mod-security rules in Apache

I've been looking into using Google Tag Manager on my website, but I've failed at the first hurdle due to the default Google include code being blocked by the mod-security installation on my server:

Standard GTM include code:

<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- End Google Tag Manager -->

Response from mod-security:

WARNING:    Possibly malicious iframe tag in output
Message:    Outbound Anomaly Score Exceeded (score 15): Possibly malicious iframe tag in output

The rules triggered are ids 981000 and 981001.

I can understand why mod-security might think an iframe with "display:none;visibility:hidden" could be possibly malicious, and removing the style attribute stops rule 981001 from triggering, but the request still fails because of rule 981000.

981000 seems to have a strong opinion about what the width and height attributes should be, but I've tried setting them to '1' and '10' to no avail :-(

Does anyone know how to format an iframe to fit this rule? or how to change the GTM include code so that it doesn't contain the iframe?

Thanks

PS: I know you can solve this problem by removing the whole noscript area, but I'm looking for a solution that doesn't alter the functionality of the include code.

PPS: this is the pattern that rule 981000 is matching, I can understand about half of it before my brain explodes in a cloud of nested capture groups ;-)

Pattern match "<\W*iframe[^>]+?\b(?:width|height)\b\W*?=\W*?["']?[^"'1-9]*?(?:(?:20|1?\d(?:\.\d*)?)(?![\d%.])|[0-3](?:\.\d*)?%)"
like image 384
underscorePez Avatar asked Dec 07 '22 02:12

underscorePez


1 Answers

After a lot of experimentation - I found the following code works:

<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
height="21" width="21" class ="noDisplay"></iframe></noscript>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
<!-- End Google Tag Manager -->

It seems rule 981000 will fire for any iframe that is less than 21 pixels or 3% in width or height. Moving the visibility and display style information to an external stylesheet prevented rule 981001 from firing.

.noDisplay {
display:none;
visibility:hidden;
}

The code now passes mod security and includes GTM in the page in (pretty much) the way Google intended.

I hope that helps someone else struggling with the same problem :-)

like image 168
underscorePez Avatar answered Dec 11 '22 09:12

underscorePez