37 1234
发新话题
打印

[推荐]ASP完全实例教程更新中

[推荐]ASP完全实例教程更新中

1。在ASP文件中调用DLL

  动态联接库(DLL)是加快应用程序关键部分的执行速度的重要方法,但有一点恐怕大部分人都不知道,那就是在ASP文件也能通过调用DLL来加快服务器的执行速度,下面我简单的介绍一下在ASP文件调用DLL的步骤。
  首先,必须得有DLL文件,本例是通过VB5.0创建ActiveX DLL文件,这个文件模拟了一个掷色子的过程。
在VB5.0的环境下,新建一个工程,并双击新建工程窗口中ActiveX DLL图标,VB将自动为项目添加一个类模块,并将该项目类型设置为ActiveX DLL。在属性窗口将类模块的名称属性改为clsDice。从工程菜单中,选择工程属性,将工程名称改为MyDLL。从文件菜单中,选择保存clsDice,将类模块保存为myDice.cls。添加以下代码:

Option Explicit

Private Max, Point As Integer

Public Property Get Result() As Integer
Result = Point
End Property

Public Property Get Maxpoint() As Integer
Maxpoint = Max
End Property

Public Property Let Maxpoint(num As Integer)
Max = num
End Property

Public Sub Throw()
Randomize
Point = Int(Rnd * Max) + 1
End Sub

Private Sub Class_Initialize()
Max = 6
End Sub

  这个类模块定义了clsDice对象的两个属性和一个方法,这些属性和方法模拟了掷色子的过程。其中Maxpoint属性表示色子的面数,加入Property Let语句将使客户能修改色子的面数;Result属性表示最后掷出色子的点数;Throw方法代表掷色子的动作;Private Sub Class_Initialize语句将色子的面数缺省的设置为6面。

  从文件菜单中,选择生成MYDLL.DLL并将它保存到适当的地方。至此,我们就创建了一个自己的DLL文件。

  第二步要做的就是要在ASP文件中引用类clsDice。

  ASP(活动服务器页面Active Server Pages)的所有代码都是在服务器上运行的,客户只能查看以HTML形式传回的结果。它使用“<%”和“%>”标记来标识脚本代码,并不传回客户端,在代码外部,使用HTML标记来标识内容。在下面Dice.asp的代码中使用了CreateObject函数创建了一个clsDice对象实例,该对象来自于上面创建的ActiveX.DLL--MYDLL.DLL文件,下面的例子使用了VBScript脚本语言。


<!--METADATA TYPE="typelib" FILE="Path/mydll.dll" -->
'装载 METADATA 标签中指定的类型库。 Path是mydll.dll在机器上存放的路径
<html>
<head><title>在ASP文件使用DLL</title></head>
<body>
<%
On Error Resume Next ‘当程序出现意外错误时能继续执行

If Request.Form("T1")="" then
Session("point") = 6
Else
Session("point")=Request.Form("T1")
End If
'用Session("point")来存放色子的面数

Set dice1=Server.Createobject("MyDLL.clsDice")
'使用set语句创建dice1对象,其中MyDLL是上面创建dll文件时的工程名称(注意:不是文件的名称),clsDice为类模块的名称。至此我们就可以用Maxpoint,Result和Throw属性(方法)来对dice1对象进行操作。

If Request.ServerVariables("Request_Method")="POST" then
dice1.Maxpoint = Session("point") ‘设定色子的面数
dice1.Throw ’掷色子
%>
<form method="POST" action="dice.asp">
<p>当色子的面数为<input type="text" name="T1" size="5" value=<% = session("point") %>>时</p>
<p><input type="submit" value="掷色子" name="B1"></p>
</form>
<p>结果为:<% = dice1.Result %>点 </p> ‘返回结果
<%
Else
dice1.Maxpoint = Session("point")
%>
<form method="POST" action="dice.asp">
<p>当色子的面数为<input type="text" name="T1" size="5" value=<% = session("point") %>>时</p>
<p><input type="submit" value="掷色子" name="B1"></p>
</form>
<%
End If
%>
</body>
  在浏览器中浏览http://localhoat/dice.asp,结果如附图。注意:只有在WINDOWS NT+IIS3.0以上或WINDOWS9X+PWB的环境下才能正确浏览。

[此贴子已经被作者于2005-8-12 13:55:52编辑过]

网络无限,生活无限

TOP

2.ASP能读写注册表

一个例子:
<%Dim ReadComputerName
Set ReadComputerName=CreateObject("WScript.Shell")
Dim ComputerName,RegPath
RegPath="HKLM\System\CurrentControlSet\Control\ComputerName\ComputerName\ComputerName"
ComputerName=ReadComputerName.RegRead(RegPath)
response.write "计算机名为"&ComputerName %>

第二个读的代码

<%
Dim zcbpath
zcbpath=request.form("zcbpath")
if zcbpath<> "" then
'zcbpath = "HKLM\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\COMMONFILESDIR"
Set objShell = CreateObject("WScript.Shell")
Response.Write objShell.RegRead(zcbpath)
end if
%>
<form action="zcb.asp" method=post>
注册表键值<input type=text name=zcbpath id=zcbpath>
<input type=submit>
</form>

网络无限,生活无限

TOP

3.ASP 中健壮的页结构的异常处理

错误处理是让程序员牢骚满腹的东西之一。让我们来面对它,我们不写错误的代码就是了。。。或者类似的想法。不幸的是,代码中的运行时错误可能有许多的原因,从硬件、软件的改变到使用了别的开发团队的代码等等。有效的处理这些错误并使得它对于网站正常操作过程的中断最小化是每个有良知的程序员的责任。



在本文讨论的范围内,有三个不同的地方可以发生错误:脚本,中间件,以及IT内部架构。IT内部架构的错误,比方周期性的性能降低并导致IIS进行(Inetinfo.exe)崩溃几乎是无法避免的。这种类型的错误通常只能打电话要求技术支持并且会让系统管理员忙上很久。开发者不能为阻止这类错误做些什么,但是我们通常能够应付和改正脚本和中间件中的错误。 在安装了IIS以后,缺省的服务器端脚本语言被设置成VBScript。许多Web 开发团队在他们的开发环境中保持了这些缺省设置,这是不幸的,因为VBScript对于处理运行时错误的支持非常的差。在VBScript中,开发者可以使用的唯一一个错误处理结构是

On Error Resume Next (打开错误处理功能) 和
On Error GoTo 0 (关闭错误处理功能).
为了在你的ASP 页面里有效的使用这个错误处理结构,你可能需要用这些结构包括可能抛出异常的代码,就象下面这样:


