Безопасность

Программирование на Active Server Pages и VBScript.
bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Безопасность

Сообщение bs » 28.03.2006 (Вт) 12:05

У меня день назад ломанули сайт.
Сам контент сайта остался нетронутым. Поменяли только одну новость. Для публикации новостей использовался Web Wiz Site News version 3.06. Помогите, плииз, разобраться.

Итак, есть несколько вопросов по безопасности.

1. безопасно ли использовать cookies через следующую конструкцию
Есть asp файл проверки правильности введенного в форму пароля.
Если пароль правильный, то
Session("blnIsUserGood") = True

А потом, в в защищенных файлах в самом начале пишу следующее
<%
Response.Buffer=True
Response.Expires=-100
Call Response.AddHeader("Pragma", "no-cache")
Call Response.AddHeader("Cache-Control", "no-cache")
%>
<%
'If the session variable is False or does not exsist then redirect the user to the unauthorised user page
If Session("blnIsUserGood") = False or IsNull(Session("blnIsUserGood")) = True then
'Redirect to unathorised user page
Response.Redirect"unauthorised_user_page.htm"
End If
%>

Безопасна ли такая конструкция сама по себе?
Есть ли возможность взлома именно на этапе проверки If Session("blnIsUserGood") = False or IsNull(Session("blnIsUserGood")) = True then

Может ли злоумышленник как-то передать в Session("blnIsUserGood") какое-то свое значение? Если да, то как этого избежать? Какие еще конструкции можете посоветовать.

2. Что безопаснее: хранить пароль в БД или прямо в asp-файле. При «неаккуратном» обращении к БД злоумышленник может использовать SQL injection. Может, тогда хранить пароль прямо в asp?
If perPassword=”blablabla” then Session("blnIsUserGood") = True
и т.д. по вышеуказанной схеме

Или это тоже небезопасно?

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 12:07

2. надо хранить хэш пароля в базе, никогда в ASP :!:

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 12:08

и добавлю, а проверку надо реализовывать во внешней программе (DLL или базе данных)

bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Сообщение bs » 28.03.2006 (Вт) 12:15

Проверка во внещней программе не подходит. Тариф хотинга не позволяет. А не могли бы Вы пояснить свои комментарии. Разве ASP можно просмотреть в исходном виде через браузер? И еще! Не может ли кто-нибудь дать ответ на первую часть вопроса?

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 12:16

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

bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Сообщение bs » 28.03.2006 (Вт) 12:43

Спасибо за ответы. А что скажете об этой конструкции
<%
'If the session variable is False or does not exsist then redirect the user to the unauthorised user page
If Session("blnIsUserGood") = False or IsNull(Session("blnIsUserGood")) = True then
'Redirect to unathorised user page
Response.Redirect"unauthorised_user_page.htm"
End If
%>
Безопасна ли такая конструкция сама по себе?
Есть ли возможность взлома именно на этапе проверки If Session("blnIsUserGood") = False or IsNull(Session("blnIsUserGood")) = True then

Может ли злоумышленник как-то передать в Session("blnIsUserGood") какое-то свое значение? Если да, то как этого избежать? Какие еще конструкции можете посоветовать.

bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Сообщение bs » 28.03.2006 (Вт) 13:02

И почему проверку надо реализовывать во внешней программе (DLL или базе данных)? Можно ли всё-таки обойтись без внешних программ и проверять все в ASP?

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 14:07

может взломать, так как у юзера может сессия уже завершиться, а IIS об этом еще не знает и по-умолчанию она еще будет висеть минут 15-20 (зависит от настроек), в это время возможно от имени этой незварешенной сессии что-либо сделать

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 14:10

Konst_One писал(а):в это время возможно от имени этой незварешенной сессии что-либо сделать

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

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 14:17

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

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 14:25

А при открытии браузера разве он не создаёт новую сессию? Если запустить два инстанса, наппример, IE, то в каждом будет своя сессия.

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

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 14:32

