原理 跨站脚本(Cross site script,简称xss)是一种“HTML注入”,由于攻击的脚本多数时候是跨域的,所以称之为“跨域脚本”。 我们常常听到“注入”(Injection),如SQL注入,那么到底“注入”是什么?注入本质上就是把输入的数据变成可执行的程序语句。SQL注入是如此,XSS也如此,只不过XSS一般注入的是恶意的脚本代码,这些脚本代码可以用来获取合法用户的数据,如Cookie信息。 其原理如下图所示:
XSS从攻击原理上,分为三类:
1:反射型XSS 将用户输入“反射”回浏览器,即将用户的输入变成HTML传输回客户端。如: Response.Write(“”) 就是一个典型的反射型XSS。 2:存储性XSS 存储性XSS本质上也是一种反射型XSS,但是它把攻击脚本放置在服务器端,一旦被注入,可被多人多次利用。如,发表博文,就可以引入存储性的XSS。 3:DOM BASED XSS 如果用户的输入被用于修改原有HTML的DOM内容,就会引入这一类攻击。 最典型的是输入的内容用于作为某个节点的innerHTML,如果不对输入作验证,则会被注入攻击代码。 如下的一段脚本注入后,就会获取用户的Cookie
<script language=”JavaScript”> var cockieInfo =window.cockie; //send cockieInfo to luminji </javascript>实际案例 使用Fiddler,查看到某系统添加公共信息有一处Post,我们伪造如下的请求:
POST xxx.com/AddPublicInfo HTTP/1.1 Accept: */* Accept-Language: zh-cn Content-Type: application/json; charset=utf-8 Accept-Encoding: gzip, deflate Host: 192.168.80.136 Content-Length: 187 Cookie: ASP.NET_SessionId=qk1qvprjrikp2peveg2ini45; LanguageKey=zh_cn; LoginId=dean; {"type":"ExtBulletin","title":"1111asdf11","content":"22sdfs22<script>alert(/xss/);</script>","validPeriod":"1","beginDate":"","endDate":"","language":"None","linkFile":"0","fileName":""}然后,刷新公共信息页面,发现注入代码成功。如果该站点同时存在会话劫持方法的漏洞,则将注入脚本改称获取cookie,攻击者就可以伪造任意访问了本信息的用户来登录系统。 通过该例子我们也可以看到,对于XSS的防范,所有的处理应该是在服务器端的,因为客户端的验证,如使用JS来验证输入是完全可以通过伪造请求被绕过的。所以在安全架构方面对于JS脚本的定位为:JS仅用于改善用户体验。 预防: 1. 在服务器段限制输入格式,输入类型,输入长度以及输入字符 要注意避免使用一些有潜在危险的html标签,这些标签很容易嵌入一些恶意网页代码。 注意,不要仅仅在客户端使用js代码加以验证。因为客户端的js脚本可以被绕过。 2. 对于asp.NET站点,可以确保
<configuration> <system.web> <pages validateRequest="true" /> </system.web> </configuration>注意,默认情况下为true。 3. 可以使用微软推出的用于防止XSS攻击的一个类库,可实现输入白名单机制和输出转义 使用微软推荐使用的XSS类库其实很方便;首先在NuGet中获取XSS类库,然后根据自己需求可以查找具体方法;如果要将数据保存到数据库的时候一般使用AntiXss.GetSafeHtmlFragment(html)方法 ,这个方法会替换掉html里的危险字符,然后保存到数据库中; 1)下面的辅助方法是将对象中的危险字符过滤掉:
public static T FilterSensitiveWords<T>(T classObject) { if (classObject == null) { return classObject; } List<PropertyInfo> propertyInfoList = new List<PropertyInfo>(); propertyInfoList = classObject.GetType().GetProperties().ToList(); foreach (var property in propertyInfoList.Where(x => x.PropertyType == typeof(string))) { var value = property.GetValue(classObject); if (value != null) { value = Sanitizer.GetSafeHtmlFragment(value.ToString()); property.SetValue(classObject, value); } } return classObject; }2) 在使用AntiXss替换危险字段的时候,如果该项目使用mvc或者webapi来做的话可以使用 Filters 附加过滤敏感信息 ASP.NET MVC/WebApi 中加在 Controller 或 Action 上的一种 Attribute。MVC 网站在处理用户请求时,可以处理一些附加的操作,如:用户权限验证、系统日志、异常处理、缓存等。使用Filters可以使用简洁、强大的方式实现 AOP,Filter 中定义的行为可以在网站中多处简单方便的复用。 在ActionFilterAttribute过滤类中有方法OnActionExecuting(Action方法执行之前执行)和OnActionExecuted(Action方法执行之后执行) 该处我们要使用OnActionExecuting方法当调用action方法之前首先执行OnActionExecuting方法对参数进行验证 具体使用如下:
/// <summary> /// 过滤敏感字符类 /// </summary> public class SensitiveWordsFilterAttribute : ActionFilterAttribute { /// <summary> /// 在每个方法之前过滤敏感字符 /// </summary> /// <param name = "filterContext" ></ param > public override void OnActionExecuting(HttpActionContext filterContext) { var dictParameters = filterContext.ActionArguments; List<PropertyInfo> propertyInfoList = new List<PropertyInfo>(); foreach (var para in dictParameters) { propertyInfoList.Clear(); Object classObject = para.Value; if (classObject == null) { continue; } propertyInfoList = classObject.GetType().GetProperties().ToList(); foreach (var property in propertyInfoList.Where(x => x.PropertyType == typeof(string))) { var value = property.GetValue(classObject); if (value != null) { value = Sanitizer.GetSafeHtmlFragment(value.ToString()); property.SetValue(classObject, value); } } dictParameters[para.Key] = classObject; } //filterContext.ActionArguments = dictParameters; } }具体调用(就是在action上面添加该Filter名称):
[SensitiveWordsFilter] public async Task<SendMessageResponseDto> Send(SendEmailMessageRequestDto dto) { //... }备注: ActionFilterAttribute在Mvc中和在WebApi项目中两个引用命名空间是不一样的 apiController控制器对应的是System.Web.Http.Filters.ActionFilterAttribute的过滤器 Controller控制器对应的是System.Web.Http.Mvc.ActionFilterAttribute的过滤器
通过上面辅助类可以将危险字段进行替换,例如:
"<a href=\"#\" onclick=\"alert();\">aaaaaaaaa</a>javascript<P><IMG SRC=javascript:alert('XSS')><javascript>alert('a')</javascript><IMG src=\"abc.jpg\"><IMG><P>Test</P>";替换以后:
<a href="">aaaaaaaaa</a>javascript <p><img src="">alert('a')<img src="abc.jpg"><img></p> <p>Test</p>本文主要参考的文章有: XSS攻击原理 AntiXSS - 支持Html同时防止XSS攻击