<%
Dim myVar
On Error Resume Next
'下面一行代码会在MSXML 4.0没有被安装或者已经损坏的情况下产生错误
Set myVar = Server.CreateObject("MSXML2.DOMDocument.4.0")
If Err.Number <> 0 Then
' 在这里处理错误
' 结束错误处理,避免以后发生的错误无法被发现
On Error GoTo 0
Else
' myVar 现在指向 MSXML 4.0 DOMDocument的一个实例
' 结束错误处理,避免以后发生的错误无法被发现
On Error GoTo 0
End If


就象你看到的一样,如果你要在每一行现有的可能发生错误的代码上使用上面的规则,你的程序马上就会充满 "On Error" 和 "If Err.Number <> 0 Then . . ." 这样的结构。


而另一方面JScript对于健壮的错误处理机制“结构化异常处理(SEH)”有内建的支持。使用SEH能够让你的软件开发团队顺利的转移到.NET 环境上来,因为SEH是JScript.NET, VB.NET, 和 C#缺省的错误处理机制。(注意:.NET不支持VBScript。)下面的例子代码执行与VBScript代码相同的操作,但是使用JScript语言并用SEH来处理异常

<%@ LANGUAGE="JScript" %>
<%
var myVar;
try {
myVar = Server.CreateObject("MSXML2.DOMDocument.4.0");
// 如果上面发生了错误,那么catch
// 代码块就会立刻被执行
// 并在myVar上进行必要的操作。
}
catch (e) {
// 在这里处理异常,异常本身可以用
// 'e' 变量进行引用。
}
finally {
// 在这里进行所有收尾工作
// 这段代码不管错误有没有发生
// (也就是“catch”块有没有运行)
// 都会执行。
}
%>
通过在服务器端使用JScript,你就得到了SEH带来的好处,以及对复杂ASP对象,比方Server,Request和Response对象的完全使用。要把这种脚本语言设置成你的ASP页面的缺省语言,你只需要简单的在你的ASP页面上添加@LANGUAGE指令,就象上面的例子那样。

网络无限,生活无限

TOP

4.在SQL Server中保存和输出图片

介绍



有时候我们需要保存一些binary data进数据库。SQL Server提供一个叫做image的特殊数据类型供我们保存binary data。Binary data可以是图片、文档等。在这篇文章中我们将看到如何在SQL Server中保存和输出图片。



建表



为了试验这个例子你需要一个含有数据的table(你可以在现在的库中创建它,也可以创建一个新的数据库),下面是它的结构:



Column Name
Datatype
Purpose

ID
Integer
identity column Primary key

IMGTITLE
Varchar(50)
Stores some user friendly title to identity the image

IMGTYPE
Varchar(50)
Stores image content type. This will be same as recognized content types of ASP.NET

IMGDATA
Image
Stores actual image or binary data.





保存images进SQL Server数据库



为了保存图片到table你首先得从客户端上传它们到你的web服务器。你可以创建一个web form,用TextBox得到图片的标题,用HTML File Server Control得到图片文件。确信你设定了Form的encType属性为multipart/form-data。



Stream imgdatastream = File1.PostedFile.InputStream;

int imgdatalen = File1.PostedFile.ContentLength;

string imgtype = File1.PostedFile.ContentType;

string imgtitle = TextBox1.Text;

byte[] imgdata = new byte[imgdatalen];

int n = imgdatastream.Read(imgdata,0,imgdatalen);

string connstr=

((NameValueCollection)Context.GetConfig

("appSettings"))["connstr"];

SqlConnection connection = new SqlConnection(connstr);

SqlCommand command = new SqlCommand

("INSERT INTO ImageStore(imgtitle,imgtype,imgdata)

VALUES ( @imgtitle, @imgtype,@imgdata )", connection );



SqlParameter paramTitle = new SqlParameter

("@imgtitle", SqlDbType.VarChar,50 );

paramTitle.Value = imgtitle;

command.Parameters.Add( paramTitle);



SqlParameter paramData = new SqlParameter

( "@imgdata", SqlDbType.Image );

paramData.Value = imgdata;

command.Parameters.Add( paramData );



SqlParameter paramType = new SqlParameter

( "@imgtype", SqlDbType.VarChar,50 );

paramType.Value = imgtype;

command.Parameters.Add( paramType );



connection.Open();

int numRowsAffected = command.ExecuteNonQuery();

connection.Close();



从数据库中输出图片



现在让我们从数据库中取出我们刚刚保存的图片,在这儿,我们将直接将图片输出至浏览器。你也可以将它保存为一个文件或做任何你想做的。



private void Page_Load(object sender, System.EventArgs e)

{

string imgid =Request.QueryString["imgid"];

string connstr=((NameValueCollection)

Context.GetConfig("appSettings"))["connstr"];

string sql="SELECT imgdata, imgtype FROM ImageStore WHERE id = "

+ imgid;

SqlConnection connection = new SqlConnection(connstr);

SqlCommand command = new SqlCommand(sql, connection);

connection.Open();

SqlDataReader dr = command.ExecuteReader();

if(dr.Read())

{

Response.ContentType = dr["imgtype"].ToString();

Response.BinaryWrite( (byte[]) dr["imgdata"] );

}

connection.Close();

}



在上面的代码中我们使用了一个已经打开的数据库,通过datareader选择images。接着用Response.BinaryWrite代替Response.Write来显示image文件。

网络无限,生活无限

TOP

5.使用ASP.NET加密口令

当我们在网站上建立数据库时,保护用户的信息安全是非常必要的。多数用户不愿意让别人知道自己的信息,同时网管也不想因为安全问题而丢失网站的信誉。无论对于谁,安全问题都是非常重要的。
为了解决这个问题,我给大家提供一个简单实用,但是老套的方法,就是口令加密。在此我们使用ASP.NET技术对口令加密。简单的讲,就是将用户提供的口令加密之后,然后让它和存放于系统中的数据比较,如果相同,则通过验证。
在ASP中,并未提供加密的对象,我们只能使用外部的对象来进行加密。现在好了,在ASP.NET中提供了加密的解决方法。在名字空间System.Web.Security中包含了类FormsAuthentication,其中有一个方法HashPasswordForStoringInConfigFile。这个方法可以将用户提供的字符变成乱码,然后存储起来,甚至可以 存储在cookies中。
HashPasswordForStoringInConfigFile方法使用起来很简单,它支持"SHA1"和"MD5"加密算法。
下面的代码简单的演示了关于其用法:
<%@ Page language="c#" %>
<%@ Import Namespace="System.Web.Security" %>
<html>
<head>
<script language="C#" runat="server">
public void encryptString(Object sender, EventArgs e)
{
SHA1.Text = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text,"SHA1");
MD5.Text =FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "MD5") ;
}
</script>
</head>
<body>
<form runat="server" ID="Form1">
<p>
<b>Original Clear Text Password: </b>
<br>
<asp:Textbox id="txtPassword" runat="server" />
<asp:Button runat="server" text="Encrypt String" onClick="encryptString" ID="Button1" />
</p>
<p>
<b>Encrypted Password In SHA1: </b>
<asp:label id="SHA1" runat="server" />
</p>
<p>
<b>Encrypted Password In MD5: </b>
<asp:label id="MD5" runat="server" />
</p>
</form>
</body>
</html>



