Этот скрипт iframe buster выглядит безопасным?

Нас просят разместить на нашем сайте несколько скриптов блокировки iframe — они позволяют рекламе, которая подается из внешних доменов в iframe, расширяться за их пределы на хост-страницу. Наш хостинг-провайдер предупредил нас, чтобы мы обращали внимание на дыры в безопасности этих скриптов. В частности, они говорят, что некоторые из них создают дыры в межсайтовых сценариях, позволяя загружать фрагмент Javascript на наш сайт с любого URL-адреса.

Для реализации скрипта вы размещаете HTML-страницу на своем сайте. Я смотрю на пример от поставщика рекламы Atlas. В этом случае URL имеет вид http://domain.com/atlas/atlas_rm.htm. Эта страница содержит тег script с src по внешнему URL-адресу, и вот JS, который он включает:

var ARMIfbLib = function () {

    function documentWrite(htmlString) {
        document.write(htmlString);
    }

    function writeIframeBustingScript() {
        var imgSrvPath = getTlDirectoryFromQueryString(getParameterString());
        if (imgSrvPath != "") {
            var scriptURL = imgSrvPath + getScriptFileName();
            ARMIfbLib.DocumentWrite("<script language='javascript' type='text/javascript' src='" + scriptURL + "'></scr" + "ipt>");
        }
    }

    return {
        WriteIframeBustingScript: writeIframeBustingScript,
        DocumentWrite: documentWrite
    }

}();

function getValueFromDelimitedString(paramKey, delimiter, queryString) {
    if (paramKey == "imgSrv")
        return getValueFromProperties();

    var re = new RegExp(paramKey + "=" + "(.*?)" + "(" + delimiter + "|$)");
    var matchArray = queryString.match(re);
    if (matchArray == null)
        return "";
    else
        return matchArray[1];
}

function getValueFromProperties() {
    var iframename = unescape(self.name);
    if (iframename.indexOf("<form") >= 0) {
        var params = iframename.split("<input ");
        for (var i = 1; i < params.length; i++) {
            var parts = params[i].split(" ");
            for (var j = 0; j < parts.length; j++) {
                var param = parts[j].split("=");
                if (param[0].indexOf("name") >= 0 && param[1].indexOf("TL_files_path") >= 0) {
                    param = parts[j + 1].split("=");
                    if (param[0].indexOf("value") >= 0) {
                        var value = param[1].substr(1, param[1].indexOf(">"));
                        value = value.substr(value, value.lastIndexOf("/"));
                        value = value.substr(value, value.lastIndexOf("/") + 1);
                        return unescape(value);
                    }
                }
            }
        }
    }
    else if (iframename.indexOf("adparamdelim") >= 0) {
        var params = iframename.split("adparamdelim");
        for (var i = 0; i < params.length; i++) {
            var param = params[i].split("=");
            if (param[0].indexOf("TL_files_path") >= 0) {
                var value = param[1];
                value = value.substr(value, value.lastIndexOf("/"));
                value = value.substr(value, value.lastIndexOf("/") + 1);
                return value;
            }
        }
    }
    else if (/^\{.*\}$/.test(iframename)) {
        try {
            eval('var results = ' + iframename);
            var value = results.TL_files_path;
            value = value.substr(value, value.lastIndexOf("/"));
            value = value.substr(value, value.lastIndexOf("/") + 1);
            return value;
        } catch (e) {
            return "";
        }
    } else {
        var params = iframename.split("&");
        for (var i = 0; i < params.length; i++) {
            var param = params[i].split("=");
            if (param[0].indexOf("TL_files_path") >= 0) {
                var value = unescape(param[1]);
                value = value.substr(value, value.lastIndexOf("/"));
                value = value.substr(value, value.lastIndexOf("/") + 1);
                return value;
            }
        }
    }
    return "";
}

function getTlDirectoryFromQueryString(sLocation) {
    var queryVar = getValueFromDelimitedString("imgSrv", "a4edelim", sLocation);
    var temp = queryVar.substr(0, queryVar.lastIndexOf("/"));
    var tlDir = temp.substr(0, temp.lastIndexOf("/") + 1);
    return tlDir;
}

