课程表

网络安全课程

工具箱
速查手册

Web页面的私密性

当前位置:免费教程 » 其他 » 网络安全
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2018/1/18 13:47:15

互联网上的网站,除了一些原始的只有HTML页面的网站,基本上都有必须经过身份验证才能访问的页面,如网站的内容管理后台,注册用户的登录、管理后台。这些页面在经过充分而安全的身份验证前,如果暴露给攻击者,后果可能是灾难性的。

而即使是同一后台页面,也往往需要对不同的用户进行权限上的区分。比如,一个管理后台对超级管理员、普通管理员、采编人员进行区分。一个面向普通用户的用户后台,需要区分普通用户和不同级别的VIP用户。根据其身份的不同,给予其不同的权限配置。

目前,主流采取的身份验证方式是Forms形式的验证,即通过表单机制,对用户传来的用户名和密码进行逻辑验证。也可以采用OAuth 2.0协议之类的,引用第三方验证,赋予权限。也有通过IIS之类的服务器软件进行身份验证的站点,但多为局域网(Intranet)应用,并非主流。


一、Forms(表单)+会话(session)方式验证

这是目前运用最为广泛的身份验证方式。其基本的原理是,服务器为某个session(会话空间)分配一个内存,这个会话空间里保存了众多连接到服务器的客户端对象。不同的客户端,在服务器端拥有私有的(如果允许多点登录,可能相同的)session值,这些值被服务器语言解释程序直接用来判定客户端的身份,因此,从安全角度说,session的获取条件必须尽可能的苛刻。

在获取session后,我们就可以获取某个客户端特定的session值,来给予其特定的权限。

需要注意的是,一个session的存活需要指定特定的客户端,特定的服务器端以及不中断的操作时间。如果一段时间不进行任何操作,则session就会被注销,这段时间通常被俗称为掉线时间,规范一点的称谓超时时间。这个时间一般为20-30分钟,在IIS、Apache等服务器软件上可以设置这个时间。

令人感到意外的是,虽然计算机世界充斥着各种语言和技术,每种语言对某些同样或类似的东西往往有着不同的称谓,但在session这个机制上,它们却是出奇的统一:从老式的微软ASP,到ASP.net,再到PHP、JSP,会话的规范名称都是“session”。

1、执行严格的赋予session的策略

session一旦被赋予,就会被服务器端赋予各种各样的权限。因此,应该对赋予条件进行充分的判断。

一般情况下,我们会将用户账号、加密过的密码保存在服务器的数据库中。当然,你也可以存在Active Directory(Windows平台)、注册表或者动态页面代码中,非常不推荐将账号密码存在文本文件或任意其他实体文件中。但目前主流是存储在数据库中。

存在服务器上的账号和密码,账号可以以公开形式存储,但密码必须经过特定程度、方式的加密。一种十分流行的做法是使用MD5加密来对密码进行各种变种加密。由于当前存在着暴力破解MD5值的网站(免费或收费),1-3层的MD5加密已经不是绝对安全了(3层的MD5加密即对某个字符串的MD5值再进行2次MD5加密),我们应该采取另外一种方式:即自己独特的变种加密。你或许认为,1-3层的MD5加密都不够,那么明文存储密码岂不是更不安全。然而,明文存储密码这样的事情却曾经出现在大名鼎鼎的技术网站CSDN上,简直令人惊叹。2011年底爆发的CSDN泄密事件曾经震惊了整个互联网。

自己独特的变种加密如何进行呢?例如,在加密方法中混入一个较长的字符,然后进行各种嵌套,各种混入。这个加密方法应该是如此的复杂,以至于短时间内除了目前尚未成型的量子计算机,否则根本找不到破解办法。这个加密方法在用户输入特定密码字符时就应该通过JS进行本地化的处理,这样,即使攻击者截获了用户的密码字符串,得到的也只是一堆加密字符(密文)。而使用前端JS加密后,就算攻击者知道加密方法和密文,也无法进行逆向破解。

当加密过的密码被送到服务器后,与服务器上存储的密文进行比对,比对成功,则赋予该客户端权限。

