2006年08月02日

前三篇在 CSDN 论坛公布后,效果如同“神仙放屁——果然不同凡(反)响”.为感谢广大网友的热情与支持,这不,经过这一阵子的酝酿、修炼,特意准备了这第四响.
之前我们讲述的使用 Form 认证实现单点登录,正如网友所说的那样,只能在同一域名下使用.对于跨域名的单点登录,除了使用 Passport 认证外,我们还是可以用 Form 认证的,只是要讲究方法而已啦.正所谓“山不转水转,人不转心转”.
一、跨域名的解决思路
在MSDN 2003 上搜索关键字“Passport”,偶找到一篇“Passport 身份验证提供程序”.文章讲述了 Passport 的认证原理,共 8 条,我就不多说了,大伙自个看吧.其中有一句话,引起偶的注意:“……响应在查询字符串中包含一个加密的 Passport Cookie……”.也正是此句才有了下面的思路.
所谓认证的通过与否,其实质就是检测有无发放有效的 Cookie ,使用 Form 也好,运用 Passport 也罢,都是 Cookie 在起作用.也就是说,我们只要把有效的 Cookie 在登录后一次性发放给客户端就得了.
二、跨域名、跨服务器的单点登录方法
1、  如何在本机模拟跨域名、跨服务器的Single Sign On
只要浏览网址不同就相当于不同域名,在本机至少有以下三种.它们虽然是同一项目,彼此却不能共用 Session与 Cookie ,也就无法共享身份验证票:
a ). http://localhost/FormTest/Login.aspx
b ). http://127.0.0.1/FormTest/Login.aspx
c ). http://My_Computer_Name/FormTest/Login.aspx  //以电脑名称浏览站点
d ). http://192.168.0.8/FormTest/Login.aspx  //以网卡地址浏览站点
e ). http://172.meibu.com/FormTest/Login.aspx  //拥有国际域名
2、  在 asp.NET 中如何提交给其它页面
用过ViewState 的大概都知道,ViewState是保存在客户端的.不知大伙注意没有,asp.NET 为每张 .aspx 页面都配备了独自的 ViewState,且被解析后都是以一个 name=" __VIEWSTATE" 的隐藏控件值来保存ViewState.每次页面提交,服务器都会检查该控件的值有无被篡改,如此一来就注定 .aspx 只能提交给本页.服务器是死的,人是活的,我们不能被这些条条框框限定死了,我们要把程序写成活的.
下面咱们从 http://localhost/FormTest/Login.aspx 输入用户名与密码,然后提交给http://127.0.0.1/FormTest/Public/LoginTransfer.aspx .Login.aspx与LoginTransfer.aspx都包含用户名输入框一个、密码输入框一个、登录按钮一个.在 Login.aspx 页面加入以下代码:
this.Btn_Login.Attributes["onclick"]="SingleSignOn( )";
//指定执行脚本事件
在 Login.aspx 页面上插入以下脚本:
<script language="javascript">
function SingleSignOn( )
{
    //只能用脚本改变指定 Form 提交的对象
    document.getElementById( "Form1" ).action="http://127.0.0.1/FormTest/Public/LoginTransfer.aspx?FromUrl="+window.location.href;
    //把隐藏控件 __VIEWSTATE 中的值变更为 LoginTransfer.aspx 解析后出现的值,以实际看到的值为准
    document.all.__VIEWSTATE.value = "dDwtMTkyODUzMTMyNzs7Pv1cp2RaxUcr5hGYf8ILX9/EMKy8";
}
</script>
注意事项
a ).  LoginTransfer.aspx 出现的控件及其 ID ,必须能够在 Login.aspx 找到
b ). 控件的 ID 必须一致,且能一一对应
c ). 关于 __VIEWSTATE中的值,它与页面控件ID 无关,与浏览该页面的网址无关,目前我只知道和控件的数量、类型、名字空间(namespace FormTest.Public )以及存在的 ViewState有关系.大家在测试时,以直接浏览http://127.0.0.1/FormTest/Public/LoginTransfer.aspx 后,查看页面源文件所看到的值为准.
d ). 提交后,将触发并执行LoginTransfer.aspx 中的Btn_Login_Click 事件
3、  基本思路
各个站点的登录页面统一将用户名与密码提交给 LoginTransfer.aspx ,同时各个站点需要一个增加 Cookie 的页面,用于将加密后的身份验证 Cookie 添加至客户端.此乃经过一番考量后,最终确定的可行性方案.
4、  第一种思路——天女散花
何谓天女散花,就是把 Cookie 在登录后一次性全发放出去,就如同天仙在空中散花一样,场面是何等的壮观.下面开始写代码:
为更好的区分,我们将负责添加 Cookie 的页面分开命名:
a ). http://localhost/FormTest/Public/AddCookie_A.aspx
b ). http://127.0.0.1/FormTest/Public/AddCookie_B.aspx
c ). http://My_Computer_Name/FormTest/Public/AddCookie_C.aspx
这三张页面的功能一样,所以代码也就相同啰
private void Page_Load( object sender, System.EventArgs e )
{
    string from = Request["FromUrl"];
    //起始 URL 路径
    string next = Request["NextUrl"];
    //还需要跳转的 URL
    string key = Request["CookieTicket"];
    //已加密的 Cookie 文本
    if( key != null && key !="" )
    {
        System.Web.HttpCookie ck = new HttpCookie( System.Web.Security.FormsAuthentication.FormsCookieName,key );
        ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath;
       
        ck.Expires = System.DateTime.Now.AddYears( 100 );
        Response.Cookies.Add( ck );
        //将传过来的已加密的身份验证票添加至客房端
       
        string url = next.Split( ‘;
        ‘ )[0];
        //从 URL 中拆分出将要跳转的下一张页面
        next = next.Replace( url+";
        ","" );
        //带入下一轮跳转的字串
        if( url!="" )
        {
            //跳至下一页面
            Response.Redirect( url+"?CookieTicket="+key+"&FromUrl="+from+"&NextUrl="+next );
        }
        else
        //已没有下一页面可供跳转
        {
            Response.Redirect( from );
            //回到起始页面
        }
    }
}
接下来编写 LoginTransfer.aspx 的代码:
//页面常量 allLoginUrl 存放所有站点的 AddCookie.aspx 的 URL,注意以 ;
分隔
public const
string allLoginUrl =

"http://localhost/FormTest/Public/AddCookie_A.aspx;
"
+"http://127.0.0.1/FormTest/Public/AddCookie_B.aspx;
"
+"http://My_Computer_Name/FormTest/Public/AddCookie_C.aspx;
";
偶已在上面讲述了,如何点击 Login.aspx 中的登录按钮Btn_Login将用户名与密码提交给 LoginTransfer.aspx ,并执行LoginTransfer.aspx 中的Btn_Login_Click 事件.
private void Btn_Login_Click( object sender, System.EventArgs e )
{
    string from = Request["FromUrl"];
    //起始 URL 路径
    string next =
    this.allLoginUrl;
   
    //由于控件 ID 相同,所以此处得到的是由 Login.aspx 提交过来的用户名与密码
    if( this.Txt_LoginName.Text=="Admin"&&this.Txt_Password.Text=="123456" )
    {
        System.Web.Security.FormsAuthenticationTicket tk = new System.Web.Security.FormsAuthenticationTicket( 1,"Admin", System.DateTime.Now, System.DateTime.Now.AddYears( 100 ),false,"测试用户数据" );
       
        string key = System.Web.Security.FormsAuthentication.Encrypt( tk );
        //得到加密后的身份验证票字串
        string url = next.Split( ‘;’ )[0];
        //从 URL 中拆分出将要跳转的下一张页面
        next = next.Replace( url+";
        ","" );
        //带入下一轮跳转的字串
        Response.Redirect( url+"?CookieTicket="+key+"&FromUrl="+from+"&NextUrl="+next );
        //跳至下一页面
    }
}
5、  第二种思路——后羿射日
后羿射日,意思指的是用户点哪就跳哪.他若是点“火坑”,你也得往里跳,因为用户是上帝嘛.我们增加一个通行证页面 MyPassport.aspx ,由 http://127.0.0.1/FormTest/Public/LoginTransfer.aspx 发放验证 Cookie 后直接跳转至 http://127.0.0.1/FormTest/MyPassport.aspx .不要告诉我你不会,你要是真不会,那偶也没法子啦,还得请你回头看看,偶在第三篇是如何讲述发放永久性验证 Cookie 吧(http://blog.csdn.net/cityhunter172/archive/2005/12/06/545301.aspx).还需要一张用作跳板的跳转页面 MyTransfer.aspx .
MyPassport.aspx 的代码:
<a target ="_blank"
href="MyTransfer.aspx?goto=http://localhost/FormTest/Public/AddCookie_D.aspx">
美丽的天使</a>
<a target ="_blank" 
href="MyTransfer.aspx?goto=http://127.0.0.1/FormTest/Public/AddCookie_E.aspx">
快乐的天堂</a>
<a target ="_blank"
href="MyTransfer.aspx?goto=http://My_Computer_Name/FormTest/Public/AddCookie_F.aspx">
大大的火坑</a>
MyTransfer.aspx 的代码:
private void Page_Load( object sender, System.EventArgs e )
{
    //获取身份验证票
    System.Web.Security.FormsAuthenticationTicket tk =( ( System.Web.Security.FormsIdentity )User.Identity ).Ticket;
   
    string key = System.Web.Security.FormsAuthentication.Encrypt( tk );
    //每次加密后的字串都是不同的
    string next = Request["goto"];
    //将要跳转的 URL
    Response.Redirect( url+"?CookieTicket="+key );
    //跳转至下一页面
}
AddCookie_D.aspx、AddCookie_E.aspx、AddCookie_F.aspx 这三张页面的代码:
string key = Request["CookieTicket"];
//已加密的 Cookie 文本
if( key != null && key !="" )
{
    System.Web.HttpCookie ck = new HttpCookie( System.Web.Security.FormsAuthentication.FormsCookieName,key );
    ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath;
   
    ck.Expires = System.DateTime.Now.AddYears( 100 );
    Response.Cookies.Add( ck );
    //将传过来的已加密的身份验证票添加至客房端
    Response.Redirect( "../Index.aspx" );
    //跳转至你真正想带客户去的地方
}
6、  点评
两者共同点:
a ). 每个站点都需要一个登录的提交点、一张添加 Cookie 的页面.
b ). 因为只能靠发放验证 Cookie 来识别身份,所以一台电脑不能同时登录两个帐号.
c ). 都存在不同程度的安全隐患.
两者不同点:( 天女散花以下简称“开女”,后羿射日就简称“后羿” )
a ). 天女一次性发放 Cookie ,如果站点较多,处理起来还是需要一些时间的.而后羿则相反,站点再多也不怕.
b ). 天女在散花的过程中,如果中途被卡?蛐枰桓龃砦蟠砘谱龌赝舜?后羿则不需要.
c ). 天女在登录后可以直接在 IE 地址浏览其想看的站点;而后羿则必须从通行证的跳板页面进入才行.
根据上述问题,给几点建议:
a ). 不要使用永久性 Cookie ,应指明身份验证票的过期时间,注意不是 Cookie 的有效期.
b ). 在身份验证票的 UserData 中加入其它的验证信息或存放用户 ID
c ). 在网络通畅的情况下,比如局域网,站点又相对较少,建议选用天女.50 个站点之间做跳转应该不会超过 10 秒(前提是已编译好了,且不是初次访问).
三、
        跨域名、跨服务器的退出方法
只要理解了“天女散花”,退出就比较容易啦.为每个站点准备一个用于退出的页面,如下:
a ). http://localhost/FormTest/Public/Logout.aspx
b ). http://127.0.0.1/FormTest/Public/Logout.aspx
c ). http://My_Computer_Name/Public/FormTest/Logout.aspx
private void Page_Load( object sender, System.EventArgs e )
{
    System.Web.Security.FormsAuthentication.SignOut( );
    //删除 Cookie 中的身份验证票
    string from = Request["FromUrl"];
   
    string next = Request["NextUrl"];
   
    string url = next.Split( ‘;’ )[0];
    next = next.Replace( url+";
    ","" );
    if( url!="" )
    {
        Response.Redirect( url+"?FromUrl="+from+"&NextUrl="+next );
    }
    else
    {
        Response.Redirect( from );
    }
}
对啦,还有一张 LogoutTransfer.aspx. ,代码偶就不写,大家自个完成吧。

——用Form 表单认证实现单点登录(Single Sign On 

 

 

 

 

 

 

 

 

 

作者:寒羽枫(cityhunter172)

第三部分 实现单点登录(Single Sign On 

 

“等了好久终于等到今天,写了好久终于就快完结,但是网友的反应却让我有一些的伤心。盼了好久终于盼到今天,忍了好久终于把此文撰写,那些受冷落的无奈早就无所谓,累也不说累”(歌词《今天》新演绎)。看着人家的 Blog 文章的评论是一条接一条,再瞧瞧自己:“无人问津呐,真…无…奈……唉,没人理我,还是回家吧。”“哎,还没开始写,怎么就走了?回去干什么呢?”回去写作业去啊,上回交待的课外作业你做了没?(注:http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx 在第二部分第六节布置的课外作业:此项目有两部门使用,其中每个部门分别都有些特定的页面仅供本部门用户浏览使用,请问该如何使用 Web.config 达到效果?) 

 

 

 

 

 

 

 

 

 

不知有多少人做了作业,其实答案并不难。只需要在验证用户名与密码后,取得该用户的部门名称或部门代码,把它作为判断的依据就行了。最好不要用部门的数字ID,那样不利于以后的维护。 

 

 

 

 

 

 

 

 

 

有一个秘密,一般人我不告诉他。Web.config 中的 <location> 节点的path 属性可以是一张具体页面的相对 URL 路径,如下:<location path ="ManageSys/Auditing.aspx"> 

 

 

 

 

 

 

 

 

 

好了,接下来就要揭开“比根目录Web.config 的作用范围还大的配置文件”之谜啦,它就是藏匿在 Windows 系统目录下,支配整个 .Net Framework 配置的传说中的Machine.config !!下面请大家以热烈的掌声,欢迎我们这位神秘侠客的闪亮登场…… 

 

 

 

 

 

 

 

 

 

九、        Machine.config

 

 

 

 

 

 

 

 

 

Machine.config ,性别不详,年龄未知,家庭出身:XML。深藏于“云深不知处”的操作系统目录下的某某地方(注:C:\WINDOWS【或 WINNT \Microsoft.NET\Framework\v1.1.4322【或 v1.0.3705 \CONFIG),控制着“更上一层楼”的 .NET Framework 的本机配置。接下来简要的讲解一下它的内容,以及它与 Web.config 的关系。 

 

 

 

 

 

 

 

 

 

经过“松下问童子”,我们好不容易找到这位隐者,打开一看,乖乖,足有 3700 多行!!“叫我怎么能不难过,偶只想看看是啥结构,可内容实在是太多太繁琐……”还记得偶经常对同事说的一句话么:“办法是人想出来的!”它不是有三千七百多行吗,那我们就不管三七能否得出二十一啦,把它拷出来先。它不是 XML 出身吗,那咱们就还其正身,重新命名为“machine.xml”。接着用 IE 浏览器将这位改头换面的隐者打开,把节点与注释一一合拢。这回你看到了吧,是不是很有成就感?你要是想谢谢我,就让我看到你在此文下面的评论吧。多多益善,呵呵。 

 

 

 

 

 

 

 

 

 

Machine.config Web.config 是啥关系?四个字 —— 父子关系。记得我在第二部分第五节讲解 Web.config 作用范围的时提到两点 —— 继承与覆盖(详见http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx),在此也同样适用。 

 

 

 

 

 

 

 

 

 

1、  Machine.config 中的设置将作用于运行在本机的所有站点及其虚拟目录,遇到子目录将一直继承下去。 

 

 

 

 

 

 

 

 

 

2、  Web.config 中的设置将覆盖由 Machine.config 中继承下来的对应的节点设置 

 

 

 

 

 

 

 

 

 

说到这,再告诉大家一个秘密 —— “世上本无秘密,知道的人多了,便成了不是秘密的秘密!” 

 

 

 

 

 

 

 

 

 

a、  Machine.config 中的 <system.web> 节点所有内容都能出现在项目根目录下的 Web.config 中,也就是说能在 Web.config 中的内容已经在 Machine.config 中一一列出; 

 

 

 

 

 

 

 

 

 

b、  其中 <system.web> 节点下的 <pages> 还能出现在页面上,如: HTML 视图下,在WebForm1.aspx 的第一行加上<pages> 的节点内容validateRequest="false" (此句意思是不对WebForm1.aspx页面文本框输入的值,是否包含 < > 等等具有危险性的代码进行检查,下一节将具体运用到) 

 

 

 

 

 

 

 

 

 

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="FromTest.WebForm1" validateRequest="false"  %> 

 

 

 

 

 

 

 

 

 

十、        单点登录(Single Sign On)的前提条件 

 

 

 

 

 

 

 

 

 

之前说了这么多关于 Machine.config 的事,都是为了实现单点登录作铺垫,那何为单点登录(Single Sign On)?从字面理解就是在一个地方登录,通常运用于 ASP.NET 分布式环境中(跨单个服务器上的多个应用程序或在网络场中)的 Forms 身份验证。打个比方,就好比现在 Sohu(搜狐)  Chinren(中国校友录) 的做法,我在 Sohu 登录以后就不需要在 Chinaren 登录了。台湾与香港又把 Single Sign On 称之为“单一登入”。 

 

 

 

 

 

 

 

 

 

要想实现此功能,首要条件是需要一组用于加密与验证加密的密钥。它们位于 Machine.config 中,修改  <system.web> 节点下的 <machineKey> 节点属性,如下: 

 

 

 

 

 

 

 

 

 

           <machineKey firstKey="172" copyrightKey="Cityhunter172" validationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939" secondKey="meibu" decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939" validation="SHA1" thirdKey="com" />

 

 

 

 

 

 

 

 

 

1、  validationKey 为用于验证加密数据的密钥。最小长度为 40 个字符(20 字节),最大长度为 128 个字符(64 字节)。 

 

 

 

 

 

 

 

 

 

2、  decryptionKey 为用于加密数据的密钥。长度只有 16 个字符(8 字节)与 48 个字符(24 字节)两种。 

 

 

 

 

 

 

 

 

 

3、  validation 为用数据验证使用的加密类型。拥有“SHA1MD53DES”三种方法 

 

 

 

 

 

 

 

 

 

4、  大伙参照上述 <machineKey> 试着在WebForm1.aspx运行下列语句: 

 

 

 

 

 

 

 

 

 

this.TextBox2.Text ="ht"+"tp"+"://"+firstKey+"."+secondKey +"."+thirdKey

 

 

 

 

 

 

 

 

 

大家在修改之前请先备份一下 Machine.config ,到时要是出错可别怪我没提醒你。以上密钥并不是胡乱得来的,接下来向大家介绍生成密钥的方法。 

 

 

 

 

 

 

 

 

 

我们把上一节中提到的 WebForm1.aspx 拖入本项目的 Public 目录下,再往页面上拖入一个 TextMode=MultiLine TextBox3 与一个 Button 编写按钮事件与函数: 

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

 

 

 

         {

 

 

 

 

 

 

 

 

 

              string decStr = this.CreateKeyString(int.Parse(this.TextBox1.Text));

 

 

 

 

 

 

 

 

 

              string valStr = this.CreateKeyString(int.Parse(this.TextBox2.Text));

 

 

 

 

 

 

 

 

 

              this.TextBox3.Text=string.Format("<machineKey validationKey=\"{0}\" decryptionKey=\"{1}\" validation=\"SHA1\"/>",valStr,decStr);

 

 

 

 

 

 

 

 

 

     }

 

 

 

 

 

 

 

 

 

         /// <summary>

 

 

 

 

 

 

 

 

 

         /// 生成加密型强随机 Key  

 

 

 

 

 

 

 

 

 

         /// </summary>

 

 

 

 

 

 

 

 

 

         /// <param name="i">Key 的有效长度: 

 

 

 

 

 

 

 

 

 

         /// decryptionKey 的有效值为 8 24 

 

 

 

 

 

 

 

 

 

         /// validationKay 的有效值为 20 64

 

 

 

 

 

 

 

 

 

         /// </param>

 

 

 

 

 

 

 

 

 

         private string CreateKeyString(int i)

 

 

 

 

 

 

 

 

 

         {

 

 

 

 

 

 

 

 

 

              System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();  //加密随机数生成器 

 

 

 

 

 

 

 

 

 

              byte[] bt = new byte[i];

 

 

 

 

 

 

 

 

 

              rng.GetBytes(bt);//用加密型强随机值序列填充字节数组 

 

 

 

 

 

 

 

 

 

              System.Text.StringBuilder str = new System.Text.StringBuilder();

 

 

 

 

 

 

 

 

 

              for(int j= 0;j<i;j++)

 

 

 

 

 

 

 

 

 

              {

 

 

 

 

 

 

 

 

 

                   str.Append(string.Format("{0:X2}",bt[j])); //转换成大写的十六进制文本 

 

 

 

 

 

 

 

 

 

              }

 

 

 

 

 

 

 

 

 

              return str.ToString();

 

 

 

 

 

 

 

 

 

         }

 

 

 

 

 

 

 

 

 

每次点击按钮生成密钥都不同,大家不妨多点几次。切换至 HTML 视图,到WebForm1.aspx 第一行把 validateRequest="false" 去掉,然后再多点几次 Button1试试,看看会有什么效果,嘿嘿……… 

  • 事件源对象
    event.srcElement.tagName
    event.srcElement.type
  • 捕获释放
    event.srcElement.setCapture(); 
    event.srcElement.releaseCapture(); 
  • 事件按键
    event.keyCode
    event.shiftKey
    event.altKey
    event.ctrlKey
  • 事件返回值
    event.returnValue
  • 鼠标位置
    event.x
    event.y
  • 窗体活动元素
    document.activeElement
  • 绑定事件
    document.captureEvents(Event.KEYDOWN);
  • 访问窗体元素
    document.all("txt").focus();
    document.all("txt").select();
  • 窗体命令
    document.execCommand
  • 窗体COOKIE
    document.cookie
  • 菜单事件
    document.oncontextmenu
  • 创建元素
    document.createElement("SPAN"); 
  • 根据鼠标获得元素:
    document.elementFromPoint(event.x,event.y).tagName=="TD
    document.elementFromPoint(event.x,event.y).appendChild(ms) 
  • 窗体图片
    document.images[索引]
  • 窗体事件绑定
    document.onmousedown=scrollwindow;
  • 元素
    document.窗体.elements[索引]
  • 对象绑定事件
    document.all.xxx.detachEvent(‘onclick’,a);
  • 插件数目
    navigator.plugins
  • 取变量类型
    typeof($js_libpath) == "undefined"
  • 下拉框
    下拉框.options[索引]
    下拉框.options.length
  • 查找对象
    document.getElementsByName("r1");
    document.getElementById(id);
  • 定时
    timer=setInterval(’scrollwindow()’,delay);
    clearInterval(timer);
  • UNCODE编码
    escape() ,unescape
  • 父对象
    obj.parentElement(dhtml)
    obj.parentNode(dom)
  • 交换表的行
    TableID.moveRow(2,1)
  • 替换CSS
    document.all.csss.href = "a.css";
  • 并排显示
    display:inline
  • 隐藏焦点
    hidefocus=true
  • 根据宽度换行
    style="word-break:break-all"
  • 自动刷新
    <meta HTTP-EQUIV="refresh" CONTENT="8;URL=http://c98.yeah.net">
  • 简单邮件
    <a  href="
    mailto:aaa@bbb.com?subject=ccc&body=xxxyyy"> 
  • 快速转到位置
    obj.scrollIntoView(true)

  • <a name="first">
    <a href="#first">anchors</a>
  • 网页传递参数
    location.search();
  • 可编辑
    obj.contenteditable=true
  • 执行菜单命令
    obj.execCommand
  • 双字节字符
    /[^\x00-\xff]/
    汉字
    /[\u4e00-\u9fa5]/
  • 让英文字符串超出表格宽度自动换行
    word-wrap: break-word; word-break: break-all;
  • 透明背景
    <IFRAME src="1.htm" width=300 height=180 allowtransparency></iframe>
  • 获得style内容
    obj.style.cssText
  • HTML标签
    document.documentElement.innerHTML
  • 第一个style标签
    document.styleSheets[0]
  • style标签里的第一个样式
    document.styleSheets[0].rules[0]
  • 防止点击空链接时,页面往往重置到页首端。
    <a href="BLOCKED SCRIPTfunction()">word</a>
  • 上一网页源
    asp:
    request.servervariables("HTTP_REFERER")
    BLOCKED SCRIPT
    document.referrer
  • 释放内存
    CollectGarbage();
  • 禁止右键
    document.oncontextmenu = function() { return false;}
  • 禁止保存
    <noscript><iframe src="*.htm"></iframe></noscript>
  • 禁止选取<body oncontextmenu="return false" ondragstart="return false" onselectstart ="return false" onselect="document.selection.empty()" oncopy="document.selection.empty()" onbeforecopy="return false"onmouseup="document.selection.empty()> 
  • 禁止粘贴
    <input type=text onpaste="return false">
  • 地址栏图标
    <link rel="Shortcut Icon" href="favicon.ico">
    favicon.ico 名字最好不变16*16的16色,放虚拟目录根目录下
  • 收藏栏图标
    <link rel="Bookmark" href="favicon.ico">
  • 查看源码
    <input type=button value=查看网页源代码 onclick="window.location = ‘view-source:’+ ‘http://www.csdn.net/’">
  • 关闭输入法
    <input style="ime-mode:disabled">
  • 自动全选
    <input type=text name=text1 value="123" onfocus="this.select()">
  • ENTER键可以让光标移到下一个输入框
    <input onkeydown="if(event.keyCode==13)event.keyCode=9">
  • 文本框的默认值
    <input type=text value="123" onfocus="alert(this.defaultValue)">
  • title换行
    obj.title = "123&#13sdfs&#32"
  • 获得时间所代表的微秒
    var n1 = new Date("2004-10-10".replace(/-/g, "\/")).getTime()
  • 窗口是否关闭
    win.closed
  • checkbox扁平
    <input type=checkbox style="position: absolute; clip:rect(5px 15px 15px 5px)"><br>
  • 获取选中内容
    document.selection.createRange().duplicate().text
  • 自动完成功能
    <input  type=text  autocomplete=on>打开该功能 
    <input  type=text  autocomplete=off>关闭该功能   
  • 窗口最大化
    <body onload="window.resizeTo(window.screen.width – 4,window.screen.height-50);window.moveTo(-4,-4)">
  • 无关闭按钮IE
    window.open("aa.htm", "meizz", "fullscreen=7");
  • 统一编码/解码
    alert(decodeURIComponent(encodeURIComponent("http://你好.com?as= hehe")))
    encodeURIComponent对":"、"/"、";" 和 "?"也编码
  • 表格行指示
    <tr onmouseover="this.bgColor=’#f0f0f0′" onmouseout="this.bgColor=’#ffffff’">

    //各种尺寸

    s  +=  "\r\n网页可见区域宽:"+  document.body.clientWidth;  
    s  +=  "\r\n网页可见区域高:"+  document.body.clientHeight;  
    s  +=  "\r\n网页可见区域高:"+  document.body.offsetWeight  +"  (包括边线的宽)";  
    s  +=  "\r\n网页可见区域高:"+  document.body.offsetHeight  +"  (包括边线的宽)";  
    s  +=  "\r\n网页正文全文宽:"+  document.body.scrollWidth;  
    s  +=  "\r\n网页正文全文高:"+  document.body.scrollHeight;  
    s  +=  "\r\n网页被卷去的高:"+  document.body.scrollTop;  
    s  +=  "\r\n网页被卷去的左:"+  document.body.scrollLeft;  
    s  +=  "\r\n网页正文部分上:"+  window.screenTop;  
    s  +=  "\r\n网页正文部分左:"+  window.screenLeft;  
    s  +=  "\r\n屏幕分辨率的高:"+  window.screen.height;  
    s  +=  "\r\n屏幕分辨率的宽:"+  window.screen.width;  
    s  +=  "\r\n屏幕可用工作区高度:"+  window.screen.availHeight;  
    s  +=  "\r\n屏幕可用工作区宽度:"+  window.screen.availWidth;  

//过滤数字

 

//特殊用途

 

//不缓存

 

//正则匹配

 

匹配中文字符的正则表达式: [\u4e00-\u9fa5]
匹配双字节字符(包括汉字在内):[^\x00-\xff]
匹配空行的正则表达式:\n[\s| ]*\r
匹配HTML标记的正则表达式:/<(.*)>.*<\/\1>|<(.*) \/>/ 
匹配首尾空格的正则表达式:(^\s*)|(\s*$)(像vbscript那样的trim函数)
匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配网址URL的正则表达式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
以下是例子:
利用正则表达式限制网页表单里的文本框输入内容:
用正则表达式限制只能输入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,”)" onbeforepaste="clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^\u4E00-\u9FA5]/g,”))"
1.用正则表达式限制只能输入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,”)" onbeforepaste="clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^\uFF00-\uFFFF]/g,”))"
2.用正则表达式限制只能输入数字:onkeyup="value=value.replace(/[^\d]/g,”) "onbeforepaste="clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^\d]/g,”))"
3.用正则表达式限制只能输入数字和英文:onkeyup="value=value.replace(/[\W]/g,”) "onbeforepaste="clipboardData.setData(‘text’,clipboardData.getData(‘text’).replace(/[^\d]/g,”))"