正如你所看到的这样简单易用。我们可以把这段加密程序封装在一个函数里便于重复的使用。代码如下:
public string EncryptPassword(string PasswordString,string PasswordFormat )
{
if (PasswordFormat="SHA1"){
EncryptPassword=FormsAuthortication.HashPasswordForStoringInConfigFile(PasswordString ,"SHA1");
}
elseif (PasswordFormat="MD5")
{ EncryptPassword=FormsAuthortication.HashPasswordForStoringInConfigFile(PasswordString ,"MD5");
}
else
{
EncryptPassword="";
}

我们可以在数据库中添加一个字段,使用insert将加密的口令作为一个string存入数据库中。当用户登陆的时候,就可以将用户输入的口令加密结果和数据库中的正确结果比较,通过这种办法来验证口令的正确性了。在此,我就不往下写了,关于数据库的知识还得读者自己去学习。

网络无限,生活无限

TOP

6.web.config一个中文解释

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<system.web>

<!-- 动态调试编译
设置 compilation debug="true" 以将调试符号(.pdb 信息)
插入到编译页中。因为这将创建执行起来
较慢的大文件,所以应该只在调试时将该值设置为 true,而所有其他时候都设置为
false。有关更多信息,请参考有关
调试 ASP.NET 文件的文档。
-->
<compilation defaultLanguage="vb" debug="true" />

<!-- 自定义错误信息
设置 customErrors mode="On" 或 "RemoteOnly" 以启用自定义错误信息,或设置为 "Off" 以禁用自定义错误信息。
为每个要处理的错误添加 <error> 标记。
-->
<customErrors mode="RemoteOnly" />

<!-- 身份验证
此节设置应用程序的身份验证策略。可能的模式是 \“Windows\”、
\“Forms\”、\“Passport\”和 \“None\”
-->
<authentication mode="Windows" />


<!-- 授权
此节设置应用程序的授权策略。可以允许或拒绝用户或角色访问
应用程序资源。通配符:"*" 表示任何人,"?" 表示匿名
(未授权的)用户。
-->
<authorization>
<allow users="*" /> <!-- 允许所有用户 -->

<!-- <allow users="[逗号分隔的用户列表]"
roles="[逗号分隔的角色列表]"/>
<deny users="[逗号分隔的用户列表]"
roles="[逗号分隔的角色列表]"/>
-->
</authorization>

<!-- 应用程序级别跟踪记录
应用程序级别跟踪在应用程序内为每一页启用跟踪日志输出。
设置 trace enabled="true" 以启用应用程序跟踪记录。如果 pageOutput="true",则
跟踪信息将显示在每一页的底部。否则,可以通过从 Web 应用程序
根浏览 "trace.axd" 页来查看
应用程序跟踪日志。
-->
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />


<!-- 会话状态设置
默认情况下,ASP.NET 使用 cookie 标识哪些请求属于特定的会话。
如果 cookie 不可用,则可以通过将会话标识符添加到 URL 来跟踪会话。
若要禁用 cookie,请设置 sessionState cookieless="true"。
-->
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;user id=sa;password="
cookieless="false"
timeout="20"
/>

<!-- 全球化
此节设置应用程序的全球化设置。
-->
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />

</system.web>

</configuration>

网络无限,生活无限

TOP

7。尝尝ASP.NET中的小甜饼

Cookie对于使用过ASP的读者来讲并不陌生,但是我们要讲的是在ASP.NET中的Cookie。我们知道,Cookie存在于用户计算机浏览器中,我们可以使用Cookie来存放一些很简单的数据。但是,有一点别说我没提醒你:记住这不是个好办法,因为用户可以在任何时间删除Cookie信息,也可以关闭Cookie功能。好了,开场白就这些。

使用ASP.NET我们可以很容易的对Cookie集合进行操作。它和ASP中的Cookie一样,都是附属于Request和Response对象的。Listing1和2分别给出了如何读和写Cookie的方法。图1和2则是相应的显示。
Listing 1这个文件的功能是写入cookie
<%@ language="C#" %>
<HTML>
<script language="C#" runat="server">
void WriteClicked(Object Sender, EventArgs e)
{
//创建一个新Cookie,其cookie名来自于NameField.Text
HttpCookie cookie = new HttpCookie(NameField.Text);

//设定Cookie的值
cookie.Value = ValueField.Text;

//设定cookie生命为1 minute,TimeSpan()是一个专门设定时间间隔的类,我们定义了其实例tsMinute
DateTime dtNow = DateTime.Now;
TimeSpan tsMinute = new TimeSpan(0, 0, 1, 0);
cookie.Expires = dtNow + tsMinute;

//添加Cookie
Response.Cookies.Add(cookie);

Response.Write("Cookie written. <br><hr>");
}
</script>
<body>
<h3>
Use the button below to write cookies to your browser
</h3>
The cookies will expire in one minute.
<form runat="server" ID="Form1">
Cookie Name
<asp:textbox id="NameField" runat="server" />
<br>
Cookie Value
<asp:textbox id="ValueField" runat="server" />
<br>
<asp:button text="WriteCookie" onclick="WriteClicked" runat="server" ID="Button1" />
<br>
</form>
<a href="readcookies.aspx">Read the cookies</a>
</body>
</HTML>
图1
Listing 2 这个文件是为了读取刚才写入的cookie值
<%@ language="C#" %>
<script runat="server">
void ReadClicked(Object Sender, EventArgs e)
{
//取得想要的Cookie名
String strCookieName = NameField.Text;

//取得此Cookie名对应的对象,注意目前的得到的cookie是个对象
HttpCookie cookie = Request.Cookies[strCookieName];

//检验Cookie是否已经存在
if (null == cookie) {
Response.Write("Cookie not found. <br><hr>");
}
else {
//显示Cookie的值
String strCookieValue = cookie.Value.ToString();
Response.Write("The " + strCookieName + " cookie contains: <b>"
+ strCookieValue + "</b><br><hr>");
}
}
</script>
<html>
<body>
Use the button below to read a cookie
<br>
<form runat="server" ID="Form1">
Cookie Name
<asp:textbox id="NameField" runat="server" />
<asp:button text="ReadCookie" onclick="ReadClicked" runat="server" ID="Button1" />
</form>
<a href="writecookies.aspx">Write Cookies</a>
</body>
</html>

图2
为了更好的了解cookie的读写,代码分析如下。
在Listing 1中,为了将cookie写入用户的浏览器,我们调用了HttpCookie对象,并且建立了一个HttpCookie对象的实例cookie,写入cookie时,我们使用了Response.Cookies对象的方法Add(),最后我们设定了此cookie的生命期限为一分钟。
在Listing 2中,我们尝试了读取Cookie的方法。很简单,就是访问了Request.Cookies集合。
Cookie只能存放string类型的数据,如果想要存放更为复杂的数据类型,那么必须先将其转换为string类型。提示一种办法可以向Cookie写入复杂的数据类型,就是将想存放的复杂数据类型转化为XML串,然后写入Cookie。另外,我们还可以在一个cookie中存储多个值,在此就不多说了,留给有兴趣的读者去研究吧。
点击下载本文示例源代码

网络无限,生活无限

TOP

8。用asp.net实现的把本文推荐给好友功能

///<summary>
///<author>飞鹰@ASPCool.com</author>
///<description>本文用asp.net实现把此文推荐给好友的功能。</desciption>
///<copyright>ASP酷技术资讯网(www.ASPCool.com)</copyright>
///</summary>

这里飞鹰用一个简单的例子向大家介绍如何使用asp.net的邮件发送功能。首先,我们先做一个发送界面。tuijian.asp, 其中title是代表文章的标题,id代表文章的编号。

<html>
<body>
您好,欢迎使用ASP酷技术资讯网文章推荐功能,您推荐的文章为:《<%=request("title")%>》.<BR>
<form action="mail.aspx">
您的信箱:<INPUT TYPE="text" NAME="sender"><BR>
收件人信箱:<INPUT TYPE="text" NAME="accepter"><BR>
<INPUT TYPE="hidden" name="title" value="<%=request("title")%>">
<INPUT TYPE="hidden" name="id" value="<%=request("id")%>">
<INPUT TYPE="submit" value="发送"><INPUT TYPE="reset" value="重写">
</form>
</body>
</html>

下面我们就用asp.net来实现推荐文章功能,mail.aspx

<% @Page Language="C#" Debug="true"%>
<% @Import Namespace="System.Web.Mail" %>
<%


MailMessage msgMail = new MailMessage();

msgMail.To = Request["accepter"]; //邮件接受者
msgMail.Cc = "webmaster@aspcool.com";
msgMail.From = Request["sender"];
msgMail.Subject = "您的朋友从ASPCOOL.COM给您推荐了一篇文章。";

msgMail.BodyFormat = MailFormat.Html;
string strBody = "<html><body><b>" + Request["accepter"] +"</b>,您好。<br>" +
"您的朋友: <font color=\"red\">"+ Request["sender"]+ "</font>从<a href=http://www.aspcool.com>ASP酷技术资讯网</a>给您推荐了一篇文章--<a href=http://www.aspcool.com/lanmu/dot.asp?ID=" +Request["id"]+ Request["title"]+"</a>.请<a href=http://www.aspcool.com/lanmu/dot.asp?ID=" +Request["id"]+ ">点此查看</a>。</body></html>"; //邮件内容

msgMail.Body = strBody;

SmtpMail.Send(msgMail);

Response.Write("您好,您的推荐信已经发出去了,谢谢您对<a href=http://www.aspcool.com>ASP酷技术资讯网</a>的支持!请<a href=http://www.aspcool.com>返回</a>");
%>

看,是不是很简单,如果你有支持asp.net的空间的话就可以轻松推荐您的网站了。

网络无限,生活无限

TOP

9。开发BtoC电子商务系统(ASP.NET)

原文还有两个图
在对ASP.NET Web表单的编程模型有了基本的认识后,通过应用于现实的开发案例来提高对ASP.NET Web表单内在运作机制的了解,以及由此带来的对系统架构的掌控是很有必要的。我们没有为编程而编程的高贵姿态,我们深深懂得能够开发出高效,健壮,强大的应用程序始终是编程的终极。我们下面通过一个完整的BToC电子商务系统的开发流程来展示ASP.NET Web表单是怎样具体搭建面向下一代网络平台的。
这是一个典型的基于B/S(浏览器/服务器) 三层架构的食品,饮料电子商务零售系统——“玉米地零食店”。前端为产品浏览器,为消费者提供浏览/选购商品,下订单购物等各个环节的功能;中间层为销售商的税率,优惠等商务逻辑;后端为与整个零售系统相关的产品,顾客,订单等数据库。我们采用ASP.NET+IIS 5来构建前端和中间层,SQL Server 2000来管理后端数据库,整个系统运行于Windows XP。相关硬件配置只要满足上述软件的基本配置,系统性能便可保证。下面为该网上零售系统的前端界面图示:

在编制Web 表单商业前端和中间层之前,我们有必要对后端数据库做一个简单的介绍。后端数据库 CornfieldGrocer 由4个表组成:产品类别表Categories ,产品细节表 Details ,产品表 Products ,客户信息表Customers。考虑到演示系统的的简洁性,我们没有添加相关的存储过程,视图,规则等,这些在实际的系统的开发中对提高系统的性能是很有必要,尤其是在大数据量的情况下。下面为4个表的字段的图示介绍:

各个表的字段的表义已经相当清楚,我们不在这里赘述。我们下面向大家展示一下整个电子商务零售系统——“玉米地零食店”的物理文件组成及其结构,下图为示意图:

所有的文件位于ASP.NET站点目录CornfieldGrocer下,其中还有Web表单页面用到的图片子目录Images下的文件就不再在这里列出了。
下面我们开始编写前端和中间层代码,为了更清楚地展示Web Form ASP.NET的底层代码构造,我们采用记事本来完成整个代码的编写过程。需要说明的是在真正的工程项目开发实践中,如能借助Visual Studio.Net等可视集成开发工具,开发效率会大大提高。但在ASP.NET代码的底层机制没有谙熟的情况下,笔者强烈建议初期的开发学习不妨放在Windows系统自带的“记事本”这一简单却能够把代码暴露得相当清晰的工具里。
由于篇幅有限,我们不可能将所有的代码都在这里展示给大家。如前所述,web.config为每个站点级的基于XML的配置文件,负责一些ASP.NET的安全认证,编码选择,诊断测试等ASP.NET的配置工作,为浏览器请求ASP.NET Web表单时通过 IIS处理后的第一站。下面为其内容:

<configuration>
<system.web>
<globalization requestEncoding="UTF-8" responseEncoding="UTF-8" />
</system.web>
</configuration>


容易看到这里的配置内容相当简单,仅指定请求/发送的编码为“UTF-8”。我们对此不再赘述。
global.asax文件及其由后端代码文件global.asax.cs编译成的Bin\CornfieldGrocer.dll共同组成该网上零售系统的ASP.NET应用程序定义。我们先来看文件global.asax:

<%@ Application Inherits="CornfieldGrocer.Global" %>

该文件只有一行指示符,它表示ASP.NET应用程序的定义继承自Global类,而Global类正是在global.asax.cs文件中定义:

using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;

namespace CornfieldGrocer
{
public class Global : System.Web.HttpApplication
{
protected void Session_Start(Object sender, EventArgs e)
{
if (Session["ShoppingCart"] == null)
{
Session["ShoppingCart"] = new CornfieldGrocer.OrderList();
}
}
}
}

在Global类里,我们定义了区段(Session)意义下的购物卡(ShoppingCart)——这里采用了C#中的索引器。购物卡的类型为CornfieldGrocer命名空间中的OrderList类,在CornfieldGrocer.cs文件中有定义。我们当然也可以在global.asax文件中用脚本语言的形式将上面两个文件的内容合并起来,但那不是ASP.NET推荐的做法,因为脚本语言的第一次执行还要进行动态编译,这回损失一部分性能,而将CS文件提前编译成dll文件则会降低这种代价——当然这里的编译的意思还是指将CS的源代码文件编译成微软中间语言的过程。其次,页面与后端代码分离的原则易于项目管理,是Visual Studio.NET推荐的工程性的做法。
文件Default.aspx为整个网上零售系统的前端页面HTML代码,Default.aspx.cs为其后端控制Web表单行为的CS代码。由于篇幅关系我们这里不再赘述其HTML代码,实际上从前面给出的前端界面图示,我们可以基本了解Default.aspx的HTML代码结构。Style.css文件为Default.aspx文件的页面样式定义文件,定义一些页面元素的颜色,格式,间距等修饰性的东西,我们也不再多言。下面只向大家展示Default.aspx的页面指示符:

<%@ AutoEventWireup="false" Inherits="CornfieldGrocer.MainForm" %>

我们用“Inherits="CornfieldGrocer.MainForm"”来表示我们的页面继承自MainForm类,这样我们就实现了对ASP.NET Web 表单行为的控制代码与页面显示的HTML的分离。其中“AutoEventWireup="false"”表示页面事件非自动使能——页面事件非自动使能的意思是所有页面事件必须经过用户明确的操作才能触发,由于该属性缺省为“true”表示自动使能,但我们的商业逻辑要求非自动使能,故这里的语句很有必要,否则会引起系统处理的混乱。下面我们来看MainForm类:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace CornfieldGrocer
{
public class MainForm: System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label CurrentCategory;
protected System.Web.UI.WebControls.Label Name;
protected System.Web.UI.WebControls.Label SubTotal;
protected System.Web.UI.WebControls.ImageButton Imagebutton1;
protected System.Web.UI.WebControls.Label Description;
protected System.Web.UI.WebControls.Label Company;
protected System.Web.UI.WebControls.Repeater DetailsListing;
protected System.Web.UI.WebControls.DataList ProductListing;
protected System.Web.UI.WebControls.DataList ShoppingCartList;
protected System.Web.UI.HtmlControls.HtmlSelect CategoryList;
protected System.Web.UI.WebControls.Button btnSelect;
protected System.Web.UI.WebControls.Label Tax;
protected System.Web.UI.WebControls.Label Total;
protected System.Web.UI.WebControls.ImageButton Imagebutton4;
protected System.Web.UI.WebControls.ImageButton Imagebutton5;
protected System.Web.UI.WebControls.ImageButton Imagebutton6;
protected System.Web.UI.HtmlControls.HtmlInputText Qty;
protected System.Web.UI.HtmlControls.HtmlGenericControl CheckoutPanel;
protected System.Web.UI.HtmlControls.HtmlImage SelectedProdPicture;

public MainForm()
{
Page.Init += new System.EventHandler(Page_Init);
}
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
ProductListing.SelectedIndex = 0;

UpdateProducts();
UpdateShoppingCart();
}
}
private void Page_Init(object sender, EventArgs e)
{
InitializeComponent();
}
private void InitializeComponent()
{
this.btnSelect.Click +=
new System.EventHandler(this.CategoryList_Select);
this.ProductListing.SelectedIndexChanged+=
new System.EventHandler(this.ProductListing_Select);
this.Imagebutton1.Click+=
new ImageClickEventHandler(this.AddBtn_Click);
this.Imagebutton4.Click+=
new ImageClickEventHandler(this.Recalculate_Click);
this.Imagebutton6.Click+=
new ImageClickEventHandler(this.ClearCart_Click);
this.Load +=
new System.EventHandler(this.Page_Load);
}
private void CategoryList_Select(Object sender, EventArgs e)
{
CurrentCategory.Text =
CategoryList.Items[CategoryList.SelectedIndex].Text;
UpdateProducts();
}
private void ProductListing_Select(Object sender, EventArgs e)
{
UpdateProducts();
}
private void AddBtn_Click(Object sender, ImageClickEventArgs e)
{
int productID = Int32.Parse
(ProductListing.DataKeys[ProductListing.SelectedIndex].ToString());

InventoryDB market = new InventoryDB();
DataRow product = market.GetProduct(productID);

CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);

