Механизм безопасности: проверки входных данных | Снижение риска

Продукт или служба Статья
Веб-приложение
База данных
Веб-API
Azure DocumentDB
WCF

Отключайте скрипты XSLT для всех операций преобразования, использующих ненадежные таблицы стилей

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Безопасность XSLT, XsltSettings.EnableScript Property (Свойство XsltSettings.EnableScript)
Шаги XSLT поддерживает использование скриптов в таблицах стилей с применением элемента <msxml:script>. Таким образом пользовательские функции можно задействовать в преобразовании XSLT. Сценарий выполняется в контексте процесса, выполняющего преобразование. При работе в ненадежной среде скрипт XSLT нужно отключить, чтобы предотвратить выполнение ненадежного кода. При использовании .NET скрипты XSLT отключены по умолчанию. Тем не менее необходимо убедиться, что они не были явно включены в свойстве XsltSettings.EnableScript.

Пример

XsltSettings settings = new XsltSettings();
settings.EnableScript = true; // WRONG: THIS SHOULD BE SET TO false

Пример

При использовании MSXML 6.0 скрипты XSLT отключены по умолчанию. Тем не менее необходимо убедиться, что они не были явно включены в свойстве AllowXsltScript объекта XML модели DOM.

doc.setProperty("AllowXsltScript", true); // WRONG: THIS SHOULD BE SET TO false

Пример

Если вы используете MSXML версии 5 или более ранней, скрипты XSLT включены по умолчанию. Их необходимо явно отключать. Задайте для свойства AllowXsltScript объекта XML модели DOM значение false.

doc.setProperty("AllowXsltScript", false); // CORRECT. Setting to false disables XSLT scripting.

Убедитесь, что каждая страница, на которой может быть содержимое, управляемое пользователем, не использует автоматическое обнаружение типов MIME

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки IE8 Security Part V — Comprehensive Protection (Безопасность IE8, часть 5: комплексная защита)
Шаги

Для каждой страницы, на которой может быть содержимое, управляемое пользователем, необходимо использовать HTTP-заголовок X-Content-Type-Options:nosniff. Чтобы выполнить это требование, можно установить требуемый заголовок постранично для страниц, на которых может быть настраиваемое пользователем содержимое, или задать его глобально для всех страниц в приложении.

С каждым типом файлов, доставленных с веб-сервера, связан тип MIME (также называется content-type), описывающий характер содержимого (изображение, текст, приложение и т. д.).

Заголовок X-Content-Type-Options — это HTTP-заголовок, используя который разработчики могут запретить определение типов MIME содержимого. Этот заголовок обеспечивает защиту от атак путем определения типов MIME. В Internet Explorer 8 (IE8) добавлена поддержка этого заголовка.

Заголовком X-Content-Type-Options смогут воспользоваться только пользователи Internet Explorer 8 (IE8). В предыдущих версиях Internet Explorer не предусмотрена поддержка этого заголовка.

Только в одном из основных браузеров Internet Explorer 8 (или более поздних версий) можно отключить обнаружение типов MIME. Когда подобная возможность будет реализована в других популярных браузерах (Firefox, Safari, Chrome), мы обновим эту рекомендацию и добавим синтаксис для соответствующих браузеров.

Пример

Чтобы включить требуемый заголовок глобально для всех страниц в приложении, выполните одно из следующих действий.

  • Добавьте заголовок в файл web.config, если приложение размещено в службах IIS 7.
<system.webServer> 
  <httpProtocol> 
    <customHeaders> 
      <add name=""X-Content-Type-Options"" value=""nosniff""/>
    </customHeaders>
  </httpProtocol>
</system.webServer> 
  • Добавьте заголовок с помощью глобальной функции Application_BeginRequest
void Application_BeginRequest(object sender, EventArgs e)
{
  this.Response.Headers[""X-Content-Type-Options""] = ""nosniff"";
} 
  • Внедрите пользовательский HTTP-модуль.
public class XContentTypeOptionsModule : IHttpModule 
  {
    #region IHttpModule Members 
    public void Dispose() 
    { 

    } 
    public void Init(HttpApplication context)
    { 
      context.PreSendRequestHeaders += newEventHandler(context_PreSendRequestHeaders); 
    } 
    #endregion 
    void context_PreSendRequestHeaders(object sender, EventArgs e) 
      { 
        HttpApplication application = sender as HttpApplication; 
        if (application == null) 
          return; 
        if (application.Response.Headers[""X-Content-Type-Options ""] != null) 
          return; 
        application.Response.Headers.Add(""X-Content-Type-Options "", ""nosniff""); 
      } 
  } 

  • Чтобы включить требуемый заголовок только для определенных страниц, добавьте его в отдельные ответы:
this.Response.Headers[""X-Content-Type-Options""] = ""nosniff""; 

Усильте защиту для разрешения сущностей XML или отключите его

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки XML Entity Expansion (Расширения сущностей XML), XML Denial of Service Attacks and Defenses (XML: атаки типа "отказ в обслуживании" и способы защиты от них), Общие сведения о безопасности MSXML, Рекомендации по обеспечению безопасности кода MSXML, NSXMLParserDelegate Protocol Reference (Справочник по протоколу NSXMLParserDelegate), Разрешение внешних ресурсов
Шаги

