Search code examples
javascriptcssevalobfuscationemail-address

Referencing JS code stored in CSS Content property


UPDATE: After having the code out in the wild for a while, I found two issues on Citrix and iOS Safari. Both seem to be around the use of Eval. The citrix issue could have been resolved by updating the CSS to :

emailerrormessage = 'please enable Javascript'; ahref.attr('data-edomain') + '\0040' + ahref.attr('data-ename');

The iOS Safari issue was not something I managed to resolve. I ended up cutting out the CSS element altogether.

EDIT: I'm opening up this question for recommendations on why my solution might be considered bad programming in general, and if anyone else has a better way of obfuscating emails through a combination of CSS, HTML and JS. I've added an answer of my own findings, but haven't marked it as the answer in case someone else might have better insight into this technique.

I've been tasked to obfuscate email addresses on some webpages, and after encountering an answer suggesting use of CSS and data attributes I tried implementing it myself and found that getting the produced email address back into a mailto element was impossible without some JavaScript. The next problem encountered was that the JavaScript I ended up using to grab the rendered email address was not cross-browser as some browsers retrieve "attr(data-xx)" instead of the actual value. However I still like the idea of producing a solution that spans HTML, JS and CSS for maximum complexity. The last resort was to store a line of JS in the CSS content property, and use eval to produce the final email address.

Obfuscation is not supposed to be pretty, but I want to know if what I've done is potentially compromising security or performance by introducing eval() and/or storing JS in CSS. I haven't found another example of someone doing something similar (maybe for good reason).

My HTML is

<a class="redlinktext ninjemail" data-ename="snoitagitsevni" data-edomain="ua.moc.em" data-elinktext="click me"></a>

My CSS is

.ninjemail:before {
    content: "'please enable Javascript'; ahref.attr('data-edomain') + '\0040' + ahref.attr('data-ename');"
}

My JavaScript is

$('.ninjemail').each(function () {
    var fullLink = "ma";
    var ahref = $(this);
    fullLink += "ilto" + ":";
    var codeLine = window.getComputedStyle(this, ':before').content.replace(/\"|\\/g, '');
    var emailAddress = eval(codeLine);
    emailAddress = emailAddress.split('').reverse().join('');
    fullLink += emailAddress;
    ahref.attr('href', fullLink);
    var linkText = ahref.attr('data-elinktext');
    if (linkText && linkText.length > 0) {
        ahref.text(linkText);
    } else {
        ahref.text(emailAddress);
    }
    ahref.removeClass('ninjemail');
});

Solution

  • Based on the research I've done so far the only real drawback from using this method for obfuscation is that in teams where there is a clear separation of roles, Javascript in CSS files may confuse layout designers, and vice versa (programmers won't want to have to edit CSS files).

    Performance wise there will always be more overhead in processing the email address across the three technologies. I can't say I'm an expert on performance testing, but I did a page refresh timing of before and after and got a DOMContentLoaded time of .956s vs .766s without obfuscation. Load time was 1.22s vs 1.17s without obfuscation. Not a concern for my own situation, but may be an issue on more intensive applications. Note that this was a once off test, and not an average of multiple runs in a controlled environment.