你还可以使用多重验证法,即除了比对数据库里面的用户名和密码,还可以将类似“密钥”的东西存储在程序代码中,用户输入“密钥”后,该输入被进行本地化加密,传送到服务器,用后端语言对其值和代码值进行比对,只有账号、密码完全正确的同时,密钥也正确,才赋予权限。这里特别要注意语法的正确性,如果语法不正确,服务器可能会将技术细节返回到客户端。即使“密钥”的内容就算被攻击者获取到了,如果没有开放站外登录,短时间内也难以破解,但始终这是一种隐患,因为它使得攻击者了解了正确的“密钥”是什么。

下面介绍各种语言的session赋予办法。

2、ASP

先从ASP说起,ASP创建一个名字为“admin”的session,并将其值设置为“myname”,语法如下:

  1. Session("admin")="myname"

一旦值被存入 session 变量,它就能被 ASP 应用程序中的任何页面使用:

  1. Welcome <%Response.Write(Session("admin"))%>

这段代码会显示为“Welcome myname”。

修改session和创建的语法一样。只要直接赋值就行。而删除session也很简单,其语法如下:

  1. <%
  2. Session.Abandon
  3. %>

更详细的使用方法,请点击这里:ASP Session

3、ASP.net

ASP.net创建session的方式也很简单,直接赋值就行了,但要注意,session的名称要放到中括号里,而不是老式ASP中的圆括号:

  1. Sesssion["admin"] = "myname";

使用起来也很简单:

  1. string userName=Session["admin"].ToString();

修改session和创建的语法一样(这一点和老式ASP一样)。只要直接赋值就行。而删除所有session语法如下:

  1. Session.Clear();

4、PHP

在PHP中,在您把用户信息存储到 PHP session 中之前,首先必须启动会话。session_start() 函数必须位于 标签之前:

  1. <?php session_start();
  2. $_SESSION['admin']="myname";
  3. ?>
  4. <html>
  5. <body>
  6. </body>
  7. </html>

使用起来也很方便:

  1. echo $_SESSION['admin'];

如果您希望删除某些 session 数据,可以使用 unset() 或 session_destroy() 函数。

unset() 函数用于释放指定的 session 变量:

  1. <?php
  2. unset($_SESSION['admin']);
  3. ?>

也可以通过 session_destroy() 函数彻底终结所有 session:

  1. <?php
  2. session_destroy();
  3. ?>

有关PHPsession的章节:PHP Sessions

5、JSP

JSP中,设置一个session的语法如下:

  1. HttpSession session = request.getSession();
  2. session.setAttribute("admin", "myname");

获取session的语法如下:

  1. request.getSession().getAttribute("admin");

如何删除session呢,可以调用public void removeAttribute("admin") 方法来移除指定的session,也可以调用public void invalidate()方法来使整个session无效。

更多关于JSP session的相关知识,请访问我们的JSP Session章节

6、如何维持session

不同语言的session有着不同的超时时间,一旦过了这个时间,服务器端将会自动删除该客户端的session,客户端将会自动失去会话状态。而如何维持这个session呢?从代码角度说,有HTML/JS代码(即前端方法)和服务器端方法之分。

最常用的前端方法有2个:一是通过JS+HTML DOM,另一种则是通过meta标签。

JS+HTML DOM方法代码如下(这里刷新时间设定为10分钟):

  1. <script>
  2. functionrefresh(seconds){
  3. setTimeout("self.location.reload()",seconds*1000);
  4. }
  5. refresh(600);//调用方法启动定时刷新,数值单位:秒。
  6. </script>

通过meta标签方法的代码如下,可以将该代码放到<head>与</head>之间:

  1. <meta http-equiv="refresh" content="600" />

在上述两种方案中,较好的为第二种,因为如果当前页面是在IE浏览器的模式窗口中打开的,默认情况下,self.location.reload()方法将会失效,而refresh meta标签在IE模式窗口下仍然有效。但是,要注意的是,不要在主页面中直接使用这2种方法!因为如果直接使用它们,存在致命的缺陷。试想一下,如果用户在论坛敲了许多字,突然碰到自动刷新页面,那么用户体验将是极差的。如何避免这一缺陷呢?我们可以用两种方法:一是Ajax,定期的向服务器发出请求,来维持session,但缺点是在某些浏览器里会被屏蔽(如,微信的内置浏览器会屏蔽Ajax机制),二是通过插入一个宽高皆为0像素、看不到的iframe页面,但这样做叶有缺点,姑且不论会消耗更多客户端内存,而是现在的技术标准已经逐渐废弃了<iframe>标签,在可预见的未来,<iframe>标签将会被彻底的放弃。