Хранить ip клиента. При открытии сессии работы с приложением, записать в базу адрес клиента и выдать ему идентифиткатор сессии из базы (какой-нибудь счетчик), а потом проверять, сопадают ли ip запроса и номер сессии из него с теми, что записаны в базе.
Лучший способ понять что-то самому — объяснить это другому.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 14:41

Во-первых, что значит "адрес клиента"? Наверное SessionId? Выражайтесь тщательнее.

Во-вторых, если уж кто-то смог подломить сессию, то скопировать из адресной строки идентификатор ему труда не составит.

В-третьих, этот UIN придётся за собой таскать по всем страницам.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 14:45

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

Код: Выделить всё
'top.asp во всех страничках
<OBJECT runat="server" progid="MyDll.System" id="objSys" VIEWASTEXT></OBJECT>
<%
Sub AccessSession()
   UID = Coalesce(StrToVar(vbLong, Session("UID")), 0)
   If UID = 0 Then
      Server.Execute "include\session-authorize.asp"
      UID = Coalesce(StrToVar(vbLong, Session("UID")), 0)
   End If
End Sub

Sub BasePage_Load()
Dim objSiteMapNode, IsAccessGranted, PageRoles
   PageURL = GetURLFileName(Request.ServerVariables("PATH_INFO"))
   Call AccessSession()
   Set objSiteMapNode = GetSiteMap().selectSingleNode("//siteMapNode[@url='" & PageURL & "']")
   If Not objSiteMapNode Is Nothing Then
      PageTitle = objSiteMapNode.getAttribute("title")
      PageRoles = objSiteMapNode.getAttribute("roles")
      IsAccessGranted = (InStr(1, PageRoles, Session("Role")) > 0) Or (PageRoles = "*")
   End If
   If IsAccessGranted <> True Then
      Server.Transfer "include\session-denied.asp"
   End If

   If PageURL = "main.asp" Then
      If InStr(Request.ServerVariables("HTTP_REFERER"), PageURL) = 0 Then
         Session.Contents.Remove("post:" & PageURL)
      End If
   Else
      If Request.Form.Count > 0 Then
         Call Page_Post()
      ElseIf InStr(Request.ServerVariables("HTTP_REFERER"), PageURL) = 0 Then
         Session.Contents.Remove("post:" & PageURL)
      End If
   End If


   Call Page_Load()
End Sub
%>


'session-authorize.asp
<%
Call Authorization()

Sub Authorization()
Dim Login, UID
   ' authorization
   Login = "" & Request.ServerVariables("AUTH_USER")
   ' Force user to authenticate if they aren't already
   If Len(Login) = 0 Then
      Response.Status = "401 Unauthorized"
      Response.End
   Else
                     'здесь проверка логина и запись в сессию нужных параметров клиента
                     'objSys
                     UID = objSys.UserLogin(Login)
      If UID > 0 Then
         Dim rsUser: Set rsUser = objSys.UserGet(UID, UID)
         Session("UID") = UID
         Session("UserLogin") = rsUser("Login")
         Session("UserName") = rsUser("Name")
         Session("UserRoleID") = rsUser("RoleID")
         Session("UserRole") = rsUser("Role")
         Session("Role") = rsUser("RoleID")
      Else
         If Err.Number = 0 Then
            Response.Write "<html><head>" & _
                  "<meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>" & _
                  "<title>" & Application("AppName") & " - Доступ запрещен</title>" & _
                     "<h3>Доступ запрещен.</h3>" & _
                     "<p>Пользователь " & Login & " не является администратором системы.</p>" & _
                  "</head><body></body></html>"
         Else
            Response.Write "<html><head>" & _
                  "<meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>" & _
                  "<title>" & Application("AppName") & " - Ошибка идентификации</title>" & _
                     "<h3>Ошибка идентификации.</h3>" & _
                     "<p>Пользователь " & Login & ".</p>Код ошибки: " & Err.Number & "<br>Описание: " & Err.Description & "<br>Источник: " & Err.Source & _
                  "</head><body></body></html>"
         End If
         Response.End
      End If

               end if
end sub
%>

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 14:56