function getDocumentQueryString() {
    return window.location.search;
}

function getIframeParameterString() {
    var ret = "";
    var qs = getDocumentQueryString();
    if (qs.length > 0)
        ret = qs.substring(1);
    return ret;
}

function getScriptParameterString() {
    var ret = "";
    var scripts = document.getElementsByTagName('script');
    for (var i = 0; i < scripts.length; i++) {
        var scriptSrc = scripts[i].src;
        if (scriptSrc.toLowerCase().indexOf("newiframescript") != -1 && scriptSrc.indexOf("?") != -1) {
            ret = scriptSrc.substr(scriptSrc.indexOf("?") + 1);
            break;
        }
    }
    return ret;
}

function getParameterString() {
    var qs = getIframeParameterString();
    if (qs.length > 0 && qs.indexOf("a4edelim") > 0)
        return qs;
    return getScriptParameterString();
}

function getScriptFileName() {
    var armdelim = ",";
    var fileName = "ifb.0";
    var queryString = getParameterString();
    var parmValue = "";
    if (queryString.length > 0) {
        parmValue = getValueFromDelimitedString("armver", "a4edelim", queryString);
    }
    if (parmValue.length > 0) {
        var fileNames = parmValue.split(armdelim);
        for (var i = 0; i < fileNames.length; i++) {
            if (fileNames[i].toLowerCase().indexOf("ifb") != -1) {
                fileName = fileNames[i];
                break;
            }
        }
    }
    return fileName + ".js";
}

if (typeof(armTestMode) == "undefined") {
    ARMIfbLib.WriteIframeBustingScript();
}

Я потратил пару часов на изучение этого, чтобы попытаться понять, что он делает, но я увяз в различных вызовах функций. Кажется, он захватывает параметр строки запроса или значение из имени iframe, предположительно iframe, который содержит рекламу.

Кто-нибудь может понять, что делает этот JS? Выглядит ли это достаточно безопасным с точки зрения XSS?

=========================================

РЕДАКТИРОВАТЬ

В случае, если это будет полезно кому-то еще, мы упомянули об этой проблеме провайдерам, и их ответ был следующим:

  1. Страница iframe buster будет работать только в том случае, если она находится в iframe.
  2. Код в файле ftlocal.html будет работать только в том случае, если домен iframe уже совпадает с доменом родительской страницы. Таким образом, любой код в любом случае уже будет иметь доступ к родительской странице.

person And Finally    schedule 14.02.2013    source источник
comment
Если вы включаете ссылку на JavaScirpt из внешнего домена, ваша страница зависит от сценария. Вы фактически позволяете своей странице доверять внешнему домену, поэтому скрипт может манипулировать любым вашим контентом через DOM.   -  person SilverlightFox    schedule 15.02.2013
comment
Спасибо SilverlightFox, я понимаю, что вы должны доверять провайдеру - меня больше беспокоят злонамеренные третьи лица.   -  person And Finally    schedule 15.02.2013


Ответы (1)


Сценарий JS создает динамически сгенерированный тег сценария на вашей странице.

ARMIfbLib.DocumentWrite("<script language='javascript' type='text/javascript' src='" + scriptURL + "'></scr" + "ipt>");

Если вы покопаетесь в том, откуда берется scriptURL, окажется, что это параметр, переданный в window.location.search (строка запроса).

Из того, что я вижу, это эффективно позволяет передать любой скрипт на вашу страницу в строке запроса, что делает ее уязвимой для DOM XSS, если только он не защищен эффективно, чтобы разрешить установку домена по имени фрейма на вашей странице. Я бы провел некоторое тестирование, используя ваши собственные домены и передав искомые строковые переменные запроса (строковые литералы в JS).

person SilverlightFox    schedule 15.02.2013
comment
Спасибо SilverlightFox, это подтверждает мое впечатление об этом скрипте. - person And Finally; 16.02.2013