//消除图像工具栏

 

<IMG SRC="mypicture.jpg" HEIGHT="100px" WIDTH="100px" GALLERYIMG="false"
or
<head>
<meta http-equiv="imagetoolbar" content="no">
</head>

//无提示关闭

function Close()
{
 var ua=navigator.userAgent
 var ie=navigator.appName=="Microsoft Internet Explorer"?true:false
 if(ie)
 {
      var IEversion=parseFloat(ua.substring(ua.indexOf("MSIE ")+5,ua.indexOf(";",ua.indexOf("MSIE "))))
  if(IEversion< 5.5)
  {
   var str  = ’<object id=noTipClose classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">’
       str += ’<param name="Command" value="Close"></object>’;
       document.body.insertAdjacentHTML("beforeEnd", str);
       document.all.noTipClose.Click();
  }
      else
  {
       window.opener =null;
       window.close();
      }
   }
 else
 {
  window.close()
   }
}

//取得控件得绝对位置(1)

<script language="javascript"
function getoffset(e)

 var t=e.offsetTop; 
 var l=e.offsetLeft; 
 while(e=e.offsetParent)
 { 
  t+=e.offsetTop; 
  l+=e.offsetLeft; 
 } 
 var rec = new Array(1);
 rec[0]  = t;
 rec[1] = l;
 return rec

</script>

//获得控件的绝对位置(2)

oRect = obj.getBoundingClientRect();
oRect.left
oRect.

//最小化,最大化,关闭

 

 

//光标停在文字最后

 

<script language="javascript">
function cc()
{
 var e = event.srcElement;
 var r =e.createTextRange();
 r.moveStart(‘character’,e.value.length);
 r.collapse(true);
 r.select();
}
</script>
<input type=text name=text1 value="123" onfocus="cc()">

//页面进入和退出的特效

进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
推出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)"
这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使
用哪种特效,取值为1-23:
  0 矩形缩小 
  1 矩形扩大 
  2 圆形缩小
  3 圆形扩大 
  4 下到上刷新 
  5 上到下刷新
  6 左到右刷新 
  7 右到左刷新 
  8 竖百叶窗
  9 横百叶窗 
  10 错位横百叶窗 
  11 错位竖百叶窗
  12 点扩散 
  13 左右到中间刷新 
  14 中间到左右刷新
  15 中间到上下
  16 上下到中间 
  17 右下到左上
  18 右上到左下 
  19 左上到右下 
  20 左下到右上
  21 横条 
  22 竖条 
  23 

//网页是否被检索

 

//打印分页

 

//设置打印

<object id="factory" style="display:none" viewastext
  classid="clsid:1663ed61-23eb-11d2-b92f-008048fdd814"
  codebase="http://www.meadroid.com/scriptx/ScriptX.cab#Version=5,60,0,360"
></object>
<input type=button value=页面设置 onclick="factory.printing.PageSetup()">
<input type=button value=打印预览 onclick="factory.printing.Preview()">
 
<script language=javascript>
function window.onload()
{
   // – advanced features
   factory.printing.SetMarginMeasure(2) // measure margins in inches
   factory.printing.SetPageRange(false, 1, 3) // need pages from 1 to 3
   factory.printing.printer = "HP DeskJet 870C"
   factory.printing.copies = 2
   factory.printing.collate = true
   factory.printing.paperSize = "A4"
   factory.printing.paperSource = "Manual feed"
   // – basic features
   factory.printing.header = "居左显示&b居中显示&b居右显示页码,第&p页/共&P页"
   factory.printing.footer = "(自定义页脚)"
   factory.printing.portrait = false
   factory.printing.leftMargin = 0.75
   factory.printing.topMargin = 1.5
   factory.printing.rightMargin = 0.75
   factory.printing.bottomMargin = 1.5
}
function Print(frame) {
  factory.printing.Print(true, frame) // print with prompt
}
</script>
<input type=button value="打印本页" onclick="factory.printing.Print(false)">
<input type=button value="页面设置" onclick="factory.printing.PageSetup()">
<input type=button value="打印预览" onclick="factory.printing.Preview()"><br>
<a href="http://www.meadroid.com/scriptx/docs/printdoc.htm?static"  target=_blank>具体使用手册,更多信息,点这里</a>
 

//自带的打印预览

WebBrowser.ExecWB(1,1) 打开 
Web.ExecWB(2,1) 关闭现在所有的IE窗口,并打开一个新窗口 
Web.ExecWB(4,1) 保存网页 
Web.ExecWB(6,1) 打印 
Web.ExecWB(7,1) 打印预览 
Web.ExecWB(8,1) 打印页面设置 
Web.ExecWB(10,1) 查看页面属性 
Web.ExecWB(15,1) 好像是撤销,有待确认 
Web.ExecWB(17,1) 全选 
Web.ExecWB(22,1) 刷新 
Web.ExecWB(45,1) 关闭窗体无提示 
<style media=print> 
.Noprint{display:none;}<!–用本样式在打印时隐藏非打印项目–> 
.PageNext{page-break-after: always;}<!–控制分页–> 
</style> 
<object  id="WebBrowser"  width=0  height=0  classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2">    
</object>    
 
<center class="Noprint" >
<input type=button value=打印 onclick=document.all.WebBrowser.ExecWB(6,1)> 
<input type=button value=直接打印 onclick=document.all.WebBrowser.ExecWB(6,6)> 
<input type=button value=页面设置 onclick=document.all.WebBrowser.ExecWB(8,1)> 
</p> 
<p> <input type=button value=打印预览 onclick=document.all.WebBrowser.ExecWB(7,1)> 
</center>

//去掉打印时的页眉页脚

<script  language="JavaScript">  
var HKEY_Root,HKEY_Path,HKEY_Key;
HKEY_Root="HKEY_CURRENT_USER";
HKEY_Path="\\Software\\Microsoft\\Internet Explorer\\PageSetup\\";
//设置网页打印的页眉页脚为空
function PageSetup_Null()
{
 try
 {
         var Wsh=new ActiveXObject("WScript.Shell");
  HKEY_Key="header";
  Wsh.RegWrite(HKEY_Root+HKEY_Path+HKEY_Key,"");
  HKEY_Key="footer";
  Wsh.RegWrite(HKEY_Root+HKEY_Path+HKEY_Key,"");
 }
 catch(e){}
}
//设置网页打印的页眉页脚为默认值
function  PageSetup_Default()
{  
 try
 {
  var Wsh=new ActiveXObject("WScript.Shell");
  HKEY_Key="header";
  Wsh.RegWrite(HKEY_Root+HKEY_Path+HKEY_Key,"&w&b页码,&p/&P");
  HKEY_Key="footer";
  Wsh.RegWrite(HKEY_Root+HKEY_Path+HKEY_Key,"&u&b&d");
 }
 catch(e){}
}
</script>
<input type="button" value="清空页码" onclick=PageSetup_Null()>
<input type="button" value="恢复页码" onclick=PageSetup_Default()>

//浏览器验证

function checkBrowser()

   this.ver=navigator.appVersion 
   this.dom=document.getElementById?1:0 
   this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom)?1:0; 
   this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom)?1:0; 
   this.ie4=(document.all && !this.dom)?1:0; 
   this.ns5=(this.dom && parseInt(this.ver) >= 5) ?1:0; 
   this.ns4=(document.layers && !this.dom)?1:0; 
   this.mac=(this.ver.indexOf(‘Mac’) > -1) ?1:0; 
   this.ope=(navigator.userAgent.indexOf(‘Opera’)>-1); 
   this.ie=(this.ie6 || this.ie5 || this.ie4) 
   this.ns=(this.ns4 || this.ns5) 
   this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns5 || this.ns4 || this.mac || this.ope) 
   this.nbw=(!this.bw) 
   return this;
}

//计算内容宽和高

 

<SCRIPT  language="javascript">  
function  test(obj)  
{  
       var  range  =  obj.createTextRange();  
       alert("内容区宽度:  "  +  range.boundingWidth    
                                                 +  "px\r\n内容区高度:  "  +  range.boundingHeight  +  "px");  
             
}  
</SCRIPT>  
<BODY>  
<Textarea id="txt" height="150">sdf</textarea><INPUT  type="button"  value="计算内容宽度"  onClick="test(txt)">  
</BODY>

//无模式的提示框

 

function modelessAlert(Msg)
{
   window.showModelessDialog("BLOCKED SCRIPTalert(\""+escape(Msg)+"\");window.close();","","status:no;resizable:no;help:no;dialogHeight:height:30px;dialogHeight:40px;");
}

 

//屏蔽按键

 

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
  <noscript><meta http-equiv="refresh" content="0;url=about:noscript"></noscript>
  <title>屏蔽鼠标右键、Ctrl+N、Shift+F10、Alt+F4、F11、F5刷新、退格键</title>
</head>
<body>
<script language="Javascript"><!–
  //屏蔽鼠标右键、Ctrl+N、Shift+F10、F11、F5刷新、退格键
  //Author: meizz(梅花雨) 2002-6-18
function document.oncontextmenu(){event.returnValue=false;}//屏蔽鼠标右键
function window.onhelp(){return false//屏蔽F1帮助
function document.onkeydown()
{
  if ((window.event.altKey)&&
      ((window.event.keyCode==37)||   //屏蔽 Alt+ 方向键 ←
       (window.event.keyCode==39)))   //屏蔽 Alt+ 方向键 →
  {
     alert("不准你使用ALT+方向键前进或后退网页!");
     event.returnValue=false;
  }
     /* 注:这还不是真正地屏蔽 Alt+ 方向键,
     因为 Alt+ 方向键弹出警告框时,按住 Alt 键不放,
     用鼠标点掉警告框,这种屏蔽方法就失效了。以后若
     有哪位高手有真正屏蔽 Alt 键的方法,请告知。*/

  if ((event.keyCode==8)  ||                 //屏蔽退格删除键
      (event.keyCode==116)||                 //屏蔽 F5 刷新键
      (event.ctrlKey && event.keyCode==82)){ //Ctrl + R
     event.keyCode=0;
     event.returnValue=false;
     }
  if (event.keyCode==122){event.keyCode=0;event.returnValue=false;}  //屏蔽F11
  if (event.ctrlKey && event.keyCode==78) event.returnValue=false;   //屏蔽 Ctrl+n
  if (event.shiftKey && event.keyCode==121)event.returnValue=false;  //屏蔽 shift+F10
  if (window.event.srcElement.tagName == "A" && window.event.shiftKey) 
      window.event.returnValue = false;             //屏蔽 shift 加鼠标左键新开一网页
  if ((window.event.altKey)&&(window.event.keyCode==115))             //屏蔽Alt+F4
  {
      window.showModelessDialog("about:blank","","dialogWidth:1px;dialogheight:1px");
      return false;
  }
}
</script>
屏蔽鼠标右键、Ctrl+N、Shift+F10、Alt+F4、F11、F5刷新、退格键
</body>
</html>

//屏蔽打印
<style>
@media print{
* {display:none}
}
</style>

//移动的图层,拖动

1.<span style=’position:absolute;width:200;height:200;background:red’ onmousedown=MouseDown(this) onmousemove=MouseMove() onmouseup=MouseUp()>meizz</span>
<script language=javascript>
var Obj;
function MouseDown(obj)
{
  Obj=obj;
  Obj.setCapture();
  Obj.l=event.x-Obj.style.pixelLeft;
  Obj.t=event.y-Obj.style.pixelTop;
}
function MouseMove()
{
  if(Obj!=null)
  {
    Obj.style.left = event.x-Obj.l;
    Obj.style.top = event.y-Obj.t;
  }
}
function MouseUp()
{
  if(Obj!=null)
  {
    Obj.releaseCapture();
    Obj=null;
  }
}
</script>
2.
<div id="myDiv" src="logo.gif" ondrag="doDrag();" onmouseover="this.style.cursor=’hand’" style="position:absolute;left=100;top=100;" onmousedown="doMouseDown();">
<a href="#" onclick="return false"><h1>wlecome</h1></a>
</div>
<script language="JavaScript" type="text/javascript">
var orgMouseX;
var orgMouseY;
var orgObjX;
var orgObjY;
function doDrag()
{
var myObject=document.all.myDiv;

var x=event.clientX;
var y=event.clientY;
myObject.style.left=x-(orgMouseX-orgObjX);
myObject.style.top=y-(orgMouseY-orgObjY);
 
}
function doMouseDown()
{
orgMouseX=event.clientX;
orgMouseY=event.clientY;
orgObjX=parseInt(document.all.myDiv.style.left);
orgObjY=parseInt(document.all.myDiv.style.top);
}

</script>
 

//文档状态改变

<iframe src="a.html" id="f" name="f" scrolling="no" frameborder=0 marginwidth=0 marginheight=0></iframe>
<script>
var doc=window.frames["f"].document;
function s(){
 if (doc.readyState=="complete"){
  document.all.f.style.height=doc.body.scrollHeight
  document.all.f.style.width=doc.body.scrollWidth
 }
}
doc.onreadystatechange=s
</script>

//刷新后不变的文本框

 

//访问剪贴板

 

//操作COOKIE

function SetCookie(sName, sValue)
{
 document.cookie = sName + "=" + escape(sValue) + "; ";
}
function GetCookie(sName)
{
 var aCookie = document.cookie.split("; ");
 for (var i=0; i < aCookie.length; i++)
 {
  
  var aCrumb = aCookie[i].split("=");
  if (sName == aCrumb[0]) 
  return unescape(aCrumb[1]);
 }
 
}
function DelCookie(sName)
{
document.cookie = sName + "=" + escape(sValue) + "; expires=Fri, 31 Dec 1999 23:59:59 GMT;";
}

//setTimeout增加参数

<script>
var _st = window.setTimeout;
window.setTimeout = function(fRef, mDelay) {
 if(typeof fRef == ’function‘){
  var argu = Array.prototype.slice.call(arguments,2);
  var f = (function(){ fRef.apply(null, argu); });
  return _st(f, mDelay);
 }
 return _st(fRef,mDelay);
}
function test(x){
 alert(x);
}
window.setTimeout(test,1000,’fason’);
</script>

//自定义的apply,call

Function.prototype.apply = function (obj, argu) {
 if (obj) obj.constructor.prototype._caller = this
 var argus = new Array();
 for (var i=0;i<argu.length;i++)
  argus[i] = "argu[" + i + "]";
 var r;
 eval("r = " + (obj ? ("obj._caller(" + argus.join(",") + ");") : ("this(" + argus.join(",") + ");")));
 return r;
};
Function.prototype.call = function (obj) {
 var argu = new Array();
 for (var i=1;i<arguments.length;i++)
  argu[i-1] = arguments[i];
 return this.apply(obj, argu);
};       

//下载文件

function DownURL(strRemoteURL,strLocalURL)
{
 try
 {
  var xmlHTTP=new ActiveXObject("Microsoft.XMLHTTP");
  xmlHTTP.open("Get",strRemoteURL,false);
  xmlHTTP.send();
  var adodbStream=new ActiveXObject("ADODB.Stream");
  adodbStream.Type=1;//1=adTypeBinary
  adodbStream.Open();
  adodbStream.write(xmlHTTP.responseBody);
  adodbStream.SaveToFile(strLocalURL,2);
  adodbStream.Close();
  adodbStream=null;
  xmlHTTP=null;
  
 }
 catch(e)
 {
  window.confirm("下载URL出错!");
 }
 //window.confirm("下载完成.");
}

//检验连接是否有效

 

//组件是否安装
isComponentInstalled("{6B053A4B-A7EC-4D3D-4567-B8FF8A1A5739}", "componentID"))

//检查网页是否存在

function CheckURL(URL)
{
  var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  xmlhttp.Open("GET",URL, false);
  try
  { 
    xmlhttp.Send(); 
    var result = xmlhttp.status;
  }
  catch(e) {return(false); }
  if(result==200)
  { 
    return true;
  }
  xmlhttp = null;
  return false;
}

//连接数据库

<script language="javascript">
  //用 JavaScript 写服务器端连接数据库的代码示例
  var conn = new ActiveXObject("ADODB.Connection");
  conn.Open("Provider=SQLOLEDB.1; Data Source=localhost; User ID=sa; "
    +"Password=; Initial Catalog=pubs");
  var rs = new ActiveXObject("ADODB.Recordset");
  var sql="select * from authors";
  rs.open(sql, conn);
 shtml = "<table width=’100%’ border=1>";
 shtml +="<tr bgcolor=’#f4f4f4′><td>au_id</td><td>au_lname</td><td>au_fname</td><td>phone</td><td>address</td><td> city</td><td>state</td><td>zip</td></tr>";
  while(!rs.EOF)
  {
 shtml += "<tr><td>" + rs("au_id") + "</td><td>" + rs("au_lname") + "</td><td>" + rs("au_fname") + "</td><td>" + rs("phone") + "</td><td>" + rs("address") + "</td><td>" + rs("city") + "</td><td>" + rs("state") + "</td><td>" + rs("zip") + "</td></tr>";
 rs.moveNext;
  }
  shtml += "</table>";
  document.write(shtml);
  rs.close(); 
  rs = null
  conn.close(); 
  conn = null;
</script>

//使用数据岛

 

<html>
<body>
srno:<input type=text datasrc=#xmldate DataFLD=srno size="76"><BR>
times:<input type=text datasrc=#xmldate DataFLD=times size="76"><BR>
<input id="first" TYPE=button value="<< 第一条记录" onclick="xmldate.recordset.moveFirst()">
<input id="prev" TYPE=button value="<上一条记录" onclick="xmldate.recordset.movePrevious()">  
<input id="next" TYPE=button value="下一条记录>" onclick="xmldate.recordset.moveNext()">  
<input id="last" TYPE=button value="最后一条记录>>" onclick="xmldate.recordset.moveLast()">   
<input id="Add" TYPE=button value="添加新记录" onclick="xmldate.recordset.addNew()">  

<XML ID="xmldate">
<infolist>
<info ><srno>20041025-01</srno><times>null</times></info>
<info ><srno>20041101-09</srno><times>2004年10月1日2点22分0秒</times></info>
</infolist>
</XML>
</body>
</html>

//获得参数

 

<body>
<a href="BLOCKED SCRIPTlocation.href=location.href + ’?a=1&b=2′">search</a>
<script language="JavaScript">
<!–
var a = location.search.substr(1);
if(a.length>0)
{
 var re = /([^&]*?)\=([^&]*)/g
 var s = a.match(re);
 for(var i= 0;i<s.length;i++)
 {
  alert(s[i]);
  alert(s[i].split("=")[1]);
 }
}
//–>
</script>
</body>

//可编辑SELECT

 

<input type=text name=re_name style="width:100px;height:21px;font-size:10pt;"><span style="width:18px;border:0px solid red;"><select name="r00" style="margin-left:-100px;width:118px; background-color:#FFEEEE;" onChange="document.all.re_name.value=this.value;">
                <option value="1">11111111<option>
                <option value="2">222222</option>
                <option value="3">333333</option>
              </select>
              </span>

//设置光标位置