shoppingCart.Add(new CornfieldGrocer.OrderItem(productID,
(String) product["ProductName"],
Double.Parse(product["UnitPrice"].ToString()), 1));

UpdateShoppingCart();
}
private void Recalculate_Click(Object sender, ImageClickEventArgs e)
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);

for (int i=0; i<ShoppingCartList.Items.Count; i++) >
{
HtmlInputText qty =
(HtmlInputText) ShoppingCartList.Items.FindControl("Qty");
try
{
shoppingCart[(String) ShoppingCartList.DataKeys]].Quantity
= Int32.Parse(qty.Value);
}
catch (Exception)
{
}
}
UpdateShoppingCart();
}
private void ClearCart_Click(Object sender, ImageClickEventArgs e)
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);

shoppingCart.ClearCart();
UpdateShoppingCart();
}
void UpdateProducts()
{
InventoryDB market = new InventoryDB();

int categoryID = Int32.Parse
(CategoryList.Items[CategoryList.SelectedIndex].Value);
ProductListing.DataSource =
market.GetProducts(categoryID).DefaultView;
ProductListing.DataBind();

int productID = Int32.Parse
(ProductListing.DataKeys[ProductListing.SelectedIndex].ToString());
DataRow product = market.GetProduct(productID);

Name.Text = product["ProductName"].ToString();
SelectedProdPicture.Src = product["ImagePath"].ToString();
Description.Text = product["ProductDescription"].ToString();
Company.Text = product["Manufacturer"].ToString();

DetailsListing.DataSource =
market.GetProductCalories(productID).DefaultView;
DetailsListing.DataBind();
}
void UpdateShoppingCart()
{
CornfieldGrocer.OrderList shoppingCart =
((CornfieldGrocer.OrderList) Session["ShoppingCart"]);

SubTotal.Text = String.Format("{0:C}", shoppingCart.SubTotal);
Tax.Text = String.Format("{0:C}", shoppingCart.Tax);
Total.Text = String.Format("{0:C}", shoppingCart.Total);

ShoppingCartList.DataSource=shoppingCart.Values;
ShoppingCartList.DataBind();
}
}
}
MainForm类中共有11个方法,19个保护域。其中的19个保护域和前面给出的前端界面图示的页面元素相对应,这里不再赘述。11个方法中MainForm()为构建器,其添加了页面初始化事件Page_Init(),这是ASP.NET Web表单最先处理的事件,一般进行一些基础的初始化操作。我们可以看到在Page_Init()中进行了初始化组件InitializeComponent()的操作。Page_Load()事件出现在用户发出请求后,页面装载的时候,在这里一般可做一些商业逻辑初始化方面的操作,比如数据库的连接,购物卡的初始化等。我们这里进行了产品展示UpdateProducts()和购物卡的初始化UpdateShoppingCart()的操作。
其他四个方法分别为产品类别的选择ProductListing_Select(),购买产品的添加AddBtn_Click(),购物卡的重新计算Recalculate_Click(),购物卡的清除ClearCart_Click()都是通过对ASP.NET控件的操作来触发相应的事件完成商业逻辑。上面的代码已经展示的相当清楚,我们不再赘述。
最后我们要向大家说明的是中间层商务逻辑的组件。它由三个类构成:库存数据类InventoryDB,订单项目类OrderItem和订单列表类OrderList。它们共同在文件CornfieldGrocer.cs文件中定义。自解释的编程方式已经它们的结构展示的相当清除,我们下面只给出该文件的CS源代码:

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