Существует редко используемая функция XML, благодаря которой средство синтаксического анализа XML расширяет макро-сущности за счет значений, определенных в документе, или из внешних источников. Например, документ может определить сущность "companyname" со значением "Майкрософт", чтобы каждый раз, когда текст "&companyname;" отображается в документе, он автоматически заменяется текстом Майкрософт. Или в документе может быть определена сущность MSFTStock, которая ссылается на внешнюю веб-службу, чтобы получить текущее значение акций Майкрософт.

Затем в документе появится "&MSFTStock", он автоматически заменяется текущей ценой акций. Тем не менее этой возможностью можно злоупотребить, что приведет к атаке типа "отказ в обслуживании". Злоумышленник может вложить несколько сущностей, чтобы создать механизм экспоненциального расширения XML, занимающий весь объем памяти в системе.

Злоумышленник также может создать внешнюю ссылку, которая выполняет потоковую передачу неограниченного количества данных или приводит к зависанию передачи потока. В результате всем командам необходимо полностью отключить внутреннее и/или внешнее разрешение сущностей XML, если приложение не использует эту функцию, или вручную ограничить объем памяти и количество времени, которые приложение может тратить на разрешение сущностей, если эта функция крайне необходима. Если приложению не требуется разрешение сущностей, отключите его.

Пример

Для кода .NET Framework можно применять следующие подходы:

XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);

// for .NET 4
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(stream, settings);

Обратите внимание, что значение по умолчанию параметра ProhibitDtd в параметре XmlReaderSettings — true, но в параметре XmlTextReader это значение false. При использовании XmlReaderSettings не нужно явно задавать для параметра ProhibitDtd значение true, но по соображениям безопасности это стоит сделать. Кроме того, обратите внимание, что по умолчанию класс XmlDocument поддерживает разрешение сущностей.

Пример

Чтобы отключить разрешение сущностей для объектов XmlDocument, используйте перезагрузку XmlDocument.Load(XmlReader) метода Load и задайте соответствующие свойства в аргументе XmlReader, как показано в следующем коде:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument doc = new XmlDocument();
doc.Load(reader);

Пример

Если в вашем приложении невозможно отключить разрешение сущностей, задайте для свойства XmlReaderSettings.MaxCharactersFromEntities значение в соответствии с требованиями приложения. Это ограничит воздействие потенциальных атак типа "отказ в обслуживании" с экспоненциальным расширением. В коде ниже приведен пример такого подхода.

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1000;
XmlReader reader = XmlReader.Create(stream, settings);

Пример

Если необходимо разрешать встроенные сущности, но не внешние сущности, задайте для свойства XmlReaderSettings.XmlResolver значение null. Например:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1000;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);

Обратите внимание, что в MSXML6 параметр ProhibitDTD имеет значение true (отключение обработки DTD) по умолчанию. Для кода Apple OSX или iOS можно использовать два средства синтаксического анализа XML: NSXMLParser и libXML2.

Приложения, использующие драйвер http.sys, выполняют проверку нормализации URL-адресов

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Н/П
Шаги

При работе с любым приложением, использующим драйвер http.sys, следует придерживаться следующих правил:

  • Ограничьте длину URL-адреса 16 384 знаками (ASCII или Юникод). В соответствии с параметрами по умолчанию служб IIS 6 это максимальная длина URL-адреса. По возможности для веб-сайтов следует создавать более короткие URL-адреса.
  • Используйте стандартные классы файлового ввода-вывода платформы .NET Framework (например, FileStream), так как таким образом вы сможете воспользоваться правилами нормализации в .NET FX.
  • Создайте список разрешенных известных имен файлов явным образом.
  • Явно отклоните известные типы файлов, для которых не будет выдаваться отклонение UrlScan: EXE, BAT, CMD, COM, HTW, IDA, IDQ, HTR, IDC, SHTM[L], STM, PRINTER, INI, POL, DAT.
  • Реализуйте перехват следующих исключений:
    • System.ArgumentException (для имен устройств);
    • System.NotSupportedException (для потоков данных);
    • System.IO.FileNotFoundException (для недопустимых экранированных имен файлов);
    • System.IO.DirectoryNotFoundException (для недопустимых экранированных каталогов).
  • Не вызывайте файловые API ввода-вывода Win32. При получении недопустимого URL-адреса реализуйте корректное возвращение ошибки 400 пользователю и зарегистрируйте фактическую ошибку.

Убедитесь, что при приеме файлов от пользователей обеспечиваются соответствующие меры безопасности.

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Unrestricted File Upload (Неограниченная передача файлов), File Signature Table (Таблица подписей файлов)
Шаги

Переданные файлы представляют серьезную угрозу для приложений.

Первый этап множества атак — это внедрение кода в атакуемую систему. Затем механизму атаки достаточно найти способ выполнения кода. За счет передачи файла злоумышленник выполняет первый этап. Неограниченная передача файлов приводит к самым разным последствиям: перехват системы, перегруженность файловой системы или базы данных, перенаправление атак на внутренние системы и просто искажение внешнего вида.

Последствия зависят от того, что приложение делает с переданным файлом, и в особенности от того, где сохранился этот файл. На стороне сервера не предусмотрена проверка передаваемых файлов. Для отправки файлов нужно внедрять следующие меры безопасности:

  • Проверка расширений файлов (должны приниматься только определенные допустимые типы файлов).
  • Ограничение максимального размера файлов.
  • Запрет на передачу файлов в webroot. В качестве расположения нужно использовать каталог на несистемном диске.
  • Соблюдение условий соглашения об именовании. Передаваемому файлу назначается случайное имя, чтобы предотвратить перезапись файла.
  • Сканирование файлов с помощью антивирусных программ перед записью на диск.
  • Проверка имени файла и других метаданных (например, путь к файлу) на наличие вредоносных знаков.
  • Проверка формата подписи файла, чтобы запретить отправку замаскированных файлов (например, передача EXE-файла с заменой расширения на TXT).

