ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 28.04.2024

Просмотров: 100

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

Hacked

Welcome

Try again

Welcome

Try again

Welcome

Try again

You a hacked" >> index.htm' —Процедура sp_who позволяет просмотреть, кто сейчас подключен к серверу: exec sp_whoПример результата выполнения этого SQL-запроса: spid ecid status loginame host 1 11 11 1—1 11 Д l dbname cmd 9 0 background sa 0 master TASK MANAGER 10 0 background sa 0 master TASK MANAGER 11 0 background sa 0 master TASK MANAGER 51 0 runnable CYD\flenov 0 Northwind SELECT 52 0 sleeping CYD\flenov 0 master AWAITING COMMAND Подробную информацию о текущей базе данных можно получить и с помощью процедуры sp_heip: exec sp_helpПример результата выполнения этой процедуры: NAMEИмя OwnerВладелец Object TypeТип объекта Invoices dbo view Order Subtotals dbo view Orders Qry dbo view Quarterly Orders dbo view Sales by Category dbo view Sales Totals by Amount dbo view Sysconstraints dbo view Syssegments dbo view Categories dbo user table CustomerCustomerDemo dbo user table CustomerDemographics dbo user table Customers dbo user table Employees dbo user table Syscolumns dbo system table Syscomments dbo system table Sysdepends dbo system table sysfilegroups dbo system table Следующие две процедуры, которые таят в себе опасность, — sp_adduser и sp_grantdbaccess. Для начала рассмотрим первую из них. Процедуре sp_adduser нужно передать три параметра (но только первый параметр является обязательным):♦ имя пользователя (login); имя учетной записи в СУБД. Если этот параметр не указан, то будет использо­вано имя из первого параметра; имя группы или роли, в которую автоматически попадает пользователь. При добавлении пользователя указанное имя уже должно существовать в MS SQL Server или в ОС Windows.Рассмотрим пример. В ОС Windows уже существует гостевая учетная запись. Да­вайте выдадим ей права на доступ к текущей базе данных:EXEC sp_adduser 'notebook\rocTb'Учетная запись "Гость" присутствует в Windows-системах по умолчанию. Если эта учетная запись не заблокирована, то хакер сможет с помощью хранимых процедур наделить ее правами доступа к СУБД и использовать для своих целей. Но хакеру еще желательно знать сетевое имя компьютера. Это легко сделать с помощью про­цедуры xp_getnetname.Процедура sp_adduser считается устаревшей и оставлена только для совместимости со старыми приложениями. В данный момент рекомендуется использовать проце­дуру sp_grantdbaccess, которой нужно передать следующие параметры: имя пользователя (login), которое зарегистрировано в ОС Windows NT или соз­дано в MS SQL Server; имя учетной записи в СУБД. Если этот параметр не указан, то будет использо­вано имя из первого параметра. В итоге, добавление гостевой учетной записи с помощью процедуры sp_grantdbaccess будет выглядеть следующим образом:EXEC sp_grantdbaccess 'notebook\rocTb'Для удаления пользователя применяется процедура sp_dropuser, которой нужно передать имя пользователя СУБД (мы его указывали во втором параметре процеду­ры sp_adduser или sp_grantdbaccess). В следующем примере мы удаляем гостевую учетную запись из текущей базы:EXEC sp_dropuser 'notebook\guest'Управление — это хорошо, но нужно уметь определить, какие вообще существуют учетные записи в системе. Для этого предназначена хранимая процедура sp_helpuser. Выполните ее, и перед вами появится таблица с информацией о поль­зователях текущей СУБД. Результирующая таблица состоит из следующих полей: userName — имя пользователя; GroupName — название роли, в которую входит пользователь; LoginName — имя, используемое для входа на сервер; DefDBName — база данных по умолчанию; useriD — идентификатор пользователя; sid — пользовательский идентификатор безопасности. Не менее опасной для web-сервера и удобной для хакера может оказаться процеду­ра xp_terminate_process, которая позволяет уничтожить указанный процесс по его идентификатору.Следующие хранимые процедуры позволяют работать с реестром Windows, что тоже достаточно опасно: xp_regenumkeys; xp_regenumvalues; xp_regread; xp_regwrite; xp_regdeletekey; xp_regdeletevalue. Честно сказать, я понятия не имею, зачем они добавлены в СУБД?Для работы с диском можно выделить следующие процедуры: xp_availablemedia; xp_fileexist; xp_dirtree. Первая из этих процедур возвращает доступные устройства, вторая определяет на­личие указанного файла в системе, а третья получает дерево каталогов.Все рассмотренные процедуры должны быть запрещены для выполнения с правами учетной записи, под которой работают ваши сценарии. И это далеко не полный список, есть еще процедуры создания, управления и удаления ролей, от которых зависят права доступа. Чтобы не ошибиться, вы должны запретить все и разрешить доступ явно только к тем, которые используют ваш сценарий. Распределение прав доступа Но все запреты будут бессмысленны, если простому пользователю разрешено вы­полнение операторов grant, revoke или deny. С помощью этих операторов можно давать или снимать права, а также запрещать доступ.Для назначения разрешающих прав доступа используется оператор grant, вид кото­рого зависит от того, на что выделяются права. Если на операторы, то grant выгля­дит следующим образом:GRANT { ALL | оператор [ ,...n ] }TO пользователь [ ,...n ]Операторы SQL, на которые вы можете назначать права доступа для пользователя: CREATE database; CREATE DEFAULT; create function; CREATE procedure; CREATE rule; CREATE TABLE; CREATE VIEW; backup database; BACKUP LOG. Рассмотрим пример, в котором пользователю с именем Mikhail выделяются права на создание таблиц и объектов просмотра:GRANT CREATE TABLE, CREATE VIEW TO MikhailДля упрощения работы с правами доступа можно использовать роли. Допустим, что у нас есть десять учетных записей для работников бухгалтерии и все они объе­динены в одну роль Buh. Если все работники роли нуждаются в возможности созда­ния таблиц, то можно назначить разрешение всей роли:GRANT CREATE TABLE, CREATE VIEW TO BuhЕсли нужно разрешить выполнение всех перечисленных ранее операторов, то мож­но воспользоваться ключевым словом all. Следующий пример предоставляет пол­ный доступ роли Buh:GRANT ALL TO BuhЗа более полной информацией советую обратиться к файлу-справке, а также могу порекомендовать мою книгу "Transact-SQL".При добавлении прав доступа на объекты необходимо указать оператор grant, за которым идет перечисление разрешений на объект. После ключевого слова on пи­шем имя объекта, а после то — имя пользователя или роли. В упрощенном вариан­те распределение прав выглядит следующим образом:GRANT разрешения ON объект TO пользовательНапример, следующей командой мы разрешаем пользователю Hacker выполнять оператор select в таблице tbPeopies:GRANT SELECT ON tbPeopies TO HackerЕсли пользователю нужно предоставить все права на объект, то, чтобы не перечис­лять их, можно написать ключевое слово ALL:GRANT ALL ON tbPeopies TO BuhНеобходимо отметить, что по стандарту надо писать all privileges, но Microsoft разрешила ленивым программистам не писать длинное слово privileges. Я, напри­мер, всегда забываю, как оно пишется, поэтому благодарен корпорации Microsoft. Итак, если следовать стандарту, то мы должны были бы написать запрос на изме­нение привилегий следующим образом:GRANT ALL PRIVILEGES ON tbPeoples TO BuhДля задания запретов используется оператор deny, который так же имеет два вари­анта: для операторов и объектов. Рассмотрим каждый из них.Общий вид команды deny для операторов выглядит следующим образом:DENY { ALL | оператор [ ,...n ] }TO пользователь [ ,...n ]Операторы, которые могут использоваться, те же, что и у grant. Например, сле­дующий запрос явно запрещает пользователю Hacker создавать таблицы и объекты просмотра:DENY CREATE TABLE, CREATE VIEW TO HackerЕсли нужно отменить все права на операторы, то можно указать ключевое слово all. В следующем примере отменяются права для бухгалтерии:REVOKE All FROM Buh Опасные SQL-запросы Даже не имея прав доступа к выполнению команд, злоумышленник может навре­дить, используя SQL-запросы. Как мы уже выяснили при рассмотрении MySQL (см. разд. 5.2), к СУБД можно отправлять SQL-запросы на обновление и удаление. В случае с MS SQL Server все рассмотренное остается в силе.Например, дефейс можно совершить и с помощью запросов. Необходимо только найти таблицу, в которой хранятся данные, отображаемые на главной web- странице — например, новости. После этого с помощью запроса update обновля­ем новости так, чтобы последняя из них (можно и все) содержали необходимый текст. Например, если новости хранятся в таблице news, и заголовок новости — в колонке Title, то хакер может выполнить следующий запрос:UPDATE NewsSET Title='Hacked by MegaHacker'Это тоже изменение главной web-страницы, и его можно отнести к дефейсу.Наиболее интересными для хакера являются имена таблиц. Чтобы обновлять и уда­лять данные, необходимо знать названия объектов, с которыми вы работаете. Для этого используется таблица tables из information_schema или просто: information_schema. tables. Чтобы получить все имена таблиц, необходимо выпол­нить запрос:SELECT TABLE_NAMEFROM INFORMATION_SCHEMA.TABLESИногда бывает необходимость получить только одну запись из таблицы. Это легко сделать, ограничив результат с помощью оператора top n, который ставится после select, где n — это количество нужных строк. Так, следующий пример выбирает первые две записи:SELECT TOP 2 TABLE_NAME FROM INFORMATION_SCHEMA.TABLESКак можно получить следующую запись? Да очень просто, выбрать верхнюю за­пись из InformatIon_schema. tableS и ограничить запрос так, чтобы известное вам имя отсекалось. Например, вы уже знаете, что в базе данных есть таблица Users. Для получения следующего имени таблицы пишем:SELECT TOP 2 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME<>'Users'Когда известно несколько таблиц, можно перечислить их с помощью not in, на­пример, следующим образом:SELECT TOP 2 TABLE_NAME FROM INFORMATION_SCHEMA.TABLESWHERE TABLE_NAME NOT IN ('Users', 'Passwords', 'Data')Чтобы получить имена всех колонок, необходимо обратиться к таблице columns из I nformat I on_schema. Например, следующий запрос возвратит имена колонок табли­цы Users:SELECT COLUMN_NAMEFROM INFORMATION_SCHEMA.COLUMNSWHERE TABLE_NAME='Users' Рекомендации по безопасности MS SQL Server Безопасность MS SQL Server не является темой данной книги, но раз уж мы рас­сматриваем взлом и безопасность web-серверов, то обсудим некоторые рекоменда­ции, ведь СУБД — своеобразная часть web-сервера.Для защиты СУБД от хакеров все сценарии должны выполняться от имени непри­вилегированного пользователя. Этот пользователь должен ограничиваться только выборкой данных, а вставка и обновление должны быть доступны лишь для тех таблиц, где это действительно нужно. Чем мне нравится MS SQL Server, так этотем, что он предоставляет очень удобное средство управления — SQL Server Enter­prise Manager. С его помощью очень удобно управлять и правами. Tm SQL Server Enterprise Manager - [Console Root\Microsoft SQL Servers\SQL Server Group\CYD (Windows . TJni Консоль Действие Вид Tools Окно Справка _ в ^ Haul KnfGg, if * vs вив m ca Permit | Console Root •zl) Microsoft SQL Servers В ^ SQL Server Group -a» CYD (Windows NT)В Cj Databases В U masterЩ Tables 6V1 ViewsStored Procedures Extended Stored Procedures ijfl Users Roles | RulesHal DefaultsP, User Defined Data Types User Defined Functions @ Q model Ш 0 rnsdb s Q Northwmd Ш й pubs s й tempdbВ Data Transformation Services 1+ C3 Management