namespace CornfieldGrocer
{
public class InventoryDB
{
public DataTable GetProducts(int categoryID)
{
SqlConnection sqlConnect= new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Products where categoryid="+categoryID,sqlConnect);
DataSet products = new DataSet();
sqlAdapter1.Fill(products, "products");
return products.Tables[0];
}
public DataRow GetProduct(int productID)
{
SqlConnection sqlConnect= new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Products where productID=" + productID, sqlConnect);
DataSet product = new DataSet();
sqlAdapter1.Fill(product, "product");
return product.Tables[0].Rows[0];
}
public DataTable GetProductCalories(int productID)
{
SqlConnection sqlConnect = new SqlConnection
("server=(local);database=CornfieldGrocer;Trusted_Connection=yes");
SqlDataAdapter sqlAdapter1 = new SqlDataAdapter
("Select * from Details where productID="+productID,sqlConnect);
DataSet details = new DataSet();
sqlAdapter1.Fill(details, "details");
return details.Tables[0];
}
}

public class OrderItem
{
public int productID;
public int quantity;
public String name;
public double price;
public OrderItem(int productID, String name, double price, int quantity)
{
this.productID = productID;
this.quantity = quantity;
this.name = name;
this.price = price;
}
public int ProductID
{
get { return ProductID; }
}
public int Quantity
{
get { return quantity; }
set { quantity=value; }
}
public String Name
{
get { return name; }
}
public double Price
{
get { return price; }
}
public double Total
{
get { return quantity * price; }
}
}

public class OrderList
{
private Hashtable orders = new Hashtable();
private double taxRate = 0.08;
public double SubTotal
{
get
{
if (orders.Count == 0)
return 0.0;
double subTotal = 0;
IEnumerator items = orders.Values.GetEnumerator();
while(items.MoveNext())
{
subTotal += ((OrderItem) items.Current).Price *
((OrderItem) items.Current).Quantity;
}
return subTotal;
}
}
public double TaxRate
{
get { return taxRate; }
set { taxRate = value; }
}
public double Tax
{
get { return SubTotal * taxRate; }
}
public double Total
{
get { return SubTotal * (1 + taxRate); }
}
public ICollection Values {
get {
return orders.Values;
}
}
public OrderItem this[String name] {
get {
return (OrderItem) orders[name];
}
}
public void Add(OrderItem value)
{
if (orders[value.Name] == null) {
orders.Add(value.Name, value);
}
else
{
OrderItem oI = (OrderItem)orders[value.Name];
oI.Quantity = oI.Quantity + 1;
}
}
public void ClearCart() {
orders.Clear();
}
}
}