Пример

Подробные сведения о проверке подписи формата файла см. в классе ниже:

        private static Dictionary<string, List<byte[]>> fileSignature = new Dictionary<string, List<byte[]>>
                    {
                    { ".DOC", new List<byte[]> { new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } } },
                    { ".DOCX", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
                    { ".PDF", new List<byte[]> { new byte[] { 0x25, 0x50, 0x44, 0x46 } } },
                    { ".ZIP", new List<byte[]> 
                                            {
                                              new byte[] { 0x50, 0x4B, 0x03, 0x04 },
                                              new byte[] { 0x50, 0x4B, 0x4C, 0x49, 0x54, 0x55 },
                                              new byte[] { 0x50, 0x4B, 0x53, 0x70, 0x58 },
                                              new byte[] { 0x50, 0x4B, 0x05, 0x06 },
                                              new byte[] { 0x50, 0x4B, 0x07, 0x08 },
                                              new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70 }
                                                }
                                            },
                    { ".PNG", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
                    { ".JPG", new List<byte[]>
                                    {
                                              new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
                                              new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 },
                                              new byte[] { 0xFF, 0xD8, 0xFF, 0xE8 }
                                    }
                                    },
                    { ".JPEG", new List<byte[]>
                                        { 
                                            new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
                                            new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
                                            new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 }
                                        }
                                        },
                    { ".XLS", new List<byte[]>
                                            {
                                              new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 },
                                              new byte[] { 0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00 },
                                              new byte[] { 0xFD, 0xFF, 0xFF, 0xFF }
                                            }
                                            },
                    { ".XLSX", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } },
                    { ".GIF", new List<byte[]> { new byte[] { 0x47, 0x49, 0x46, 0x38 } } }
                };

        public static bool IsValidFileExtension(string fileName, byte[] fileData, byte[] allowedChars)
        {
            if (string.IsNullOrEmpty(fileName) || fileData == null || fileData.Length == 0)
            {
                return false;
            }

            bool flag = false;
            string ext = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(ext))
            {
                return false;
            }

            ext = ext.ToUpperInvariant();

            if (ext.Equals(".TXT") || ext.Equals(".CSV") || ext.Equals(".PRN"))
            {
                foreach (byte b in fileData)
                {
                    if (b > 0x7F)
                    {
                        if (allowedChars != null)
                        {
                            if (!allowedChars.Contains(b))
                            {
                                return false;
                            }
                        }
                        else
                        {
                            return false;
                        }
                    }
                }

                return true;
            }

            if (!fileSignature.ContainsKey(ext))
            {
                return true;
            }

            List<byte[]> sig = fileSignature[ext];
            foreach (byte[] b in sig)
            {
                var curFileSig = new byte[b.Length];
                Array.Copy(fileData, curFileSig, b.Length);
                if (curFileSig.SequenceEqual(b))
                {
                    flag = true;
                    break;
                }
            }

            return flag;
        }

Убедитесь, что в веб-приложении для доступа к данным используются параметры типобезопасности

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Н/П
Шаги

При использовании коллекции параметров SQL рассматривает входные данные как литеральное значение, а не как исполняемый код. Используя коллекцию параметров, можно принудительно ограничить тип и длину входных данных. Значения вне диапазона вызывают исключение. Если параметры типобезопасности SQL не используются, злоумышленники могут выполнить атаку путем внедрения кода в нефильтрованные входные данные.

Используйте параметры типобезопасности при создании SQL-запросов, чтобы предотвратить возможные атаки путем внедрения кода SQL в нефильтрованные входные данные. Эти параметры можно использовать с хранимыми процедурами и динамическими инструкциями SQL. В базе данных параметры обрабатываются как литеральные значения, а не как исполняемый код. Кроме того, проверяется тип и длина параметров.

Пример

В следующем коде показано, как использовать параметры типобезопасности с SqlParameterCollection при вызове хранимой процедуры.

using System.Data;
using System.Data.SqlClient;

using (SqlConnection connection = new SqlConnection(connectionString))
{ 
DataSet userDataset = new DataSet(); 
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure", connection); 
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure; 
myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11); 
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text; 
myCommand.Fill(userDataset);
}  

В предыдущем примере кода длина входного значения не должна превышать 11 знаков. Если тип и длина данных не соответствуют типу или длине, определенным в параметре, класс SqlParameter выдает исключение.