从服务器端来说,又分为:服务器软件设定法和代码方法两种。服务器软件设定法即设置IIS、Apache等服务器软件中的超时时间,将超时时间设置长一点。这个方法虽然简洁,但有很大的缺陷:对所有类型的session都是一样的(我们往往只需要保持一种session长期在线),这样就会消耗大量服务器资源。

而代码方法大致又分为两种:一是修改页面超时时间。二是通过cookies保存账号密码。

先来说说通过代码方式修改页面超时时间。主流的语言,修改超时方式的语法都很简洁。首先我们看老式的ASP(时间为分钟):

  1. <%
  2. Session.Timeout=30
  3. %>

再来看下ASP.net。ASP.net有3种修改超时时间的办法:可以通过Machine.config、Web.config、单个页面代码修改。

Machine.config方式修改的是全局超时时间,即对所有服务器上的站点都一视同仁,因此缺乏灵活性。代码如下,这里设置为默认的90秒:

  1. <httpRuntime executionTimeout="90" maxRequestLength="4096" useFullyQualifiedRedirectUrl="false" minFreeThreads="8" minLocalRequestFreeThreads="4" appRequestQueueLimit="100" />

Web.config可以设置单个站点超时时间,这里设置的为720秒,前面的属性maxRequestLength为用户上传文件限制大小:

  1. <system.web>
  2. <httpRuntime maxRequestLength="102400" executionTimeout="720" />
  3. </system.web>

单个页面也可以规定本页面的超时时间,可以使用Server.ScriptTimeout来设定超时:

  1. Server.ScriptTimeout = 120;

如果在Web.config里设置了debug属性,此时,ScriptTimeout会被忽略:

  1. <compilation debug="true" targetFramework="4.0">

PHP修改页面超时时间有2种办法,一是通过设置php.ini配置文件,二是通过代码方法。先来看看php.ini的配置方法,通过设置session.gc_maxlifetime和session.cookie_lifetime节点属性值可以设置超时时间:

  1. ini_set('session.gc_maxlifetime', "3600"); // 秒
  2. ini_set("session.cookie_lifetime","3600"); // 秒

第二种方法即通过代码方法设置Session时间戳:

  1. $_SESSION['expiretime'] = time() + 3600; // 刷新时间戳,单位:秒

JSP可以调用 public void setMaxInactiveInterval(int interval) 方法来设置session超时。

页面session超时时间如果设置的很长,会拖慢服务器。一个更加长期保存session的办法是使用cookies保存账号密码,但是必须注意一点,保存到cookies中的密码,必须经过独特的加密(不要采取简单的公有方法,如1-3层的MD5等),取而代之,可以采取一种独特的可逆加密方法,这个方法的加密解密需要自己写。然后在用户再次访问页面的时候,将账号和加密过的密码送回服务器端,服务器端代码对加密后的密码进行解密,并将其与数据库或者存在其他地方的账密进行比对。比对成功,则重新赋予session。如果不知道从哪里下手,可以参照接下来的相关章节。但这种办法的安全性并不高,一旦机器中毒,cookies被恶意软件读取,就可以被攻击者利用,容易造成账号密码的丢失。

在这里,提供另一个思路,可以通过IP+cookies保存账号的办法,来维持登录状态。即如果处于特定IP下的机器,如果同时拥有特定的cookies,则赋予其登录状态。另一个更严苛的办法是,IP+cookies保存账号和密码。同上面的方法一样,由于cookies本身的特性,这种机制同样不是很安全。


二、ASP.net独有验证方式

1、设置ASP.net身份验证方式

ASP.net有3种方式进行身份验证:Windows身份验证、Forms身份验证、.net Passport身份验证。

Windows身份验证适合Intranet(局域网)应用。在一个机器中,所有的.net应用都共有一个Machine.config,这个文件的设置对该机器上所有.net应用有效,除非它被Web.config的设置覆盖。而Web.config位于每个.net应用程序中,它是该程序的设置,甚至连子目录都可以有自己的Web.config,且如果其覆盖了父级Web.config的设置,则其权限比父Web.config文件还高。

Web.config中的<system.web>节的子节<authentication>中,为该应用设置身份验证方法。mode参数被设置为以下值中的一种:Windows、Forms、Passport或none。下面的示例,将验证办法设置为Windows身份验证:

  1. <system.web>
  2. <authentication mode="Windows" />
  3. </system.web>