需要说明的是我们将三个文件CornfieldGrocer.cs,Default.aspx.cs,Global.asax.cs用编译命令“csc /t:library /out:CornfieldGrocer.dll cornfieldgrocer.cs default.aspx.cs global.asax.cs”将它们全部封装在CornfieldGrocer命名空间里,虽然这并不是必须的。上面的编译器输出CornfieldGrocer.dll文件,我们配置该网上零售站点时只需将该文件拷贝到站点根目录中的Bin目录下即可。
到此为止,我们已经完整的向大家展示了利用ASP.NET Web表单建立一个小型的网上交易系统的编码,配置等工作。当然作为演示案例,它还没有真正系统的完善的性能,安全,界面等各个方面的优化考虑和设计。但它向我们展示的ASP.NET Web表单模型却非常典型且底层,大家不防在此基础上通过不断的修改和扩充来开发适合自己的交易系统。比如对于Default.aspx文件中AutoEventWireup="false"如果设置为“true”或去掉这个语句,在运行页面时会出现什么情况?通过这些练习便会不断的加深我们对ASP.NET底层的认识,最后达到游刃有余的把握。实际上技术的学习,尤其是编程,除了一定的兴趣和悟性外,大量代码实例的锻炼也是很有必要的,这本身就是笔者成长的一个过程,也是本文中笔者竭力要给大家展示的。

网络无限,生活无限

TOP

10.保护 XML Web 服务免受黑客攻击

Matt Powell
Microsoft Corporation


简介
在与开发人员就 XML Web 服务的将来谈话的过程中我们得知,他们最大的担心之一就是害怕软件中存在的弱点可能使服务受到不怀好意的用户的攻击。这可以说既是一个坏消息,又是一个好消息。说它是坏消息,是因为攻击可能导致服务的可用性受限制、私有数据泄露,更糟糕的情况是,使计算机的控制权落入这些不怀好意的用户的手中。说它是好消息,是因为您可以获得一些真正的保护,以减少这些攻击所带来的风险。我们将介绍已出现的攻击类型,以及您如何保护自己在部署、设计和开发领域的心血。此主题的第一篇专栏文章将集中讲述部署时应考虑的问题,下一篇专栏文章将讲述在开发 XML Web 服务时需注意的设计和开发问题。

攻击类型
要找出风险所在并了解如何避免,第一步应了解服务可能遭受的攻击类型。在了解了可能遇到的问题种类后,就可以采取适当的措施来减小这些问题所带来的风险。