Посмотрим на следующий пример:

public ActionResult Index()

{

SqlConnection connection = new SqlConnection(); connection.ConnectionString = "строка соединения"; connection.Open();

return View () ;

}

Внимание, вопрос — когда будет закрыто соединение с базой данных? Да, соеди­нение будет закрыто за нас, и нам не нужно, по идее, заботиться о ресурсах, но вот когда эти ресурсы будут освобождены? А фиг его знает. После выполнения этого кода соединение будет все еще открытым и занятым. Реальное освобождение ре­сурсов может произойти через минуту, а может через пять. Это значит, что на сер­вере будет большое количество открытых ресурсов, запрещенных к использова­нию. Сервер не безграничен в количестве одновременно доступных соединений, тут все зависит от настроек, и когда вы дойдете до максимума, новое соединение открыть будет невозможно и сайт упадет до тех пор, пока сборщик мусора не осво­бодит неиспользуемые соединения.

Внимание, тут я упомянул два очень важных термина — открытые и занятые со­единения. Надо понимать, что это разные вещи. Давайте посмотрим на цикл жизни соединения. Когда вы впервые открываете (вызываете метод Open) объект SqlConnection, то .NET делает следующее:

  • выделяет необходимые объекту ресурсы;

  • устанавливает соединение с базой данных.

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