Используйте отдельные классы привязки моделей или списки привязки фильтров для устранения уязвимости массового назначения MVC

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии MVC 5, MVC 6
Атрибуты Н/П
Ссылки Класс MetadataTypeAttribute, Public Key Security Vulnerability And Mitigation (Уязвимость системы безопасности в виде открытого ключа и способы ее устранения), Complete Guide to Mass Assignment in ASP.NET MVC (Полное руководство по массовому назначению в ASP.NET MVC), Getting Started with EF using MVC (Начало работы с EF с использованием MVC)
Шаги
  • Когда нужно проверять уязвимости типа overposting? - Уязвимости с избыточной публикацией могут возникать в любом месте, где вы привязываете классы моделей из входных данных пользователя. Платформы, такие как MVC, могут представлять данные пользователя в пользовательских классах .NET, включая Plain Old CLR Object (POCO). MVC автоматически заполняет эти классы модели данными из запроса, предоставляя удобный способ обработки входных данных пользователя. Если эти классы содержат свойства, которые не должны устанавливать пользователи, приложение может быть уязвимо к атакам типа overposting, при которых пользователи могут управлять данными приложения, которыми они не должны управлять. Как и привязка моделей MVC, технологии доступа к базе данных, такие как реляционные модули сопоставления, например Entity Framework, часто также поддерживают использование объектов POCO для представления данных базы данных. Эти классы модели данных обеспечивают удобство при работе с данными базы данных, как и MVC при работе с входными данными пользователя. Так как MVC и база данных поддерживают аналогичные модели, например объекты POCO, достаточно просто повторно использовать те же классы и там, и там. Однако при таком подходе не удается сохранить разделение областей ответственности. Именно в этом общем случае непредусмотренные свойства используются для привязки модели, что приводит к возникновению атак типа overposting.
  • Почему нельзя использовать прямые имена классов базы данных в качестве параметров для действий MVC? - Поскольку привязка модели MVC привязывает все, что в этом классе. Даже если данные не отображаются, злоумышленник может отправить HTTP-запрос с этими данными, а MVC привяжет их, так как в действии указано, что класс базы данных должен приниматься в качестве входных данных пользователя.
  • Почему важно думать о форме, используемой для привязки модели? - Использование привязки модели MVC ASP.NET с чрезмерно широкими моделями предоставляет приложению чрезмерное размещение атак. В ходе такой атаки злоумышленник может изменить данные приложения так, чтобы они расходились с указанными разработчиком, например переопределить цену на товар или привилегии безопасности для учетной записи. Приложения должны использовать модели привязки для конкретных действий (или для списков конкретных допустимых фильтров свойств), чтобы явно определить, какие ненадежные действия ввода следует разрешать через привязку модели.
  • Разве отдельные модели привязки — это не просто дублирование кода? - Нет, это вопрос разделения проблем. При повторном использовании моделей баз данных в методах действий вы указываете, что пользователь может задать любое свойство (или подсвойство) в классе в HTTP-запросе. Если вам нужно в MVC совсем не это, создайте список фильтров или отдельный тип класса, чтобы сообщить MVC, какие данные могут поступать при вводе пользователя.
  • Нужно ли копировать все атрибуты аннотации данных, если для входных данных пользователя заданы отдельные модели привязки? - Не обязательно. MetadataTypeAttribute можно использовать в классе модели базы данных для связывания метаданных в классе привязки модели. При этом учтите, что тип, на который ссылается MetadataTypeAttribute, должен быть подмножеством ссылающегося типа (в нем может быть меньше свойств, но не больше).
  • Перемещать данные между моделями входных данных пользователя и моделями базы данных утомительно. Можно ли просто скопировать все свойства с использованием отражения? - Да. В моделях привязки содержатся только те свойства, которые определены как безопасные для ввода пользователя. С точки зрения безопасности можно копировать все общие свойства двух моделей путем отражения.
  • Можно ли использовать привязку [Bind(Exclude ="…")] вместо того, чтобы создавать отдельные модели привязки? - Такой подход не рекомендуется. При использовании [Bind(Exclude ="…")] любое новое свойство будет доступно для привязки по умолчанию. При добавлении нового свойства обеспечение защиты должно быть дополнительным этапом. Не нужно обеспечивать безопасность всей структуры по умолчанию. В зависимости от разработчика проверка этого списка при каждом добавлении свойства может быть рискованной.
  • Полезен ли атрибут [Bind(Include ="…")] для операций редактирования? - № [Bind(Include ="…")] подходит только для операций вставки (добавление новых данных). В операциях обновления (пересмотр имеющихся данных) используйте другой подход, например создание отдельных моделей привязки или передача явного списка допустимых свойств в UpdateModel или TryUpdateModel. Добавление атрибута [Bind(Include ="…")] для операции редактирования означает, что MVC будет создавать экземпляр объекта и задавать только указанные свойства, оставляя для всех прочих свойств значения по умолчанию. При сохранении данных имеющаяся сущность будет полностью заменена, а все пропущенные свойства будут сброшены к значениям по умолчанию. Например, если IsAdmin не указано в атрибуте [Bind(Include ="…")] для операции редактирования, для любого пользователя, имя которого был изменено с помощью этого действия, значение свойства будет сброшено к IsAdmin = false (любой измененный пользователь утратит статус администратора). Если нужно запретить обновление определенных свойств, используйте один из перечисленных выше методов. Обратите внимание, что некоторые версии средств MVC создают классы контроллера с атрибутом [Bind(Include ="…")] для действий изменения и подразумевают, что удаление свойства из этого списка позволит предотвратить атаки чрезмерной передачи данных (overposting). Тем не менее, как описано выше, этот подход не действует надлежащим образом. При его использовании все данные в пропущенных свойствах будут сброшены к значениям по умолчанию.
  • Возникают ли проблемы при использовании [Bind(Include ="…")] вместо отдельных моделей привязки для операций создания? - Да. Во-первых, этот подход не действует в операциях изменения. Чтобы устранить все уязвимости типа overposting, следует применять два отдельных подхода. Во-вторых, отдельные модели привязки применяют разделение областей ответственности между фигурой, используемой для ввода данных пользователем, и фигурой, используемой для сохраняемости. Эта возможность недоступна в [Bind(Include ="…")]. В-третьих, обратите внимание, что [Bind(Include ="…")] может обрабатывать только свойства верхнего уровня: в атрибут нельзя включать только части подсвойств (например, Details.Name). Последняя, и самая главная, проблема заключается в том, что использование [Bind(Include ="…")] добавляет дополнительный этап, о котором необходимо помнить всегда, когда класс используется для привязки модели. Если вы привязываете новый метод действия к классу данных напрямую и забываете включить атрибут [Bind(Include ="…")], метод может быть уязвим к атакам типа overposting, поэтому использование [Bind(Include ="…")] по умолчанию менее безопасно. Если вы используете [Bind(Include ="…")], его необходимо указывать каждый раз, когда классы данных используются как параметры метода действия.
  • Для операций создания можно ли поместить атрибут [Bind(Include ="…")] в сам класс модели? Ведь так можно не беспокоиться о добавлении этого атрибуте во все методы действия. - Этот подход работает в некоторых случаях. Использование [Bind(Include ="…")] в самом типе модели (а не в параметрах действий, использующих этот класс) не исключает необходимость добавления атрибута [Bind(Include ="…")] в каждый метод действия. Если использовать атрибут непосредственно в классе, создается отдельная контактная зона этого класса для привязки модели. Однако такой подход позволяет использовать привязку модели одного типа на класс модели. Если одному методу действия нужно разрешать привязку модели определенной области (например, действие только для администратора, обновляющее роли пользователей), а другим действиям нужно запрещать ее, этот подход будет безрезультатным. Каждый класс может иметь только одну фигуру привязки модели. Если разным действиям требуются разные фигуры привязки моделей, они должны представлять эти отдельные фигуры с помощью отдельных классов привязки моделей или отдельных атрибутов [Bind(Include ="…")] в методах действий.
  • Что такое модели привязки? Это то же самое, что и модели просмотра? - Это две связанные концепции. Термин "модель привязки" относится к классу модели, используемому в действии, который представляет собой список параметров (тип, передаваемый из привязки модели MVC в метод действия). Термин "модель представления" относится к классу модели, передаваемому из метода действия в представление. Использование модели для конкретного представления — это распространенный способ передачи данных из метода действия в представление. Часто этот тип также подходит для привязки модели. Термин "модель представления" можно использовать в отношении одной и той же модели, используемой в обоих методах. Если точнее, здесь рассматриваются именно модели привязки, в которых внимание уделяется типу, который передается в действие. Это важно для массового назначения.