function getCaret(textbox)
{
 var control = document.activeElement;
 textbox.focus();
 var rang = document.selection.createRange();
  rang.setEndPoint("StartToStart",textbox.createTextRange())
 control.focus();
 return rang.text.length;
}
function setCaret(textbox,pos)
{
 try
 {
  var r =textbox.createTextRange();
   r.moveStart(‘character’,pos);
   r.collapse(true);
   r.select();
 }
 catch(e)
 {}
}
function selectLength(textbox,start,len)
{
 try
 {
  var r =textbox.createTextRange();
 
  r.moveEnd(‘character’,len-(textbox.value.length-start));
  r.moveStart(‘character’,start);
  
  r.select();
 }
 catch(e)
 {//alert(e.description)}
}
function insertAtCaret(textbox,text)
{
 textbox.focus();
 document.selection.createRange().text = text;
}

//页内查找

function findInPage(str)
{
 var txt, i, found,n = 0;
 if (str == "")
 {
  return false;
 }
 txt = document.body.createTextRange();
 for (i = 0; i <= n && (found = txt.findText(str)) != false; i++)
 {
  txt.moveStart("character", 1);
  txt.moveEnd("textedit");
 }
 if (found)
 {
  txt.moveStart("character", -1);
  txt.findText(str);
  txt.select();
  txt.scrollIntoView();
  n++;  
 }
 else
 {
  if (n > 0)
  {
   n = 0;
   findInPage(str);
  }
  else
  {
   alert(str + "…            您要找的文字不存在。\n \n请试着输入页面中的关键字再次查找!");
  }
 }
 return false;
}

//书

<script language="javascript">
function jStartExcel() {
 var xls = new ActiveXObject ( "Excel.Application" );
 xls.visible = true;
 var newBook = xls.Workbooks.Add;
 newBook.Worksheets.Add;
 newBook.Worksheets(1).Activate;
 xls.ActiveWorkBook.ActiveSheet.PageSetup.Orientation = 2;
 xls.ActiveWorkBook.ActiveSheet.PageSetup.PaperSize = 5;
 newBook.Worksheets(1).Columns("A").columnwidth=50;
 newBook.Worksheets(1).Columns("A").WrapText = true;
 newBook.Worksheets(1).Columns("B").columnwidth=50;
 newBook.Worksheets(1).Columns("B").WrapText = true;
 newBook.Worksheets(1).Range("A1:B1000").NumberFormat = "0";
 newBook.Worksheets(1).Range("A1:B1000").HorizontalAlignment = -4131;
 newBook.Worksheets(1).Cells(1,1).Interior.ColorIndex="15";
 newBook.Worksheets(1).Cells(1,1).value="First Column, First Cell";
 newBook.Worksheets(1).Cells(2,1).value="First Column, Second Cell";
 newBook.Worksheets(1).Cells(1,2).value="Second Column, First Cell";
 newBook.Worksheets(1).Cells(2,2).value="Second Column, Second Cell";
 newBook.Worksheets(1).Name="My First WorkSheet";
}
</script>

//自定义提示条

<a href="#" title="这是提示">tip</a>
<script Language="JavaScript">
//***********默认设置定义.*********************
tPopWait=50;//停留tWait豪秒后显示提示。
tPopShow=5000;//显示tShow豪秒后关闭提示
showPopStep=20;
popOpacity=99;
//***************内部变量定义*****************
sPop=null;
curShow=null;
tFadeOut=null;
tFadeIn=null;
tFadeWaiting=null;
document.write("<style type=’text/css’id=’defaultPopStyle’>");
document.write(".cPopText {  background-color: #F8F8F5;color:#000000; border: 1px #000000 solid;font-color: font-size: 12px; padding-right: 4px; padding-left: 4px; height: 20px; padding-top: 2px; padding-bottom: 2px; filter: Alpha(Opacity=0)}");
document.write("</style>");
document.write("<div id=’dypopLayer’ style=’position:absolute;z-index:1000;’ class=’cPopText’></div>");

function showPopupText(){
var o=event.srcElement;
MouseX=event.x;
MouseY=event.y;
if(o.alt!=null && o.alt!=""){o.dypop=o.alt;o.alt=""};
        if(o.title!=null && o.title!=""){o.dypop=o.title;o.title=""};
if(o.dypop!=sPop) {
sPop=o.dypop;
clearTimeout(curShow);
clearTimeout(tFadeOut);
clearTimeout(tFadeIn);
clearTimeout(tFadeWaiting);
if(sPop==null || sPop=="") {
dypopLayer.innerHTML="";
dypopLayer.style.filter="Alpha()";
dypopLayer.filters.Alpha.opacity=0;
}
else {
if(o.dyclass!=null) popStyle=o.dyclass 
else popStyle="cPopText";
curShow=setTimeout("showIt()",tPopWait);
}
}
}
function showIt(){
dypopLayer.className=popStyle;
dypopLayer.innerHTML=sPop;
popWidth=dypopLayer.clientWidth;
popHeight=dypopLayer.clientHeight;
if(MouseX+12+popWidth>document.body.clientWidth) popLeftAdjust=-popWidth-24
else popLeftAdjust=0;
if(MouseY+12+popHeight>document.body.clientHeight) popTopAdjust=-popHeight-24
else popTopAdjust=0;
dypopLayer.style.left=MouseX+12+document.body.scrollLeft+popLeftAdjust;
dypopLayer.style.top=MouseY+12+document.body.scrollTop+popTopAdjust;
dypopLayer.style.filter="Alpha(Opacity=0)";
fadeOut();
}
function fadeOut(){
if(dypopLayer.filters.Alpha.opacity<popOpacity) {
dypopLayer.filters.Alpha.opacity+=showPopStep;
tFadeOut=setTimeout("fadeOut()",1);
}
else {
dypopLayer.filters.Alpha.opacity=popOpacity;
tFadeWaiting=setTimeout("fadeIn()",tPopShow);
}
}
function fadeIn(){
if(dypopLayer.filters.Alpha.opacity>0) {
dypopLayer.filters.Alpha.opacity-=1;
tFadeIn=setTimeout("fadeIn()",1);
}
}
document.onmouseover=showPopupText;
</script>

//插入文字

document.onclick =function(){ 
var oSource = window.event.srcElement; 
if(oSource.tagName!="DIV"
return false
var sel = document.selection; 
if (sel!=null) { 
var rng = sel.createRange(); 
if (rng!=null
rng.pasteHTML("<font color=red>插入文字</font>"); 

//netscapte下操作xml

 

//判断键值

 

//禁止FSO

1.注销组件
regsvr32 /u scrrun.dll
2.修改PROGID 
HKEY_CLASSES_ROOT\Scripting.FileSystemObject
Scripting.FileSystemObject
3.对于使用object的用户,修改HKEY_CLASSES_ROOT\Scripting.

//省略号

 

//检测media play版本

 

//图象按比例

 

//细线SELECT

 

function getComputerName()
{
 var objWMIService = GetObject("Winmgmts:root\cimv2");
 for(e = new Enumerator(objWMIService) ; !e.atEnd() ; e.moveNext())
 {
    var getComputer = e.item();
    return getComputer.Name;
 }
}

//条件编译

 

<script language=javascript>
/*@cc_on @*/
/*@if (@_win32 && @_jscript_version>5)
function window.confirm(str)
{
    execScript("n = msgbox(‘"+ str +"’, 257)", "vbscript");
    return(n == 1);
}
@end @*/

</script>

//取得innerText

<SCRIPT LANGUAGE="JavaScript">
<!–
 var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.4.0");
 var currNode;
 xmlDoc.async = false;
 xmlDoc.async = false;
 xmlDoc.loadXML("<TABLENAME>      你好你阿三    大法     司法等四              </TABLENAME>");
 currNode = xmlDoc.documentElement;
   
  var s = currNode.xml;
  var r = /\<([^\>\s]*?)[^\>]*?\>([^\<]*?)\<\/\1\>/
  var b = s.replace(r,"$2");
  alert(b);
//–>
</SCRIPT>

//mergeAttributes 复制所有读/写标签属性到指定元素。

<SCRIPT>
function fnMerge(){
oSource.children[1].mergeAttributes(oSource.children[0]);
}
</SCRIPT>
<SPAN ID=oSource>
<DIV
ID="oDiv"
ATTRIBUTE1="true"
ATTRIBUTE2="true"
onclick="alert(‘click’);"
onmouseover="this.style.color=’#0000FF’;"
onmouseout="this.style.color=’#000000′;"
>
This is a sample <B>DIV</B> element.
</DIV>
<DIV ID="oDiv2">
This is another sample <B>DIV</B> element.
</DIV>
</SPAN>
<INPUT
TYPE="button"
VALUE="Merge Attributes"
onclick="fnMerge()"
>

<span style="border:1px solid #000000; position:absolute; overflow:hidden;" >
<select style="margin:-2px;">
<option>1111</option>
<option>11111111111111</option>
<option>111111111</option>
</select></span>

//Import

function Import() {
 for( var i=0; i<arguments.length; i++ ) {
  var file = arguments[i];
  if ( file.match(/\.js$/i)) 
   document.write(‘<script type=\"text/javascript\" src=\"’ + file + ’\"></sc’ + ’ript>’);
  else
   document.write(‘<style type=\"text/css\"
>@import \"’ + file + ’\" ;</style>’);
 }
};

//js枚举

<script language="JavaScript">
<!–
//图片按比例缩放
var flag=false;
function DrawImage(ImgD){
 var image=new Image();
 var iwidth = 80;  //定义允许图片宽度
 var iheight = 80;  //定义允许图片高度
 image.src=ImgD.src;
 if(image.width>0 && image.height>0){
 flag=true;
 if(image.width/image.height>= iwidth/iheight){
  if(image.width>iwidth){  
  ImgD.width=iwidth;
  ImgD.height=(image.height*iwidth)/image.width;
  }else{
  ImgD.width=image.width;  
  ImgD.height=image.height;
  }
  ImgD.alt=image.width+"×"+image.height;
  }
 else{
  if(image.height>iheight){  
  ImgD.height=iheight;
  ImgD.width=(image.width*iheight)/image.height;  
  }else{
  ImgD.width=image.width;  
  ImgD.height=image.height;
  }
  ImgD.alt=image.width+"×"+image.height;
  }
 }

//–>
</script>
<img src=".." onload = "DrawImage(this)">

<IE:clientCaps ID="oClientCaps" style="{behavior:url(#default#clientcaps)}" />
<SCRIPT>
var flash="";
    WMPVersion= oClientCaps.getComponentVersion("{22D6F312-B0F6-11D0-94AB-0080C74C7E95}","ComponentID"); 
    if (WMPVersion != "") {
    flash = "";
    var version = WMPVersion.split(",");
    var i;
    for (i = 0; i < version.length; i++) {
      if (i != 0)
    flash += ".";
      flash += version[i];
    }
     document.write("您的Windows Media Player 版本是:"+flash+"<p>");
  }
</SCRIPT>

<DIV STYLE="width: 120px; height: 50px; border: 1px solid blue;
            overflow: hidden; text-overflow:ellipsis"
>
<NOBR>就是比如有一行文字,很长,表格内一行显示不下.</NOBR>
</DIV>

<html>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<head>
<script language="javascript">
var ie  =navigator.appName=="Microsoft Internet Explorer"?true:false;
  
function keyDown(e)
{
 if(!ie)
 {
  var nkey=e.which;
  var iekey=’现在是ns浏览器’;
  var realkey=String.fromCharCode(e.which);
 }
 if(ie)
 {
  var iekey=event.keyCode;
  var nkey=’现在是ie浏览器’;
  var realkey=String.fromCharCode(event.keyCode);
  if(event.keyCode==32){realkey=’\' 空格\”}
  if(event.keyCode==13){realkey=’\' 回车\”}
  if(event.keyCode==27){realkey=’\' Esc\”}
  if(event.keyCode==16){realkey=’\' Shift\”}
  if(event.keyCode==17){realkey=’\' Ctrl\”}
  if(event.keyCode==18){realkey=’\' Alt\”}
 }
 alert(‘ns浏览器中键值:’+nkey+’\n’+'ie浏览器中键值:’+iekey+’\n’+'实际键为’+realkey);
}
document.onkeydown = keyDown;
</script>
</head>
<body>
//Javascript Document.
<hr>
<center>
<h3>请按任意一个键。。。。</h3>
</center>
</body>
</html>

doc = new ActiveXObject("Msxml2.DOMDocument");
doc = new ActiveXObject("Microsoft.XMLDOM")
->>
doc = (new DOMParser()).parseFromString(sXML,’text/xml’)

function getXML(URL) 
{
 var xmlhttp = new ActiveXObject("microsoft.xmlhttp");
 xmlhttp.Open("GET",URL, false); 
 try
 { 
  xmlhttp.Send();
 }
 catch(e){}
 finally 
 {
  var result = xmlhttp.responseText;
  if(result) 
  {
   if(xmlhttp.Status==200)
   {
    return(true);
   }
   else 
   {
    return(false);
   }
  }
  else 
  {
   return(false);
  }
 }
}

//POST代替FORM

 

<SCRIPT language="VBScript">
Function URLEncoding(vstrIn)
    strReturn = ""
    For i = 1 To Len(vstrIn)
        ThisChr = Mid(vStrIn,i,1)
        If Abs(Asc(ThisChr)) < &HFF Then
            strReturn = strReturn & ThisChr
        Else
            innerCode = Asc(ThisChr)
            If innerCode < 0 Then
                innerCode = innerCode + &H10000
            End If
            Hight8 = (innerCode  And &HFF00)\ &HFF
            Low8 = innerCode And &HFF
            strReturn = strReturn & "%" & Hex(Hight8) &  "%" & Hex(Low8)
        End If
    Next
    URLEncoding = strReturn
End Function
Function bytes2BSTR(vIn)
    strReturn = ""
    For i = 1 To LenB(vIn)
        ThisCharCode = AscB(MidB(vIn,i,1))
        If ThisCharCode < &H80 Then
            strReturn = strReturn & Chr(ThisCharCode)
        Else
            NextCharCode = AscB(MidB(vIn,i+1,1))
            strReturn = strReturn & Chr(CLng(ThisCharCode) * &H100 + CInt(NextCharCode))
            i = i + 1
        End If
    Next
    bytes2BSTR = strReturn
End Function
dim strA,oReq
strA = URLEncoding("submit1=Submit&text1=中文")
set oReq = CreateObject("MSXML2.XMLHTTP")
oReq.open "POST","http://ServerName/VDir/TstResult.asp",false
oReq.setRequestHeader "Content-Length",Len(strA)
oReq.setRequestHeader "CONTENT-TYPE","application/x-www-form-urlencoded"
oReq.send strA
msgbox bytes2BSTR(oReq.responseBody)
</SCRIPT>

//readyState是xmlhttp返回数据的进度,0=载入中,1=未初始化,2=已载入,3=运行中,4=完成

(1)拖拽访问
event.dataTransfer.setData("URL", oImage.src);
sImageURL = event.dataTransfer.getData("URL")
(2)普通访问
window.clipboardData.setData("Text",oSource.innerText);
window.clipboardData.getData("Text");

<HTML>
<HEAD>
<META NAME="save" CONTENT="history">
<STYLE>
   .sHistory {behavior:url(#default#savehistory);}
</STYLE>
</HEAD>
<BODY>
<INPUT class=sHistory type=text id=oPersistInput>
</BODY>
</HTML>

<p  style="page-break-after:always">page1</p>  
<p  style="page-break-after:always">page2</p>  

<meta name="ROBOTS" content="属性值">
  其中属性值有以下一些:
  属性值为"all": 文件将被检索,且页上链接可被查询;
  属性值为"none": 文件不被检索,而且不查询页上的链接;
  属性值为"index": 文件将被检索;
  属性值为"follow": 查询页上的链接;
  属性值为"noindex": 文件不检索,但可被查询链接;
  属性值为"nofollow"

<object id=min classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"
<param name="Command" value="Minimize"></object> 
<object id=max classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11"
<param name="Command" value="Maximize"></object> 
<OBJECT id=close classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"
<PARAM NAME="Command" value="Close"></OBJECT> 
<input type=button value=最小化 onclick=min.Click()> 
<input type=button value=最大化 onclick=max.Click()> 
<input type=button value=关闭 onclick=close.Click()> 

<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="0">

 

<input type=button value=导入收藏夹 onclick="window.external.ImportExportFavorites(true,’http://localhost’);">
<input type=button value=导出收藏夹 onclick="window.external.ImportExportFavorites(false,’http://localhost’);">
<input type=button value=整理收藏夹 onclick="window.external.ShowBrowserUI(‘OrganizeFavorites’, null)">
<input type=button value=语言设置   onclick="window.external.ShowBrowserUI(‘LanguageDialog’, null)">
<input type=button value=加入收藏夹 onclick="window.external.AddFavorite(‘http://www.google.com/’, ’google’)">
<input type=button value=加入到频道 onclick="window.external.addChannel(‘http://www.google.com/’)">
<input type=button value=加入到频道 onclick="window.external.showBrowserUI(‘PrivacySettings’,null)">

<input type=text onkeypress="return event.keyCode>=48&&event.keyCode<=57||(this.value.indexOf(‘.’)<0?event.keyCode==46:false)" onpaste="return !clipboardData.getData(‘text’).match(/\D/)" ondragenter="return false">

ASP.NET 安全认证(二)

 

 

 

 

 

 

 

 

——灵活运用 Form 表单认证中的 deny allow 及保护 .htm 等文件

 

 

 

 

 

 

 

 

 

作者:寒羽枫(cityhunter172)

 

 

 

 

 

 

 

 

 

第二部分 Form 认证的实战运用 

 

话说上回,简单地说了一下 Form 表单认证的用法。或许大家觉得太简单,对那些大内高手来说应该是“洒洒水啦”“小 Kiss 啦(小意思)”。今天咱们来点的花样吧:古有六扇门,拒收叶孤城;东门不刮风,吹雪姓西门;缎带作凭证,决战紫禁城

 

 

 

 

 

 

 

 

 

五、        Web.config 的作用范围

 

 

 

 

 

 

 

 

 

新建项目时, VS.Net 会在项目根目录建立一个内容固定的 Web.config。除了在项目根目录,你还可以在任一目录下建立 Web.config ,条件就是应用程序级别的节点只能在根目录的 Web.config 中出现。至于哪些是应用程序级别节点呢,这个问题嘛,其实我也不太清楚,呵呵。电脑不是我发明的,微软不是我创建的,C# 更不是我说了算的,神仙也有不知道的,所以我不晓得是正常的。话虽如此,只要它不报错,那就是对的

 

 

 

 

 

 

 

 

 

关于 Web.config 设置的作用范围,记住以下两点:

 

 

 

 

 

 

 

 

 

1、  Web.config 的设置将作用于所在目录的所有文件及其子目录下的所有东东(继承:子随父姓)

 

 

 

 

 

 

 

 

 

2、  子目录下的 Web.config 设置将覆盖由父目录继承下来的设置(覆盖:县官不如现管)

 

 

 

 

 

 

 

 

 

给大家提个问题:有没有比根目录Web.config 的作用范围还大的配置文件呢?看完第三部分便知分晓。

 

 

 

 

 

 

 

 

 

六、        学会拒绝与巧用允许

 

 

 

 

 

 

 

 

 

回到我们在第一回合新建的测试项目“FormTest ,既然要进行验证,按国际惯例,就得有用户名与密码。那,这些用户是管理员自己在数据库建好呢,还是用户注册、管理员审核好呢。只要不是一般的笨蛋,都知道选择后者。你们还别说,我公司还真有个别项目是管理员连到数据库去建帐号的,属于比较特殊的笨蛋,咱们不学他也罢,还是老老实实添加两个页面吧——注册页面(Register.aspx)与审核页面(Auditing.aspx)。

 

 

 

 

 

 

 

 

 

问题终于就要浮出水面啦,当你做好 Register.aspx 时,想访问它的时候突然觉得不对劲,怎么又回到了登录页面?你仔细瞧瞧网址,是不是成了:Login.aspx?ReturnUrl=Register.aspx 。怎么办,用户就是因为没有帐号才去访问注册页面的呀?(这句纯属废话,有帐号谁还跑去注册。)我时常对我的同事说:“办法是人想出来滴!!”

 

 

 

 

 

 

 

 

 

1、  新建一个目录 Public ,用于存放一些公用的文件,如万年历、脚本呀……

 

 

 

 

 

 

 

 

 

2、  在“解决方案资源管理器”中右击点击目录 Public ,新增一个 Web.config

 

 

 

 

 

 

 

 

 

3、  把上述 Web.config 的内容统统删除,仅留以下即可:

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

 

 

 

<configuration>

 

 

 

 

 

 

 

 

 

  <system.web>

 

 

 

 

 

 

 

 

 

   <authorization><allow users="*"/></authorization>

 

 

 

 

 

 

 

 

 

 </system.web>

 

 

 

 

 

 

 

 

 

</configuration>

 

 

 

 

 

 

 

 

 

终于切入正题了,不容易呀。根据“覆盖”原则,我们知道上述 Web.config 将替代根目录 Web.config 中的 <authorization> 节点设置,即:

 

 

 

 

 

 

 

 

 

       <allow users="*"/> 替换 <deny users="?"></deny>

 

 

 

 

 

 

 

 

 

注解:“allow”允许的意思;“*”表示所有用户;

 

 

 

 

 

 

 

 

 

        deny 拒绝的意思;“?”表示匿名用户;

 

 

 

 

 

 

 

 

 

因此,处于 Public 目录下的文件,允许所有人浏览,包括未验证的用户。把 Register.aspx 进来吧,再也不会有人阻止你浏览啦。

 

 

 

 

 

 

 

 

 

除了注册页面,我们还提到一个审核页面(Auditing.aspx),审核权限一般都在管理员或主管手里,并不想让其他人浏览此页面(真理往往掌握在少数人的手里,这也是没法子的事),怎么办?“办法是人想出来滴”呵呵……新建一个管理员的目录 ManageSys ,在此目录下再新增一个 Web.config。内容如下:

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

 

 

 

<configuration>

 

 

 

 

 

 

 

 

 

<system.web>

 

 

 

 

 

 

 

 

 

<authorization>

 

 

 

 

 

 

 

 

 

<allow users="Admin"/>

 

 

 

 

 

 

 

 

 

<deny users="*"/>

 

 

 

 

 

 

 

 

 

</authorization>

 

 

 

 

 

 

 

 

 

  </system.web>

 

 

 

 

 

 

 

 

 

</configuration>

 

 

 

 

 

 

 

 

 

现在的问题就是怎么才能知道谁是“Admin”呢,这个问题就有点象“我的鞋底有个洞”—— 天不知地知,你不知我知。闲话少说(要是有稿费多好,我就有多写几个字的动力,唉……),大家还记得我在第一部分的结尾吗?什么,忘啦!罚你回去看一百遍,记住了再回来。站住,回来!一想到你的记性,我就不放心,第一部分的浏览网址是http://blog.csdn.net/cityhunter172/archive/2005/11/06/524043.aspx ,回到此处的网址是http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx

 

 

 

 

 

 

 

 

 

好了,不管那些记不好的家伙了,大伙继续往下看。

 

 

 

 

 

 

 

 

 

System.Web.Security.FormsAuthentication.SetAuthCookie(this.Txt_UserName.Text,false); //通过验证,发放 Cookie

 

 

 

 

 

 

 

 

 

之前我曾强调,要注意,第一个参数很重要,重要到什么程度?说到这,恐怕地球人都知道了——它就是allowdeny的依据。假如此处用户填写的是“Admin”即 this.Txt_UserName.Text = "Admin"; 那么进入系统后,他就能访问 ManageSys 目录下的网页了,其它闲杂人等一律拒之门外。

 

 

 

 

 

 

 

 

 

为巩固上述内容,给大伙留个课外作业:此项目有两部门使用,其中每个部门分别都有些特定的页面仅供本部门用户浏览使用,请问该如何使用 Web.config 达到效果?同样,答案在第三部分揭晓

 

 

 

 

 

 

 

 

 

七、        分散与集中

 

 

 

 

 

 

 

 

 

乍看之下,就象是马克思列宁主义、毛泽东思想、邓小平理论中的辩证关系,大伙放心,偶是学理科的,只明白“高举程序员的伟大旗帜,以编写代码为中心”。停……

 

 

 

 

 

 

 

 

 

到目前为此,我们的测试项目“FormTest”已经拥有两个目录三个 Web.config ,伴随用户需求的多样化,Web.config 也会越来越多,比如常用的文件上传功能等等。众多的 Web.config 分布在不同的目录里面,维护起来肯定比较烦人。能不能集中起来管理呢,应该咋办哩?“办法是……”哟,有人先说出来啦。不错,“办法的确是人想出来滴” ,我不说,你是不是只有在一边凉伴?开玩笑的,为了让更多的人记住这句话,我打算告诉你集中管理的办法。

 

 

 

 

 

 

 

 

 

要想集中管理,不得不用到 <location> 节点与 path 属性。在本项目中,我们将目录 Public ManageSys 下的设置放在根目录下的 Web.config 里面,如下:

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

 

 

 

 

 

 

 

 

 

<configuration>

 

 

 

 

 

 

 

 

 

<location path ="Public">

 

 

 

 

 

 

 

 

 

            <system.web>

 

 

 

 

 

 

 

 

 

                <authorization>

 

 

 

 

 

 

 

 

 

<allow users="*"/>

 

 

 

 

 

 

 

 

 

</authorization>

 

 

 

 

 

 

 

 

 

            </system.web>

 

 

 

 

 

 

 

 

 

       </location>

 

 

 

 

 

 

 

 

 

<location path ="ManageSys">

 

 

 

 

 

 

 

 

 

            <system.web>

 

 

 

 

 

 

 

 

 

       <authorization>

 

 

 

 

 

 

 

 

 

<allow users="Admin"/>

 

 

 

 

 

 

 

 

 

<deny users="*"/>

 

 

 

 

 

 

 

 

 

</authorization>

 

 

 

 

 

 

 

 

 

            </system.web>

 

 

 

 

 

 

 

 

 

       </location>

 

 

 

 

 

 

 

 

 

       <system.web>

 

 

 

 

 

 

 

 

 

                            <!– 这里放置原来根目录 Web.config 的内容,就不列出来了 –>

(本文出自寒羽枫 cityhunter172 的博客:http://blog.csdn.net/cityhunter172 个人站点:http://172.meibu.com

 

 

 

 

 

 

 

 

 

       </system.web>

 

 

 

 

 

 

 

 

 

</configuration>

 

 

 

 

 

 

 

 

 

       需要提醒的是

 

 

 

 

 

 

 

 

 

1、  <location> 节点的位置是在 <configuration> 的一个子节点,它与原有的 <system.web> 属于并列关系

 

 

 

 

 

 

 

 

 

2、  <location> 节点只需要放入对应子目录 Web.config 中的 <system.web> 的节点内容

 

 

 

 

 

 

 

 

 

八、        额外的保护

 

 

 

 

 

 

 

 

 

第二部分就要结束了,现在时间已是凌晨 4 点50分,我容易嘛我。认证的目的就是为了防止他人非法浏览页面,或未经许可使用某些功能。当然,世上没有绝对的安全,如今 MD5 加密都被我们国人给破解了,就是最好的例证。

 

 

 

 

 

 

 

 

 

细心的人可能早就发现 ASP.NET 的安全认证只针对 .aspx.ascx …… ASP.NET 文件起作用,而对普通页面与文件却“视而不见”,如 .htm.js .jpg 等。通过以下步骤你就可以保护你想保护的文件类型。

 

 

 

 

 

 

 

 

 

1、  打开 Internet 信息服务(IIS)管理器 右击本项目虚拟 属性,如下图

(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm01.JPG)

 

 

 

 

 

 

 

 

 

 

 

 

2、  点击按钮“配置”,出现如下对话框:

(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm02.JPG)

 

 

 

 

 

 

 

 

 

 

 

 

3、  双击 .aspx 的应用程序扩展 查看对话框内容,如下图:

(http://blog.csdn.net/images/blog_csdn_net/cityhunter172/85935/r_aspxForm03.JPG)

 

 

 

 

 

 

 

 

 

 

 

 

4、  复制“可执行文件”的全路径名称后 点击“取消”返回上一层对话框 点击按钮“添加”

 

 

 

 

 

 

 

 

 

5、  粘贴刚才复制的内容(我的系统装在 D 盘,所以内容为 D:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll 填写后缀名为 .htm 填写动作限制为“GET,HEAD,POST,DEBUG”(为方便省事你可选全部)

 

 

 

 

 

 

 

 

 

6、  最后点击“确定” 往项目中添加 HtmlPage1.htm IE 浏览器的地址栏直接输入http://localhost/FormTest/HtmlPage1.htm 观看测试效果

 

 

 

 

 

 

 

 

 

最后送大家一段 Web.config 设置,发完睡觉,实在是困的不行了。

 

 

 

 

 

 

 

 

 

<location path ="决战紫禁城">

 

 

 

 

 

 

 

 

 

            <system.web>

 

 

 

 

 

 

 

 

 

                <authorization>

 

 

 

 

 

 

 

 

 

<allow users="叶孤城"/>

 

 

 

 

 

 

 

 

 

<allow users="西门吹雪"/>

 

 

 

 

 

 

 

 

 

<deny users="*"/>

 

 

 

 

 

 

 

 

 

</authorization>

 

 

 

 

 

 

 

 

 

            </system.web>

 

 

 

 

 

 

 

 

 

       </location>

 

 

 

 

 

 

 

 

 

<location path ="金銮殿屋脊">

 

 

 

 

 

 

 

 

 

            <system.web>

 

 

 

 

 

 

 

 

 

       <authorization>

 

 

 

 

 

 

 

 

 

<allow users="腰系缎带之人"/>

 

 

 

 

 

 

 

 

 

<deny users="*"/>

 

 

 

 

 

 

 

 

 

</authorization>

 

 

 

 

 

 

 

 

 

            </system.web>

 

 

 

 

 

 

 

 

 

       </location>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ASP.NET 安全认证(一)

 

——如何运用 Form 表单认证

 

作者寒羽枫(cityhunter172)

 

 

代码写 N 久了,总想写得别的。这不,上头说在整合两个项目,做成单一登录(Single Sign On),也有人称之为“单点登录”。查阅相关文档后,终于实现了,现在把它拿出来与大家一起分享。或许大家会问:“这与标题不符呀?”别急,在下笔之前,我脑子里想到了我刚使用 Form 认证时遇到的一些问题,以及使用过程用到的一些技巧(实乃投机取巧是也 ^_^ )。偶打初中那时,语文水平就不怎么滴,考试常常作文写不出来,所以写作水平有限,还请大家海量。对了,本人不仅写作水平有限,编程能力也不是很好,此文供大家学习交流之用,欢迎广大劳苦群众拎着鸡蛋、捧着鲜花前来评论。转载请注明原创作者乃寒羽枫是也,不甚感激!

 

废话也说的差不多了,言归正传, ASP.NET 的安全认证,共有“Windows”“Form”“Passport”“None”四种验证模式。“Windows”与“None”没有起到保护的作用,不推荐使用;“Passport”我又没用过,唉……所以我只好讲讲“Form”认证了。我打算分三部分:

 

第一部分 —— 怎样实现From 认证;

 

第二部分 —— Form 认证的实战运用;

 

第三部分 —— 实现单点登录(Single Sign On

 

第一部分 如何运用 Form 表单认证

 

一、        新建一个测试项目

 

为了更好说明,有必要新建一个测试项目(暂且为“FormTest”吧),包含三张页面足矣(Default.aspxLogin.aspxUserInfo.aspx。啥?有人不会新建项目,不会新增页面?你问我咋办?我看这么办好了:拖出去,打回原藉,从幼儿园学起……

 

二、        修改 Web.config

 

1、  双击项目中的Web.config(不会的、找不到的打 PP

 

2、  找到下列文字 <authentication mode="Windows" /> 把它改成:

<authentication mode="Forms">

 

<forms loginUrl="Login.aspx" name=".ASPXAUTH"></forms>

 

</authentication>

 

3、  找到<authorization> <allow users="*" /></authorization>换成

<authorization><deny users="?"></deny></authorization>

 

这里没什么好说的,只要拷贝过去就行。虽说如此,但还是有人会弄错,如下:

 

<authentication mode="Forms">

 

       <forms loginUrl="Login.aspx" name=".APSX"></forms>

 

<deny users="?"></deny>

 

 </authentication>

 

若要问是谁把 <deny users="?"></deny> 放入 <authentication> 中的,我会很荣幸地告诉你,那是 N 年前的我:<authentication> <authorization> 都是以 auth 字母开头又都是以 ation 结尾,何其相似;英文单词背不下来的我以为他们是一伙的……

 

三、        编写 .cs 代码——登录与退出

 

1、  登录代码:

 

a、  书本上介绍的

 

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

 

         {

 

              if(this.Txt_UserName.Text=="Admin" && this.Txt_Password.Text=="123456")

 

              {

 

     System.Web.Security.FormsAuthentication.RedirectFromLoginPage(this.Txt_UserName.Text,false);

 

     }

 

}

 

b、  偶找了 N 久才找到的

 

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

 

         {

 

              if(this.Txt_UserName.Text=="Admin" && this.Txt_Password.Text=="123456")

 

              {

 

System.Web.Security.FormsAuthentication.SetAuthCookie(this.Txt_UserName.Text,false);

 

     Response.Redirect("Default.aspx");

 

     }

 

}

 

以上两种都可发放验证后的 Cookie ,即通过验证,区别:

 

方法 a) 指验证后返回请求页面,俗称“从哪来就打哪去”。比如:用户没登录前直接在 IE 地址栏输入 http://localhost/FormTest/UserInfo.aspx ,那么该用户将看到的是 Login.aspx?ReturnUrl=UserInfo.aspx ,输入用户名与密码登录成功后,系统将根据“ReturnUrl”的值,返回相应的页面

 

方法 b) 则是分两步走:通过验证后就直接发放 Cookie ,跳转页面将由程序员自行指定,此方法多用于 Default.aspx 使用框架结构的系统。

 

 

2、  退出代码:

 

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

 

     {

 

System.Web.Security.FormsAuthentication.SignOut();

 

}

 

四、        如何判断验证与否及获取验证后的用户信息

 

有的时候,在同一张页面需要判断用户是否已经登录,然后再呈现不同的布局。有人喜欢用 Session 来判断,我不反对此类做法,在此我只是想告诉大家还有一种方法,且看下面代码:

 

if(User.Identity.IsAuthenticated)

 

         {

 

              //你已通过验证,知道该怎么做了吧?

 

}

 

User.Identity 还有两个属性AuthenticationType(验证类型)与 Name(用户名称) ,大家要注意的是 Name 属性,此处的User.Identity.Name将得到,验证通过(RedirectFromLoginPage SetAuthCookie)时,我们带入的第一个参数 this.Txt_UserName.Text 。这个参数很重要,关系到种种……种种的情况,何出此言,且听下回分解……

 

ASP.NET 安全认证(二)—— 灵活运用 Form 表单认证中的 deny allow 及保护 .htm 等文件

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2006年08月01日

构建安全的 ASP.NET 应用程序

身份验证、授权和安全通信

J.D. Meier、Alex Mackman、Michael Dunner 和 Srinath Vasireddy
Microsoft Corporation
2002 年 10 月

ASP.NET 安全性

总结

本章提供用于构建安全的 ASP.NET Web 应用程序的指南和建议。本章提供的大多数指南和建议同样适用于开发 ASP.NET Web 服务和由 ASP.NET 驻留的 .NET Remoting 对象。

内容


ASP.NET
安全体系结构

ASP.NET 与 IIS、.NET 框架和操作系统所提供的基础安全服务配合使用,共同提供一系列身份验证和授权机制。图 8.1 中总结了这些情况。

图 8.1 ASP.NET 安全服务

图 8.1 阐释了 IIS 和 ASP.NET 所提供的身份验证和授权机制。当客户端发出 Web 请求时,就会发生下面一系列身份验证和授权事件:

    1. 接收来自网络的 HTTP(S) Web 请求。可以使用 SSL 确保服务器身份(使用服务器证书)和客户端身份(可选)。

      注意:SSL 还提供了一个安全通道,以便保护在客户端和服务器之间传送的机密数据。

    2. IIS 使用基本、摘要、集成(NTLM 或 Kerberos)或证书身份验证对调用方进行身份验证。如果站点的所有或部分内容不需要经过身份验证即可访问,则可以将 IIS 配置为使用匿名身份验证。IIS 为每个已验证的用户创建一个 Windows 访问令牌。如果选择匿名身份验证,则 IIS 为匿名 Internet 用户帐户(默认情况下为 IUSR_MACHINE)创建访问令牌。
    3. IIS 授予调用方访问所请求资源的权限。使用附加到所请求资源的 ACL 定义的 NTFS 权限授权访问。IIS 也可以配置为只接受来自特定 IP 地址的客户端计算机的请求。
    4. IIS 将已验证的调用方的 Windows 访问令牌传递到 ASP.NET(如果使用的是匿名身份验证,则它可能是匿名 Internet 用户的访问令牌)。
    5. ASP.NET 对调用方进行身份验证。
      如果将 ASP.NET 配置为使用 Windows 身份验证,则此时不会发生任何其他的身份验证。ASP.NET 将接受它从 IIS 收到的任何令牌。
      如果将 ASP.NET 配置为使用表单身份验证,将根据数据存储(通常为 Microsoft? SQL Server? 数据库或 Active Directory? 目录服务)对调用方提供的凭据进行身份验证(使用 HTML 表单)。如果将 ASP.NET 配置为使用 Passport 身份验证,则将用户重定向到 Passport 站点,然后 Passport 身份验证服务对用户进行身份验证。
    6. ASP.NET 授权访问所请求的资源或操作。
      UrlAuthorizationModule(系统提供的 HTTP 模块)使用在 Web.config 中配置的授权规则(具体来说就是 <authorization> 元素),确保调用方可以访问所请求的文件或文件夹。
      在 Windows 身份验证中,FileAuthorizationModule(另一个 HTTP 模块)检查调用方是否具有访问所请求资源的必要权限。将调用方的访问令牌与保护资源的 ACL 进行比较。
      也可以使用 .NET 角色(以声明方式或编程方式)确保给调用方授予访问所请求资源或执行所请求操作的权限。
    7. 应用程序中的代码使用特定标识来访问本地和/或远程资源。默认情况下,ASP.NET 不执行模拟,因此,配置的 ASP.NET 进程帐户提供标识。也可以选择原调用方的标识(如果启用了模拟)或已配置的服务标识。

网关守卫
ASP.NET Web 应用程序中的授权点(或关守)是由 IIS 和 ASP.NET 提供的:

IIS
如果关闭了匿名身份验证,则 IIS 只允许来自特定用户的请求,即它可以在其自己的域或受信任域中验证这些用户的身份。
对于静态文件类型(例如 .jpg、.gif 和 .htm 文件,即没有映射到 ISAPI 扩展的文件),IIS 使用与所请求文件关联的 NTFS 权限执行访问控制。

ASP.NET
ASP.NET 关守包括 UrlAuthorizationModuleFileAuthorizationModule 以及主体权限要求和角色检查。

UrlAuthorizationModule
可以配置应用程序 Web.config 文件中的 <authorization> 元素,控制哪些用户和用户组可以访问应用程序。授权是以存储在 HttpContext.User 中的 IPrincipal 对象为基础。

FileAuthorizationModule
对于由 IIS 映射到 ASP.NET ISAPI 扩展 (Aspnet_isapi.dll) 的文件类型,使用已验证用户的 Windows 访问令牌(可能为 IUSR_MACHINE),根据附加到所请求的 ASP.NET 文件中的 ACL 自动执行访问检查。


注意:要进行文件授权,并不要求模拟.

FileAuthorizationModule 类仅对所请求的文件执行访问检查,而不对所请求页面中的代码访问的文件执行访问检查,但 IIS 对这些文件执行访问检查。
例如,如果您请求 Default.aspx 并且它包含一个嵌入的用户控件 (Usercontrol.ascx),该控件又包含一个图像标记(指向 Image.gif),则 FileAuthorizationModule 对 Default.aspx 和 Usercontrol.ascx 执行访问检查,因为 IIS 将这些文件类型映射到 ASP.NET ISAPI 扩展。
FileAuthorizationModule 不对 Image.gif 执行检查,因为它是由 IIS 内部处理的静态文件。但是,由于 IIS 对静态文件执行访问检查,因此,仍须使用进行相应配置的 ACL 给已验证用户授予读取该文件的权限。
图 8.2 中显示了此方案。

 


系统管理员注意事项:需要给已验证用户授予读取此方案中涉及的所有文件的 NTFS 权限。唯一的变化是使用哪个关守来执行访问控制。ASP.NET 进程帐户只需要读取 ASP.NET 注册文件类型的访问权限。


图 8.2 IIS 和 ASP.NET 关守一起使用

在此方案中,您可以在文件入口处禁止访问。如果您配置了附加到 Default.aspx 的 ACL 并且拒绝访问某个特定的用户,则 Default.aspx 中的代码无法将用户控件或任何嵌入图像发送到客户端。如果该用户直接请求图像,则 IIS 亲自执行访问检查。

主体权限要求和明确的角色检查
除了可以用 IIS 和 ASP.NET 配置的关守外,还可以将主体权限要求(以声明方式或编程方式)用作附加的细分访问控制机制。通过使用主体权限检查(由 PrincipalPermissionAttribute 类执行),您可以根据各个用户的标识和组成员身份(由附加到当前线程的 IPrincipal 对象定义)控制对类、方法或个别代码块的访问。


注意:用于请求角色成员身份的主体权限要求与调用 IPrincipal.IsInRole 来测试角色成员身份不同;如果调用方不是指定角色的成员,则前者产生异常,而后者仅返回一个布尔值以确认角色成员身份。

在 Windows 身份验证中,ASP.NET 自动将一个代表已验证身份用户的 WindowsPrincipal 对象连接到当前的 Web 请求(使用 HttpContext.User)。表单身份验证和 Passport 身份验证创建具有相应标识但没有角色的 GenericPrincipal 对象,并将它附加到 HttpContext.User。

更多信息

  • 有关配置安全性的详细信息,请参见本章后面的“配置安全性”。
  • 有关编程安全性(和 IPrincipal 对象)的详细信息,请参见本章后面的“编程安全性”。


身份验证和授权策略

ASP.NET 提供了若干以声明方式和编程方式进行授权的机制,这些机制可与各种身份验证方案配合使用。这样,您就可以开发深入的授权策略以及可以配置为提供各种粒度级别(例如,基于角色的每用户或每用户组)的授权策略。
本节说明一组常用身份验证选项的可用授权选项(可进行配置和编程)。
下面概述了身份验证选项:

  • 带模拟的 Windows 身份验证
  • 不带模拟的 Windows 身份验证
  • 使用固定身份的 Windows 身份验证
  • 表单身份验证
  • Passport 身份验证 可用的授权选项

    下表列出了一组可用的授权选项。对于每个选项,该表都指出了是否需要 Windows 身份验证和/或模拟。如果特定授权选项不需要 Windows 身份验证,则该选项适用于所有其他的身份验证类型。可以使用该表优化身份验证/授权策略。
    表 8.1:Windows 身份验证和模拟要求

    授权选项 需要 Windows 身份验证 需要模拟
    FileAuthorizationModule
    UrlAuthorizationModule
    主体权限要求
    .NET 角色
    Enterprise Services 角色 是(在 ASP.NET Web 应用程序中)
    NTFS 权限(用于直接请求的静态文件类型;没有映射到 ISAPI 扩展的文件类型) 不适用 – ASP.NET 不处理这些文件。 在任何(非匿名)IIS 身份验证机制中,应为各个已验证的用户配置权限。  在匿名身份验证中,应为 IUSR_MACHINE 配置权限。 否(IIS 执行访问检查。)
    NTFS 权限(用于 Web 应用程序代码访问的文件) 否 如果使用模拟,请根据模拟的 Windows 标识配置 ACL,该标识可以是原调用方,也可以是 Web.config 中的 <identity> 元素指定的标识。*

    * 模拟的标识可以是原调用方,也可以是 Web.config 中的 <identity> 元素指定的标识。请看下面两个 <identity> 元素。

     

    <identity impersonate="true"/>
    <identity impersonate="true" userName="Bob" password="pwd" />

    第一种配置导致模拟原调用方(已由 IIS 验证了身份),而第二种配置导致模拟标识 Bob。由于以下两个原因,建议不要使用第二种配置:

    • 它要求您在 Microsoft Windows? 2000 操作系统上为 ASP.NET 进程标识授予“充当操作系统的一部分”权限。
    • 它还要求您在 Web.config 中包含纯文本密码。

    下一个 .NET 框架版本将取消这两个限制。

    带模拟的 Windows 身份验证

    以下配置元素向您显示了如何明确启用 Web.config 或 Machine.config 中的 Windows (IIS) 身份验证和模拟。


    注意:应根据每个应用程序的具体情况,在应用程序的 Web.config 文件中配置身份验证。

    <authentication mode="Windows" />
    <identity impersonate="true"/>

     

    在此配置中,ASP.NET 应用程序代码模拟已由 IIS 验证身份的调用方。

    可配置的安全设置

    当您将 Windows 身份验证和模拟功能一起使用时,就可以使用下列授权选项:

    Windows ACL

    • 客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用方的访问令牌和附加到请求资源的 ACL 以便执行访问检查。
      对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用方的访问令牌和附加到文件的 ACL 执行访问检查。
    • 应用程序访问的资源。可以根据原调用方,在应用程序访问的资源(文件、文件夹、注册表项和 Active Directory 对象等)上配置 Windows ACL。

    URL 授权 在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 的格式,并且角色与 Windows 组一一对应。

    <authorization>
    <deny user="DomainName\UserName" />
    <allow roles="DomainName\WindowsGroup" />
    </authorization>

    Enterprise Services (COM+) 角色。角色保存在 COM+ 目录中。可以使用“组件服务”管理工具或脚本配置角色。

    编程安全性
    编程安全性是指 Web 应用程序代码中的安全检查。在您使用 Windows 身份验证和模拟功能时,可以使用下列程序安全设置选项:

    PrincipalPermission 请求

    • 命令性(嵌入方法的代码内)
      PrincipalPermission permCheck = new PrincipalPermission(
      null, @"DomainName\WindowsGroup");
      permCheck.Demand();
    • 声明性(属性位于接口、类和方法之前)
      [PrincipalPermission(SecurityAction.Demand,
      Role=@"DomainName\WindowsGroup)]

    明确的角色检查 您可以使用 IPrincipal 接口执行角色检查。
    IPrincipal.IsInRole(@"DomainName\WindowsGroup");

    Enterprise Services (COM+) 角色 可以使用 ContextUtil 类以编程方式执行角色检查。ContextUtil.IsCallerInRole("Manager")


    何时使用

    使用 Windows 身份验证和模拟的情况:

    • 应用程序的用户已经有了可以由服务器验证的 Windows 帐户。
    • 您需要将原调用方的安全性上下文传递到 Web 应用程序的中间层和/或数据层以支持细分(每用户)授权。
    • 您需要将原调用方的安全性上下文传递到下游各层以支持操作系统级审核。

    在应用程序中使用模拟之前,确保将此方法与使用受信任的子系统模型进行比较,了解此方法的优缺点。第 3 章“身份验证和授权”中的“选择资源访问模型”详细阐述了这些内容。
    模拟的缺点包括:

    • 由于无法有效地对数据库连接进行池处理,因而降低了应用程序的可伸缩性。
    • 由于需要给各个用户配置后端资源的 ACL,因而增加了管理工作。
    • 委派需要 Kerberos 身份验证和进行适当配置的环境。

      更多信息

      • 有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。
      • 有关模拟的详细信息,请参见本章后面的“模拟”。
      • 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。
      • 有关 Enterprise Services (COM+) 角色的详细信息,请参见第 9 章“Enterprise Services 安全性”。
      • 有关 PrincipalPermission 要求的详细信息,请参见本指南“入门”部分的“主体”。

    不带模拟的 Windows 身份验证

    下列配置元素显示了如何在 Web.config 中明确声明启用不带模拟功能的 Windows (IIS) 身份验证。

    <authentication mode="Windows" />
    <!– The following setting is equivalent to having no identity element –>
    <identity impersonate="false"/>

    可配置的安全设置
    当您使用不带模拟的 Windows 身份验证时,可以使用以下授权选项:

    Windows ACL

    • 客户端请求的资源。ASP.NET FileAuthorizationModule 对映射到 ASP.NET ISAPI 的请求文件类型执行访问检查。它使用原调用方的访问令牌和附加到请求资源的 ACL 以便执行访问检查。模拟不是必需选项。
      对于静态文件类型(没有映射到 ISAPI 扩展),IIS 使用调用方的访问令牌和附加到文件的 ACL 执行访问检查。
    • 应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。

    URL 授权 在 Web.config 中配置 URL 授权。在 Windows 身份验证中,用户名采用 DomainName\UserName 的格式,并且角色与 Windows 组一一对应。
    <authorization>
    <deny user="DomainName\UserName" />
    <allow roles="DomainName\WindowsGroup" />
    </authorization>

    程序安全性
    可以使用下列编程安全选项:

    主体权限要求

    • 命令性
      PrincipalPermission permCheck = new PrincipalPermission(
      null, @"DomainName\WindowsGroup");
      permCheck.Demand();
    • 说明性
      [PrincipalPermission(SecurityAction.Demand,
      Role=@"DomainName\WindowsGroup")]

    明确的角色检查 您可以使用 IPrincipal 接口执行角色检查。
    IPrincipal.IsInRole(@"DomainName\WindowsGroup");

    何时使用
    使用不带模拟的 Windows 身份验证的情况:

    • 应用程序的用户已经有了可以由服务器验证的 Windows 帐户。
    • 需要使用固定标识来访问下游资源(例如数据库)以便支持连接池。

      更多信息

      • 有关 Windows 身份验证的详细信息,请参见本章后面的“Windows 身份验证”。
      • 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。
      • 有关 PrincipalPermission 要求的详细信息,请参见本指南“入门”部分的“主体”。

    使用固定标识的 Windows 身份验证

    Web.config 中的 <identity> 元素支持可选的用户名和密码属性,这样,您就可以为应用程序配置特定的固定标识以进行模拟。这显示在以下配置文件片段中。
    <identity impersonate="true" userName="DomainName\UserName"
    password="ClearTextPassword" />

    何时使用
    对于安全环境中的当前 .NET 框架版本(版本 1),由于以下两个原因,建议不要使用此方法:

    • 不应以纯文本形式将用户名和密码存储在配置文件中,尤其是存储在虚拟目录中的配置文件。
    • 在 Windows 2000 上,此方式将强制您授予 ASP.NET 进程帐户“充当操作系统的一部分”权限。一旦攻击者攻击 Web 应用程序进程,这将会降低 Web 应用程序的安全性并增加潜在的威胁。

    .NET 框架 1.1 版将在 Windows 2000 上提供此方案的改进版本:

    • 凭据将进行加密。
    • 登录将由 IIS 进程执行,这样 ASP.NET 就不需要“充当操作系统的一部分”权限了。

    表单身份验证

    以下配置元素显示了如何在 Web.config 中以声明方式启用表单身份验证。
    <authentication mode="Forms">
    <forms loginUrl="logon.aspx" name="AuthCookie" timeout="60" path="/">
    </forms>
    </authentication>

    可配置的安全设置
    在使用表单身份验证时,可以使用以下授权选项:

    Windows ACL

    • 客户端请求的资源。请求的资源需要 ACL 以允许对匿名 Internet 用户帐户进行读取访问。(在使用表单身份验证时,应该将 IIS 配置为允许匿名访问)。
      无法使用 ASP.NET 文件授权,因为它需要 Windows 身份验证。
    • 应用程序访问的资源。根据 ASP.NET 进程标识,在应用程序所访问的资源(文件、文件夹、注册表项和 Active Directory 对象)上配置 Windows ACL。

    URL 授权
    在 Web.config 中配置 URL 授权。在表单身份验证中,用户名的格式取决于自定义数据存储、SQL Server 数据库或 Active Directory。

    • 如果使用的是 SQL Server 数据存储:

      <authorization>
      <deny users="?" />
      <allow users="Mary,Bob,Joe" roles="Manager,Sales" />
      </authorization>

    • 如果使用 Active Directory 作为数据存储,则以 X.500 格式显示用户名和组名:

      <authorization>
      <deny users="someAccount@domain.corp.yourCompany.com" />
      <allow roles ="CN=Smith James,CN=FTE_northamerica,CN=Users,
      DC=domain,DC=corp,DC=yourCompany,DC=com" />
      </authorization>


    程序安全性

    可以使用下列编程安全选项:

    主体权限要求

    • 命令性

      PrincipalPermission permCheck = new PrincipalPermission(
      null, "Manager");
      permCheck.Demand();

    • 说明性

      [PrincipalPermission(SecurityAction.Demand,
      Role="Manager")]

    明确的角色检查 您可以使用 IPrincipal 接口执行角色检查。
    IPrincipal.IsInRole("Manager");

    何时使用
    表单身份验证最适合于 Internet 应用程序。如果出现以下情况,则应该使用表单身份验证:

    • 应用程序用户没有 Windows 帐户。
    • 您希望用户通过使用 HTML 表单输入凭据的方式登录到应用程序。

      更多信息

      • 有关表单身份验证的详细信息,请参见本章后面的“表单身份验证”。
      • 有关 URL 授权的详细信息,请参见本章后面的“URL 授权注意事项”。

    Passport 身份验证

    以下配置元素显示了如何在 Web.config 中以声明方式启用 Passport 身份验证。
    <authentication mode="Passport" />

    何时使用
    如果应用程序用户没有 Windows 帐户,并且您希望实现单次登录解决方案,则应该在 Internet 上使用 Passport 身份验证。如果用户以前使用 Passport 帐户在参与的 Passport 站点进行登录,则不必登录到使用 Passport 身份验证配置的站点。

    配置安全性

    本节说明配置 ASP.NET Web 应用程序安全性所需的实际步骤。图 8.3 中总结了这些情况。

    图 8.3 配置 ASP.NET 应用程序安全性

    配置 IIS 设置
    要配置 IIS 安全性,您必须执行以下步骤:

    1. (可选)安装 Web 服务器证书(如果需要 SSL 的话)。
      有关详细信息,请参见本指南的“参考”部分的“如何做:在 Web 服务器上设置 SSL”。
    2. 配置 IIS 身份验证。
    3. (可选)配置客户端证书映射(如果使用证书身份验证的话)。
      有关客户端证书映射的详细信息,请参见 Microsoft 知识库文章 Q313070“How to Configure Client Certificate Mappings in Internet Information Services (IIS) 5.0”(如何在 Internet 信息服务 (IIS) 5.0 中配置客户端证书映射)。
    4. 设置文件和文件夹的 NTFS 权限。IIS 和 ASP.NET FileAuthorizationModule 共同检查已验证用户(或匿名 Internet 用户帐户)是否具有访问所请求文件的必要权限(根据 ACL 设置)。

    配置 ASP.NET 设置
    应用程序级别配置设置保存在 Web.config 文件中,这些文件位于应用程序的虚拟根目录或者(可选)其他子文件夹中(这些设置有时可以覆盖父文件夹设置)。

    1. 配置身份验证。应该在应用程序虚拟根目录下的 Web.config 文件中基于每个应用程序对它进行设置(而不是在 Machine.config 中)。

    <authentication mode="Windows|Forms|Passport|None" />

    2. 配置模拟。默认情况下,ASP.NET 应用程序不使用模拟。应用程序使用配置的 ASP.NET 进程标识(通常为 ASPNET)运行,并且应用程序执行的所有资源访问都使用此标识。仅在以下情况下需要使用模拟:

    • 您使用 Enterprise Services 并且要使用 Enterprise Services (COM+) 角色授权访问服务组件所提供的功能。
    • 将 IIS 配置为使用匿名身份验证,而且要使用匿名 Internet 用户帐户进行资源访问。有关此方法的详细信息,请参见本章后面的“访问网络资源”。
    • 您需要将已验证用户的安全性上下文传递到下一层(例如数据库)。
    • 您已将传统的 ASP 应用程序移植到 ASP.NET,并且需要同样的模拟行为。默认情况下,传统 ASP 模拟调用方。

      要配置 ASP.NET 模拟,请在应用程序的 Web.config 中使用下面的 <identity> 元素。
      <identity impersonate="true"/>

    3. 配置授权。URL 授权确定用户或角色是否可以将特定的 HTTP 谓词(例如,GET、HEAD 和 POST)发送给特定的文件。要实现 URL 授权,请执行以下任务。

    a. 将 <authorization> 元素添加到应用程序虚拟根目录下的 Web.config 文件中。

    b. 使用 allow 和 deny 属性限制对用户和角色的访问。下面的示例摘自 Web.config,它使用 Windows 身份验证并允许 Bob 和 Mary 的访问,但拒绝其他人的访问。
    <authorization>
    <allow users="DomainName\Bob, DomainName\Mary" />
    <deny users="*" />
    </authorization>

    重要信息:您需要在 <authorization> 元素的结尾添加 <deny users="?"/> 或 <deny users="*"/>,否则将给所有已验证的标识授予访问权限。

    URL 授权注意事项
    在配置 URL 授权时,请注意以下几点:

    • "*" 指所有标识。
    • "?" 指未经过验证的标识(即匿名标识)。
    • 要使 URL 授权能够正常工作,并不需要进行模拟。
    • Web.config 中的授权设置通常适用于当前目录和所有子目录中的所有文件(除非子目录包含它自己的 Web.config,并且该文件包含 <authorization> 元素。在这种情况下,子目录中的设置覆盖父目录的设置)。

      注意:URL 授权只适用于由 IIS 映射到 ASP.NET ISAPI 扩展 (aspnet_isapi.dll) 的文件类型。

      可以使用 <location> 标记将授权设置应用于个别文件或目录。下面的示例显示了如何将授权应用于特定的文件 (Page.aspx)。

      <location path="page.aspx" />
      <authorization>
      <allow users="DomainName\Bob, DomainName\Mary" />
      <deny users="*" />
      </authorization>
      </location>

    • 用于 URL 授权的用户和角色是由身份验证设置决定的:
      • 如果设置了 <authentication mode=”Windows” />,则给 Windows 用户和组帐户授予访问权限。
        用户名采用“DomainName\WindowsUserName”的格式
        角色名采用“DomainName\WindowsGroupName”的格式

        注意:本地管理员组称为“BUILTIN\Administrators”。本地用户组称为“BUILTIN\Users”。

      • 如果设置了 <authentication mode=”Forms” />,则根据存储在当前 HTTP 上下文中的 IPrincipal 对象的用户和角色进行授权。例如,如果使用表单身份验证根据数据库验证用户的身份,则根据从数据库中检索的角色进行授权。
      • 如果设置了 <authentication mode=”Passport” />,则根据从存储中检索的 Passport 用户 ID (PUID) 或角色进行授权。例如,可以将 PUID 映射到特定的帐户和在 SQL Server 数据库或 Active Directory 中存储的一组角色。

        注意:此功能将被内置到 Microsoft Windows Server 2003 操作系统中。

      • 如果设置了 <authentication mode=”None” />,则不能执行授权。“None”指定您不想执行任何身份验证,或者不想使用任何 .NET 身份验证模块,而是使用您自己的自定义机制。
        但是,如果使用自定义身份验证,则应创建具有角色的 IPrincipal 对象,并将其存储到 HttpContext.User 中。在随后执行 URL 授权时,将根据 IPrincipal 对象中保存的用户和角色(无论以何种方式检索它们)执行授权。

    URL 授权示例
    下面的列表列出了一些典型 URL 授权示例的语法:

    • 拒绝匿名帐户的访问
      <deny users="?" />
    • 拒绝所有用户的访问
      <deny users="*" />
    • 拒绝 Manager 角色的访问
      <deny roles="Manager"/>
    • 表单身份验证示例
      <configuration>
      <system.web>
      <authentication mode="Forms">
      <forms name=".ASPXUSERDEMO"
      loginUrl="login.aspx"
      protection="All" timeout="60" />
      </authentication>
      <authorization>
      <deny users="jdoe@somewhere.com" />
      <deny users="?" />
      </authorization>
      </system.web>
      </configuration>


    更多信息

    <authorization> 元素可用于存储在 HttpContext.User 和 HttpContext.Request.RequestType 中的当前 IPrincipal 对象。

    保护资源

    1. 使用 Windows ACL 保护资源,包括文件、文件夹和注册表项。
    如果不使用模拟,则应用程序需要访问的任何资源的 ACL 必须给 ASP.NET 进程帐户至少授予读取访问权限。
    如果使用模拟,文件和注册表项的 ACL 必须给已验证用户(或匿名 Internet 用户帐户,如果匿名身份验证生效的话)至少授予读取访问权限。

    2. 保护 Web.config 和 Machine.config:

    使用正确的 ACL 如果 ASP.NET 使用模拟,则模拟的标识需要读取访问权限。否则,ASP.NET 进程标识需要读取访问权限。对 Web.config 和 Machine.config 使用以下 ACL。
    系统:完全控制
    管理员:完全控制
    进程标识或模拟的标识:读取
    如果没有模拟匿名 Internet 用户帐户 (IUSR_MACHINE),则应该拒绝该帐户的访问。

    注意:如果将应用程序映射到 UNC 共享,则 UNC 标识也需要读取配置文件的访问权限。

    删除不需要的 HTTP 模块 Machine.config 包含一组默认的 HTTP 模块(在 <httpModules> 元素内)。它们包括:

    • WindowsAuthenticationModule
    • FormsAuthenticationModule
    • PassportAuthenticationModule
    • UrlAuthorizationModule
    • FileAuthorizationModule
    • OutputCacheModule
    • SessionStateModule

    如果应用程序没有使用特定的模块,请将其删除,以免将来在应用程序中出现与该模块有关的任何潜在安全问题。

    3. (可选)将 <location> 元素与 allowOverride="false" 属性一起使用以锁定配置设置(如下所示)。

    锁定配置设置

    配置设置是分层的。子目录中的 Web.config 文件设置覆盖父目录中的 Web.config 设置。另外,Web.config 设置覆盖 Machine.config 设置。
    通过将 <location> 元素与 allowOverride 属性一起使用,可以锁定配置设置以防止它们被低级别的设置覆盖。例如:

    <location path="somepath" allowOverride="false" />
    . . . arbitrary configuration settings . . .
    </location>

    请注意,路径可以指 Web 站点或虚拟目录,并且它适用于指定的目录和所有子目录。如果将 allowOverride 设置为 false,则可以防止任何低级别的配置文件覆盖 <location> 元素中指定的设置。锁定配置设置的功能适用于所有设置类型,而不是仅限于安全设置(如身份验证模式)。

    禁止下载文件

    可以使用 HttpForbiddenHandler 类禁止通过 Web 下载某些文件类型。该类由 ASP.NET 在内部使用以禁止下载某些系统级别文件(例如,包括 web.config 在内的配置文件)。有关可用这种方法进行限制的文件类型的完整列表,请参见 machine.config 中的 <httpHandlers> 节。
    对于应用程序在内部使用但不能进行下载的文件,应考虑使用 HttpForbiddenHandler。

    注意:还必须使用 Windows ACL 来保护文件,控制哪些用户在登录到 Web 服务器上时可以访问这些文件。

    使用 HttpForbiddenHandler 禁止下载特定的文件类型

    • 在 IIS 中为指定的文件类型创建应用程序映射,以便将其映射到 Aspnet_isapi.dll。

      a. 在任务栏上,依次单击“开始”按钮、“程序”、“管理工具”,然后选择“Internet 信息服务”。
      b. 选择应用程序的虚拟目录,右击,然后单击“属性”。
      c. 选择“应用程序设置”,然后单击“配置”。
      d. 单击“添加”以创建新的应用程序映射。
      e. 单击“浏览”,然后选择 c:\winnt\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll。
      f. 在“扩展名”字段中输入要禁止下载的文件类型的扩展名(例如 .abc)。
      g. 确保选中“所有谓词”和“脚本引擎”,并且没有选中“检查文件是否存在”。
      h. 单击“确定”关闭“添加/编辑应用程序扩展映射”对话框。
      i 单击“确定”关闭“应用程序配置”对话框,然后再单击“确定”关闭“属性”对话框。

    • 在 Web.config 中,为指定的文件类型添加 <HttpHandler> 映射。
      下面显示了一个 .abc 文件类型的示例。

      <httpHandlers>
      <add verb="*" path="*.abc"
      type="System.Web.HttpForbiddenHandler"/>
      </httpHandlers>

    安全通信
    结合使用 SSL 和 Internet 协议安全 (IPSec) 以保护通信链路。

    详细信息

    • 有关使用 SSL 保护数据库服务器链路的信息,请参见“如何做:使用 SSL 来确保与 SQL Server 2000 安全通信”。
    • 有关在两台计算机之间使用 IPSec 的信息,请参见“如何做:使用 IPSec 以便在两台服务器之间安全通信”。


    编程安全性

    在确定 Web 应用程序可配置的安全设置后,您需要以编程方式进一步改进和优化应用程序的授权策略。这包括在程序集中使用说明性的 .NET 属性,以及在代码中执行命令性的授权检查。
    本节重点介绍在 ASP.NET Web 应用程序中执行授权所需的主要编程步骤。

    授权模式
    下面总结了在 Web 应用程序中对用户进行授权的基本模式:
    1. 检索凭据
    2. 验证凭据
    3. 将用户放到角色中
    4. 创建一个 IPrincipal 对象
    5. 将 IPrincipal 对象放到当前的 HTTP 上下文中
    6. 基于用户标识/角色成员身份进行授权
    重要信息:如果配置了 Windows 身份验证,则 ASP.NET 自动执行步骤 1 到 5。对于其他身份验证机制(表单、Passport 和自定义方法),您必须编写代码以执行这些步骤(如下所示)。

    检索凭据
    首先,必须从用户检索一组凭据(用户名和密码)。如果应用程序没有使用 Windows 身份验证,则需要确保使用 SSL 在网络上正确保护明文凭据。

    验证凭据
    如果配置了 Windows 身份验证,则操作系统的基本服务就会自动对凭据进行验证。
    如果使用其他身份验证机制,则必须编写代码以根据数据存储(如 SQL Server 数据库或 Active Directory)对凭据进行验证。
    有关如何将用户凭据安全地存储在 SQL Server 数据库中的详细信息,请参见第 12 章“数据访问安全性”中的“对数据库进行用户身份验证”。

    将用户放到角色中

    用户数据存储还应包含每个用户的角色列表。必须编写代码以检索已验证用户的角色列表。

    创建一个 IPrincipal 对象
    授权是针对已验证用户进行的,这些用户的标识和角色列表保存在 IPrincipal 对象中(该对象在当前 Web 请求的上下文中传递)。
    如果配置了 Windows 身份验证,则 ASP.NET 自动构造 WindowsPrincipal 对象。该对象包含已验证用户的标识以及角色列表(它等同于用户所属的 Windows 组列表)。
    如果使用的是表单、Passport 或自定义身份验证,则必须在 Global.asax 的 Application_AuthenticateRequest 事件处理程序中编写代码以创建 IPrincipal 对象。GenericPrincipal 类是由 .NET 框架提供的,在大多数情况下应该使用该类。

    将 IPrincipal 对象放到当前的 HTTP 上下文中
    将 IPrincipal 对象附加到当前的 HTTP 上下文中(使用 HttpContext.User 变量)。如果使用 Windows 身份验证,则 ASP.NET 自动完成此任务。否则,您必须手动附加该对象。

    基于用户标识和/或角色成员身份进行授权
    如果应用程序需要更细分的授权逻辑,请在代码中以声明方式(获取类或方法级授权)或命令性方式使用 .NET 角色。
    可以使用说明性或命令性用户权限要求(使用 PrincipalPermission 类),也可以通过调用 IPrincipal.IsInRole() 方法执行明确的角色检查。
    下面的示例采用 Windows 身份验证并显示了说明性主体权限要求。仅当已验证用户是 Manager Windows 组的成员时,才执行该属性后面的方法。如果调用方不是该组的成员,就会发生 SecurityException。

    [PrincipalPermission(SecurityAction.Demand,
    Role=@"DomainName\Manager")]
    public void SomeMethod()
    {
    }

    下面的示例显示了代码中的明确角色检查。该示例采用 Windows 身份验证。如果使用非 Windows 身份验证机制,则代码基本上是一样的。只是将 User 对象转换为 GenericPrincipal 对象,而不是 WindowsPrincipal 对象。

    // Extract the authenticated user from the current HTTP context.
    // The User variable is equivalent to HttpContext.Current.User if you are using // an .aspx or .asmx page
    WindowsPrincipal authenticatedUser = User as WindowsPrincipal;
    if (null != authenticatedUser)
    {
    // Note: To retrieve the authenticated user’s username, use the
    // following line of code
    // string username = authenticatedUser.Identity.Name;

    // Perform a role check
    if (authenticatedUser.IsInRole(@"DomainName\Manager") )
    {
    // User is authorized to perform manager functionality
    }
    }
    else
    {
    // User is not authorized to perform manager functionality
    }

    更多信息
    有关以上表单身份验证模式的实际实现,请参见本章后面的“表单身份验证”部分。

    创建自定义 IPrincipal 类
    当使用非 Windows 身份验证机制时,大多数情况下应使用.NET 框架提供的 GenericPrincipal 类。它使用 IPrincipal.IsInRole 方法提供角色检查。
    有时,您可能需要实现您自己的 IPrincipal 类。实现您自己的 IPrincipal 类的原因包括:

    • 您想扩展角色检查的功能。您可能需要一些方法来使您能够检查某一特定用户是否是一个多角色成员。例如:CustomPrincipal.IsInAllRoles( "Role", "Role2", "Role3" )
      CustomPrincipal.IsInAnyRole( "Role1", "Role2", "Role3" )
    • 您可能需要实现一个额外的方法或属性,以数组形式返回角色列表。例如:string[] roles = CustomPrincipal.Roles;
    • 您想让应用程序强制实施角色分级逻辑。例如,高级管理员被认为在层次结构中高于普通管理员。可以用类似下面所示的方法进行测试。
      CustomPrincipal.IsInHigherRole("Manager");
      CustomPrincipal.IsInLowerRole("Manager");
    • 您可能需要实现惰性的角色列表初始化。例如,只有在需要进行角色检查时,才能动态加载角色列表。
    • 您可能需要实现 IIdentity 接口以使用 X509ClientCertificate 标识的用户。例如:
      CustomIdentity id = CustomPrincipal.Identity;
      X509ClientCertificate cert = id.ClientCertificate;

      更多信息
      有关创建您自己的 IPrincipal 类的详细信息,请参见本指南“参考”部分的“如何做:实现自定义 IPrincipal 类”。

    Windows 身份验证

    如果应用程序用户使用可由服务器进行身份验证的 Windows 帐户(例如,在 Intranet 方案中),请使用 Windows 身份验证。
    如果将 ASP.NET 配置为使用 Windows 身份验证,则 IIS 使用配置的 IIS 身份验证机制执行用户身份验证。图 8.4 中显示了这种情况。

    图 8.4 ASP.NET Windows 身份验证使用 IIS 验证调用方的身份

    已验证调用方(如果将 IIS 配置为使用匿名身份验证,则它可能是匿名 Internet 用户帐户)的访问令牌可供 ASP.NET 应用程序使用。请注意以下方面:

    • 这将允许 ASP.NET FileAuthorizationModule 使用原调用方的访问令牌,对请求的 ASP.NET 文件执行访问检查。
      重要信息:ASP.NET 文件授权只对映射到 Aspnet_isapi.dll 的文件类型执行访问检查。
    • 文件授权不要求使用模拟。如果启用了模拟,则应用程序执行的所有资源访问均使用被模拟的调用方的标识。在这种情况下,请确保附加到资源上的 ACL 包含一个访问控制项 (ACE),它可给原调用方标识至少授予读取访问权限。

    标识已验证身份的用户
    ASP.NET 将 WindowsPrincipal 对象与当前的 Web 请求关联起来。这包含已验证身份的 Windows 用户的标识以及该用户所属的角色列表。在 Windows 身份验证中,角色列表是由用户所属的 Windows 组集组成的。
    以下代码显示如何获取已验证 Windows 用户的标识,以及如何执行简单的角色授权测试。

    WindowsPrincipal user = User as WindowsPrincipal;
    if (null != user)
    {
    string username = user.Identity.Name;
    // Perform a role check
    if ( user.IsInRole(@"DomainName\Manager") )
    {
    // User is authorized to perform manager functionality
    }
    }
    else
    {
    // Throw security exception as we don’t have a WindowsPrincipal
    }


    表单身份验证

    当使用表单份验证时,如果未验证身份的用户试图访问受保护的文件或资源(其中,URL 授权拒绝用户访问),该用户所触发的事件顺序如图 8.5 所示。

    图 8.5 表单身份验证的事件顺序

    下面说明了图 8.5 中显示的事件顺序:

    1. 用户发出一个针对 Default.aspx 的 Web 请求。
      由于启用了匿名访问,因此 IIS 允许进行此类请求。ASP.NET 检查 <authorization> 元素并查找 <deny users=?”/> 元素。
    2. 将用户重定向到由 <forms> 元素的 LoginUrl 属性指定的登录页 (Login.aspx)。
    3. 用户提供凭据并提交登录表单。
    4. 根据数据存储(SQL Server 或 Active Directory)验证凭据,并检索角色(可选)。如果要使用基于角色的授权,则必须检索角色列表。
    5. 使用 FormsAuthenticationTicket 创建一个 Cookie 并将其发回到客户端。将角色存储到票中(可选)。通过在票中存储角色列表,可以避免为相同用户的每个后续 Web 请求访问数据库重新检索列表。
    6. 客户端重定向将用户重定向到原请求页 (Default.aspx)。
    7. 在 Application_AuthenticateRequest 事件处理程序(在 Global.asax 中)中,使用票创建 IPrincipal 对象并将其存储在 HttpContext.User 中。
      ASP.NET 检查 <authorization> 元素并查找 <deny users=?”/> 元素。但是,此时对用户进行身份验证。
      ASP.NET 检查 <authorization> 元素以确保用户在 <allow> 元素中。
      给用户授予访问 Default.aspx 的权限。

    表单身份验证的开发步骤
    以下列表重点介绍了实现表单身份验证时必须执行的主要步骤:
    1. 将 IIS 配置为使用匿名访问。
    2. 将 ASP.NET 配置为使用表单身份验证。
    3. 创建登录 Web 表单并验证提供的凭据。
    4. 从自定义数据存储中检索角色列表。
    5. 创建表单身份验证票(在票中存储角色)。
    6. 创建一个 IPrincipal 对象。
    7. 将 IPrincipal 对象放到当前的 HTTP 上下文中。
    8. 基于用户名/角色成员身份对用户进行授权。

    将 IIS 配置为使用匿名访问

    必须在 IIS 中将应用程序的虚拟目录配置为使用匿名访问。

    将 IIS 配置为使用匿名访问
    1. 启动 Internet 信息服务管理工具。
    2. 选择应用程序的虚拟目录,右击,然后单击“属性”。
    3. 单击“目录安全性”。
    4. 在“匿名访问和验证控件”组中,单击“编辑”。
    5. 选择“匿名访问”。

    将 ASP.NET 配置为使用表单身份验证
    下面显示了一个配置示例。
    <authentication mode="Forms">
    <forms name="MyAppFormsAuth"
    loginUrl="login.aspx"
    protection="Encryption"
    timeout="20"
    path="/" >
    </forms>
    </authentication>

    创建登录 Web 表单并验证提供的凭据
    根据 SQL Server 数据库或 Active Directory 验证凭据。

    更多信息

    • 请参见本指南“参考”部分的“如何做:将表单身份验证用于 SQL Server 2000”。
    • 请参见本指南“参考”部分的“如何做:将表单身份验证用于 Active Directory”。

    从自定义数据存储中检索角色列表
    从 SQL Server 数据库表中获取角色,或从 Active Directory 内配置的组/分发列表中获取角色。有关详细信息,请参考前面的资源。

    创建表单身份验证票
    在票中存储检索到的角色。下面的代码阐释了此过程。

    // This event handler executes when the user clicks the Logon button
    // having supplied a set of credentials
    private void Logon_Click(object sender, System.EventArgs e)
    {
    // Validate credentials against either a SQL Server database
    // or Active Directory
    bool isAuthenticated = IsAuthenticated( txtUserName.Text,
    txtPassword.Text );
    if (isAuthenticated == true )
    {
    // Retrieve the set of roles for this user from the SQL Server
    // database or Active Directory.The roles are returned as a
    // string that contains pipe separated role names
    // for example "Manager|Employee|Sales|"
    // This makes it easy to store them in the authentication ticket

    string roles = RetrieveRoles( txtUserName.Text, txtPassword.Text );

    // Create the authentication ticket and store the roles in the
    // custom UserData property of the authentication ticket
    FormsAuthenticationTicket authTicket = new
    FormsAuthenticationTicket(
    1, // version
    txtUserName.Text, // user name
    DateTime.Now, // creation
    DateTime.Now.AddMinutes(20),// Expiration
    false, // Persistent
    roles ); // User data
    // Encrypt the ticket.
    string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
    // Create a cookie and add the encrypted ticket to the
    // cookie as data.
    HttpCookie authCookie =
    new HttpCookie(FormsAuthentication.FormsCookieName,
    encryptedTicket);

    // Add the cookie to the outgoing cookies collection.
    Response.Cookies.Add(authCookie);
    // Redirect the user to the originally requested page
    Response.Redirect( FormsAuthentication.GetRedirectUrl(
    txtUserName.Text,
    false));
    }
    }

    创建一个 IPrincipal 对象
    在 Global.asax 内的 Application_AuthenticationRequest 事件处理程序中创建 IPrincipal 对象。除非您需要基于角色的扩展功能,否则,请使用 GenericPrincipal 类。在这种情况下,创建一个实现 IPrincipal 的自定义类。

    将 IPrincipal 对象放到当前的 HTTP 上下文中
    GenericPrincipal 对象的创建过程如下所示。

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
    // Extract the forms authentication cookie
    string cookieName = FormsAuthentication.FormsCookieName;
    HttpCookie authCookie = Context.Request.Cookies[cookieName];
    if(null == authCookie)
    {
    // There is no authentication cookie.
    return;
    }
    FormsAuthenticationTicket authTicket = null;
    try
    {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch (Exception ex)
    {
    // Log exception details (omitted for simplicity)
    return;
    }
    if (null == authTicket)
    {
    // Cookie failed to decrypt.
    return;
    }
    // When the ticket was created, the UserData property was assigned a
    // pipe delimited string of role names.
    string[] roles = authTicket.UserData.Split(new char[]{‘|’});

    // Create an Identity object
    FormsIdentity id = new FormsIdentity( authTicket );
    // This principal will flow throughout the request.
    GenericPrincipal principal = new GenericPrincipal(id, roles);
    // Attach the new principal object to the current HttpContext object
    Context.User = principal;
    }

    基于用户名或角色成员身份对用户进行授权
    使用说明性的主体权限要求来限制对方法的访问。使用命令性主体权限要求和/或明确角色检查 (IPrincipal.IsInRole) 在方法中执行细分的授权。

    表单实现原则

    • 当使用 HTML 表单捕获凭据时,请使用 SSL。
      无论何时通过网络发送凭据或身份验证 Cookie,除了对登录页使用 SSL 外,还应该对其他页使用 SSL。这样,可以减轻与 Cookie 重播攻击相关的威胁。
    • 根据自定义数据存储验证用户的身份。请使用 SQL Server 或 Active Directory。
    • 从自定义数据存储中检索角色列表,并在 FormsAuthenticationTicket 类的 UserData 属性中存储分隔的角色列表。这样,不必为每个 Web 请求重复访问数据存储,从而提高了性能;而且还免去了在身份验证 Cookie 中存储用户凭据的麻烦。
    • 如果角色列表很大并且有超过 Cookie 大小限制的危险,请在 ASP.NET 缓存对象或数据库中存储角色的详细信息,并在每个后续请求中检索这些信息。
    • 对于初始身份验证后的每个请求:
      • 在 Application_AuthenticateRequest 事件处理程序中,从票中检索角色。
      • 创建一个 IPrincipal 对象并将其存储在 HTTP 上下文 (HttpContext.User) 中。.NET 框架还将其与当前 .NET 线程 (Thread.CurrentPrincipal) 关联起来。
      • 除非您有特殊的原因需要创建自定义的 IPrincipal 实现(例如,支持基于角色的增强操作),否则请使用 GenericPrincipal 类。
    • 使用两种 Cookie:一种用于个性化,另一种用于安全的身份验证和授权。将个性化 Cookie 作为永久性的 Cookie(确保它不包含允许请求执行受限操作的信息;例如在站点中的安全部分下订单)。
    • 对于每个 Web 应用程序,请使用单独的 Cookie 名称(使用 <forms> 元素的 Forms 属性)和路径。如果针对某个应用程序验证了用户的身份,这可确保在使用同一 Web 服务器承载的第二个应用程序时,不会将这些用户作为已验证的用户处理。
    • 确保在客户端浏览器中启用 Cookie。对于不需要 Cookie 的表单身份验证方法,请参见本章后面的“无 Cookie 表单身份验证”。

      更多信息

      • 请参见本指南“参考”部分的“如何做:将表单身份验证用于 SQL Server 2000”。
      • 请参见本指南“参考”部分的“如何做:将表单身份验证用于 Active Directory”。
      • 请参见本指南“参考”部分的“如何做:将表单身份验证用于 GenericPrincipal 对象”。

    承载多个使用表单身份验证的应用程序
    如果在同一 Web 服务器上承载多个使用表单身份验证的 Web 应用程序,在某一应用程序中已验证身份的用户可以请求另一个应用程序,而无需重定向到该应用程序的登录页。第二个应用程序中的 URL 授权规则可能会拒绝该用户的访问,而不会提供使用登录表单提供登录凭据的机会。
    仅在以下情况下发生这种情况:多个应用程序的 <forms> 元素的名称和路径属性是相同的,而且每个应用程序在 Web.config 中使用相同的 <machineKey> 元素。

    更多信息
    有关此问题的详细信息以及解决方法,请参见以下知识库文章:

    • Q313116“PRB: Forms Authentication Requests Are Not Directed to loginUrl Page(PRB:没有将表单身份验证请求定向到 loginUrl 页)”
    • Q310415“PRB: Mobile Forms Authentication and Different Web Applications(PRB:移动表单身份验证和各种 Web 应用程序)”

    无 Cookie 表单身份验证
    如果您需要无 Cookie 表单身份验证解决方案,请考虑使用 Microsoft Mobile Internet Toolkit 所使用的方法。移动表单身份验证建立在表单身份验证之上,但使用查询字符串来传递身份验证票而不是使用 Cookie 。

    更多信息
    有关移动表单身份验证的详细信息,请参见 Microsoft 知识库文章 Q311568“INFO: How To Use Mobile Forms Authentication with Microsoft Mobile Internet Toolkit(INFO:如何将移动表单身份验证用于 Microsoft Mobile Internet Toolkit)”。


    Passport
    身份验证

    如果应用程序用户使用 Passport 帐户,而且您要在其他支持 Passport 的站点上实现单次登录解决方案,则应使用 Passport 身份验证。
    当将 ASP.NET 配置为使用 Passport 身份验证时,就会提示用户登录并将该用户重定向到 Passport 站点。在成功验证了凭据后,就会将用户重定向回您的站点。

    将 ASP.NET 配置为使用 Passport 身份验证
    要将 ASP.NET 配置为使用 Passport 身份验证,请使用以下 Web.config 设置。

    <authentication mode="Passport">
    <passport redirectUrl="internal" />
    </authentication>
    <authorization>
    <deny users="?" />
    <allow users="*" />
    </authorization>

    将 Passport 标识映射为 Global.asax 中的角色
    要将 Passport 标识映射为角色,按如下所示在 Global.asax 中实现 PassportAuthentication_OnAuthentication 事件处理程序。

    void PassportAuthentication_OnAuthenticate(Object sender,
    PassportAuthenticationEventArgs e)
    {
    if(e.Identity.Name == "0000000000000001")
    {
    string[] roles = new String[]{"Developer", "Admin", "Tester"};
    Context.User = new GenericPrincipal(e.Identity, roles);
    }
    }

    测试角色成员身份
    以下代码片段显示了如何在 aspx 页中检索已验证身份的 Passport 标识和检查角色成员身份。

    PassportIdentity passportId = Context.User.Identity as PassportIdentity;
    if (null == passportId)
    {
    Response.Write("Not a PassportIdentity<br>");
    return;
    }
    Response.Write("IsInRole: Develeoper?" + Context.User.IsInRole("Developer"));


    自定义身份验证

    如果 .NET 框架提供的身份验证模块均不能满足您的确切身份验证需要,则可以使用自定义身份验证并实现您自己的身份验证机制。例如,您的公司可能已经制订了一个可由其他应用程序广泛使用的自定义身份验证策略。
    要在 ASP.NET 中实现自定义身份验证,请执行下列操作:

    • 按如下所示在 Web.config 中配置身份验证模式。这将通知 ASP.NET 不要调用它的任何内置身份验证模块。
      <authentication mode="None" />
    • 创建实现 System.Web.IHttpModule 接口的类以创建自定义的 HTTP 模块。此模块应该挂钩到 HttpApplication.AuthenticateRequest 事件中,并在要求身份验证时对每个应用程序请求提供要调用的委派。
      身份验证模块必须:
      • 从调用方获取凭据。
      • 根据存储验证凭据。
      • 创建一个 IPrincipal 对象并将其存储在 HttpContext.User 中。
      • 创建并保护已验证身份的令牌,并将其发回到用户(通常在查询字符串、Cookie 或隐藏的表单字段中)。
      • 在后续请求中获取身份验证令牌,对它进行验证,然后重新分发。

      更多信息
      有关如何实现自定义 HTTP 模块的详细信息,请参见 Microsoft 知识库文章 Q307996“HOW TO: Create an ASP.NET HTTP Module Using Visual C# .NET(如何做:使用 Visual C# .NET 创建 ASP.NET HTTP 模块)”。


    ASP.NET
    的进程标识

    使用权限最少的帐户运行 ASP.NET(具体来说就是 Aspnet_wp.exe 辅助进程)。

    使用权限最少的帐户
    使用权限最少的帐户可以减少与进程攻击相关的威胁。如果某个顽固的攻击者设法破坏了运行 Web 应用程序的 ASP.NET 进程,则这些应用程序可以轻易地继承和使用给该进程帐户授予的特权和访问权限。配置为权限最少的帐户可以限制可能的潜在危害。

    避免作为 SYSTEM 运行
    不要使用高权限的 SYSTEM 帐户来运行 ASP.NET,也不要给 ASP.NET 进程帐户授予“充当操作系统的一部分”权限。您可能很想使用其中的一种方法,通过代码调用 LogonUser API 以获取固定的标识(通常用于网络资源访问)。有关替代方法,请参见本章后面的“访问网络资源”。
    不要以 SYSTEM 的身份运行或不授予“充当操作系统的一部分”权限的原因包括:

    • 当系统遭到攻击时,它会大大增加攻击者所造成的危害,但不能增加防范攻击的能力。
    • 它破坏了最少权限原则。已将 ASPNET 帐户明确配置为运行 ASP.NET Web 应用程序使用的权限最少的帐户。

      更多信息
      有关“充当操作系统的一部分”权限的详细信息,请参见 1999 年 8 月的 Microsoft Systems Journal 专栏文章 Security Briefs。

    域控制器和 ASP.NET 进程帐户
    一般情况下,不建议在域控制器上运行 Web 服务器,因为对服务器的攻击就是对域的攻击。正如 Microsoft 知识库文章 Q315158“BUG: ASP.NET Does Not Work with the Default ASPNET Account on a Domain Controller(BUG:在域控制器上 ASP.NET 不能使用默认 ASPNET 帐户)”中所概述的,如果需要在域控制器上运行 ASP.NET,则需要给 ASP.NET 进程帐户授予相应的权限。

    使用默认 ASPNET 帐户
    已将本地 ASPNET 帐户明确配置为使用尽可能最少的权限集运行 ASP.NET Web 应用程序。如果可能,尽量使用 ASPNET。
    正如 Machine.config 中的 <processModel> 元素所配置的一样,默认情况下,ASP.NET Web 应用程序使用此帐户运行。
    <processModel userName="machine" password="AutoGenerate" />


    注意:machine 用户名表示 ASPNET 帐户。当安装 .NET 框架时,使用加密型强密码创建该帐户。除了在安全帐户管理器 (SAM) 数据库中进行配置外,还将密码存储在本地计算机上的本地系统授权 (LSA) 中。当系统启动 ASP.NET 辅助进程时,系统就会从 LSA 中检索密码。

    如果应用程序访问网络资源,则 ASPNET 帐户必须能够由远程计算机验证身份。您有两种选择:

    • 将 ASPNET 帐户的密码重置为某个已知值,然后在远程计算机上创建一个重复帐户(具有相同的名称和密码)。在以下情况下,此方法是唯一的选择:
      • Web 服务器和远程计算机位于单独的域中,并且域之间没有信任关系。
      • Web 服务器和远程计算机由防火墙隔开,而且您不想打开支持 Windows 身份验证所需的端口。
    • 如果您主要关心管理简便性问题,请使用权限最少的域帐户。
      要避免必须手动更新和同步密码,可以使用权限最少的域帐户运行 ASP.NET。一定要完全锁定域帐户以减轻进程攻击的威

      。如果某个攻击者设法攻击了 ASP.NET 辅助进程,则他或她可以访问域资源,除非该帐户已完全锁定。
      注意:如果您使用本地帐户而且该帐户已被攻击,则唯一遭受攻击的计算机是您在上面创建重复帐户的计算机。如果您使用域帐户,则该帐户对域中的每台计算机都是可见的。但是,该帐户仍然需要拥有访问这些计算机的权限。

    <processModel> 元素
    Machine.config 文件中的 <processModel> 元素包含 userName 和 password 属性,这些属性指定应该使用哪些帐户来运行 ASP.NET 辅助进程 (Aspnet_wp.exe)。您可以使用多种方法来配置此设置。例如:

    • "machine"。辅助进程作为最少权限的默认 ASPNET 帐户运行。此帐户拥有网络访问权限,但不能在网络上的任何其他计算机上验证该帐户的身份,因为此帐户是计算机的本地帐户,并且没有颁发机构担保此帐户。在网络上,此帐户表示为“MachineName\ASPNET”。
    • "system"。辅助进程作为本地 SYSTEM 帐户运行。此帐户在本地计算机上具有广泛的权限,而且还能够使用计算机的凭据访问网络。在网络上,此帐户表示为“DomainName\MachineName$”。
    • 特定凭据。当您为 userName 和 password 提供凭据时,请记住最少权限原则。如果您指定本地帐户,则在网络上不能对 Web 应用程序进行身份验证,除非您在远程计算机上创建重复帐户。如果您选择使用权限最少的域帐户,请确保它仅有权访问网络上所需的计算机。
      在 .NET 框架 1.1 版中,您可以在注册表中存储已加密的 userName 和 password 属性。

      注意:与传统 ASP 应用程序的运行方式相比,ASP.NET 代码从不在 dllhost.exe 进程中运行或作为 IWAM_MACHINENAME 帐户运行,即使在 IIS 中将应用程序保护级别设置为“高(独立)”。
      发送到 IIS 的 ASP.NET 请求被直接路由到 ASP.NET 辅助进程 (Aspnet_wp.exe)。ASP.NET ISAPI 扩展 Aspnet_isapi.dll 在 IIS (Inetinfo.exe) 进程地址空间中运行。(这是由 InProcessIsapiApps 元数据库项控制的;不要修改该元数据库项)。ISAPI 扩展负责将请求路由到 ASP.NET 辅助进程。然后,ASP.NET 应用程序在 ASP.NET 辅助进程中运行,其中应用程序域提供隔离边界。
      在 IIS 6 中,您可以通过配置应用程序池来隔离 ASP.NET 应用程序,其中每个池都有自己的应用程序实例。

    更多信息

    • 有关从 ASP.NET Web 应用程序访问网络资源的详细信息,请参见本章后面的“访问网络资源”。
    • 有关如何创建用于运行 ASP.NET 的自定义帐户的详细信息,请参见本指南“参考”部分的“如何做:创建自定义帐户以便运行 ASP.NET”。


    模拟

    随着 FileAuthorizationModule 的引入以及有效地使用关守和信任边界,模拟技术在 ASP.NET 中现在看来是弊大于利。

    模拟和本地资源
    如果使用模拟并且从 Web 应用程序代码访问本地资源,则必须配置附加到每个受保护资源的 ACL,以包含一个至少给已验证用户授予读取访问权限的 ACE。
    更好的方法是避免使用模拟,将权限授予 ASP.NET 进程帐户,并使用 URL 授权、文件授权以及基于角色的说明性和命令性检查组合。

    模拟和远程资源
    如果您使用模拟,然后从 Web 应用程序代码访问远程资源,则除非您使用基本身份验证、表单身份验证或 Kerberos 身份验证,否则访问将会失败。如果您使用 Kerberos 身份验证,则必须将用户帐户相应地配置为使用委派。在 Active Directory 中,必须将它们标记为“敏感帐户,不能被委派”。

    更多信息
    有关如何配置 Kerberos 委派的详细信息,请参见:

    • 第 5 章“Intranet 安全性”中的“将原调用方传递到数据库”。
    • 本指南“参考”部分的“如何做:对 Windows 2000 实现 Kerberos 委派”。

    模拟和线程
    如果某个正在模拟的线程创建了一个新线程,则该新线程将继承 ASP.NET 进程帐户的安全性上下文,而不是继承被模拟帐户的安全性上下文。


    访问系统资源

    默认情况下,ASP.NET 不执行模拟。因此,如果 Web 应用程序访问本地系统资源,则它使用与 Aspnet_wp.exe 辅助进程关联的安全性上下文完成此任务。安全性上下文是由运行辅助进程使用的帐户决定的。

    访问事件日志
    权限最少的帐户拥有足够的权限,能够使用现有事件源将记录写入到事件日志中。但是,它们没有足够的权限来创建新的事件源,这要求在下面的注册表配置单元下面设置一个新项。

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\<log>

    为避免出现此问题,请在安装时创建由应用程序使用的事件源(如果可以使用管理员权限的话)。一个好的方法是使用可由 Windows Installer(如果使用 .msi 部署的话)或 InstallUtil.exe 系统实用程序(如果没有使用 .msi 部署)实例化的 .NET 安装程序类。
    如果在安装时无法创建事件源,则必须将权限添加到以下注册表项中,并给某个被模拟帐户的 ASP.NET 进程帐户授予访问权限(如果应用程序使用模拟的话)。

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog

    帐户必须拥有以下最少权限:

    • 查询项值
    • 设置项值
    • 创建子项
    • 枚举子项
    • 通知
    • 读取

    在将权限应用于注册表后,可以使用以下代码从 ASP.NET 写入应用程序事件日志:

    string source = "Your Application Source";
    string logToWriteTo = "Application";
    string eventText = "Sample Event";

    if (!EventLog.SourceExists(source))
    {
    EventLog.CreateEventSource(source, logToWriteTo);
    }
    EventLog.WriteEntry(source, eventText, EventLogEntryType.Warning, 234);

    访问注册表
    应用程序访问的任何注册表项要求在 ACL 中使用 ACE,以便至少给 ASP.NET 进程帐户授予读取访问权限。

    更多信息
    有关安装程序类和 InstallUtil.exe 实用程序的详细信息,请参见 MSDN 上的 .NET 框架工具。

    访问 COM 对象
    在传统的 ASP 中,使用单线程单元 (STA) 线程池中的线程来处理请求。在 ASP.NET 中,使用多线程单元 (MTA) 线程池中的线程来处理请求。这会给调用单元模型对象的 ASP.NET Web 应用程序造成不利影响。

    单元模型对象
    当 ASP.NET Web 应用程序调用单元模型对象(如 Visual Basic 6 COM 对象)时,需要注意以下两个问题:

    • 您必须用 AspCompat 指令标记 ASP.NET 页面(如下所示)。
      <%@ Page Language="C#" AspCompat="True" %>
    • 不要在特定的 Page 事件处理程序以外创建 COM 对象。始终在 Page 事件处理程序(例如,Page_Load 和 Page_Init)中创建 COM 对象。不要在页面的构造函数中创建 COM 对象。

    需要 AspCompat 指令
    默认情况下,ASP.NET 使用 MTA 线程来处理请求。在从 ASP.NET 调用单元模型对象时,将会导致线程切换,这是因为 MTA 线程不能直接访问单元模型对象(COM 将使用 STA 线程)。
    如果指定 AspCompat,则 STA 线程处理页面。这可避免从 MTA 到 STA 的线程切换。如果 Web 应用程序使用模拟功能,从安全角度讲这是非常重要的,因为线程切换将会导致丢失模拟令牌。新的线程将没有关联的模拟令牌。
    ASP.NET Web 服务不支持 AspCompat 指令。这意味着,在从 Web 服务代码调用单元模型对象时,将会发生线程切换并且丢失线程模拟令牌。这通常导致出现“拒绝访问”异常错误。

    更多信息

    • 有关详细信息,请参见以下知识库文章:
      • 文章 Q303375“INFO: XML Web Services and Apartment Objects”(INFO:XML Web 服务和单元对象)
      • 文章 Q325791“PRB: Access Denied Error Message Occurs When Impersonating in ASP.NET and Calling STA COM Components”(PRB:在 ASP.NET 中进行模拟以及调用 STA COM 组件时出现“拒绝访问”错误消息)
    • 有关如何确定当前执行代码的标识的详细信息,请参见第 13 章“疑难解答”中的“我是谁?”一节。

    不要在特定 Page 事件以外创建 COM 对象
    不要在特定 Page 事件处理程序以外创建 COM 对象。以下代码片段阐释了不要执行哪些操作。

    <%@ Page Language="C#" AspCompat="True" %>
    <script runat="server">
    // COM object created outside of Page events
    YourComObject obj = new apartmentObject();
    public void Page_Load()
    {
    obj.Foo()
    }
    </script>

    在使用单元模型对象时,一定要在特定 Page 事件(例如 Page_Load)中创建对象(如下所示)。

    <%@ Page Language="C#" AspCompat="True" %>
    <script runat="server">
    public void Page_Load()
    {
    YourComObject obj = new apartmentObject();
    obj.Foo()
    }
    </script>

    更多信息
    有关详细信息,请参见 Microsoft 知识库文章 Q308095“PRB: Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Impacts Performance”(PRB:在 ASP.NET ASPCOMPAT 模式下,如果在构造函数中创建 STA 组件,将会对性能产生负面影响)。

    COM+ 中的 C# 和 VB .NET 对象
    Microsoft C#? 开发工具和 Microsoft Visual Basic? .NET 开发系统支持所有的线程模型(自由线程、中性、两者和单元)。默认情况下,将 COM+ 中驻留的 C# 和 Visual Basic .NET 对象标记为“两者”。因此,当 ASP.NET 调用它们时,可以直接进行访问,而不会发生线程切换。


    访问网络资源

    应用程序可能需要访问网络资源。一定要能够标识以下内容:

    • 应用程序需要访问的资源。
      例如,文件共享上的文件、数据库、DCOM 服务器和 Active Directory 对象等等。
    • 用来执行资源访问的标识。
      如果应用程序访问远程资源,则远程计算机必须能够对此标识进行验证。

      注意:有关访问远程 SQL Server 数据库的信息,请参见第 12 章“数据访问安全性”。

    可以使用以下任一方法,从 ASP.NET 应用程序中访问远程资源:

    • 使用 ASP.NET 进程标识。
    • 使用服务组件。
    • 使用匿名 Internet 用户帐户(例如,IUSR_MACHINE)。
    • 使用 LogonUser API 和模拟特定的 Windows 标识。
    • 使用原调用方。

    使用 ASP.NET 进程标识
    如果没有将应用程序配置为使用模拟,在应用程序试图访问远程资源时,ASP.NET 进程标识就会提供默认标识。如要使用 ASP.NET 进程帐户访问远程资源,您有三种选择:

    • 使用镜像帐户。
      这是最简单的方法。您在远程计算机上使用匹配的用户名和密码创建一个本地帐户。您必须在用户管理器中将 ASPNET 帐户密码更改为已知值(始终使用强密码)。然后,必须在 Machine.config 中的 <processModel> 元素上明确地设置它,并替换现有的 "AutoGenerate" 值。

      重要信息:如果将 ASPNET 密码更改为一个已知值,则 LSA 中的密码不再与 SAM 帐户密码匹配。如果需要恢复为 "AutoGenerate" 默认值,则需要执行以下任一操作:
      运行 Aspnet_regiis.exe,将 ASP.NET 重置为其默认配置。有关详细信息,请参见 Microsoft 知识库文章 Q306005“HOWTO: Repair IIS Mapping After You Remove and Reinstall IIS”(如何做:删除和重新安装 IIS 后维修 IIS 映射)。

    • 创建一个权限最少的自定义本地帐户以运行 ASP.NET,并在远程计算机上创建一个重复帐户。
    • 使用一个权限最少的域帐户来运行 ASP.NET。
      假设客户端计算机和服务器计算机都位于同一个域或信任域内。

    更多信息
    有关配置 ASP.NET 进程帐户的详细信息,请参见本指南“参考”部分的“如何做:创建自定义帐户以便运行 ASP.NET”。

    使用服务组件
    可以使用配置为以固定标识运行的进程外服务组件来访问网络资源。图 8.6 中显示了此方式。

    图 8.6 使用进程外服务组件为网络资源访问提供固定标识

    使用进程外服务组件(在 Enterprise Services 服务器应用程序中)具有以下优点:

    • 在标识使用上具有很大的灵活性。不是仅依赖于 ASP.NET 标识。
    • 受信任的或具有更高权限的代码可以与主要 Web 应用程序分开。
    • 从安全角度来讲,由于增加了一个进程,因而提高了安全门槛。对于攻击者而言,穿过进程边界到达具有更高权限的进程要困难得多。
    • 如果您需要使用 LogonUser API 调用进行手动模拟,则可以在与主要 Web 应用程序分开的进程中执行此操作。

      注意:要调用 LogonUser,您必须给 Enterprise Services 进程帐户授予“充当操作系统的一部分”权限。可以通过提高与 Web 应用程序分开的进程的权限来减少安全隐患。

    使用匿名 Internet 用户帐户
    如果将 IIS 配置为使用匿名身份验证,则可以使用匿名 Internet 用户帐户访问网络资源。如果以下任一情况属实,就会发生这种情况:

    • 应用程序支持匿名访问。
    • 应用程序使用表单、Passport 或自定义身份验证(其中将 IIS 配置为使用匿为访问)。

      使用匿名帐户访问远程资源

      1. 将 IIS 配置为使用匿名身份验证。可以根据应用程序的身份验证要求,将 ASP.NET 身份验证模式设置为“Windows”、“表单”、“Passport”或“无”。

      2. 将 ASP.NET 配置为使用模拟。在 Web.config 中使用下列设置:
      <identity impersonate="true"/>

      3. 将匿名帐户配置为权限最少的域帐户,
      -或-
      在远程计算机上使用相同的用户名和密码复制匿名帐户。在不信任的域之间进行调用时,或者通过没有打开支持集成 Windows 身份验证所需端口的防火墙进行调用时,必须使用此方法。
      要支持这种方法,您还必须:

      a. 使用 Internet 服务管理器清除匿名帐户的“允许 IIS 控制密码”复选框。
      如果选择此选项,使用指定匿名帐户创建的登录会话最终得到的是 NULL 网络凭据(因此不能用来访问网络资源)。如果不选择此选项,则登录会话是一个具有网络凭据的交互式登录会话。
      b. 在用户管理器和 Internet 服务管理器中均设置帐户的凭据。

      重要信息:如果您模拟匿名帐户(例如,IUSR_MACHINE),则必须禁止该帐户访问资源(使用进行适当配置的 ACL)。对于应用程序需要访问的资源,必须(至少)给匿名帐户授予读取访问权限。应拒绝匿名帐户访问所有其他的资源。

    承载多个 Web 应用程序
    对于 Web 站点中的每一个虚拟根目录,可以使用一个单独的匿名 Internet 用户帐户。在承载环境中,这允许您分别授权、跟踪和审核来自不同 Web 应用程序的请求。图 8.7 中显示了此方式。

    图 8.7 为每个应用程序模拟不同的匿名 Internet用户帐户 (v-dir)

    为特定的虚拟目录配置匿名 Internet 用户帐户
    1. 从“管理工具”程序组中启动“Internet 服务管理器”。
    2. 选择要配置的虚拟目录,右键单击,然后单击“属性”。
    3. 单击“目录安全性”选项卡。
    4. 在“匿名访问和验证控件”组中,单击“编辑”。
    5. 选择“匿名访问”,然后单击“编辑”。
    6. 输入在匿名用户连接到站点时希望 IIS 使用的帐户的用户名和密码。
    7. 确保没有选择“允许 IIS 控制密码”。

    使用 LogonUser 并模拟特定的 Windows 标识
    可以使用以下方法模拟特定的标识:在 Web.config 中的 <identity> 元素上配置用户名和密码属性,或者在应用程序代码中调用 Win32? LogonUser API。

    重要信息:建议不要使用这些方法。在 Windows 2000 服务器上应避免使用这两种方法,因为它强制给 ASP.NET 进程帐户授予“充当操作系统的一部分”权限。这会显著降低 Web 应用程序的安全性。
    Windows Server 2003 将取消此限制。

    使用原调用方
    要使用原调用方的标识访问远程资源,您必须能够将调用方的安全性上下文从 Web 服务器委派到远程计算机。

    可伸缩性警告:如果使用原调用方的模拟标识访问应用程序的数据服务层,则会严重影响应用程序的伸缩性,这是因为数据库连接池的效率非常低。对于每个用户而言,数据库连接的安全性上下文是不同的。

    以下身份验证方案支持委派:

    • Kerberos。有关详细信息,请参见本指南“参考”部分的“如何做:对 Windows 2000 实现 Kerberos 委派”。
      映射到 Windows 帐户的客户端证书。映射必须由 IIS 执行。
    • 基本。基本身份验证支持远程资源访问,因为在 Web 服务器上以明文形式提供原调用方的凭据。可以使用这些凭据响应来自远程计算机的身份验证质询。
    • 必须将基本身份验证与交互式或批处理登录会话配合使用。可以在 IIS 元数据库中配置从基本身份验证产生的登录会话类型。有关详细信息,请参见 MSDN 上的 Platform SDK:Internet 信息服务 5.1。

    重要信息:在支持委派的方法中,基本身份验证是最不安全的一种方法。这是因为明文用户名和密码通过网络从浏览器传递到服务器,并且将它们缓存在 Web 服务器的内存中。可以使用 SSL 在传递过程中保护凭据,但应当尽量避免在 Web 服务器上缓存明文凭据。

    使用原调用方访问远程资源

    1. 将 IIS 配置为使用集成 Windows (Kerberos)、证书(带 IIS 证书映射)或基本身份验证。
    2. 将 ASP.NET 配置为使用 Windows 身份验证和模拟。
      <authentication mode="Window" />
      <identity impersonate="true"/>
    3. 如果使用 Kerberos 委派,请将 Active Directory 帐户配置为使用委派。

    更多信息

    • 有关配置 Kerberos 委派的详细信息,请参见本指南“参考”部分的“如何做:对 Windows 2000 实现 Kerberos 委派”。
      有关 IIS 证书映射的详细信息,请参见 http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/ad/windows2000/howto/mapcerts.asp。
      有关 ASP.NET 模拟的详细信息,请参见 MSDN 中的 .NET 框架开发人员指南。

    访问 UNC 文件共享上的文件
    如果应用程序需要使用 ASP.NET 访问统一命名约定 (UNC) 共享上的文件,则一定要添加共享文件夹的 NTFS 权限。还需要设置共享的权限,以便给 ASP.NET 进程帐户或模拟的标识至少授予读取访问权限(如果将应用程序配置为使用模拟的话)。

    访问非 Windows 网络资源
    如果应用程序需要访问非 Windows 资源(例如位于非 Windows 平台上的数据库或大型机应用程序),则需要考虑以下问题:

    • 与资源相关的关守和信任边界是什么?
    • 身份验证需要哪些凭据?
    • 资源是否需要知道原调用方的标识,或者它是否信任调用应用程序(使用固定进程或服务标识)?
    • 与建立连接相关的性能开销有多大?如果开销很高,则可能需要实现连接池;例如,使用 Enterprise Services 的对象池功能。

    如果资源需要能够对原调用方进行身份验证(并且不能选用 Windows 身份验证),则可以选择以下方法:

    • 使用(方法调用)参数传递凭据。
    • 在连接字符串中传递凭据。使用 SSL 或 IPSec 保护通过网络传递的明文凭据。
      在应用程序中安全地存储凭据,例如使用 DPAPI。有关安全地存储数据库连接字符串的详细信息,请参见第 12 章“数据访问安全性”中的“安全存储数据库连接字符串”。
    • 使用两个平台都能访问的集中数据存储进行身份验证;例如 LDAP 目录。

    安全通信

    使用 SSL 保护浏览器和 Web 服务器之间通信链路的安全。SSL 提供消息机密性和消息完整性。使用 SSL 和/或 IPSec 提供从 Web 服务器到应用程序服务器或数据库服务器的安全通道。

    更多信息
    有关安全通信的详细信息,请参见第 4 章“安全通信”。


    存储机密

    Web 应用程序通常需要存储机密。需要妥善保管这些机密,以防止不道德的管理员和有恶意的 Web 用户进行访问,例如:

    • 不道德的管理员。不应给管理员和其他不道德的用户授予查看特权信息的权限。例如,不应给 Web 服务器管理员授予读取网络中 SQL Server 计算机上的 SQL Server 登录帐户密码的权限。
    • 恶意的 Web 用户。即使可以使用某些组件(例如 FileAuthorizationModule)禁止用户访问特权文件(如果攻击者确实获得访问配置文件的权限),文件中的机密也不应以纯文本形式存储。

    机密的典型示例包括:

    • SQL 连接字符串。一个常见的错误是以纯文本形式存储用户名和密码。建议使用 Windows 身份验证而不是 SQL 身份验证。如果不能使用 Windows 身份验证,请参见第 12 章“数据访问安全性”中的以下部分,它们介绍了其他的安全方案:
      • “安全地存储数据库连接”
      • “安全通信”
    • SQL 应用程序角色使用的凭据。必须使用需要角色名及相关密码的存储过程激活 SQL 应用程序角色。有关详细信息,请参见第 12 章“数据访问安全性”中的“授权”。
    • Web.config 中的固定标识。例如:
      <identity impersonate=”true” userName="bob" password="inClearText"/>
      在 .NET 框架 1.1 版中,ASP.NET 提供加密用户名和密码并将其安全地存储到注册表项中的功能。
    • Machine.config 中的进程标识。例如:
      <process userName="cUsTuMUzerName" password=”kUsTumPazzWerD” >
      如果使用“Machine”用户名和“AutoGenerate”密码,则默认情况下由 ASP.NET 管理机密。
      在 .NET 框架 1.1 版中,ASP.NET 提供加密用户名和密码并将其安全地存储到注册表项中的功能。
    • 用于安全地存储数据的密钥。无法在软件中安全地存储密钥。但是,可以使用某些任务减轻风险。例如,创建一个自定义的配置节处理程序,它使用不对称加密对会话密钥进行加密。然后,可以将会话密钥存储在配置文件中。
    • SQL Server会话状态。要使用 SQL 服务器管理 ASP.NET Web 应用程序会话状态,请使用以下 Web.config 设置。
      <sessionState … stateConnectionString=“tcpip=127.0.0.1:42424”
      sqlConnectionString=“data source=127.0.0.1;
      user id=UserName;password=MyPassword” />
      在 .NET 框架 1.1 中,ASP.NET 提供加密此信息的功能。
    • 用于根据数据库进行表单身份验证的密码。
      如果应用程序根据数据库对身份验证凭据进行验证,请不要将密码存储在数据库中。使用带有 Salt 值的密码哈希值并对哈希值进行比较。
      有关详细信息,请参见第 12 章“数据访问安全性”中的“对数据库进行用户身份验证”。

    在 ASP.NET 中存储机密的选项
    .NET Web 应用程序开发人员可以使用多种方法来存储机密。它们包括:

    • .NET 加密类。.NET 框架包含可用于加密和解密的类。这些方法要求安全地存储加密密钥。
    • 数据保护 API (DPAPI)。DPAPI 是一对 Win32 API,它使用从用户密码派生的密钥对数据进行加密和解密。在使用 DPAPI 时,您并不需要进行密钥管理。操作系统对作为用户密码的密钥进行管理。
    • COM+ 构造函数字符串。如果应用程序使用服务组件,则可以在对象构造字符串中存储机密。该字符串以明文形式存储在 COM+ 目录中。
    • CAPICOM。这是一个 Microsoft COM 对象,它提供对基础加密 API 基于 COM 的访问。
    • 加密 API。这些 API 是执行加密和解密的低级 Win32 API。

      更多信息
      有关详细信息,请参见 MSDN 上 Platform SDK 中的加密技术、CryptoAPI 和 CAPICOM 条目。

    考虑将机密存储在单独逻辑卷上的文件中
    考虑将 Web 应用程序目录安装到操作系统所在卷以外的逻辑卷上(例如 E: 而不是 C:)。这意味着 Machine.config(位于 C:\WINNT\Microsoft.NET 下)和其他可能包含机密的文件(例如通用数据链接 (UDL) 文件)位于 Web 应用程序目录以外的逻辑卷上。
    此方法的基本原理是防止出现可能的文件规范化和目录遍历错误,因为:

    • 文件规范化错误可能会公开 Web 应用程序文件夹中的文件。

      注意:文件规范化例程返回文件路径的规范形式。这通常是绝对路径名,其中已完全解析所有相对引用和对当前目录的引用。

    • 目录遍历错误可能会公开同一逻辑卷上其他文件夹中的文件。

      公开其他逻辑卷上文件的上述类型错误尚未发布。


    保护会话和视图状态

    Web 应用程序必须管理各种类型的状态,其中包括视图状态和会话状态。本节讨论 ASP.NET Web 应用程序的安全状态管理。

    保护视图状态
    如果 ASP.NET Web 应用程序使用视图状态:

    • 按如下所示将 enableViewStateMac 设置为 true,以确保视图状态的完整性(确保在传递过程中没有对它进行修改)。这样,在从客户端发回页面时,ASP.NET 就会在该页面的视图状态上生成消息身份验证代码 (MAC)。
      <% @ Page enableViewStateMac=true >
    • 配置 Machine.config 中 <machineKey> 元素的 validation 属性,指定数据验证所使用的加密类型。请考虑以下几个方面的问题:
      • 安全哈希算法 1 (SHA1) 生成的哈希大小比消息摘要 5 (MD5) 大,因而可以认为它更安全。但是,在传递过程中或在客户端可能会解码使用 SHA1 或 MD5 保护的视图状态,并可能以纯文本形式进行查看。
      • 使用三重数据加密标准 (3DES) 检测视图状态中的变化,并且还可以在传递过程中对视图状态进行加密。在处于这种状态时,即使视图状态被解码,也不能以纯文本形式进行查看。

    保护 Cookie
    在传递过程中,应该使用 SSL 保护包含身份验证或授权数据或其他机密数据的 Cookie。对于表单身份验证,可以使用 FormsAuthentication.Encrypt 方法加密以 Cookie 形式在客户端和服务器之间传递的身份验证票。

    保护 SQL 会话状态
    默认(进程内)ASP.NET 会话状态处理程序会受到某些限制。例如,它不能在网络场中的其他计算机上运行。为了克服此限制,ASP.NET 允许在 SQL Server 数据库中存储会话状态。
    可以在 Machine.config 或 Web.config 中配置 SQL 会话状态。Machine.config 的默认设置如下所示。

    <sessionState mode="InProc"
    stateConnectionString="tcpip=127.0.0.1:42424"
    stateNetworkTimeout="10"
    sqlConnectionString="data source=127.0.0.1;user id=sa;password="
    cookieless="false" timeout="20"/>

    默认情况下,SQL 脚本 InstallSqlState.sql(用于生成 SQL 会话状态使用的数据库)安装在以下位置:

    C:\WINNT\Microsoft.NET\Framework\v1.0.3705

    在使用 SQL 会话状态时,需要考虑以下两个问题。

    • 必须保护数据库连接字符串的安全。
    • 在网络上传递时,必须保护会话状态的安全。

    保护数据库连接字符串
    如果使用 SQL 身份验证连接到服务器,则将用户 ID 和密码信息以纯文本形式存储在 web.config 中(如下所示)。

    <sessionState
    cookieless="false"
    timeout="20"
    mode="InProc"
    stateConnectionString="tcpip=127.0.0.1:42424"
    sqlConnectionString=
    "data source=127.0.0.1;user id=UserName;password=ClearTxtPassword" />

    默认情况下,HttpForbiddenHandler 禁止下载配置文件。但是,任何可以直接访问存储配置文件的文件夹的用户仍然可以看到用户名和密码。更好的方法是对 SQL Server 使用 Windows 身份验证。
    要使用 Windows 身份验证,可以使用 ASP.NET 进程标识(通常是 ASPNET)
    1. 在数据库服务器上创建一个重复帐户(使用相同的名称和密码)。
    2. 为该帐户创建 SQL 登录。
    3. 在 ASPState 数据库中创建一个数据库用户,并将 SQL 登录映射到该新用户。
    ASPState 数据库是由 InstallSQLState.sql 脚本创建的。
    5. 创建一个用户定义的数据库角色,并将数据库用户添加到该角色。
    6. 在数据库中为该数据库角色配置权限。

    然后,可以更改连接字符串以使用受信任的连接(如下所示):

    sqlConnectionString="server=127.0.0.1;
    database=StateDatabase;
    Integrated Security=SSPI;"

    在网络上保护会话状态
    在通过网络将会话状态传送到 SQL Server 数据库时,可能需要对会话状态进行保护。这取决于承载 Web 服务器和数据服务器的网络的安全性。如果已在受信任环境中对数据库进行物理保护,则可能不必采取这一额外的安全措施。
    可以使用 IPSec 保护 Web 服务器和 SQL Server 之间的所有 IP 通信,或者使用 SSL 保护到 SQL Server 的链路。通过使用此方法,您可以选择只加密用于会话状态的连接,而不是在计算机之间进行的所有通信。

    更多信息

    • 有关如何设置 SQL 会话状态的详细信息,请参见 Microsoft 知识库文章 Q317604“HOW TO: Configure SQL Server to Store ASP.NET Session State”(如何做:配置 SQL Server 以存储 ASP.NET 会话状态)。
    • 有关对 SQL Server 使用 SSL 的详细信息,请参见本指南“参考”部分的“如何做:使用 SSL 来确保与 SQL Server 2000 安全通信”。
    • 有关使用 IPSec 的详细信息,请参见本指南“参考”部分的“如何做:使用 IPSec 以便在两个服务器之间安全通信”。

    网络场注意事项

    在网络场方案中,不能保证来自同一客户端的后续请求由同一 Web 服务器提供服务。对于状态管理和任何取决于 Machine.config 中 <machineKey> 元素所保存的属性的加密而言,这会产生不利影响。

    会话状态
    默认 ASP.NET 进程内会话状态处理(它镜像以前的 ASP 功能)产生服务器关系,并且不能在网络场方案中使用。对于网络场部署,必须在进程外将会话状态存储到 ASP.NET 状态服务或 SQL Server 数据库中(如前所述)。
    注意:不能依赖应用程序状态来保存网络场(将 Web 应用程序配置为在多台服务器上运行)或网络园(将 Web 应用程序配置为在多个处理器上运行)方案中的全局计数器或唯一值,因为在进程或计算机之间不能共享应用程序状态。

    DPAPI
    DPAPI 能够与机器存储或用户存储(需要一个已加载的用户配置文件)配合使用。如果您将 DPAPI 和机器存储一起使用,那么加密字符串是给定计算机所特有的,因此您必须在每台计算机上生成加密数据。不要在网络场或群集中跨计算机复制加密数据。
    如果将 DPAPI 和用户存储一起使用,则可以用一个漫游的用户配置文件在任何一台计算机上解密数据。

    更多信息
    有关 DPAPI 的详细信息,请参见第 12 章“数据访问安全性”。

    在网络场中使用表单身份验证
    如果使用表单身份验证,则网络场中的所有服务器必须共享一个通用机器密钥,此密钥用于身份验证票的加密、解密和验证。
    机器密钥保存在 Machine.config 的 <machineKey> 元素中。默认设置如下所示。

    <machineKey validationKey="AutoGenerate"
    decryptionKey="AutoGenerate"
    validation="SHA1"/>

    此设置导致每台机器生成一个不同的验证和解密密钥。必须更改 <machineKey> 元素,并将通用密钥值放到网络场中的所有服务器上。

    <machineKey> 元素
    可以使用 Machine.config 中的 <machineKey> 元素,配置用于加密和解密表单身份验证 Cookie 数据和视图状态的密钥。
    在调用 FormsAuthentication.Encrypt 或 FormsAuthentication.Decrypt 方法以及创建或检索视图状态时,将参考 <machineKey> 元素中的值。

    <machineKey validationKey="autogenerate|value"
    decryptionKey="autogenerate|value"
    validation="SHA1|MD5|3DES" />

    validationKey 属性
    validationKey 属性值用于创建和验证视图状态和表单身份验证票的 MAC 代码。此验证属性表明在执行 MAC 生成时使用哪种算法。请注意以下方面:

    • 在使用表单身份验证时,此密钥与 <forms> protection 属性配合使用。如果将保护属性设置为 Validation,然后调用 FormsAuthentication.Encrypt 方法,则使用票值和 validationKey 计算附加到 Cookie 中的 MAC。在调用 FormsAuthentication.Decrypt 方法时,就会计算 MAC 并将它与附加到票上的 MAC 进行比较。
    • 在使用视图状态时,可以使用控件的视图状态值和 validationKey 来计算附加到视图状态上的 MAC。在将视图状态从客户端发回时,应重新计算 MAC 并将它与附加到视图状态上的 MAC 进行比较。

    decryptionKey 属性
    decryptionKey 属性值用于加密和解密表单身份验证票和视图状态。可以使用 DES 或 Triple DES (3DES) 算法。具体的算法取决于服务器上是否安装了 Windows 2000 高度加密包。如果安装了该程序包,则使用 3DES,否则使用 DES。请注意以下方面:

    • 在使用表单身份验证时,密钥与 <forms> protection 属性配合使用。如果将 protection 属性设置为 Encryption,并且调用了 FormsAuthentication.Encrypt 或 Decrypt 方法,则使用指定的 decryptionKey 值加密或解密票值。
    • 通过使用视图状态,在将控件的视图状态值发送到客户端时,使用 decryptionKey 值对它进行加密;并在客户端将数据发回服务器时对它进行解密。

    Validation 属性
    此属性规定验证、加密和解密时使用哪种算法。它可以采用 SHA1、MD5 或 3DES 值。以下是这些值的描述:

    • SHA1。如果设置为 SHA1,则实际使用 HMACSHA1 算法。它生成 160 位(20 个字节)的输入哈希值或摘要。HMACSHA1 是一种加密哈希算法。此算法的输入密钥是由 validationKey 属性指定的。
      SHA1 由于比其他算法具有更大的摘要,因此成为常用的算法。
    • MD5。它使用 MD5 算法生成 20 个字节哈希值。
    • 3DES。它使用 Triple DES (3DES) 算法加密数据。

      注意:在将验证属性设置为 3DES 时,表单身份验证实际上并不使用它,而是使用 SHA1。

    更多信息

    有关如何创建适于放在 Machine.config 中的密钥的信息,请参见 Microsoft 知识库文章 Q312906“HOW TO: Create Keys w/ C# .NET for Use in Forms Authentication”(如何做:使用 C# .NET 创建在表单身份验证中使用的密钥)。

    有关 Windows 2000 高度加密包的详细信息,请参见 http://www.microsoft.com/windows2000/downloads/recommended/encryption/


    总结

    本章介绍了各种保护 ASP.NET Web 应用程序的技术和方法。本章提供的大多数指南和建议同样适用于开发 ASP.NET Web 服务和由 ASP.NET 驻留的 .NET Remoting 对象。概括起来如下所示:

    • 如果应用程序使用表单身份验证,而且在用户身份验证中需要考虑性能问题,则检索角色列表并将其存储在身份验证票中。
    • 如果使用表单身份验证,则始终给每个请求创建一个主体并将其存储在上下文中。
    • 如果角色太多而无法存储在身份验证 Cookie 中,则使用全局应用程序缓存来存储角色。
    • 不要创建权限最少的自定义帐户来运行 ASP.NET。而是应更改 ASPNET 帐户密码,并在应用程序需要访问的任何远程 Windows 服务器上创建重复帐户。
    • 如果必须创建自定义帐户以运行 ASP.NET,请使用权限最少的用户。例如:
      • 如果主要考虑管理问题,请使用权限最少的域帐户。
      • 如果使用本地帐户,则必须在 Web 应用程序需要访问的任何远程计算机上创建重复帐户;如果应用程序需要访问非信任域中的资源或者防火墙禁止 Windows 身份验证,则必须使用本地帐户。
      • 不要使用本地 SYSTEM 帐户来运行 ASP.NET。
      • 不要给 ASPNET 帐户授予“充当操作系统的一部分”权限。
    • 在以下情况中使用 SSL:
      • 在浏览器和 Web 服务器之间传送安全敏感信息时。
      • 使用基本身份验证(以保护凭据)时。
      • 使用表单身份验证进行身份验证(与个性化相对)时。
    • 避免使用纯文本形式存储机密。
  • 2006年07月28日

    震撼!一位中学学生会主席让人发冷汗的讲演
    ——一个中学生对中华民族明天的担忧

      一、首先让我们好好听听下面两段发人警醒的语言:

      抗美援朝胜利以后,一位参加过战争的美国指挥官无奈而又充满敬意地说:“中国军人是不可战胜的, 而中国男人更是绝对意义上的真正强者,照这样下去,这个国家的崛起谁也无法阻挡,假如要瓦解这个国家,必须要瓦解这个国家的民族气节,首先要从精神上、灵魂上瓦解可怕的中国男人,这是重新战胜中国的最重要前提。”

      藤田俊雄:…..记得他们的“文化大革命”刚刚结束不久,一个爱猫扑.爱生活军人曾经对他们的一群男孩子们说,过去的炮弹在大炮的弹仓里,现在的炮弹在兵工厂的流水线上,未来的炮弹在你们最优秀男孩子的脑袋里。混蛋!爱猫扑.爱生活人都是愚蠢的猪,他们懂什么炮弹?未来的炮弹现在正在我们大日本优秀男孩的思想里。爱猫扑.爱生活的明天有的只是没思想和虚荣的女人,没有男人了,他们那种不顾一切的爱女厌男教育方法将彻底摧毁他们国家优秀男人的创业敬业精神和爱国报国精神,埋没掉无数的科学精英、技术精英、工业精英、体育精英及社会其他精英,葬送掉他们最优秀男人的聪明才智、创新智慧和技术革新与创新能力。所有这些将使得爱猫扑.爱生活人的科学技术和经济变得落后、 百姓变得贫穷、国防变得虚弱、国家变得软弱、他们的女人变得没有思想和失去保护。这种高深道理爱猫扑.爱生活蠢猪听得懂吗?有智慧去领悟吗?所以明天优秀的大和民族在世界上将是不可战胜的!

      二、人民解放军以核制美背后的无奈

      几个月以前,中国人民解放军少将朱成虎向美日等国家发出了警告表示,如果中美两国因台湾问题发生军事冲突,中国别无选择,只能动用核武。如果美国将飞弹和制导武器攻击中国领土,我想我们只能用核子武器来反击。所谓中国领土,包含中国解放军所属战舰及战机。他并警告说,如果美国有心干预,我们也有决心做出反应,中国人已做好西安以东城市全数遭到摧毁的准备,当然,美国也必须做好准备数百座城市被中国摧毁。

      朱成虎将军的言论无疑给我们所有的中国人打入了一剂强心剂,鼓舞了我们的斗志,但是,私下里一想,似乎有感觉有什么不太对劲的地方,他说我们无法同美国答应一场传统的战争。我们赢不了只能动用核武器,每当我想到这句话,心里就总要有一种莫名的痛。为什么我们与美国无法打一场传统的战争?我童年的记忆中人民解放军是英勇无敌的男子汉、战无不胜的战神,他们曾有在朝鲜战场以一挑联合国军十六国的壮举,他们曾经有过以手中的手榴弹对抗原子弹的豪迈。而在我们经济高速发展,科技进步的今天,却没有当年的勇气,而今能以核武器作为我们最后的防线。当年人民解放军的勇气哪里去了?我很困惑。

      我想这也许正是将军的无奈吧,一个优秀的军人是铁骨铮铮的硬汉,不是一个冲动者。他或许深深的明白今天中国军事力量的软肋:军事装备相对于美国来说要落后,这个道理恐怕每个人都会明白,我们的很多武器对比美日的武器存在差距,不用多分析大家都清楚,这是他的无奈之一;中国的军事生产体系方面,由于各国的封锁,很多生产设备相对落后,而且,我们几十年来在武器装备的设计上一直是仿制苏制的武器,而很少有自己的创新。自己能够创造出的领先世界的概念性的武器几乎没有,这是他的无奈之二;人的问题最重要,一切武器都需要人来驾驶,来操纵。一件相对落后的武器在一个高素质、勇敢的军人的手中往往可以击败握有比自己先进很多的武器的敌人。这一点,在我们的人民解放军的身上最能体现:朝鲜战场,中国人民志愿军以落后的装备沉痛打击武装到牙齿的美帝国主义军队,正是我们的人民军队发扬了一不怕死、二不怕苦的英勇斗志和创造性的战术、战略打法,以他们顽强地意志打垮了美国为首的16国200万联合国军和他们先进的飞机大炮,可见,在现代战争中,人的作用仍然是不可忽视的,恐怕朱成虎将军最无奈的也正是这一点,人民军队不是天上降下来的战神,他的来源就是我们周围的普普通通的男孩子。这些男孩到了军队接收革命军队的训练,成为我们的人民子弟兵。因此,人民军队的战斗力的如何,取决于我们民族是否拥有优秀的男孩。然而今天的中国的男孩们是否还能够担负起明天“振兴中华”的重任吗?还能够象上个世纪八十年代的许多优秀男人那样迸发出“只要有我,世界上就没有难题”的豪迈吗?还能够做到“天下兴亡,匹夫有责”吗?如果国家的未来发生了战争,今天的男孩子究竟能不能谱写新时代的“血染的风采”?明天的“黄继光”、“董存瑞”们在哪里?中华民族的未来怎么办?谁来保护我们祖国,人民,尤其是现在台海局势表面缓和,实际紧张,美国日本介入程度越来越深的今天。中国的安全形势越来越危机,资源的进口的来源于通道也越来越被敌对势力所控制,中华爱猫扑.爱生活怎么办?这些看来严峻的问题不仅是今天必须想到的事情、而且是我们有责任感的男子汉都必须直面正视的职责问题所在,也是中国的生存和发展应该考虑到的情况,更是中华民族明天将要面对的现实,这恐怕才是他最大的的无奈。

      三、哈日、网络、酷文化让男孩们学习目标不明确,做优秀男人还是做“酷”男人?

      现在大街上的帅哥儿越来越多,男孩子们都很前卫,很多人都是同一风格,头发有点黄,还有点波浪,一看就知道,这是一个哈日族,在网吧里,无数的男孩在那里整天的打着网络游戏,其中有很多就是我的同学。他们在网络上是英雄,而在现实生活中,却不敢面对,他们没有什么责任心,不清楚自己的未来究竟想要什么?在网上一天天的消耗着自己的青春,消耗着父母的钱财,同时也把自己的未来的希望悄悄地埋葬。这看似无关大局的事情,其实正在为中国的未来的崛起买下隐患。

      中华民族从来就是一个英雄辈出的民族,自古以来的教育始终贯彻着英雄主义,长期以来的宣传也是以英雄主义为主线,在这样的社会文化、文艺氛围下,男孩子从小就树立了成为国家脊梁的意识,尤其新中国成立以后,学英雄、作英雄成为中国人、特别是男孩子们的崇高理想。进入改革开放的八十年代,随着对越自卫反击战英雄事迹、老山前线英雄团体等一系列男子汉英雄团体的榜样作用引导,当时很多男孩子学习刻苦、心怀坦荡,乐于助人,他们之中的优秀者也成为那个时代的典范,被人们广泛传颂。进入九十年代以后,由于种种原因,文化传播方面出现了显著偏差,社会上丑化男人的风气一浪高过一浪, “小白脸”和“奶油小生”替代了“郭建光”、港台柔化、中性化明星大行其道,男孩子也逐步由勤奋学习,报效国家变成了追求享受和毫无理想,由崇拜英雄变成崇尚明星,整个社会在越来越柔弱化的文化、文艺宣传氛围下变得委靡、男人也在阴柔化的社会氛围下变得越来越委靡不振,丧失了男子汉应该具有的阳刚之气。

      而日韩的垃圾文化更是加剧了这一点,要想得到女孩的青睐,就必须要做一个酷男孩,今天的男孩经常把时间花费在如何打扮自己,如何购买名牌,让自己变得像日韩明星。而要想在同龄人中能够扬眉吐气就要看谁的电子游戏打的最有水平。而在身体锻炼和学习知识上,男孩收到许多混杂不清的信息,让他们分不清“酷哥”一样的阳光男孩和向赖宁、潘冬子的“优秀男孩”、“英雄男孩”哪一个角色更重要。这两个角色经常是矛盾的,优秀的男孩常不是男孩女孩心目中的“酷哥”,和男孩比,女孩比较有学业目标。而今天的男孩子经常是随大流,什么“酷”做什么。可惜,缺少知识的“阳光男孩”在学习上和今后的生活中处处碰壁,在竞争中只有垫底的份,也无法为祖国创造出真正的价值。整天沉迷网络,不锻炼身体的“酷”男孩在战场上只有挨打的份,那时敌人是不会给你改正错误的机会。

      我们知道,一个国家的民族精神很大程度是靠文化来发扬光大、靠文艺作品的影响力来代代传扬,当弱化、丑化男人成为一种社会时尚的时候,一个民族的男子汉也就会逐渐消声匿迹,这就是为什么那个时候的人们要“寻找男子汉”而今天“娘娘腔”却风靡全国,由于男人退化严重,社会呈现越来越严重的阴盛阳衰,所以说文化、文艺界的阴盛阳衰毒化了中国男人的精神。而对于女孩来说,我觉得酷文化本身就是一种肤浅的文化,“酷”男孩未必会有临危不惧以及处事果断的勇气和 “坚毅卓绝,诚正信责”的信念,当你遇到危险的时候,“酷”男孩未必会给你应有的保护。而只有那些优秀的男孩才能够挺身而出,成为真正的护花使者。

      四、沉迷网络,不能自拔

      一些别有用心的人利用今天社会盲目追求经济价值和过分的“女性优势”放弃对男孩子的理想、英雄主义教育,放任男孩子不知不觉沉浸在网络游戏等严重影响学习的“课外活动”中,对于上个世纪九十年代以前的优秀男孩子——我们的前辈们为什么就能顽强刻苦学习,排除社会不良干扰,不作宣传研究。今天很多男孩子放弃学业,整天在网吧里完成这他们所谓的“学业”,他们不考虑自己的未来会怎样,不考虑家人为他们担心,更不会考虑中华的未来需要他们的努力和男子汉应尽的责任。在他们的眼中有的只是花花绿绿的打斗画面,有的只是不断的升级,而他们不知道,除了在网络中的虚幻,他们在现实中正在逐渐变得一无所有。

      深圳某中学初二学生×××曾离家出走,混迹网吧3昼夜,被母亲找回后锁在房里,竟在夜里4点钟从窗户爬出,沿着下水管从4楼爬到底楼,溜回网吧;江西一名17岁的高三学生连续逃课上网两个月,在玩网络游戏时,因紧张激动在网吧倒地猝死;深圳某初二男生,沉迷于网络,妈妈在禁止无效后,将家里电脑的鼠标收起来,他上网找不到鼠标时,竟然砸烂大衣橱的镜子,并用碎玻璃把家里的地扳划得七零八碎的;江苏某16岁男孩为了“反抗”父母禁止他去网吧,竟用菜刀砍下自己的左手小指……,这一幕幕活生生的事例真是触目惊心!

      五、不锻炼身体,身体素质差,战场上自保难

      中日韩少年的夏令营,我们搞过好几次了,每一次都让我们产生巨大的心理震撼,中国的孩子无论在生存能力还是在创造力上都比日本的孩子差了一大截,一个日本少年临走时对中国少年说:“如果是在战场上,爱猫扑.爱生活男??也体现了这一点,男生的表现真的差强人意,不能吃苦,请病假,表现差。很多人甚至比看谁能够偷懒。平时不好好训练,不检讨自己的缺点,等到战场上,敌人不会给你检讨的时间,我们要付出多大的代价?难道还要象抗日战争中那样用几十个中国将士换一个日军么( 中国军民伤亡3500万,日军在中国战场死亡40万)。在战场上面对敌人,“阳光男孩”只有挨打的份,中华民族的未来需要我们的男孩子做到“坚毅卓绝,诚正信责”,而不是象现在的所谓“阳光男孩”这样不学习、不吃苦、会享受。

      六、教育僵化,阴盛阳衰化,学生的创造力被扼杀,缺乏勇气

      今天中国的教育是一种应试教育?不对,连应试的教育也不是!而是一种急功近利的教育、一种阴盛阳衰的女性化教育、一种显性的教育。

      首先在教学体制上,采取了从根本上压制毁灭男人个性的教育管理方法,表现最突出的就是在小学和初中时期几乎全部任用女学生干部管理一切,由于男孩子语言机能、生理发育晚一些,这样作就能够从小培养女孩盲目的大胆,同时利用这种生理特点达到对男孩子个性培养的压制;二是采用了文科化、记忆化、形象化来抑制抽象推理、 理解创新、概念判断等教学理念,将男孩子的优势封杀,等到了高中,男孩子们潜在优势已经被扼杀,弱化的个性已经形成,又假惺惺地“重视”男生,由于在智力和性格成长最关键的时期男孩子一直没有锻炼过,缺乏适应于男孩特点的学习方法,很多方面都欠缺,那些所谓的教育工作者们就可以“断言”:女孩子本来就聪明、能力强,都这样照顾男生了,他们还是不如女生,今天的女性进步了,“谁说女子不如男”,至于上个世纪九十年代以前的科学管理、教育方法,人为掩饰,只字不提。

      其次在教材系列方面采用了与之配套的方法,把数理化教材简单化、文科化和形象化,完全根据女孩特点设计,同时增大英语的难度,语文的偏度,不适应女生的东西一律删除,不适应男生的内容一律保留和继续发挥,至于后果将会严重抑制学生的思维、思考能力的培养,对中华民族将来的科学事业和直接关系到我们国家和民族生存的国防事业严重有害的事实可以完全不顾。

      再次是考试评价系统方面一方面采用机械式题海战术、题海作业、死记硬背考试、取消课外活动的办法压抑男孩子活泼好动的个性,取代适合于男孩子学习的理解、推理、创造、抽象归纳的方法,虽然这种方法对女孩子也有害,但由于男女不同的天性,对男孩子是一种致命打击;另一方面是考试题型、模式的女性化,最明显的就是理科“高考3+X模式”,这种模式将男人擅长的物理、化学的分值压缩到一张试卷上,并且试题简单,将男人特长明显的数学简单化,同时提高外语试卷的难度和语文试卷的偏度,造成男孩成绩的虚假劣势,其实我们只要看一看20年前的教材和理科7门课710分总分的高考模式、难度和六年前还比较科学、合理的“高考3+2模式”,对比一下今天所谓的高考,就什么都明白了。

      今天的很多女老师倾向女孩,而对男孩则是一副恶嘴脸,说女孩比较容易符合教师心目中的“乖学生”形象,比如坐直,安静,而男孩因为做一个男孩而受到惩罚,比如大声,爱闹并且容易竞争。在女教师眼中,这些男孩的性格特点被看作“有毒性的”大男人主义的起点。给孩子的暗示就是如果你想在班级里呆下去,最好全部模仿女孩子。这下好了,我们培养出来的孩子个个听话,像绵羊。看看我们学校的男孩,大多数胆小怕事,做事情缺乏勇气和激情,不少父母抱怨自己的儿子缺乏男子气,可这又能怨谁?!今天的中国男孩缺少日本孩子那种果敢,那种处事爱猫扑.爱生活的素质,据我所知,日本是世界上少有的几个学校对男孩的攻击性非常鼓励的国家,他们认为男孩不攻击,那么说明长大后肯定是个懦夫。【这样的国家还有以色列、北朝鲜、德国、印度,呵呵,好像都是现在正在崛起的大国哟】。十几年后的未来用这样的绵羊兵员来与日本军国主义教育出来的小狼们较量么?

      十年树木,百人树人,培养一个人是一个长期的系统工程,现在家长对孩子的期望很高,希望能明显地看到自己的孩子比别人的强,于是一种显性的教育方式就出现了,如唱歌、舞蹈、才艺比赛、作文比赛、兴趣小组、讲故事、绘画等,这种观念同时又影响着学校教育,我们到底要什么样的教育?是要一帮能歌善舞的酷男孩,还是要在危急时刻,在中国需要的时候能够挺身上前的男子汉?还是能够为祖国的科技强国,强军作出成效的优秀男人?男孩子在创造力和动手能力方面强,如科技活动项目。从首届上海青少年科技创新市长奖获奖的4名学生全部是男生就能看出。但这样有利于男孩发展的项目并不多,许多男孩很喜欢参加航模班,但家长和老师却不支持。国家不应该太急功近利,要从培养人的长远目标出发,学校和教育工作者也要为男孩子创设更多的展示舞台。这方面我们要向日本、德国那样从长远打算,而不是光看眼前。因此我们也就不难理解,为什么中国的学者不能获得诺贝尔奖,中国为什么总是仿造人家的东西。中国的武器为什么没有自己创造的概念武器。我们不能永远的靠着别人的东西,如果我们总是等到别人先研制出来,我们再去学习,那么我们将永远的走在别的国家的后面。

      七、没有责任心,传统孝道丧失

      网络游戏的可重复性让孩子们认为什么事情都可以重来,这使得很多孩子做事没有责任心,对父母不孝敬。在这个问题上,是不该做争论的。祖宗留下来的家法就是男孩长大后一定要孝敬父母,因此,作为儿子,必须孝敬他们,这是你的天生的职责,这个职责就像你在家族、国家遇到危险的时候必须挺身而出来保卫国家一样,没有什么讨价还价的余地,父母生了你,你就有义务这也是几千年来老祖宗留下来的规矩。

      虽然我承认养儿防老时代应该过时了,但是这不代表作为儿子就要放弃对老人们的孝敬,我们的邻国日本,韩国,仍然延续着我们国家的养儿防老的传统,虽然他们的社会福利体制很完善,但是他们仍然保持了由长子必须抚养父母的传统。我们在网上总是谩骂日本为禽兽,谩骂韩国不是好东西,但是既然禽兽能够做到长幼有序,爱戴父母,为什么我们自称为泱泱中华,礼仪之邦,创立了以孝道治天下的中华儿郎今天却偏偏做不到呢?别忘了,我们中国创造了孝道的赡养父母的制度,而我们却不如我们的学生的继承的好。连自己的父母都不爱的人,怎么会热爱自己的祖国?!

      每个人只有一双父母,如果我们不能让我们的父母过的快乐,那么首先你就是一个失败的男人,无论你在其他的方面做的成就有多大。当你还在网上打着 “CS”或是发表着慷慨激昂的爱国言论的时候,你是否想到,还有你的父母在为你的整晚在网上冲浪而担忧你的身体的健康;当你整夜的泡在网吧的时候,还有你的父母在望眼欲穿的盼望你早点回家;当你的工作没有着落,你的父母不仅要供养你,还要为你的今后的前途操心。你的每一步都有父母在我们背后的付出。当你遇到不顺心的事情的时候,又是谁在与你共同分担着痛苦?。

      千万不要让你的父母为他们当初要一个儿子而伤心、后悔,要知道,当他们最初看到他们生了你的时候,他们是多么的充满着期望,内心是多么的满足,千万不要让他们昨日的期望与惊喜,化作今日的悲哀。

      八、男子汉应该给我们的女孩们带来欢乐、美丽、鲜花和对未来的美好憧憬,决不能也决不允许给她们带来痛苦、眼泪、不安和失望;尊敬,尊重女性是中华民族社会文明进步的标志,不断塑造最优秀男子汉是我们这个民族永远创新和发展的必要保证

      我想我现在有责任和义务代表有责任感的中华男儿说出我们的心里话:我希望中国现阶段众多的血性男儿多多地为国家和民族未来思索、勇敢承担自己的社会责任,为民族的未来分忧解难!男子汉应该放眼世界和站在中华民族的肩上看问题!为了中华民族的伟大复兴、为了实现我们的理性和信念、为了中华新一代血性男儿的优秀和阳刚,我们应该旗帜鲜明地反对阴盛阳衰的社会化、扩大化,坚决抵制和防范极端女权主义盲目恶性膨胀给我们的国家带来形形色色的矛盾、社会危机以及西方敌对国家利用这种女权运动对中华民族崛起和复兴的干涉,但是反对阴盛阳衰不等于歧视女性和漠视中华民族的下一代女孩。

      优秀男子汉群体(毕竟男孩子有更好的理科优势和创造性优势)一方面为我们的国家塑造出优秀的人才,强化了我们的科学研究力量、强化了我们国家的整体国防实力,强大的中华人民共和国是我们所有女孩子们的最好的坚强后盾,也是她们最有利的生存和发展环境;另一方面通过对优秀男孩子们的正确引导,他们将来会成为下一代女孩子们的最好的“老师”和保护者,他们的优秀品质、丰富的特长知识将会使"下一代女孩子们受益非浅,让女孩子们在自己的特长上面学会优秀男孩子的理科优势和坚韧的气质,有助于关爱女孩的更好实现,使未来的女孩子们更加优秀、同时也能建立更加和谐的健康的社会关系。

      关怀女性、关爱女孩,培养优秀的女孩子们,使她们成长为中华民族未来的建设者们,一方面为我们的国家培养了优秀的女性人才(女孩子有文科优势、语言优势和公关社交优势,这些都是国家发展壮大不可缺少的关键要素),她们将在各行各业的管理岗位、教育岗位、金融财政等重要部门发挥她们的聪明才智,是我们国家井然有序不可缺少的重要力量。另一方面,我们说“一位优秀的女性就是最好的老师”,优秀的妻子是她的丈夫最强大的事业支持者和合作者;优秀的母亲可以培养、教育出更加优秀的儿子,这是中华民族未来的优秀男子汉形成和成长所不可缺少的家庭环境;优秀的女教师可以培养出更加形象完美的中华民族优秀好男儿。优秀的女性往往更能够促进和谐的健康的社会关系、家庭关系的更加稳定和谐。

      九、没有文化素质和综合优良品德的男人永远是愚蠢的男人;没有文化素质和综合优良品德男人的国家永远是贫弱的国家;没有文化素质和综合优良品德男人的民族永远是没落的民族

      我想没有一个忠孝仁义作为精神支撑,没有毛泽东思想这个科学信仰作为支撑的人民军队是不可能具有顽强的斗志来保卫祖国的。同样,一支不注重学习,没有知识的军队是一支愚蠢的军队,没无法打胜仗的。

      当一个男孩来到这个世界上将意味着什么?一位重点中学的教师回答的好:“对于国家来讲他们是民族未来的塑造者、对于他们个人而言应该是振兴中华的实现者、对于父母,他们是父母未来的依靠。对于女孩子来说,必须是最称职的‘护花使者’,但是男孩不应该是花朵,过去不做,现在不做,将来永远也不做,要做民族大厦的脊梁!只有当男孩子在经历过一生的坎坷发出真实的心声‘下辈子或许不愿意再作男人,当男子汉真累’的时候,才是真正成功的血性男儿、只有具备了 ‘男儿苦,男儿累,为国为民甘受罪’和‘不要问社会给了我什么,要问自己为中华民族做了什么’意识的男儿才是真正的、纯粹的男人”。

      二零零四年被某些无知的人捧上天的主观唯心主义色彩严重的奥地利关爱女孩协会的“著名提问”偏激片面地认为:如果一个家庭有一双儿女,但只有一笔教育经费,你投给谁?他们的答案是:投给女孩。因为教育了一个男孩,你只教育了一个个体,而教育了一个女孩你就教育了一个家庭,教育了一个民族,教育了一个国家。胡说八道!只有教育好一个国家的全体国民才能说教育了一个国家!当今中国最可怕的问题之一是严重漠视男子汉形象教育、严重忽视了对男孩子的培养,某种程度上讲中华民族已经到了最危险的时候了!因为面对“台独”日益严重、面对日本军国主义复活的浊流、面对美国对中国崛起的无礼干涉、面对北约东扩对我们未来的挑战、面对中国周边生存环境的日益恶化、面对职工下岗失业的内部压力,大家该不该忧虑啊!二十一世纪的中华民族,是崛起还是沉沦,或许就在于我们明天的男子汉同对方的较量以后,今天的男孩状况还能让我们放心吗?因为教育好一个男孩是为一个民族塑造未来的脊梁,教育好一个女孩是为这个民族的发展提供必要的后续支持,教育好男孩和教育好女孩同样重要,两者不能偏废。自古以来,无论在任何国家、任何民族、任何社会,忘记了男子汉形象的基础教育,这个国家、这个民族必定会在今后的激烈竞争中走向失败、走向灭亡。错误的教育方法,最后只能让这个国家的的国民在自己的祖国国破家亡以后成为敌人的高学历俘虏而已,他(她)们以后的命运会是什么?不言而喻!悲惨啊!因为没有文化素质和综合优良品德的男人永远是愚蠢的男人;没有文化素质和综合优良品德男人的国家永远是贫弱的国家;没有文化素质和综合优良品德男人的民族永远是劣等的民族。

      面向未来的中国,我们每一个真正的中华民族血性男儿都不希望将来看到这一幕发生:当我们父母和年轻的姐妹们被敌人押解时绝望地痛哭:优秀人民子弟兵,你们在哪里?中国男子汉,你们在哪里?

      同学们,走出网吧,我们不能无休止的沉迷于那个虚幻的世界里,因为我们最终必须面对现实。男同学们,我们不需要外在的东西来修饰我们自己,需要有自己的闪光点,但这个闪光点应该是实力、知识和创造能力、报效祖国的能力,不应该是外在的虚荣。我们需要用知识来武装自己、用强健的体魄来表现自己。虽然我们不排斥日本文化,但我们也不能过分的追逐他们。伟大领袖毛主席说过:古为今用,洋为中用。这句话是永恒的真理!今天必须要批判的吸收外国的东西,继承和发扬我们的中华文化,努力学习,以赖宁,宋振中这些优秀的男孩子的行为为榜样,发挥我们创造力为国家创造出更加先进的技术。努力锻炼身体,磨练自我,当祖国需要我们的时候,我们才能够勇往直前。

      很多人发电子邮件问我,中国什么时候能强大,台湾什么时候能回归,我要对他们说,在网络上以嘴爱国,永远也解决不了问题,谩骂美国、日本不会让他们害怕我们,只有我们开始认认真真学习,勤勤恳恳锻炼,踏踏实实爱国,这时中国强大的日子就不远了,美日才能真的害怕中国,中华民族的伟大复兴也就真的来临了。

      作为重点中学的年级第一名、校学生会的主席,这些都不是骄傲的资本,更不是可以轻视女同学的理由,之所以择录、收集这些资料并写这篇文章,完全是自己对中华民族未来的担心和对目前教育界盲目重视女孩子同时压抑、毁灭男生培养的一种焦虑和不安,自古以来落后就要挨打,而不能清醒地认识阴盛阳衰的严重危害、甚至还天真地认为这是文明进步的人不知道想没想到:这其实是一种真正的全民族自杀行为。

    2006年07月22日

    随着社会的进步,人们越来越关注生活的质量,越来越关心生活的环境,环境污染问题也越来越引起人们的重视。人们看到了无线上网带来了自由自在的体验,同时也有部分朋友提出,无线辐射是否对人体有辐射呢?是否若干年后各种受辐射的症状就会慢慢显露出来,不由得不让人在体验无线冲浪得时候,心存一丝顾虑。笔者今天就和大家来谈谈这个问题。

      区别两个概念

      首先大家要区别电磁辐射和电磁污染两个概念,电磁辐射无处不在、无时不在,电磁辐射只有在能量达到一定数值时,才会成为电磁污染,才会对人体产生伤害。小量辐射人体自身的调节能力完全可以抵消其影响。

      适当的电磁辐射不但对人无害,而且对人体有益。

      与同类比较

      现在几乎是人手“一机”了,不管你是GSM、CDMA还是小灵通,都存在电磁辐射的问题,你如果敢放心的使用他们,那么你大可以更放心的去使用无线设备了,因为与上述设备对人体的辐射要比无线设备大的多,下面还是让数据来说话吧。

      目前普遍使用的GSM手机900MHz频段最大发射功率为2W,,1800MHz频段最大发射功率为1W,手机接通的时候功率比普通情况下要大一些,我们就算它是700毫瓦吧。被称为绿色手机的CDMA其实也并不环保,我们有一种错误的认识,CDMA手机在接听来电的时候不会对身边的电话、音箱和屏幕产生干扰,就断定其辐射要比GSM的低很多,其实据专家经过严格的测试,两者对人体辐射不相上下。与前两者相比,小灵通确实可以被称为绿色精灵,其突发发射功率大约80毫瓦。

      而与之相比WLAN无线网卡的发射功率就更小了,一般在40毫瓦左右,而且离人体的距离也比较远,不像手机一样贴在身体上,到达人体一般都不到1毫瓦。

      有的朋友提出微波炉与802.11b的无线设备同处在一个工作频段,所以担心无线网卡的辐射也大,可是一个微波炉的功率都能达到700瓦,而无线网卡才多少啊,所以不用有此担心。

      无线网络中另一对人体的辐射来自于发射无线信号的无线AP或无线路由器,但无线局域网接入点AP的发射功率一般都不超过100毫瓦,这个功率仅相当于小灵通基站的1/5。所以对人的影响要少的多。

    随着社会的进步,人们越来越关注生活的质量,越来越关心生活的环境,环境污染问题也越来越引起人们的重视。人们看到了无线上网带来了自由自在的体验,同时也有部分朋友提出,无线辐射是否对人体有辐射呢?是否若干年后各种受辐射的症状就会慢慢显露出来,不由得不让人在体验无线冲浪得时候,心存一丝顾虑。笔者今天就和大家来谈谈这个问题。

      区别两个概念

      首先大家要区别电磁辐射和电磁污染两个概念,电磁辐射无处不在、无时不在,电磁辐射只有在能量达到一定数值时,才会成为电磁污染,才会对人体产生伤害。小量辐射人体自身的调节能力完全可以抵消其影响。

      适当的电磁辐射不但对人无害,而且对人体有益。

      与同类比较

      现在几乎是人手“一机”了,不管你是GSM、CDMA还是小灵通,都存在电磁辐射的问题,你如果敢放心的使用他们,那么你大可以更放心的去使用无线设备了,因为与上述设备对人体的辐射要比无线设备大的多,下面还是让数据来说话吧

    2005年07月31日

    Writing the Personal Statement

    Brought to you by the Purdue University Online Writing Lab


    An excellent source of help is a book available in the Writing Lab (226 Heavilon Hall):
    Richard Stelzer’s How to Write a Winning Personal Statement for Graduate and Professional School (Princeton, NJ: Peterson’s Guides, 1989). $9.95

    The book has guidelines for writing, examples of successful statements, and advice from admissions officers. This handout summarizes Stelzer’s guidelines and contains a few of the examples he includes of statements and admissions officers’ advice. If you wish to read more examples and do not purchase the book, you may read the Writing Lab’s copy, which is on reserve in the lab.


    The personal statement, your opportunity to sell yourself in the application process, generally falls into one of two categories:

    1. The general, comprehensive personal statement:

    This allows you maximum freedom in terms of what you write and is the type of statement often prepared for standard medical or law school application forms.

    2. The response to very specific questions:

    Often, business and graduate school applications ask specific questions, and your statement should respond specifically to the question being asked. Some business school applications favor multiple essays, typically asking for responses to three or more questions.

    Questions to ask yourself before you write:

    • What’s special, unique, distinctive, and/or impressive about you or your life story?
    • What details of your life (personal or family problems, history, people or events that have shaped you or influenced your goals) might help the committee better understand you or help set you apart from other applicants?
    • When did you become interested in this field and what have you learned about it (and about yourself) that has further stimulated your interest and reinforced your conviction that you are well suited to this field? What insights have you gained?
    • How have you learned about this field–through classes, readings, seminars, work or other experiences, or conversations with people already in the field?
    • If you have worked a lot during your college years, what have you learned (leadership or managerial skills, for example), and how has that work contributed to your growth?
    • What are your career goals?
    • Are there any gaps or discrepancies in your academic record that you should explain (great grades but mediocre LSAT or GRE scores, for example, or a distinct upward pattern to your GPA if it was only average in the beginning)?
    • Have you had to overcome any unusual obstacles or hardships (for example, economic, familial, or physical) in your life?
    • What personal characteristics (for example. integrity. compassion. persistence) do you possess that would improve your prospects for success in the field or profession? Is there a way to demonstrate or document that you have these characteristics?
    • What skills (for example, leadership, communicative, analytical) do you possess?
    • Why might you be a stronger candidate for graduate school–and more successful and effective in the profession or field than other applicants?
    • What are the most compelling reasons you can give for the admissions committee to be interested in you?

    General advice

    Answer the questions that are asked

    • If you are applying to several schools, you may find questions in each application that are somewhat similar.
    • Don’t be tempted to use the same statement for all applications. It is important to answer each question being asked, and if slightly different answers are needed, you should write separate statements. In every case, be sure your answer fits the question being asked.

    Tell a story

    • Think in terms of showing or demonstrating through concrete experience. One of the worst things you can do is to bore the admissions committee. If your statement is fresh, lively, and different, you’ll be putting yourself ahead of the pack. If you distinguish yourself through your story, you will make yourself memorable.

    Be specific

    • Don’t, for example, state that you would make an excellent doctor unless you can back it up with specific reasons. Your desire to become a lawyer, engineer, or whatever should be logical, the result of specific experience that is described in your statement. Your application should emerge as the logical conclusion to your story.

    Find an angle

    • If you’re like most people, your life story lacks drama, so figuring out a way to make it interesting becomes the big challenge. Finding an angle or a "hook" is vital.

    Concentrate on your opening paragraph

    • The lead or opening paragraph is generally the most important. It is here that you grab the reader’s attention or lose it. This paragraph becomes the framework for the rest of the statement.

    Tell what you know

    • The middle section of your essay might detail your interest and experience in your particular field, as well as some of your knowledge of the field. Too many people graduate with little or no knowledge of the nuts and bolts of the profession or field they hope to enter. Be as specific as you can in relating what you know about the field and use the language professionals use in conveying this information. Refer to experiences (work, research, etc.), classes, conversations with people in the field, books you’ve read, seminars you’ve attended, or any other source of specific information about the career you want and why you’re suited to it. Since you will have to select what you include in your statement, the choices you make are often an indication of your judgment.

    Don’t include some subjects

    • There are certain things best left out of personal statements. For example, references to experiences or accomplishments in high school or earlier are generally not a good idea. Don’t mention potentially controversial subjects (for example, controversial religious or political issues).

    Do some research, if needed

    • If a school wants to know why you’re applying to it rather than another school, do some research to find out what sets your choice apart from other universities or programs. If the school setting would provide an important geographical or cultural change for you, this might be a factor to mention.

    Write well and correctly

    • Be meticulous. Type and proofread your essay very carefully. Many admissions officers say that good written skills and command of correct use of language are important to them as they read these statements. Express yourself clearly and concisely. Adhere to stated word limits.

    Avoid clichés

    • A medical school applicant who writes that he is good at science and wants to help other people is not exactly expressing an original thought. Stay away from often-repeated or tired statements.

    Some examples of successful statements

    Statement #1

    My interest in science dates back to my years in high school, where I excelled in physics, chemistry, and math. When I was a senior, I took a first-year calculus course at a local college (such an advanced-level class was not available in high school) and earned an A. It seemed only logical that I pursue a career in electrical engineering.

    When I began my undergraduate career, I had the opportunity to be exposed to the full range of engineering courses, all of which tended to reinforce and solidify my intense interest in engineering. I’ve also had the opportunity to study a number of subjects in the humanities and they have been both enjoyable and enlightening, providing me with a new and different perspective on the world in which we live.

    In the realm of engineering, I have developed a special interest in the field of laser technology and have even been taking a graduate course in quantum electronics. Among the 25 or so students in the course, I am the sole undergraduate ate. Another particular interest of mine is electromagnetics, and last summer, when I was a technical assistant at a world-famous local lab, I learned about its many practical applications, especially in relation to microstrip and antenna design. Management at this lab was sufficiently impressed with my work to ask that I return when I graduate. Of course, my plans following completion of my current studies are to move directly into graduate work toward my master’s in science. After I earn my master’s degree, I intend to start work on my Ph.D. in electrical engineering. Later I would like to work in the area of research and development for private industry. It is in R & D that I believe I can make the greatest contribution, utilizing my theoretical background and creativity as a scientist.

    I am highly aware of the superb reputation of your school, and my conversations with several of your alumni have served to deepen my interest in attending. I know that, in addition to your excellent faculty, your computer facilities are among the best in the state. I hope you will give me the privilege of continuing my studies at your fine institution.

    (Stelzer pp. 38-39)

    Statement #2

    Having majored in literary studies (world literature) as an undergraduate, I would now like to concentrate on English and American literature.

    I am especially interested in nineteenth-century literature, women’s literature, Anglo-Saxon poetry, and folklore and folk literature. My personal literary projects have involved some combination of these subjects. For the oral section of my comprehensive exams, I specialized in nineteenth century novels by and about women. The relation ship between "high" and folk literature became the subject for my honors essay, which examined Toni Morrison’s use of classical, biblical, African, and Afro-American folk tradition in her novel. I plan to work further on this essay, treating Morrison’s other novels and perhaps preparing a paper suitable for publication.

    In my studies toward a doctoral degree, I hope to examine more closely the relationship between high and folk literature. My junior year and private studies of Anglo-Saxon language and literature have caused me to consider the question of where the divisions between folklore, folk literature, and high literature lie. Should I attend your school, I would like to resume my studies of Anglo-Saxon poetry, with special attention to its folk elements.

    Writing poetry also figures prominently in my academic and professional goals. I have just begun submitting to the smaller journals with some success and am gradually building a working manuscript for a collection. The dominant theme of this collection relies on poems that draw from classical, biblical, and folk traditions, as well as everyday experience, in order to celebrate the process of giving and taking life, whether literal or figurative. My poetry draws from and influences my academic studies. Much of what I read and study finds a place in my creative work as subject. At the same time, I study the art of literature by taking part in the creative process, experimenting with the tools used by other authors in the past.

    In terms of a career, I see myself teaching literature, writing criticism, and going into editing or publishing poetry. Doctoral studies would be valuable to me in several ways. First, your teaching assistant ship program would provide me with the practical teaching experience I am eager to acquire. Further, earning a Ph.D. in English and American literature would advance my other two career goals by adding to my skills, both critical and creative, in working with language. Ultimately, however, I see the Ph.D. as an end in itself, as well as a professional stepping stone; I enjoy studying literature for its own sake and would like to continue my studies on the level demanded by the Ph.D. program.

    (Stelzer pp. 40-41)

    Some advice from admissions representatives:

    Lee Cunningham
    Director of Admissions and Aid
    The University of Chicago Graduate School of Business

    The mistake people make most often is not to look at what the questions are asking. Some people prepare generic statements because they’re applying to more than one school and it’s a lot of work to do a personal essay for each school. On the other hand, generic statements detract from the applicant when we realize that we’re one of six schools and the applicant is saying the same thing to each and every school despite the fact that there are critical differences between the kinds of schools they may be applying to. They don’t take the time. They underestimate the kind of attentions that is paid to these essays. Take a look at what the essay asks and deal with those issues articulately and honestly.

    At least 2, and sometimes 3, people read each essay. I read them to make the final decision. Our process works so that each person who reads the application does a written evaluation of what he or she has read and the written evaluations are not seen by the other reader.

    (adapted from Stelzer, p. 49)

    Steven DeKrey
    Director of Admissions and Financial Aid
    J. L. Kellogg Graduate School of Management (Northwestern University)

    We’re looking for a well-written, detailed essay that responds directly to the question. The questions are about extracurricular activities, motivation, challenges, commitment to the school that kind of thing. We see a variety and that’s fine. Our approach is very individualized. The way the applicant devises the answer, determines the length, develops the response, is all part of the answer. The level of effort applicants put into essays varies considerably, which sends messages to the admissions committee as well. Over-involved, elaborate essays send one message, while very brief and superficial essays send another message.

    Trying to second-guess what we are looking for is a common mistake–which we can sense.

    We can tell when applicants use answers to other schools’ questions for our essays; we’re sensitive to this. Poorly written essays are a bad reflection on the applicant.

    Don’t over-elaborate; we’re reading a lot of these kinds of essays. Also, don’t be too brief or superficial. We like to have major ideas presented well.

    ( adapted from Stelzer, p. 55)

    Michael D. Rappaport
    Assistant Dean of Admissions
    UCLA School of Law

    Applicants should take the time to look at what the law school is asking them to write about. At UCLA, we say, "we know you have lots of extracurricular activities–we want to know how you differ, what makes you unique? What can you bring to the first year class that’s going to make you distinctive from the other 99 people who are already there?" The fact that you were active in your fraternity or sorority is really not going to do it. What we’re looking for is somebody who, in their personal statement, stands out as being so unusual, so diverse, that they’re extremely attractive as a law student for the first-year class. Maybe what’s going to make them distinctive is the fact they spent six months living in a log cabin in Alaska. You try to give the law school some justification for admitting you. With a lot of people, there’s nothing that’s going to make them distinctive. If that’s the case, they’ve got to recognize that, indeed, the essay is not going to make that much difference here at UCLA.

    We’re also asking if there’s any reason their LSAT or grades are not predictive. You’d be amazed at the number of people who completely ignore this–they don’t take advantage of the opportunity.

    Most law schools operate fairly similarly. There’s a certain group of applicants whose grades and LSAT scores are so high that the presumption is that the applicants are going to be admitted unless they do something terribly stupid to keep themselves out. I have seen applicants whose personal statement has done that, but it’s extremely rare. At the other extreme is another group of applicants who, no matter what they write, are not going to get in.

    The applicant has to realize, first of all, where he or she stands. If you have a straight-A grade point average and a perfect LSAT score, you don’t have to spend a lot of time worrying about your personal statement. On the other hand, if you know you’re in the borderline area, that’s where the personal statement becomes very, very important.

    The applicant should take the time to read the application to see what the schools are asking for. Sometimes the school will ask for a general description of why you want to go to law school, or why they should admit you, something of that nature. In such case you can be fairly sure that the school is just interested in the essay to see how well you write. So what you say isn’t as important as how you say it. On the other hand, some schools are more specific–UCLA being a very good example of that.

    Make sure the essay is grammatically and technically correct and well written. Avoid sloppy essays, coffee stained essays, or ones that are handwritten so you can’t read them. You’d be amazed at what we get!

    (Stelzer, pp. 70-71)

    Beth O’Neil
    Director of Admissions and Financial Aid
    University of California at Berkeley School of Law (Boalt Hall)

    We’re trying to gauge the potential for a student’s success in law school, and we determine that, principally, on the basis of what the student has done in the past. The personal statement carries the responsibility of presenting the student’s life experiences.

    Applicants make a mistake by doing a lot of speculation about what they’re going to do in the future rather than telling us about what they’ve done in the past. It is our job to speculate, and we are experienced at that.

    Applicants also tend to state and not evaluate. They give a recitation of their experience but no evaluation of what effect that particular experience head on them, no assessment of what certain experiences or honors meant.

    They also fail to explain errors or weaknesses in their background. Even though we might wish to admit a student, sometimes we can’t in view of a weakness that they haven’t made any effort to explain. For example, perhaps they haven’t told us that they were ill on the day that they took the LSAT or had an automobile accident on the way. Such things are legitimate reasons for poor performance. I mean, we understand that life is tough sometimes. We need to know what happened, for example, to cause a sudden drop in the GPA.

    Another mistake is that everyone tries to make himself or herself the perfect law school applicant who, of course, does not exist and is not nearly as interesting as a real human being.

    Between l and 5 people read each application.

    (Stelzer, p. 72)

    Dr. Daniel R. Alonso
    Associate Dean for Admissions
    Cornell University Medical College

    We look for some originality because nine out of ten essays leave you with a big yawn. "I like science, I like to help people and that’s why I want to be a doctor." The common, uninteresting, and unoriginal statement is one that recounts the applicant’s academic pursuits and basically repeats what is elsewhere in the application. You look for something different, something that will pique your interest and provide I some very unique insight that will make you pay some l notice to this person who is among so many other qualified applicants. If you’re screening 5,500 applications over a four- or six-month period, you want to see something that’s really interesting.

    I would simply say: Do it yourself, be careful, edit it, go through as many drafts as necessary. And more important than anything: be yourself. really show your personality. Tell us why you are unique, why we should admit you. The premise is that 9 out of 10 people who apply to medical school are very qualified. Don’t under any circumstances insert handwritten work or an unfinished piece of writing. Do a professional job. I would consider it a mistake to attempt to cram in too much information, too many words. Use the space as judiciously as possible. Don’t submit additional pages or use only 1/20th of the space provided.

    (Stelzer, p.81)

    John Herweg
    Chairman, Committee on Admissions
    Washington University School of Medicine

    We are looking for a clear statement that indicates that the applicant can use the English language in a meaningful and effective fashion. We frankly look at spelling as well as typing (for errors both in grammar and composition). Most applicants use the statement to indicate their motivation for medicine, the duration of that motivation, extracurricular activities, and work experience. So those are some of the general things we are looking for in the Personal Comments section.

    We also want applicants to personalize the statement, to tell us something about themselves that they think is worthy of sharing with us, something that makes them unique, different, and the type of medical student and future physician that we’re all looking for. What they have done in working with individuals–whether it’s serving as a checker or bagger at a grocery store or working with handicapped individuals or tutoring inner city kids–that shows they can relate to people and have they done it in an effective fashion? What the applicant should do in all respects is to depict why he or she is a unique individual and should be sought after. Of course, if they start every sentence on a whole page with "I," it gets to be a little bit too much.

    (Stelzer, p. 82)

    2005年06月10日

    免费建400人的群

            利用qq推出的在线企业服务建4个群,没级别限制,每个群可加100人。

            首先保证你的qq版本是2005beta1 及以上的版本。在qq的主面板上有“个人帐号”图标(就是3个硬币),单击那个图标,在打开的窗口中右击---属性。会看到一些信息例如:http://pay-client.qq.com/index.s … 05D39B8F129FE10C481

             请记住,“clientkey=”后面的那一传数字,(每个号码对应不同的验证码)打开记事本,把这个网址复制到记事本中进行修改,http://im.qq.com/cgi-bin/toc/toc … 05D39B8F129FE10C481

              把"uin="后面的数字改成你的qq号码,“signature=”后面是我让你记住的那个验证码,改完后保存,打开那个网址,在那里 就可以随便注册了~~~~哈哈,资料可以随便填写,后面的不用我说了吧~~~~~~~