Теперь, если вы попытаетесь открыть новый объект sqlconnection, то .NET прове­рит пул на наличие уже открытых соединений с такой же строкой подключения. Если они есть, то будет создан новый объект, но новое физическое соединение с сервером устанавливаться не будет, будет использовано существующее из пула. Таким образом экономится время на обмен приветственными сообщениями с базой данных, а объект Sqlconnection практически мгновенно становится доступным к использованию.

Я сопровождал сайт с миллионами пользователей, и у нас даже в час пик количест­во одновременно открытых соединений к базе данных не превышает 600. А вне ча­сы пик, держится на отметке в 200 соединений. Недавно мы запускали небольшое обновление и вне часа пик количество соединений взлетело до 1500, а в час пик сайт упал из-за того, что не хватило свободного места в пуле. Мы увидели пробле­му как раз тогда, когда сайт упал из-за недостаточного количества соединений. Сразу после обновления не проверили, сколько открытых соединений.


Проблема была как раз в одном таком коде, когда открывалось соединение, но явно не закрывалось. Из-за того, что вовремя ресурсы не освобождались, мы теряли их без особого смысла. Когда я нашел проблему и исправил, количество соединений упало опять с более чем 1000 до 200.

При разработке web-приложений, если где-то нужно открывать ресурсы, всегда ис­пользуйте конструкцию using: public ActionResult Index()