当然,除了设置身份验证模式,还可以设置其他更加详细的规则:

  1. <system.web>
  2. <authentication mode="Windows" />
  3. <authorization>
  4. <allow users="Domain\users" />
  5. <allow roles="Domain\group" />
  6. <deny users="*" />
  7. </authorization>
  8. </system.web>

如果这些设置被子目录的Web.config覆盖,则子目录会采用自己的设置。可以通过增加多个allow 和 deny来允许或拒绝某些用户或角色的访问。用户或角色的意义是由ASP.net Web应用程序配置使用的IIS身份验证类别来决定的。对于基本和集成的Windows身份验证,用户是计算机或域用户,角色是计算机或域组。

allow和deny的规则如下:

通配符 <allow>部分 <deny>部分
* 允许任何人访问 拒绝任何人访问
? 允许匿名用户访问 拒绝未授权用户访问

例如,下面的代码拒绝所有未授权用户的访问:

  1. <authorization>
  2. <deny users="?" />
  3. </authorization>

下面的代码允许名为Bill和Tom的用户访问:

  1. <authorization>
  2. <allow users="Domain\Bill,Domain\Tom" />
  3. <deny users="*" />
  4. </authorization>

但是这只是演示例子,通过Web.config的方式对单个用户进行授权是不好的习惯,如果Web.config被暴露,将会透露重大的敏感信息。

可以通过roles属性来启用基于角色的安全性,如下面的代码只允许管理员组访问:

  1. <authorization>
  2. <allow roles="Domain\Administrators" />
  3. <deny users="*" />
  4. </authorization>

<allow>和<deny>出现的顺序是很重要的,先出现的规则将会拥有更高的权限。例如,下面的配置将禁止任何用户的访问:

  1. <authorization>
  2. <deny users="*" />
  3. <allow roles="Domain\Administrators" />
  4. </authorization>

那么,如何保证单个页面或文件夹的访问安全呢?这里可以使用<location>节来配置访问权限:

  1. <location path="manager.aspx">
  2. <system.web>
  3. <authorization>
  4. <deny users="?" />
  5. </authorization>
  6. </system.web>
  7. </location>

其中的path属性也可以设置为整个文件夹。一个Web.config文件中,可以配置多个<location>节。

2、Windows身份验证

在Intranet应用中,如果用户被分配了域账户和组,就可以使用Windows身份验证。在之前的教程中,我们已经简要介绍了IIS基本、摘要式或集成式身份验证。如果ASP.net采用Windows身份验证,那么IIS可以通过使用已配置的IIS身份验证机制来执行身份验证。

使用Windows身份验证有3个步骤:

  1. 配置IIS
  2. 在Web.config中设置身份验证方式为“Windows”
  3. 在Web.config中设置授权

第1步,配置IIS,使得IIS使用下面一种身份验证:匿名、基本、摘要式、集成Windows。通常可以启用基本身份验证,如果想让除IE外的其他浏览器兼容,那么必须使用基本身份验证方式。如果客户端没有通过防火墙或者代理服务器,就可以使用Windows身份验证。

第2步,设置身份验证:

  1. <system.web>
  2. <authentication mode="Windows" />
  3. </system.web>

第3步,设置授权:

  1. <location path="manager.aspx">
  2. <system.web>
  3. <authorization>
  4. <deny users="?" />
  5. </authorization>
  6. </system.web>
  7. </location>

3、Forms身份验证

为一个ASP.net程序启用Forms身份验证,必须完成4步:

  1. 配置IIS,使用匿名身份验证
  2. 在Web.config中设置身份验证方式为“Forms”
  3. 设置授权
  4. 创建一个登陆页面

第1步在之前的教程中已有介绍,每个版本的IIS版本,设置方式也有差异,但总体来说都很简单,这里不再赘述。

第2步,设置身份验证方式,需要在Web.config中进行如下配置:

  1. <system.web>
  2. <authentication mode="Forms">
  3. <forms loginUrl="login.aspx" />
  4. </authentication>
  5. </system.web>

在这里,login.aspx是被指定的跳转页,凡是未经授权的用户,都会跳转到这个页面。必须通过SSL(安全套接字层)来保护登录页面,即https://开头的页面地址。有关SSL的知识,将在后面的内容中介绍。