攻击通常可分为三大类:

欺骗
利用错误
拒绝服务
欺骗
在要求身份验证的系统上,最常见的黑客攻击之一是算出某个用户的身份验证证书,以该用户登录,然后访问该用户的信息。这已经很糟糕了,但如果被泄露的证书属于系统管理员或其他某个具有更高权限的用户,则风险会更大。因为,在这种情况下,攻击可能不仅限于泄露单个用户的数据,而且有泄露所有用户数据的可能。

黑客可能会使用多种方法来确定用户的密码。例如:尝试对该用户有意义的字,如该用户的姓名、其宠物的名字或生日。更有恒心的黑客甚至会尝试字典中的每个字(字典攻击)。获取证书信息的其他方法包括:捕捉网络数据包并读取发送的数据中的信息;通过 DNS 欺骗,插入一台不怀好意的计算机,作为客户端和服务器之间的中介;假装系统管理员,以排除故障为由,要求用户给出其证书;或者,记录与服务器的登录握手,然后重复这一过程,尝试通过身份验证。

可以通过采取诸如强制实现加强密码等措施以及使用安全身份验证机制,来缓解由欺骗所带来的大多数风险。

利用错误
决定系统弱点的关键因素之一是运行在该系统上的代码的质量。系统错误不仅仅局限于使某个特定的线程出现异常。黑客可能利用这些弱点在系统上执行他们自己的代码,访问具有较高权限的资源,或者,只是利用可能潜在地引起系统速度减慢或变得不可用的资源漏洞(由错误引起的)。这种攻击中最著名的一个例子就是红色代码蠕虫病毒,这种病毒利用 Index Server ISAPI 扩展中的错误,在受感染的系统上执行它选择的代码,然后继续寻找其他有弱点的计算机。

另外一种常见攻击就是利用输入数据的有效性假设方面的错误。例如,XML Web Service 希望用户名作为参数输入的情况。如果您假设用户名仅包含 ASCII 字符串,并因此将它直接放入您的 SQL 查询,可能会使您的服务出现严重的弱点。例如,假设您的代码中有一个 SQL 查询,如下所示:

sqlQuery = "SELECT * FROM Users WHERE (Username='" & UsernameInput & "')

如果 UsernameInput 参数包含的内容恰好如下所示

Bob') or not (Username='0

那么您的服务可能会返回所有记录,而不只是特定用户的记录。

拒绝服务
拒绝服务攻击的目的不在于闯入一个站点,或更改其数据,而在于使站点无法服务于合法的请求。红色代码蠕虫病毒不仅感染计算机,并继而寻找并感染其他计算机,而且,还使得被感染的计算机向官方的白宫 Web 站点发送大量的数据包。因为数千台计算机被感染,所以发往白宫 Web 站点的请求的数目极高。因为红色代码蠕虫病毒会导致从大量计算机发出请求,所以被视作“分布式拒绝服务攻击”。由于涉及到如此众多的计算机,因此这种攻击极难限制。

拒绝服务请求可能有多种形式,因为可以通过多种级别发送伪请求,以攻击您的系统。例如,您的站点可能允许用户 PING 您的 IP 地址,从而使 ICMP 消息被发送到您的服务器,然后又被返回。这是一种排除连接故障的有效方法。但是,如果数百台计算机同时向您的服务器发送数千个数据包,您会发现您的计算机忙于处理 PING 请求,而无法获得 CPU 时间来处理其他正常的请求。

级别稍高的是 SYN 攻击,这种攻击需要编写一个低级网络程序,所发送的数据包看起来有如 TCP 连接握手中的第一个数据包(SYN 包)。这种攻击比 PING 请求攻击危害更大,因为对于 PING 请求,您可以在必要时将其忽略,但对于 SYN 攻击,只要有应用程序在侦听 TCP 端口(如 Web 服务器),则无论您何时收到看似有效的连接请求,都需要花费资源。

最高级别的拒绝服务攻击可以呈现一种向 XML Web Service 发送多个基本有效的 SOAP 请求的形式,这种请求将导致数据库开始查找操作。数据库查找可能需要花费一段很长的时间。因此,如果每秒钟向服务器发送数千个这样的请求,会使得接收请求的 Web 服务器和后端数据库服务器变得非常忙。而且,这也会使您的服务无法及时处理其他请求。

如果您的计算机上有包含错误的代码,那么拒绝服务攻击会更加容易。例如,如果投入使用的 Web Service 有这样一个错误:当出现某个特定类型的错误时,会显示一个消息框,黑客可以利用这一缺陷向您的计算机发送数目相对较少的请求,使该消息框显示出来。这会锁定所有的线程处理请求,因此有效地阻止了其他人访问您的服务。

部署问题
到目前为止,我们已介绍了几种不同的攻击类型,那么我们能对这些可恶的攻击采取什么措施呢?有一个好消息可以告诉您,您可以采取很多种方法来保护自己的服务,而且,这些保护大都十分简单。让我们首先来看一看只需控制 Web 服务器和后端服务器的配置方法就可以实现的保护类型。

应采取许多重要的保护措施确保您的 Web 服务器不会受到攻击的破坏,包括一些众所周知的措施,如确保具有最新的安全性更新。下面列出了自我保护措施中最重要的步骤。其中的许多步骤并不特别针对托管 Web 服务,而是适用于所有的 Web 服务器托管内容。

安装安全性更新
首先,确保您具有最新的更新,以避免受到红色代码蠕虫病毒的攻击。可以在 Installing the patch that stops the Code Red worm(英文)中找到有关安装更新的说明和下载修补程序的链接。

对红色代码蠕虫病毒的修复以及其他修复最终会包含在 Microsoft® Windows® 2000 的下一个服务包中,并已在 Microsoft® Windows® XP 中得到解决。

当然,更大的问题是如何避免其他潜在的弱点,并保护自己免受将来可能出现的问题的侵害。有关 Microsoft 产品安全问题的信息,可以订阅“Microsoft 安全性通知列表”。对于出现的任何新问题,都将以电子邮件的形式通知订阅者。有关如何订阅的说明,请查看 Product Security Notification(英文)网页。

限制 Web 服务器的访问者
如果您对攻击的问题很关注,尤其是如果您的 XML Web 服务上包含私有信息,那么您应限定仅合法的用户可以访问您的站点。这可以用多种方法来实现,但下面讲述的几种方法可以防止黑客访问您的 XML Web 服务。