{

using (Sqlconnection connection = new SqlConnection())

{

connection.ConnectionString = "строка соединения"; connection.Open();

}

return View();

}

В этом случае .NET знает, что соединение нам нужно только на период, пока мы находимся внутри using-блока. Как только мы выходим за его пределы, платформа сразу видит, что этот ресурс нам не нужен и его можно освобождать. И тут мы точ­но можем знать (если программисты Microsoft не совершат ошибку в своем коде, что маловероятно), что соединение с базой данных будет закрыто сразу после вы­хода из блока using. Вам необязательно вызывать явно метод Close, достаточно просто использовать using.

Сборка мусора в .NET работает отлично, главное, правильно ею пользоваться и по­могать платформе, указывая на то, когда ресурсы уже больше не нужны. Дальше она все возьмет на себя.

Я рекомендую использовать именно using. Посмотрим на следующий пример:

public ActionResult Index()

{

connection.ConnectionString = "строка соединения"; connection.Open();

connection.Close() ; return View () ;

}

Казалось бы, здесь все тоже отлично, мы открываем и явно закрываем соединение, поэтому утечки не должно быть. И ее не будет, если перед открытием не произой­дет ошибки. Любая исключительная ситуация между Open и Close приведет к тому, что код прервет выполнение и соединение останется открытым. Если хакер сможет найти ситуацию, при которой генерируется исключение (например, неверный па­раметр), то он может реализовать отказ в обслуживании многократным вызовом страницы с такими неверными параметрами, чтобы соединения не освобождались, и в конце концов израсходовать все возможные соединения.

А как насчет такого случая, когда нужно использовать соединение в разных местах программы для выполнения двух разных запросов в двух разных местах? Если using не может объять оба кода (они находятся в разных методах), то не стоит даже пытаться объять необъятное. Создайте два объекта SqlConnection и откройте со­единение дважды. Это не проблема для сервера, потому что он может использовать пул соединений Connection Pool. Сразу же после закрытия первого соединения, оно реально не будет закрыто. Будет уничтожен объект, и соединение будет помечено как свободное. В течение некоторого времени (легко конфигурируется) соединение будет оставаться открытым, и при создании следующего объекта SqlConnection, не нужно тратить время на установку соединения с сервером, можно использовать уже открытое из пула.