Во-первых, что значит "адрес клиента"? Наверное SessionId? Выражайтесь тщательнее.
Хранить ip клиента.
Читайте тщательнее.
Во-вторых, если уж кто-то смог подломить сессию, то скопировать из адресной строки идентификатор ему труда не составит.
А в добавок скопировать ip?
В-третьих, этот UIN придётся за собой таскать по всем страницам.
И что?

Кстати, не обязательно его таскать в адресной строке, можно и в <input type=hidden>. Соответственно все запросы должны отправляться формой. И говоря "сессия" я всегда имею ввиду идентификатор, сгенеренный базой, и все, что с ним связано в базе, а объектом Session лучше вообще никогда не пользоваться.
Лучший способ понять что-то самому — объяснить это другому.

bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Сообщение bs » 28.03.2006 (Вт) 15:05

Я тут пока открытые исходники смотрел... на WebWizе (http://www.webwizguide.info/)... Думаю, с ними многие работали... так вот там, как я понял, даже на двигле форума используется именно приведенная мною проверка... Значит ли это, что в большинстве случаев этого вполне достаточно? Неужели так уж плох объект Session? А этот форум, кстати, тоже, кажись, этот самый объект пользует...

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 15:13

2 Kost_One:
Вижу запись в сессию ID юзера:
Код: Выделить всё
         Session("UID") = UID

Вижу проверку этого UID:
Код: Выделить всё
UID = Coalesce(StrToVar(vbLong, Session("UID")), 0)
   If UID = 0 Then

Но не вижу ни записи в БД каких-либо данных, ни существенной разницы с кодом от bs.
Код: Выделить всё
If Session("blnIsUserGood") = False or IsNull(Session("blnIsUserGood")) = True then


Правда, не совсем понятно что делает функция Coalesce().


2 Antonariy:
Где хранить IP клиента? В БД? Так там и так он уже есть, мы его оттуда и берём. Вот приходит запрос. Что должно быть в нём помимо основных данных? SessionId забраковали по соображениям безопасности. Можем сварганить свой собственный УИН, и что? Проверять наш УИН и SessionId? А какая разница? Если чел. подделывает сессию, то скопировать, неважно из адресой ли строки или из переменной hidden, любые значения любых переменных для него не проблема. Это во-первых, а во-вторых, мы искать в БД наш супер-пупер навороченный и секретный УИН будем-то снова по тому же родному SessionId.

bs
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 115
Зарегистрирован: 31.01.2002 (Чт) 13:47
Откуда: Russia

Сообщение bs » 28.03.2006 (Вт) 15:21

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

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 15:34

я же тебе все сюда выкладывать не собираюсь, сам подумай:

Код: Выделить всё
Sub BeginSession()
Dim SessionID, UID, RemoteID
   On Error Resume Next
   RemoteID = "" & Request.ServerVariables("REMOTE_ADDR")
   UID = 0
   UID = objSys.ClientLogin("" & Request.Form("UNC"), "" & Request.Form("PIN"), RemoteID)
   If UID > 0 Then
      SessionID = objSys.SessionBegin(UID, 1, Session.Timeout, RemoteID)
      If SessionID > 0 Then
         On Error Goto 0
         Session("SID") = SessionID
         ' cache common data
         Session("UNC") = Request.Form("UNC")

.....


skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 16:08

Kost_One, код совсем не нужен. Словесного описания достаточно. Итак, ещё раз.

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

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

Ты, я так понял, используешь для авторизации не только свойства сессии, но и других объектов, например, Request.ServerVariables("REMOTE_ADDR"). Но в случае приведённом тобою же выше этот параметр не изменится, хотя в общем случае повышают степень защиты.

Короче, пока не убедительно. Или я чего-то важного не увидел?

ЗЫ: И нет никаких оснований проводить проверку пароля именно в DLL, а не непосредственно в коде ASP, т.к. даже при получении хакером исходников, ему будет лишь известен механизм проверки, а он как правило всегда прост (равно/не равно), и не более того.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 16:32

2 skiperski
Нужно проверять пару - id и ip. Неважно что за id - из базы или из Session - подделать и то и другое можно только находясь за тем же маршрутизатором. А если использовать id сессии и id базы и один из них передавать через адресную строку, то это еще больше осложнит жизнь злоумышленнику. Кроме того, можно сделать id базы не только скрытым, но и меняющимся при каждом запросе.
Лучший способ понять что-то самому — объяснить это другому.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 16:34

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

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 16:45

Antonariy писал(а):Нужно проверять пару - id и ip.

Я так понимаю, что IP - какой-нибудь идентификатор, например SessionId или Id пользователя из БД, а IP - IP-адрес, т.е. Request.ServerVariables("REMOTE_ADDR"). Правильно? Или снова не так? Я прошу тщательнее выражаться чтобы потом не перспрашивать, это же не устный разговор где сразу пояснить можно.

Antonariy писал(а):Кроме того, можно сделать id базы не только скрытым, но и меняющимся при каждом запросе

Можно, а зачем? Если я открою ссылку со страницы в новом окне (например, в одном клиенты, в другом - договоры), а потом попробую перемещаться поочерёдно в обоих окнах, то при таком алгоритме у меня это не получится.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 16:47

Можно, а зачем? Если я открою ссылку со страницы в новом окне (например, в одном клиенты, в другом - договоры), а потом попробую перемещаться поочерёдно в обоих окнах, то при таком алгоритме у меня это не получится.


все должно быть в одном окне

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 16:53

Konst_One писал(а):вобщем похоже , что так, но дполнительные проверки значительно увеличивают стойкость системы

Делаем вывод: хранить флаг авторизации в переменной сессии - это нормально, только необходимо подстраховаться ещё чем-нибудь, например Request.ServerVariables("REMOTE_ADDR").

Konst_One писал(а):, к тому же обычно при значимых действиях (ввод данных и тп) мы еще раз проверяем валидность прав пользователя на такие действия

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

Konst_One писал(а):надо еще учесть , что на каждой странице у нас выключен Cashe и установлен наименьший из возможного timeout

Ну, это понятно.

А что по поводу проверки пароля в DLL?

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 16:55

Я так понимаю, что IP - какой-нибудь идентификатор, например SessionId или Id пользователя из БД, а IP - IP-адрес, т.е. Request.ServerVariables("REMOTE_ADDR"). Правильно? Или снова не так? Я прошу тщательнее выражаться чтобы потом не перспрашивать, это же не устный разговор где сразу пояснить можно.
Именно так.
Можно, а зачем?
Как раз за тем, что мы тут обсуждаем. А открытие дополнительных окон в подобном приложении имхо дурной тон. Я стараюсь вообще не пользоваться тегом <a>, чтобы исключить подобные ситуации.
Лучший способ понять что-то самому — объяснить это другому.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 28.03.2006 (Вт) 16:55

Konst_One писал(а):все должно быть в одном окне

А почему должно? За что меня так наказывать? Это же вполне стандартный ход для веб-приложений. Я же привёл доволно жизненный пример, когда необходимы два окна. Можно ещё: два отчёта для сравнения вывесить рядом.

Такой ход, с динамическим ID, хорошо применим для форм. Т.е. каждая форма при первом вызове идентифицируется, помимо всего остального, ещё и своим уникальным кодом. Тогда при многошаговых формах, даже при открытии нескольких окон легко будет разобраться какая из форм посылает запрос.
Последний раз редактировалось skiperski 28.03.2006 (Вт) 17:01, всего редактировалось 1 раз.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 16:57

А что по поводу проверки пароля в DLL?
Абсолютно монописуально где его проверять. Просто если проверка сложная, луче запихнуть в dll, потому как быстрее.
Лучший способ понять что-то самому — объяснить это другому.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 28.03.2006 (Вт) 16:58

аминь :)

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 28.03.2006 (Вт) 16:59

А почему должно? За что меня так наказывать?
Да ради бога, хоть в трех. Должно - слишком сильно сказано. Но желательно, чтобы только одно из них было функциональным.
Лучший способ понять что-то самому — объяснить это другому.

След.

Вернуться в ASP и VBScript

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26

    TopList