通过使用 HTTP 身份验证来对用户进行验证,然后限定他们可以访问哪些资源。身份验证的配置方法:用鼠标右键单击 Internet 服务管理器中的 Web 站点、虚拟目录或单个文件;从弹出菜单中选择“属性”;进入“目录安全性”选项卡,单击“匿名访问和身份验证控制”下面的“编辑”按钮。
限定可以访问您的 Web 服务器的 IP 地址。如果有一些可以使用您站点的合法用户,那么可以只允许这些用户的特定 IP 地址访问您的 Web 站点。您还可以限定某些 IP 地址范围具有访问权限,或拒绝某个 IP 地址或某个 IP 地址范围的访问权限。甚至可以根据域名进行限定,但在与您计算机连接的 IP 地址上,可能需要花费很长的时间来进行域名查找。修改 IP 地址限制的方法:转至步骤 1 中提到的“目录安全性”选项卡,单击“IP 地址及域名限制”下面的“编辑”按钮。图 1 显示了“IP 地址及域名限制”对话框,其中将访问权限限制为三个特定的 IP 地址。


图 1:设置 Web 站点的 IP 地址限制

要求与客户端证书具有安全套接字层 (SSL) 连接。这可能是对访问您站点的用户进行身份验证的最安全的方法。SSL 限制也是在“目录安全性”选项卡的“安全通信”下进行设置。
将路由器配置为仅允许符合要求的访问
路由器就是您的防火墙。它可以阻断发送到您计算机的大量不合法的请求。流行的路由器大多都可以将访问限制在特定的 TCP 端口上,因此您可以只允许从端口 80(默认的 HTTP 端口)传入请求。这可以防止防火墙外的任何人试图连接到您计算机上的其他任何服务。打开其他服务的端口时请务必小心。您可以很方便地从终端服务客户端打开一个端口,连接到您的 Web 服务器,以便进行远程管理。但随后,任何人都可以通过终端服务器连接尝试连接到您的计算机。即便黑客不知道有效的用户名和密码,也仍然可以通过同时建立只显示登录屏幕的多个会话,来用完您计算机上的大量资源。

在筛选掉可能用完您计算机资源的非法数据包时,也需要用到路由器这一重要工具。对于明显存在问题的数据包,只需将它丢弃即可(大多数路由器都会自动执行这一功能)。但是,目前已有许多路由器具有检测诸如 TCP SYN 包的能力,这些数据包慌称它们是从某个 IP 地址发送过来的,但实际并非如此。通过启用这种保护措施,可以避免前面在拒绝服务攻击中提到的那些 SYN 攻击。

而且,请记住,防火墙限制只会影响到防火墙处的流量。这似乎是显而易见的事情,但假定您从 Internet 服务提供商 (ISP) 处购买了一根 T1 线,并在您所在的 T1 线的那一端放置了一个具有安全配置的路由器。如果 ISP 无法在他们的路由器上启用非法 SYN 请求检测功能,那么他们的路由器就有可能受到 SYN 攻击,从而潜在地拒绝对您的 T1 线另一端的服务,最后结果是有效地切断了对您站点的访问。

考虑更复杂的环境,如某个特定连接的两端都放置有多个路由器,由于每个路由器都有可能遭受攻击,因此可能会影响到为您站点的合法用户提供服务。要列出数据包到达您的服务器途中所要经过的路由器,请使用 TRACERT.EXE 实用工具。

配置 TCP/IP 筛选以限制接受连接的端口
如果您没有路由器作为防火墙,或者,如果您由于任何原因无法管理自己的路由器,都可以通过限制您计算机将接收的传入连接种类,有效地使您自己的计算机成为防火墙。在 Windows 2000 中,单击“开始”按钮,选择“设置”,选择“网络和拨号连接”,用鼠标右键单击连接到 Internet 上的网卡,然后选择“属性”。选择“Internet 协议 (TCP/IP)”,单击“属性”按钮,单击“高级”按钮,进入“选项”选项卡。选择“TCP/IP 筛选”,然后单击“属性”按钮。将出现如图 2 所示的一个对话框。您可以在该对话框中限制将接受连接的端口。在如图 2 所示的示例中,限制了只允许在端口 80 和 443 上分别进行 HTTP 和 HTTPS 连接。



图 2:配置 TCP/IP 筛选

删除不必要的服务和软件
计算机上运行的软件越多,就越有可能受到攻击,尤其是在您作为某种具有较高权限的用户运行服务的时候更是如此。如果您的计算机专门运行 Web 服务,且 Web 服务独立于其他服务,那么应在您的计算机上禁用其他某些服务,包括 FTP 服务、SMTP 服务以及诸如终端服务客户端等的 Windows 服务。

也应限制可通过 Internet Information Server 运行或访问的软件数量。确保仅配置了您需要的虚拟站点和目录。首先,应该删除管理 Web 站点。其次,还应该删除 IISSamples 虚拟目录。同样,如果您的计算机专门运行 Web 服务,应删除其他任何虚拟目录。

即便对于已经安装某些软件的虚拟目录,也必须弄清楚哪种软件是访问您的 Web 站点时可以使用的。在 Internet 服务管理器中,用鼠标右键单击某个站点或虚拟目录,从所出现的菜单中选择“属性”,选择“虚拟目录”选项卡,然后单击“配置”按钮,将出现“应用程序映射”选项卡,其中列出了与不同的 ISAPI 扩展或 CGI 应用程序相关联的所有扩展。如果您没有使用这些扩展,请将它们从列表中删除。.IDQ 文件的索引服务器扩展自身存在错误,红色代码蠕虫病毒就利用了这个错误。如果您是在虚拟站点级进行此项更改,那么您不需要为所创建的每个虚拟目录都进行此项工作。

使用 Microsoft Internet Information Server 安全性核对表
Microsoft 为 Internet Information Server 4.0 创建了一个安全性核对表,其中除了我在本文中提到的所有安全事项以外,还提到了其他更多的安全事项。使用此核对表来确保您至少已经考虑了所有的安全性选项。虽然您运行的可能不是 Internet Information Server 4.0(5.0 版是随 Windows 2000 一起发布的版本),但本文中的大多数步骤仍然适用,而且,对于将来 Internet Information Server 版本,也仍然适用。可以从 Microsoft Internet Information Server 4.0 Security Checklist(英文)中找到此核对表。

总结
根据您计算机和网络配置的不同,会有多种保护措施,您应采取相应的措施保护您的 Web 服务器免受黑客攻击。在下一篇专栏文章中,我们将研究开发人员和设计人员在创建其 XML Web Service 时需注意的问题,并继续探讨保护您的 XML Web Service 免受黑客攻击的方法。





--------------------------------------------------------------------------------

At Your Service

Matt Powell 是 MSDN Architectural Samples Team 的成员,他帮助开发了最新的 SOAP Toolkit 1.0。Matt 的其他成就包括与他人合著了由微软出版社出版的《Running Microsoft Internet Information Server》一书以及为各种杂志撰写了大量的文章。他有一个幸福美满的家庭,是他每天眷恋的地方。

网络无限,生活无限

TOP

 37 1234
发新话题