В этом примере я использовал в качестве иллюстрации соединение с базой данных как наиболее популярный тип ресурса для подобных приложений. То же самое мо­жет касаться и таких ресурсов, как файлы, и, наверное, чего угодно, что требует закрытия. В таких случаях классы реализуют интерфейс Idisposable, и если вы работаете с одним из таких классов, то старайтесь использовать его вместе с using.

Вы не обязаны закрывать соединение самостоятельно, хотя все же явное закрытие является хорошим тоном, и помните, что это позволит вам защититься от DoS- атаки.


ГЛАВА 9

Авторизация

Авторизацию мы рассматриваем в этой книге для понимания очень популярной и достаточно опасной атаки — XSS (Cross Site Scripting — межсайтовый скриптинг).

Обновлять информацию на web-сайте через FTP-клиента с помощью закачки новых файлов достаточно неудобно и не всегда возможно например, уже в конце 1990-х мне приходилось работать в сетях, где доступ в интернет осуществлялся только по HTTP. Именно тогда я задумался о системе администрирования web-сайтов по­средством web-интерфейса. Сейчас web-интерфейс стал стандартом для управления любым сайтом.

Сценарии администрирования позволяют управлять содержимым web-страниц, по­этому должны быть закрыты от постороннего взгляда. Для этого необходима от­дельная защита, которая позволит вам спать спокойно и не даст хакеру выполнить привилегированные операции. В качестве такой защиты можно использовать сред­ства аутентификации.

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

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

  1. Аутентификация на web-сервере

Если какой-либо каталог web-сервера должен иметь особые права доступа, то мож­но создать в нем файл .htaccess. В этом файле описываются разрешения, действую­щие на каталог, в котором он расположен. При обращении к любому файлу из дан­ного каталога web-сервер будет требовать аутентификации. Да, аутентификации будет требовать именно web-сервер, поэтому дополнительные сценарии не понадо­

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

Рассмотрим пример содержимого файла .htaccess:

AuthType Basic

AuthName "By Invitation Only"

AuthUserFile /pub/home/flenov/passwd Require valid-user

В первой строке задается тип аутентификации с помощью директивы AuthType. В данном примере используется базовая аутентификация (Basic), в этом случае web-сервер при обращении к каталогу отобразит окно для ввода имени и пароля. Текст, указанный в директиве AuthName, появится в заголовке окна (рис. 9.1).





Рис. 9.1. Окно запроса имени и пароля




Директива AuthUserFile задает имя файла, в котором находится база имен и паролей пользователей web-сайта. О том, как создавать такой файл и работать с ним, мы поговорим позже. Последняя директива Require в качестве параметра ис­пользует значение valid-user. Это значит, что файлы в текущем каталоге смогут открыть только те пользователи, которые прошли аутентификацию.

Вот таким простым способом можно запретить неавторизованный доступ к катало­гу, содержащему секретные данные или сценарии администратора. Более подроб­ную информацию об этом методе авторизации можно узнать из моих книг "Linux глазами хакера" или "PHP глазами хакера".

Такой подход к авторизации неплохо подходит для защиты страницы администри­рования. В случае с авторизацией пользователей на сайте такой подход неудобен и неэффективен, поэтому в наше время его мало кто использует.

Когда пользователь вводит имя и пароль в такое окно, то браузер запоминает эти данные, кодирует с помощью кодировки base64 и начинает отправлять на сервер с абсолютно каждым запросом в виде параметра authorization (рис. 9.2). Просмот­

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

Михаил Флёнов

accept; text /Mai, appllcat lon/«Mal>;<*•«. 9, taege/evif, luge/Mtp. feqe/epet, applltat ton/tlfln—-

Рис. 9.2. Параметр заголовка с данными авторизации

Как видно на скриншоте, у меня в заголовке параметр authorization равен Basic bWZsZW5vdjpwYXNzd29yZA==

После слова basic идет код в Base64, который легко превращается в чистый текст. В Google вбиваем Base64 decode, и вы найдете много сайтов, которые умеют декоди­ровать такой код. Воспользовавшись одним из них, вы легко узнаете, что bWZsZW5vdjpwYXNzd29yZA== на самом деле соответствует mflenov:password. До двоеточия идет имя, а после идет пароль. Да, я на самом деле для данного примера задал пароль в виде слова password. Это только для примера, в реальности, конеч­но, у меня пароли намного сложнее.