Как конкатенация URL-адресов в шаблонах в angular менее безопасна, чем в других местах?
У меня есть шаблон angularjs, который выглядит примерно так:
<img ng:src="/resources/{{id}}/thumbnail" />
Однако это приводит к ошибке $interpolate: noconcat. В отличие от этого шаблона:
<img ng:src="{{fullUrl}}" />
или даже:
<img ng:src="{{id|createThumbnailURL}}" />
(где createThumbnailURL - простой фильтр, который выполняет те же конкатенации, что и выше) работает полностью нормально.
В документации написано:
Конкатенация выражений затрудняет рассуждение о том, сочетание конкатенированных значений небезопасно для использования и может легко приводят к XSS.
Ну да, статический URL-адрес всегда легче оценить, чем конкатенированный, я вижу там пункт. Однако мне нередко приходится иметь REST-API, у которых есть URL-адреса, которые могут быть построены путем простой конкатенации и что конкатенация должна быть выполнена. Я могу сделать это в контроллере или даже на стороне сервера, но , как это улучшает что-либо, чтобы переместить конкатенацию в другом месте? И , что является рекомендуемым способом решения проблемы?
UPDATE
Ниже приведена демонстрация ошибки: http://cipher-code.de/tmp/angular3/index.xhtml
Возможно, это связано с тем, что страница является XML.
Ответы
Ответ 1
Это называется SCE (Strict Contextual Escaping):
Как и многие режимы "строгости", это настраивается. Но с V 1.2 автоматически устанавливается значение true.
Более конкретно, в контексте Angular считается уязвимым (например, url), допускается меньше интерполяции (строгость). Ваша конкатенация URL-адресов "санируется".
Вы уже знаете причину: атаки XSS. Он также используется для защиты разработчика: некорректный URL-адрес может привести к удалению или перезаписи данных.
Вероятно, вы сбиты с толку, почему полная интерполяция строк ng:src="{{fullUrl}}"
намного безопаснее, чем конкатенация строк ng:src="/resources/{{id}}/thumbnail"
. TBH, я не уверен, что есть серьезная разница, но это судебные решения.
У вас есть несколько альтернатив для борьбы с этим раздражением:
1) Оберните свою структуру URL внутри $sce.trustAs()
<img ng:src="sce.trustAs('url', '/resources/{{id}}/thumbnail')" />
2) Вы можете отключить SCE в своем приложении, если вы выберете
angular.module('myApp').config(function($sceProvider) {
$sceProvider.enabled(false);
});
Исправление:
Вы не можете вызвать службу $sce из директивы. Доступна только служба $scope. Но вы можете использовать функцию (или директиву, использующую функцию).
$scope.createUrl = function (strName) {
var truststring = '/resources/' + strName + '/thumbnail';
return truststring;
}
и ваш директивный вызов будет выглядеть как
<img ng:src="{{ createUrl(id) }}" />
В этом случае, если вы завершаете свою конкатенацию в функции, вам может даже не понадобиться дезактивировать ее, так как вы не нарушаете правило SCE.
Ответ 2
Я присоединился к партии немного поздно, но вот мои два цента:
В (очень) простых словах:
(1)
Angular использует службу $sce для выполнения "Строгое концептуальное экранирование" (SCE). В принципе, SCE требует, чтобы привязки в определенных контекстах приводили к значению, которое помечено как безопасное для использования в этом контексте.
Это механизм защиты, предоставляемый Angular разработчикам для легкой защиты (некоторых аспектов) вашего приложения (это еще более важно для приложений, которые связывают значения на основе пользовательского ввода).
(2)
Некоторые места (например, атрибуты) считаются более уязвимыми для определенных видов атак (например, XSS), а SCE использует для них более строгие правила. Несколько примеров - это форма action
или кадр или объект src
/ngSrc
.
(3)
На основе текущей реализации Angular (v1.2.16) возникает ошибка, когда этому уязвимому атрибуту присваивается значение, состоящее из более чем 1 "части". Часть (в соответствии с алгоритмом синтаксического анализа $interpolate
) является либо частью выражения, заключенного в {{
}}
, либо частью выражения, которое находится вне {{
}}
.
В вашем случае /resources/{{id}}/thumbnail
анализируется на 3 части:
/resources/
, {{id}}
, /thumbnail
Итак, в чем проблема с более чем 1 частью???
Нет ничего более неустойчивого в конкатенации в представлении против конкатенации в контроллере и использовании одночастного выражения.
Цитата из Angular источника (выделение мое):
//Конкатенация выражений затрудняет рассуждение о том, будет ли некоторая комбинация // конкатенированные значения небезопасны для использования и могут легко привести к XSS. Требовав, чтобы // для iframe [src], object [src] и т.д. используется одно выражение, мы гарантируем, что значение // используется , назначенный или сконструированный некоторым кодом JS где-то более проверяемым или
// сделать очевидным, что вы привязали значение к некоторому контролируемому пользователем значению. Это помогает уменьшить //load при аудите для проблем XSS.
Итак, это способ Angular заставить вас "более безопасную" практику. Построение значения в представлении менее подвержено тестированию и менее явно, поэтому у вас (или у кого-то еще) будет сложнее проверять приложение для уязвимостей XSS (увеличивая вероятность проблемы безопасности).
Есть несколько способов (уже упомянутых в ответе DaveA), чтобы обойти это.
(Я бы определенно не полностью отключил $sce
, хотя.)