第3步,设置授权,和上述Windows身份验证方式一样,可以指定特定的页面或文件夹的访问权限。

第4步,创建登录页面。这个登录页面拥有一个可以输入用户名和密码的表单,可以通过比对用户的输入以及服务器上存储的用户名密码,来决定是否给该用户授权。

这个验证机制的前3步,之前已经介绍过了,现在介绍关键的第4步。

这个登录页login.aspx如何验证登录呢,是通过session判定吗?NO!session的方法上一节已经介绍过了。这里,我们可以使用.net的FormsAuthentication 对象的方法来验证用户。

如何判断用户已登录呢?使用Request.IsAuthenticated属性,如果值为true,则表示已登录。如果已登录,使用HttpContext.User.Identity.Name属性可获取登录名。

下面,我们正式开始实战。为了便于说明,我们采取.net的WebPages模型,可以利用.net服务器组件将其转换为Web Forms。这里,先准备一个简单的登录页面:

  1. <h1>用户状态</h1><form action="<%= Request.RawUrl %>" method="post">
  2. <% if( Request.IsAuthenticated ) { %>
  3. 当前用户已登录,登录名:<%= Context.User.Identity.Name.HtmlEncode() %> <br />
  4. <input type="submit" name="Logon" value="退出" />
  5. <% } else { %>
  6. <b>当前用户还未登录。</b>
  7. <% } %>
  8. </form>

可以看出,当前页面只能判断用户是否已登录,但目前还没有登录框供用户进行输入。下面我们加上登录框:

  1. <h1>普通登录</h1><form action="<%= Request.RawUrl %>" method="post">
  2. 登录名:<input type="text" name="loginName" style="width: 200px" value="DoctorWho" />
  3. <input type="submit" name="NormalLogin" value="登录" />
  4. </form>

现在,我们有了一个判断区域,和一个登录区域。但是,现在我们还缺少登录过程的代码:

  1. public void Logon()
  2. {
  3. FormsAuthentication.SignOut(); //FormsAuthentication 对象的 SignOut()方法可以实现退出登录
  4. }
  5.  
  6. public void NormalLogin()
  7. {
  8. // -----------------------------------------------------------------
  9. // 注意:演示代码没有检查用户名与密码是否正确,检查用户名和密码是否正确的相关知识,参见上一节的介绍。
  10. // -----------------------------------------------------------------
  11.  
  12. string loginName = Request.Form["loginName"];
  13. if( string.IsNullOrEmpty(loginName) )
  14. return;
  15. FormsAuthentication.SetAuthCookie(loginName, true);
  16.  
  17. TryRedirect();
  18. }

现在,我们只要在登录区域的文本框中输入直接点击“登录”按钮(由于文本框有默认值DoctorWho),就可以实现登录。点击状态区域的退出按钮,就可以退出登录了。这里,我们总结一下登录与注销的方法:

  • 登录:调用FormsAuthentication.SetAuthCookie()方法,传递一个登录名即可。
  • 注销:调用FormsAuthentication.SignOut()方法。

基本的逻辑就是这样,如果想实现用户名、密码的验证,以及具体的用户登录权限,则需要结合.net的相关知识,通过C#或VB.NET 来实现具体的业务逻辑。

4、.net Passport身份验证

.net Passport身份验证是一种利用微软的账号,实现本地站点登录的身份验证方式。本质上,它与QQ账号登录、微信账号登录、微博账号登录一样,属于第三方账号登录。由于当前国内采取这种方式登录的站点比大熊猫还稀少,这里不再赘述。


三、第三方登录

第三方登录的基本过程是,用户客户端通过访问你的站点的页面,转到第三方平台(QQ、微信、微博)进行验证,第三方平台给用户带有票据信息的Cookies,再携带这个cookie访问你的站点,你的站点对其进行授权。

目前,国内主流的第三方登录有:QQ账号登录、微信账号登录、微博账号登录。支付宝/淘宝账号由于涉及资金安全问题,应用并不广泛,只在阿里系的相关网站中使用。这些地方登录都遵循着一个协议:OAuth 2.0协议。如果你想学习OAuth 2.0协议的相关技术,请访问我们的OAuth 2.0教程。具体的登录方式,各个平台大同小异,具体请参照官方的文档。这里列出这三个平台的申请地址:

注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2018/1/18 13:47:15
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号