Кодируйте ненадежные выходные веб-данные перед обработкой

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальные, веб-формы, MVC 5, MVC 6
Атрибуты Н/П
Ссылки How to prevent Cross-site scripting in ASP.NET (Защита от использования межсайтовых сценариев в ASP.NET), Cross-site Scripting (Использование межсайтовых сценариев), XSS (Cross Site Scripting) Prevention Cheat Sheet (Памятка по защите от использования межсайтовых сценариев (XSS))
Шаги Использование межсайтовых сценариев (обычно сокращается как XSS) — это атака, направленная на веб-службы либо приложение или компонент, использующие входные данные из Интернета. Используя межсайтовые сценарии, злоумышленник может выполнить сценарий в уязвимом веб-приложении на компьютере другого пользователя. Вредоносные сценарии можно использовать для хищения файлов cookie и выполнения мошеннических действий на компьютере атакуемого с помощью JavaScript. Чтобы обеспечить защиту от использования межсайтовых сценариев, следует проверять входные данные пользователя, их формат, а также кодировать их перед обработкой на веб-странице. Для проверки входных данных и кодирования выходных данных можно использовать библиотеку веб-защиты. Используйте один или несколько подходящих методов кодирования из библиотеки веб-защиты (защита от использования межсайтовых сценариев) для управляемого кода (C#, VB.net и так далее) в зависимости от контекста, в котором объявляются входные данные пользователя:

Пример

* Encoder.HtmlEncode 
* Encoder.HtmlAttributeEncode 
* Encoder.JavaScriptEncode 
* Encoder.UrlEncode
* Encoder.VisualBasicScriptEncode 
* Encoder.XmlEncode 
* Encoder.XmlAttributeEncode 
* Encoder.CssEncode 
* Encoder.LdapEncode 

Проверяйте и фильтруйте входные данные по всем свойствам модели строкового типа

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальные, MVC 5, MVC 6
Атрибуты Н/П
Ссылки Adding Validation (Добавление проверки), Validating Model Data in an MVC Application (Проверка данных модели в приложении MVC), Основные принципы ваших приложений ASP.NET MVC
Шаги

Перед использованием в приложении все входные параметры нужно проверять, чтобы убедиться, что приложение защищено от вредоносных входных данных. Проверьте входные значения с помощью проверок регулярных выражений на стороне сервера с помощью стратегии проверки разрешенного списка. Если передать в метод непроверенные входные данные или параметры, приложение подвергается риску атаки путем внедрения кода.

Точки входа для веб-приложений также включают поля форм, строки запросов, файлы cookie, заголовки HTTP и параметры веб-службы.

После привязки модели необходимо выполнить следующие проверки входных данных:

  • Свойства модели нужно пометить с помощью аннотации RegularExpression, чтобы принимались допустимые знаки, а также применялась максимально допустимая длина.
  • Методы контроллера должны выполнить проверку ModelState.

Очищайте поля форм, принимающие все знаки, например редактор форматированного текста

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Кодирование небезопасных входных данных, HTML Sanitizer (Библиотека HtmlSanitizer)
Шаги

Определите все статические теги разметки, которые нужно использовать. Зачастую при форматировании используются только безопасные элементы HTML, такие как <b> (жирный шрифт) и <i> (курсив).

Прежде чем записывать данные, закодируйте их в HTML. Таким образом, любой вредоносный скрипт становится безопасным, так как он обрабатывается как текст, а не как исполняемый код.

  1. Отключите проверку запросов ASP.NET, добавив атрибут ValidateRequest="false" в директиву @ Page.
  2. Закодируйте строковые входные данные с помощью метода HtmlEncode.
  3. Используйте StringBuilder и вызовите его метод Replace, чтобы выборочно удалить кодировку элементов HTML, которые необходимо разрешить.

Страница в ссылках отключает проверку запросов ASP.NET, задав атрибут ValidateRequest="false". Она кодирует входные данные с помощью HTML и выборочно разрешает использовать элементы <b> и <i>. Кроме того, для очистки HTML можно использовать библиотеку .NET.

HtmlSanitizer — это библиотека .NET для очистки фрагментов и документов HTML от конструкций, которые могут привести к атаке с использованием межсайтовых сценариев. Она использует AngleSharp для анализа и обработки HTML и CSS, а также для управления. HtmlSanitizer можно установить в виде пакета NuGet. Входные данные пользователя можно передать через соответствующие методы очистки HTML или CSS на стороне сервера. Обратите внимание, что очистка — это крайняя мера безопасности.

Самые эффективные меры безопасности — это проверка входных данных и кодирование выходных данных.

Не назначайте элементы модели DOM приемникам без встроенных возможностей кодирования

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Н/П
Шаги Многие функции JavaScript не выполняют кодирование по умолчанию. Назначение ненадежных входных данных элементам модели DOM через такие функции может привести к выполнению межсайтовых сценариев (XSS).

Пример

Ниже приведены примеры ненадежных входных данных.

document.getElementByID("div1").innerHtml = value;
$("#userName").html(res.Name);
return $('<div/>').html(value)
$('body').append(resHTML);   

Не используйте элемент innerHtml. Вместо него используйте innerText. Аналогичным образом вместо $("#elm").html() используйте $("#elm").text().

Убедитесь, что операции перенаправления в приложении закрыты или выполняются безопасно

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки The OAuth 2.0 Authorization Framework — Open Redirectors (OAuth 2.0 Authorization Framework: открытые средства перенаправления)
Шаги

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

Для этого:

  • Определяйте все операции перенаправления.
  • Реализуйте подходящий метод защиты для каждого перенаправления. Сюда входит список разрешений для перенаправления или подтверждение пользователя. Если веб-узел или служба с уязвимостью в виде открытого перенаправления использует поставщиков удостоверений Facebook, OAuth или OpenID, злоумышленник может похитить маркер входа пользователя и выполнять действия от его имени. Это неизбежный риск при использовании OAuth, который описан в документе RFC 6749 The OAuth 2.0 Authorization Framework (OAuth 2.0 Authorization Framework), раздел 10.15 Open Redirects (Открытые перенаправления). Аналогичным образом можно скомпрометировать учетные данные пользователя путем фишинга с использованием открытого перенаправления.

Внедрите проверку входных данных для всех параметров строкового типа, принимаемых методами контроллера

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальные, MVC 5, MVC 6
Атрибуты Н/П
Ссылки Validating Model Data in an MVC Application (Проверка данных модели в приложении MVC), Основные принципы ваших приложений ASP.NET MVC
Шаги Для методов, принимающих примитивные типы данных, а не модели в качестве аргументов, следует выполнять проверки входных данных с использованием регулярных выражений. Здесь следует использовать Regex.IsMatch с шаблоном допустимого регулярного выражения. Если входные данные не соответствуют указанному регулярному выражению, работа прекращается и отображается соответствующее предупреждение об ошибке проверки.

Задайте верхний предел времени ожидания для обработки регулярных выражений во избежание атаки типа "отказ в обслуживании" из-за недопустимого регулярного выражения

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии Универсальные, веб-формы, MVC 5, MVC 6
Атрибуты Н/П
Ссылки Свойство DefaultRegexMatchTimeout
Шаги Чтобы при использовании недопустимых регулярных выражений, из-за чего вам пришлось вернуться на много шагов, появлялась ошибка типа "отказ в обслуживании", задайте глобальное время ожидания по умолчанию. Если обработка выполняется дольше заданного верхнего предела, будет выведено исключение времени ожидания. Если ничего не настраивать, время ожидания будет бесконечным.

Пример

Например, если обработка занимает более 5 секунд, исключение RegexMatchTimeoutException вызывает следующая конфигурация:

<httpRuntime targetFramework="4.5" defaultRegexMatchTimeout="00:00:05" />

Не используйте метод Html.Raw в представлениях Razor

Заголовок Сведения
Компонент Веб-приложение
Этап SDL Сборка
Применимые технологии MVC 5, MVC 6
Атрибуты Н/П
Ссылки Н/П
Этап Веб-страницы ASP.NET (Razor) выполняют автоматическое кодирование HTML. Все строки, которые выводятся внедренными ограничителями кода (блоки @), автоматически преобразовываются в формат HTML. Однако при вызове метод HtmlHelper.Raw возвращает разметку без кодировки HTML. Если используется вспомогательный метод Html.Raw(), он обходит автоматическую защиту кодирования, обеспечиваемую Razor.

Пример

Ниже приведены примеры ненадежных входных данных.

<div class="form-group">
            @Html.Raw(Model.AccountConfirmText)
        </div>
        <div class="form-group">
            @Html.Raw(Model.PaymentConfirmText)
        </div>
</div>

Используйте метод Html.Raw() только для отображения разметки. Этот метод помогает избежать неявного кодирования выходных данных. Используйте другие вспомогательные методы ASP.NET, например @Html.DisplayFor().

Не используйте динамические запросы в хранимых процедурах

Заголовок Сведения
Компонент База данных
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Н/П
Шаги

В ходе атаки путем внедрения кода SQL используются уязвимости проверки входных данных для выполнения произвольных команд в базе данных. Это может произойти, когда приложение использует входные данные, чтобы создать динамические инструкции SQL для доступа к базе данных. Кроме того, такая атака может выполняться, если код использует хранимые процедуры, передающие строки с необработанными входными данными пользователя. В ходе атаки путем внедрения кода SQL злоумышленник может выполнять произвольные команды в базе данных. Все инструкции SQL (включая инструкции SQL в хранимых процедурах) нужно параметризовать. Параметризованные инструкции SQL без проблем принимают знаки, имеющие специальное значение в SQL (например, одинарная кавычка), так как они строго типизированы.

Пример

Ниже приведен пример небезопасной динамической хранимой процедуры.

CREATE PROCEDURE [dbo].[uspGetProductsByCriteria]
(
  @productName nvarchar(200) = NULL,
  @startPrice float = NULL,
  @endPrice float = NULL
)
AS
 BEGIN
  DECLARE @sql nvarchar(max)
  SELECT @sql = ' SELECT ProductID, ProductName, Description, UnitPrice, ImagePath' +
       ' FROM dbo.Products WHERE 1 = 1 '
       PRINT @sql
  IF @productName IS NOT NULL
     SELECT @sql = @sql + ' AND ProductName LIKE ''%' + @productName + '%'''
  IF @startPrice IS NOT NULL
     SELECT @sql = @sql + ' AND UnitPrice > ''' + CONVERT(VARCHAR(10),@startPrice) + ''''
  IF @endPrice IS NOT NULL
     SELECT @sql = @sql + ' AND UnitPrice < ''' + CONVERT(VARCHAR(10),@endPrice) + ''''

  PRINT @sql
  EXEC(@sql)
 END

Пример

Ниже приведен пример той же хранимой процедуры, реализованной безопасным образом.

CREATE PROCEDURE [dbo].[uspGetProductsByCriteriaSecure]
(
             @productName nvarchar(200) = NULL,
             @startPrice float = NULL,
             @endPrice float = NULL
)
AS
       BEGIN
             SELECT ProductID, ProductName, Description, UnitPrice, ImagePath
             FROM dbo.Products where
             (@productName IS NULL or ProductName like '%'+ @productName +'%')
             AND
             (@startPrice IS NULL or UnitPrice > @startPrice)
             AND
             (@endPrice IS NULL or UnitPrice < @endPrice)         
       END

Убедитесь, что в методах веб-API выполнена проверка моделей

Заголовок Сведения
Компонент Веб-интерфейс API
Этап SDL Сборка
Применимые технологии MVC 5, MVC 6
Атрибуты Н/П
Ссылки Проверка модели в веб-API ASP.NET
Шаги Данные, которые клиент отправляет в веб-API, нужно обязательно проверить перед обработкой. В веб-API ASP.NET, которые принимают модели в качестве входных данных, используйте аннотации данных для моделей, чтобы задать правила проверки свойств модели.

Пример

Это показано в следующем коде:

using System.ComponentModel.DataAnnotations;

namespace MyApi.Models
{
    public class Product
    {
        public int Id { get; set; }
        [Required]
        [RegularExpression(@"^[a-zA-Z0-9]*$", ErrorMessage="Only alphanumeric characters are allowed.")]
        public string Name { get; set; }
        public decimal Price { get; set; }
        [Range(0, 999)]
        public double Weight { get; set; }
    }
}

Пример

В методе действия контроллеров API достоверность модели должна быть проверена явно, как показано ниже.

namespace MyApi.Controllers
{
    public class ProductsController : ApiController
    {
        public HttpResponseMessage Post(Product product)
        {
            if (ModelState.IsValid)
            {
                // Do something with the product (not shown).

                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
    }
}

Внедрите проверку входных данных для всех параметров строкового типа, принимаемых методами веб-API

Заголовок Сведения
Компонент Веб-интерфейс API
Этап SDL Сборка
Применимые технологии Универсальные, MVC 5, MVC 6
Атрибуты Н/П
Ссылки Validating Model Data in an MVC Application (Проверка данных модели в приложении MVC), Основные принципы ваших приложений ASP.NET MVC
Шаги Для методов, принимающих примитивные типы данных, а не модели в качестве аргументов, следует выполнять проверки входных данных с использованием регулярных выражений. Здесь следует использовать Regex.IsMatch с шаблоном допустимого регулярного выражения. Если входные данные не соответствуют указанному регулярному выражению, работа прекращается и отображается соответствующее предупреждение об ошибке проверки.

Убедитесь, что в веб-API для доступа к данным используются параметры типобезопасности

Заголовок Сведения
Компонент Веб-интерфейс API
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Н/П
Шаги

При использовании коллекции параметров SQL рассматривает входные данные как литеральное значение, а не как исполняемый код. Используя коллекцию параметров, можно принудительно ограничить тип и длину входных данных. Значения вне диапазона вызывают исключение. Если параметры типобезопасности SQL не используются, злоумышленники могут выполнить атаку путем внедрения кода в нефильтрованные входные данные.

Используйте параметры типобезопасности при создании SQL-запросов, чтобы предотвратить возможные атаки путем внедрения кода SQL в нефильтрованные входные данные. Эти параметры можно использовать с хранимыми процедурами и динамическими инструкциями SQL. В базе данных параметры обрабатываются как литеральные значения, а не как исполняемый код. Кроме того, проверяется тип и длина параметров.

Пример

В следующем коде показано, как использовать параметры типобезопасности с SqlParameterCollection при вызове хранимой процедуры.

using System.Data;
using System.Data.SqlClient;

using (SqlConnection connection = new SqlConnection(connectionString))
{ 
DataSet userDataset = new DataSet(); 
SqlDataAdapter myCommand = new SqlDataAdapter("LoginStoredProcedure", connection); 
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure; 
myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11); 
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text; 
myCommand.Fill(userDataset);
}  

В предыдущем примере кода длина входного значения не должна превышать 11 знаков. Если тип и длина данных не соответствуют типу или длине, определенным в параметре, класс SqlParameter выдает исключение.

Использование параметризованных SQL-запросов для Azure Cosmos DB

Заголовок Сведения
Компонент Azure DocumentDB
Этап SDL Сборка
Применимые технологии Универсальный
Атрибуты Н/П
Ссылки Announcing SQL Parameterization in Azure Cosmos DB (Объявление о параметризации SQL в Azure Cosmos DB)
Шаги Несмотря на то что Azure Cosmos DB поддерживает исключительно запросы только на чтение, атака путем внедрения кода SQL по-прежнему возможна, если создавать запросы, объединяя их с входными данными пользователя. Пользователи могут получить доступ к данным, к которым они не должны обращаться, в одной коллекции, составляя вредоносные SQL-запросы. Используйте параметризованные SQL-запросы, если запросы создаются на основе входных данных пользователя.

Проверка входных данных WCF путем привязки к схеме

Заголовок Сведения
Компонент WCF
Этап SDL Сборка
Применимые технологии Универсальные, .NET Framework 3
Атрибуты Н/П
Ссылки MSDN
Шаги

Отсутствие проверки приводит к разным атакам путем внедрения кода.

Проверка сообщений представляет один этап защиты приложения WCF. При таком подходе сообщения проверяются с использованием схем защиты операций службы WCF от атак со стороны вредоносного клиента. Проверяйте все сообщения, полученные клиентом, чтобы защитить его от атаки вредоносной службы. При этом сообщения проверяются, когда операции используют контракты сообщений или данных. Такая возможность не обеспечивается при проверке параметров. Проверка сообщений предусматривает создание логики проверки в схемах, тем самым обеспечивая большую гибкость и ускоряя разработку. Схемы можно повторно использовать в разных приложениях в организации, создавая стандарты представления данных. Кроме того, путем проверки сообщений можно защитить операции, использующие более сложные типы данных, включая контракты, представляющие бизнес-логику.

Чтобы выполнить проверку сообщений, сначала нужно создать схему, которая представляет операции службы и типы данных, используемые этими операциями. Затем создайте класс .NET, который реализует пользовательский инспектор клиентских сообщений и пользовательский инспектор сообщений диспетчера, для проверки сообщений, отправленных службе или полученных от службы. Далее необходимо реализовать поведение пользовательской конечной точки, чтобы включить проверку сообщений клиента и службы. Наконец, нужно реализовать пользовательский элемент конфигурации в классе, который позволяет использовать расширенное поведение пользовательской конечной точки в файле конфигурации службы или клиента.

Проверка входных данных WCF с помощью инспекторов параметров

Заголовок Сведения
Компонент WCF
Этап SDL Сборка
Применимые технологии Универсальные, .NET Framework 3
Атрибуты Н/П
Ссылки MSDN
Шаги

Проверка входных данных представляет важный этап защиты приложения WCF. Следует проверять все параметры, используемые в операциях службы WCF, чтобы обеспечить защиту службы от атак вредоносного клиента. И наоборот, проверяйте все возвращенные значения, полученные клиентом, чтобы защитить его от атаки вредоносной службы.

WCF предоставляет разные точки расширения, которые позволяют настроить поведение среды выполнения WCF за счет создания пользовательских расширений. Инспекторы сообщений и инспекторы параметров представляют собой два механизма расширения, обеспечивающие более высокий уровень контроля над данными, передаваемыми между клиентом и службой. Инспекторы параметров следует использовать для проверки входных данных, а инспекторы сообщений — только для проверки всех входящих и исходящих сообщений службы.

Чтобы выполнить проверку входных данных, создайте класс .NET и внедрите пользовательский инспектор параметров для проверки параметров в операциях службы. Далее необходимо реализовать поведение пользовательской конечной точки, чтобы включить проверку в клиенте и службе. Наконец, нужно реализовать пользовательский элемент конфигурации в классе, который позволяет использовать расширенное поведение пользовательской конечной точки в файле конфигурации службы или клиента.