Рассылка закрыта
При закрытии подписчики были переданы в рассылку "BloggLand и Я | Блоггландия" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
№41 рассылки '.Net Собеседник':
Информационный Канал Subscribe.Ru |
.Net Собеседник #41
Содержание- От автора
- Обзор новостей
- 10 вещей, которые вы не должны делать с SQL Server (советы разработчику доступа к данным)
- Время кода - Фиксированный заголовок в ASP.NET DataGrid
- Форумы .Net на www.sql.ru
От автора
Здравствуйте, коллеги!
Обзор новостей
-
Вышел XStream.NET XML Serializer
- Arne Vandamme создала новый XML Serializer, основанный на популярном XStream XML Serializer на Java.
-
Вышел SQL Server 2000 Service Pack 4
- Качайте по ссылке.
-
Вышел ReSharper 1.5.1
- Исправлено много багов, подробнее на сайте.
Статья номера
10 вещей, которые вы не должны делать с SQL Server (советы разработчику доступа к данным)
ЯЗЫК: C#
Автор статьи: Doug Seven
ПЕРЕВОД: Чужа В.Ф. ака hDrummer
Вступление
Эта статья родилась из презентации, которая была впервые представлена на TechEd 2004, а впоследствии была неоднократно представлена многим группам пользователей по всей стране. Затем я понял, что проще написать такую статью, чем пытаться донести эту информацию до всех групп поочередно – что и было сделано. Содержание статьи базируется на онлайн дискуссии, которая завязалась в моём блоге и на форуме - как результат появления вопроса "Что обычно разработчики доступа к данным делают не так в случае работы с SQL Server?" Список вырос до 25 или 26 пунктов, из которых мы отобрали 10 наиболее часто читаемых, в общем – самых «горячих». Этот список и приведен ниже – 10 вещей, которые вы не должны делать с SQL Server (или по-крайней мере знать о последствиях такого выбора). Честно говоря, на определённом этапе своей карьеры я использовал все 10 подходов, которые описаны здесь (ну, никто не идеален). Итак…
10. Добавление учётной записи с низкими привелегиями к роли Администратора
Роль администратора в SQL Server сделана для тех учётных записей,
которые ДЕЙСТВИТЕЛЬНО нуждаются в правах администратора. Очень редко такими
правами должна обладать учётная запись, под которой работает ваше приложение.
Например, для приложения ASP.NET, вы не должны добавлять рабочий процесс
ASP.NET (ASPNET или NETWORK SERVICE) в группу администраторов для создания
доверительных соединений (интегрированной безопасности). Такой подход может
быть небезопасным. В этом примере рабочий процесс ASP.NET не должен работать
под учётной записью администратора БД SQL Server; наоборот, учётная запись
ASP.NET должна работать с низким уровнем привилегий. Рабочий процесс ASP.NET
устанавливается во время инсталляции .NET Framework. Если вы запускаете каркас
.NET на Windows XP или Windows 2000, то рабочий процесс ASP.NET работает под
учётной записью MachineName\ASPNET. На Windows Server 2003 этот же процесс
работает под учётной записью NT Authority\Network Service. Добавив эту запись к
роли администраторов, вы подвергаете себя возможности быть атакованным путём
SQL-инъекций, кроме всего прочего, конечно.
-- Windows 2000 / XP -- Замените "MachineName" на имя вашей машины EXEC sp_grantlogin [MachineName\ASPNET] EXEC sp_grantdbaccess [MachineName\ASPNET], [Alias] GRANT EXECUTE ON [ProcedureName] TO [Alias] GO -- Windows Server 2003 EXEC sp_grantlogin [NT AUTHORITY\NETWORK SERVICE] EXEC sp_grantdbaccess [NT AUTHORITY\NETWORK SERVICE] GRANT EXECUTE ON [ProcedureName] TO [NT AUTHORITY\NETWORK SERVICE] GO |
9. @@IDENTITY vs. SCOPE_IDENTITY
/*в тестовой БД создайте таблицу
TY*/
USE SomeTestDatabase CREATE TABLE TABLE_A ( TABLE_A_id int IDENTITY(100,5)PRIMARY KEY, ItemValue varchar(20) NULL) /*вставляем записи в таблицу TABLE_A*/ INSERT TABLE_A VALUES ('Widget') INSERT TABLE_A VALUES ('Boat') INSERT TABLE_A VALUES ('Car') GO /*создаём таблицу TABLE_B*/ CREATE TABLE TABLE_B ( TABLE_B_id int IDENTITY(1,1)PRIMARY KEY, Username varchar(20) NOT NULL) /*вставляем записи в TABLE_B*/ INSERT TABLE_B VALUES ('Doug') INSERT TABLE_B VALUES ('Erika') INSERT TABLE_B VALUES ('Lola') GO /*вставляем данные в TABLE_B*/ INSERT TABLE_B VALUES ('Kali') /*выбираем данные и смотрим значения @@IDENTITY и SCOPE_IDENTITY()*/ SELECT * FROM TABLE_A SELECT * FROM TABLE_B SELECT @@Identity AS [@@Identity], SCOPE_IDENTITY() AS [SCOPE_IDENTITY] GO /*Создаём триггер, вставляющий строку в таблицу TABLE_A, когда вставляется строка таблицу TABLE_B*/ CREATE TRIGGER TABLE_B_trig ON TABLE_B FOR INSERT AS BEGIN INSERT TABLE_A VALUES ('Airplane') END GO /*теперь вставляем запись в таблицу TABLE_B, что приведет к запуску триггера*/ INSERT TABLE_B VALUES ('Donny') /*теперь @@IDENTITY и SCOPE_IDENTITY() вернут разные значения. SCOPE_IDENTITY() вернёт значение из TABLE_A (то, что было явно вами создано), а @@IDENTITY вернёт значение из TABLE_B (созданное триггером).*/ SELECT * FROM TABLE_A SELECT * FROM TABLE_B SELECT @@Identity AS [@@Identity], SCOPE_IDENTITY() AS [SCOPE_IDENTITY] GO |
8. Выборка полустатических данных при каждом запросе
Ах, производительность. Это то, о чём здесь и пойдёт речь. Если в
вашем приложении есть полустатические данные, т.е. данные, которые не часто
изменяются, а вы часто обращаетесь к ним и при каждом запросе к хранилищу вы
перекачиваете их клиенту, то вы теряете хорошую возможность увеличить
производительность вашего приложения. Данные, являющиеся полустатичными хотя бы
на протяжении некоторого периода времени могут быть кэшированы приложением для
уменьшения нагрузки на сервер БД.
- Cache API: Cache API – кэш уровня приложения. Это то место, в которое можно поместить ЛЮБОЙ объект и определить для него правила нахождения в кэше. Размер кэша определяется количеством оперативной памяти машины, на которой работает приложение. Плюсом Cache API есть то, что можно поместить объект любой сложности в кэш, а затем извлечь его для работы. Можно определить скользящее время жизни объекта (например, кэшировать его после использования на 5 минут, а если он в течении 5 минут не используется – убивать его.) Можно определить абсолютное время окончания кэширования объекта – хранить в кэше 1 час, а затем убрать из кэша, не взирая на то был ли он использован или нет. Можно поставить наличие объекта в кэше в зависимости от наличия файла или его обновления. Это хорошо работает в случае с кэшированием данных XML, когда кэш обновляется после обновления самого файла.
- Кэширование вывода: Для тех данных, которые вы хотите кэшировать и вы уверены, что доступ к исходным данным не понадобится, можно кэшировать сам вывод, т.е., например, HTML, а не те объекты, которые использовались для его создания. Это легко реализовать, как показано во втором примере ниже.
DataTable productsTable; // здесь код для получения данных из таблицы Product //этот код помещает объект в кэш Cache.Add( "ProductsTable", //имя productsTable, //объект для кэширования null, //зависимость кэша DateTime.Now.AddSeconds(60), //абсолютное истечение TimeSpan.Zero, //плавающее истечение CacheItemPriority.High, //приоритет null //onRemoveCallback ); //с помощью этого кода можно получить объект из кэша if(Cache["ProductsTable"] != null) productsTable = (DataTable)Cache["ProductsTable"]; |
Кэширование вывода:
<%-- устанавливаем кэш в 60
секунд --%>
<%@ OutputCache Duration="60" VaryByParam="None" %> <%-- устанавливаем кэш в 60 секунд и создаём отдельную кэшированную версию страницы, базирующуюся на параметре "City" --%> <%@ OutputCache Duration="60" VaryByParam="City" %> <%-- устанавливаем кэш в 60 секунд и создаём отдельную кэшированную версию страницы, базирующуюся на заголовке Accept-Language --%> <%@ OutputCache Duration="60" VaryByParam="None" VaryByHeader="Accept-Language" %> |
7. Включение кода манипуляции данными SQL Data Manipulation Language в код приложения
Такой подход – просто прямая дорога к неприятностям. Это не только возможность быть атакованным с помощью SQL-инъекции, но также такой код тяжелее поддерживать. С кодом SQL «врезанным» в код приложения, каждое изменение запроса должно вести к перекомпиляции. Например, вот такой SQL в вашем приложении свидетельствует об отсутствии у вас какого бы то нибыло опыта разработки.
string sql = "SELECT * FROM Users WHERE username='"+Username.Text+"' AND password= '"+Encrypt(Password.Text)+"'"; SqlCommand command = new SqlCommand (sql, connection); |
Что может случиться в таком случае – читайте в статье Stop SQL Injection Attacks Before They Stop You, автор - Paul Litwin.
string sql = "SELECT * FROM Users WHERE username=@Username AND password= @Password"; SqlCommand command = new SqlCommand (sql, connection); command.Parameters.Add("@Username", SqlDbType.VarChar).Value = UserName.Text; command.Parameters.Add("@Password", SqlDbType.VarChar).Value = Encrypt(Password.Text); SqlCommand command = new SqlCommand (sql, connection); |
Ещё лучшим решением является использование ХП, пусть ваши запросы хранятся в СУБД, компилируются и оптимизируются и могут быть изменены без перекомпиляции вашего кода.
SqlCommand command = new SqlCommand ("Users_GetUser", connection); command.CommandType = CommandType.StoredProcedure; command.Parameters.Add("@Username", SqlDbType.VarChar).Value = UserName.Text; command.Parameters.Add("@Password", SqlDbType.VarChar).Value = Encrypt(Password.Text); SqlCommand command = new SqlCommand (sql, connection); |
Девиз, по которому надо жить - "врезанныйSql == смерть;"
6. Не используйте SELECT *
Достаточно странно наблюдать за тем, что многие из нас используют такой способ извлечения данных. Так вот, многие из нас используют "SELECT * FROM..." при написании запросов к источникам данных. Это плохо. Многие разработчики до сих пор пишут такие запросы на стадии разработки, поскольку на этой стадии в таблице мало полей, мало данных или существует ещё нечто, что извиняет такой подход на том этапе. Но что происходит при увеличении количества данных или добавлении полей? Например, поля Image, хранящего картинку 1024x768 с портретом пользователя? Теперь каждый вызов "SELECT * FROM..." возвращает огромный по размерам набор данных, что имеет ОГРОМНОЕ влияние на производительность.
5. ХП без обработки исключений
Каждый день вы пишите код (я надеюсь на это). И каждый день вы пишите обработку исключений, поскольку может произойти что-то непредвиденное. Странно, что не все из нас делают это в ХП. Или вы думаете, что в ХП пройдёт всё, как по маслу? Вы говорите, что обрабатываете все исключения в коде приложения? А почему бы не делать это как можно ближе к источнику ошибки? Это моя пятая рекомендация.
CREATE PROCEDURE dbo.Users_Insert @Username VARCHAR (20) AS SET NOCOUNT ON DECLARE @Err INT SET @Err = 0 --Всё ок INSERT Users (Username) VALUES (@Username) SET @Err = @@ERROR -- это устанавливает @@ERROR в 0 IF (@Err <> 0) BEGIN IF (@Err = 547) --операция, конфликтующая с ограничением BEGIN SET @Err = 32 --наша ошибка, сигнализирующая о том, что имя пользователя уже занято GOTO abort END ELSE BEGIN SET @Err = 1 -- наша ошибка 'Неизвестная ошибка' END END abort: SET NOCOUNT OFF RETURN @Err GO |
Вы можете отреагировать на возвращённое значение после возврата
кода ошибки приложению. Если это 0, то ошибки не было. Если
это 32, то смотрим файл ErrorCodes.xml для получения строкового значения:
4. Префикс для ХП "sp_"
- В БД master.
- Как ХП, для которой есть квалификатор (имя БД или обладателя БД).
- ХП, для которой обладатель - dbo, если другой не указан.
3. Вы не защищаете строку соединения с БД
2. Принимаем весь ввод
- В ASP.NET есть пять компонент контроля ввода: RequiredFieldValidator, RegularExpressionValidator, CompareValidator, RangeValidator, CustomValidator, плюс ValidationSummary.
- Компоненты Windows Forms имеют событие Validating для осуществления проверки ввода.
- Класс System.Text.RegularExpressions.RegEx является мощным инструментом для работы с регулярными выражениями.
- HttpUtility.HtmlEncode может быть использована для шифровки HTML перед выводом на для предотвращения скриптовых атак.
- ASP.NET v1.1 (2003) включает атрибут ValidateRequest (в директиве @Page или Web.config) предотвращает использование вредоносных спиртов.
1. Использование записи "sa" для доступа к БД
Честно говоря, я остолбенел, увидев этот пункт на первом месте. Я думал, что все уже знают на зубок, что эту учётную запись можно использовать только для административных целей. Всё это очевидно, однако повторю ещё раз:
- НИКОГДА не используйте запись "sa" для программного доступа к БД.
-
Используйте один или более учётных записей для программного доступа к данным
- Для доступа к данным – учётную запись, которая может выполнить только SELECT.
- Для изменения данных – учётную запись, которая может только выполнять ХП.
- Не используя "sa", вы ограничиваете потеницального хакера в выполнении системных команд или процедур.
- Если вам действительно-предействительно нужно использовать "sa", создайте новую учётную запись, назовите её "essay" (проверка) и, может быть, вы обойдётесь и без "sa".
Так что используйте эти советы, проникнитесь ими и перестаньте делать глупости :)
Время кода
Фиксированный заголовок в ASP.NET DataGrid
ЯЗЫК: -
Автор статьи:
KjellSJ
ПЕРЕВОД: Чужа В.Ф. ака hDrummer
Вступление
Часто нужно создать DataGrid, в котором будет много записей (например, список клиентов или знакомых), причём у сетки с данными должна быть фиксированная высота и полоса прокрутки в том случае, если отображаемое число записей не помещается в отведённое место. Этого легко добиться, разместив DataGrid внутри тэга DIV:
<DIV style="OVERFLOW: auto; HEIGHT:120px"> <asp:DataGrid ... </DIV> |
Бывает такое, что нужно иметь возможность прокручивать записи в сетке, а заголовок оставить фиксированным, чего можно добиться с помощью стиля:
<style type="text/css"> <!-- .DataGridFixedHeader {background-color: white; position:relative; top:expression(this.offsetParent.scrollTop);} --> </style> |
Данные должны перекрываться заголовком, как только они попадут под строку заголовка. Убедитесь в том, что стиль прописан в одну строчку, поскольку выражение, записанное в несколько строк, может некорректно работать.
<asp:DataGrid id="dgContacts" runat="server" ... > ... <HeaderStyle CssClass="ms-formlabel DataGridFixedHeader"></HeaderStyle> ... |
Кстати, вы можете указать несколько классов внутри атрибута CssClass .
Поддерживаемые браузеры
Поскольку решение базируется на выражениях CSS, то работает в MSIE 5.x и 6.x. Это чисто клиентское решение и никаким образом не связано с кодированием на стороне сервера (кроме добавления стиля), однако у вас могут быть проблемы с другими браузерами или в случае со сложной страницей.
Вот и всё.
{К содержанию}
Форумы .Net - вопросы оставшиеся без ответа
Тип
RegularExpresionValidator - проверить control на НЕ abc
На этом сорок первый выпуск .Net Собеседника закончен.
До следующего номера.
Чужа Виталий Ф. aka hDrummer, MCAD, MCDBA, MCP
hdrummer@sql.ru - жду ваши предложения и замечания.
Subscribe.Ru
Поддержка подписчиков Другие рассылки этой тематики Другие рассылки этого автора |
Подписан адрес:
Код этой рассылки: comp.soft.prog.dotnetgrains |
Отписаться
Вспомнить пароль |
В избранное | ||