[转载]Android开发过程中内存泄露检测 - 观千剑而后识器,操千曲而后晓声。 - 博客频道 - CSDN.NET

mikel阅读(1114)

[转载]Android开发过程中内存泄露检测 – 观千剑而后识器,操千曲而后晓声。 – 博客频道 – CSDN.NET.

一、内存泄露

内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。

内存泄漏可能不严重,甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。

在以下情况,内存泄漏导致较严重的后果:

1)程序运行后置之不理,并且随着时间的流失消耗越来越多的内存(比如服务器上的后台任务,尤其是嵌入式系统中的后台任务,这些任务可能被运行后很多年内都置之不理);
2)新的内存被频繁地分配,比如当显示电脑游戏或动画视频画面时;
3)程序能够请求未被释放的内存(比如共享内存),甚至是在程序终止的时候;
4)泄漏在操作系统内部发生;
5)泄漏在系统关键驱动中发生;
6)内存非常有限,比如在嵌入式系统或便携设备中;
7)当运行于一个终止时内存并不自动释放的操作系统(比如AmigaOS)之上,而且一旦丢失只能通过重启来恢复。

二、内存泄漏检测工具

当一个Java对象已经没有其他对象引用它时,Java的垃圾回收器会将其回收并释放内存。

一个Java的Heap Dump文件指的是在一个时间点上Java对象的内存镜像导出文件。它包括了所有的对象、字段、原始类型和对象引用。它可以指示当JVM产生OutOfMemory错误的情况下自动创建一个堆转储。

使 用Eclipse MAT(Eclipse Memory Analyser),有助于图形化基于Java堆转储的对象引用,并提供工具以发现潜在的内存泄露。为了能让Java虚拟机(JVM)在发生 OutOfMemory错误时生成内存镜像文件,我们可以使用-XX:+HeapDumpOnOutOfMemoryError选项,如图21.1所示。

安装Eclipse MAT的步骤如下:

1)启动Eclipse,点击Help -> Intall New Software…;
2)点击输入栏右侧小箭头,选择”Juno”(不同版本要找到和自己版本名称对应的选项);
3)等待列表更新完毕,找到并展开”General Purpose Tools”;
4)选中并下载其中的”Memory Analyser (Incubation)”和”Memory Analyser (Charts)”两项。
5)之后根据提示进行安装。

三、MAT使用示例

1)创建工程

新建Android 工程 “com.devdiv.test.mat_test”。并且新建如下类,然后运行该工程。

package com.devdiv.test.mat_test;
 
import java.util.ArrayList;
import java.util.List;
 
import android.app.Activity;
import android.os.Bundle;
 
public class MainActivity extends Activity {
 
    List<String> list = new ArrayList<String>();
//    private PersonInfo person = new PersonInfo();
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         
        new Thread () {
            @Override
            public void run() {   
                while (true){
                        MainActivity.this.list.add("OutOfMemoryError soon");
                }
            }
        }.start();
    }
   
}

2)分析内存

要获得.hprof内存镜像文件,你可以在进程运行过程中,切换到DDMS的透视图页面,选中您要查看内存镜像的进程,点击“Dump HPROF file”即可。

QQ截图20150325221152
生成的hprof文件会默认使用MAT打开,选择“Leak Suspects Report”后,点击Finish按钮。
QQ截图20150325221224
图16-2 用MAT打开内存镜像文件

经过一段时间的初始化后,就能够直观地看到关于内存泄露的饼图,如下图所示:
QQ截图20150325221258
图16-3 内存泄露饼图

然后就可以查看相关的内存泄露,如下图所示:
QQ截图20150325221332

手机App三年内将彻底消失

mikel阅读(1556)

原文《手机App三年内将彻底消失 HTML5将颠覆原生App世界?》摘要

  HTML5对开发者的7大优势

跨平台:在多屏年代,开发者的痛苦指数非常高,人人都期盼HTML5能扮演救星。多套代码、不同技术工种、业务逻辑同步,这是折磨人的过程。有 点类似个人电脑早期世界,那个时候的每家电脑都有自己的操作系统和编程语言,开发者疲于做不同版本,其实DOS的盛行也很大程度是因为开发者实在没精力给 其他电脑写程序。跨平台技术在早期大多因为性能问题夭折,但中后期硬件能力增强后又会占据主流,因为跨平台确实是刚需。

快速迭代:移动互联网是一个快鱼吃慢鱼的时代,谁对用户的需求满足的更快,谁的试错成本更低,谁就拥有巨大的优势。互联网产品大多免费、且有网 络效应,后入者抢夺用户的难度非常大。使用原生开发,从招聘、开发、上线各个环节的效率都慢一倍以上,而且参与的人越多,沟通效率往往拖慢不止一倍。

持续交付:很多人有这样的体会,一个原生应用上线Appstore,突然有一个大bug,只好连夜加班修复,然后静静等待2周或更长时间的 Apple审核,这2个星期被用户的涂抹淹死,市场上一片差评,用户大量流失。等新应用被审核上线了,用户已经卸载了。但是,HTML5没有这些问题,你 可以实时更新,有问题立即响应。

大幅下降成本:创业者融资并不容易,如何花钱更高效非常重要。如果你使用原生开发的App和竞争对手使用HTML5开发的App没什么区别,但你的开发成本高出一倍,我相信没有投资人会喜欢给你投钱。

开源生态系统发达:HTML5前端是开放的正反馈循环生态系统,大量的开源库可以使用,开发应用变得更轻松、更敏捷,当然这也体现在了快速迭代和成本下降上。不过更重要的是,这种开放的正反馈循环生态系统未来的生命力是比原生生态系统更强劲的。

开放的数据交换:HTML是以page为单元开放代码的,它无需专门开发SDK,只要不混淆,就能与其他应用交互数据。开发者可以让手机搜索引擎很容易检索到自己的数据, 也更容易通过跨应用协作来满足最终用户需求。

更容易推广、更容易爆发:导流入口多:HTML5应用导流非常容易,超级App(如微信朋友圈)、搜索引擎、应用市场、浏览器,到处都是HTML5的流量入口。而原生App的流量入口只有应用市场。聪明的HTML5开发者当然会玩转各种流量入口从而取得更强的优势。

流量大:前段时间微信朋友圈风靡一时《神经猫》,这个游戏如果放到Appstore,绝对没有那么多流量,超级App带来的流量,远大于原生应用市场。假如微信允许游戏在桌面创建快捷方式、假如游戏后续升级解决持续娱乐问题,未来不可想象。

导流效率高:除了入口多、流量大,导流效率高也不可忽视,谁都知道:页游和端游打同样的广告,广告变用户的转化率,页游远远高于端游。

观点:

互联网时代的HTML页面浏览开始,到移动互联网一直喊着HTML5标准公布,移动互联网上的HTML5的应用越来越多,是否会颠覆现有的APP开发格局,是后起之秀,还是鸡肋,从目前各种第三方的HTML5的开发框架上看还是有待改进,原生的APP开发比HTML5的优势就在于更加深入系统底层,基本上无障碍的对接手机本身的系统,而HTML5开发就更像是为了跨平台而不得不放弃很多强植入的东西,让原生APP开发的人感觉有点儿鸡肋,有些功能还要绕一圈儿才能实现,尽管可以跨Android和Ios两个平台无缝对接,但是还是有很多地方需要改进,目前市面上更多的应用都是杂交的产物,原生APP中嵌入HTML5的东西,这样的开源框架也有很多,只能说这个好现象,毕竟大家都想着简化开发过程,但是要说HTML5取代原生APP开发,说得的确有点儿过了!就像“哪种开发语言好?”的问题一样,仁者见仁智者见智,没有最好的开发语言,只有最适合的!希望HTML5更加成熟更加强大,这样为快速开发APP有很大助力!拭目以待吧!

[转载]手机App三年内将彻底消失 HTML5将颠覆原生App世界? - A5站长网

mikel阅读(859)

[转载]手机App三年内将彻底消失 HTML5将颠覆原生App世界? – A5站长网.

导读:过去这些年,HTML5颠覆了PC互联网的格局,优化了移动互联网的体验,接下来,HTML5将颠覆原生App世界。

 

2007年W3C(万维网联盟)立项HTML5,直至2014年10月底,这个长达八年的规范终于正式封稿。

过去这些年,HTML5颠覆了PC互联网的格局,优化了移动互联网的体验,接下来,HTML5将颠覆原生App世界。这听起来有点危言耸听,但若认真分析HTML5的发展史,你会发现,这个世界的发展趋势确实就是这样。

  HTML5对开发者的7大优势

跨平台:在多屏年代,开发者的痛苦指数非常高,人人都期盼HTML5能扮演救星。多套代码、不同技术工种、业务逻辑同步,这是折磨人的过程。有 点类似个人电脑早期世界,那个时候的每家电脑都有自己的操作系统和编程语言,开发者疲于做不同版本,其实DOS的盛行也很大程度是因为开发者实在没精力给 其他电脑写程序。跨平台技术在早期大多因为性能问题夭折,但中后期硬件能力增强后又会占据主流,因为跨平台确实是刚需。

快速迭代:移动互联网是一个快鱼吃慢鱼的时代,谁对用户的需求满足的更快,谁的试错成本更低,谁就拥有巨大的优势。互联网产品大多免费、且有网 络效应,后入者抢夺用户的难度非常大。使用原生开发,从招聘、开发、上线各个环节的效率都慢一倍以上,而且参与的人越多,沟通效率往往拖慢不止一倍。

持续交付:很多人有这样的体会,一个原生应用上线Appstore,突然有一个大bug,只好连夜加班修复,然后静静等待2周或更长时间的 Apple审核,这2个星期被用户的涂抹淹死,市场上一片差评,用户大量流失。等新应用被审核上线了,用户已经卸载了。但是,HTML5没有这些问题,你 可以实时更新,有问题立即响应。

大幅下降成本:创业者融资并不容易,如何花钱更高效非常重要。如果你使用原生开发的App和竞争对手使用HTML5开发的App没什么区别,但你的开发成本高出一倍,我相信没有投资人会喜欢给你投钱。

开源生态系统发达:HTML5前端是开放的正反馈循环生态系统,大量的开源库可以使用,开发应用变得更轻松、更敏捷,当然这也体现在了快速迭代和成本下降上。不过更重要的是,这种开放的正反馈循环生态系统未来的生命力是比原生生态系统更强劲的。

开放的数据交换:HTML是以page为单元开放代码的,它无需专门开发SDK,只要不混淆,就能与其他应用交互数据。开发者可以让手机搜索引擎很容易检索到自己的数据, 也更容易通过跨应用协作来满足最终用户需求。

更容易推广、更容易爆发:导流入口多:HTML5应用导流非常容易,超级App(如微信朋友圈)、搜索引擎、应用市场、浏览器,到处都是HTML5的流量入口。而原生App的流量入口只有应用市场。聪明的HTML5开发者当然会玩转各种流量入口从而取得更强的优势。

流量大:前段时间微信朋友圈风靡一时《神经猫》,这个游戏如果放到Appstore,绝对没有那么多流量,超级App带来的流量,远大于原生应用市场。假如微信允许游戏在桌面创建快捷方式、假如游戏后续升级解决持续娱乐问题,未来不可想象。

导流效率高:除了入口多、流量大,导流效率高也不可忽视,谁都知道:页游和端游打同样的广告,广告变用户的转化率,页游远远高于端游。

  HTML5对最终用户的3大优势

  大幅降低使用门槛

为什么流媒体会替代下载视频成为主流?为什么页游会如此火爆?只因用户太“懒”。让用户更方便的满足需求,有时效果好于更多的满足需求。

用户眼睛看到一个兴趣点,点击后,就应该立即开始满足用户需求。比如流媒体可以立即看,页游可以立即玩。而目前的原生应用市场,用户需要这样操作:选一个应用、等待下载、确认权限、等待安装,然后点击打开。这样糟糕的体验迟早要被颠覆。

不管是App、游戏还是音视频,未来都将即点即用。谁先满足用户这个需求,谁就制胜。

  实时更新、差量更新的优秀体验

HTML5应用可以绕开应用市场的限制进行自主实时更新,用户可以快速享受新服务。

而且这种更新完全可以是差量更新,比如某个HTML页面或某个js文件有问题,只更新这个几k的小文件就可以了,这比原生应用的更新体验好太多。

  跨应用的使用体验

目前手机应用切换是以桌面或任务管理器为中心的,但事实上这些中心很影响效率和体验。用户想出差三亚,先打开去哪App订票,然后切回桌面,再 找到并打开天气App,搜索输入三亚,再切到桌面,找到并打开航旅纵横App,输入航班号值机,哦对了,航班号多少来着,再切到桌面,找到并打开去哪 App看航班号,最后找到并打开租车App,输入租车地点,然后再切回桌面。

在原生应用体系下,用户只能这样。但在HTML5体系下,他不需要切回桌面,他可以在App间方便的直接跳来跳去,而不是使用一个一个孤岛App;他更不用重复录入数据,应用间可以方便的互相传递数据。

这种模式需要一点想象力,但未来迟早会来。

分析至此,我们可以明显的看出,不管是站在最终用户角度、还是站在开发者角度,HTML5必将取代原生应用当前的位置。并由此引发一系列颠覆。

  还有什么会被改变?

HTML5的爆发,原生App生态系统的颠覆,是一场产业革命,很多角色都会受到影响,我们来预测一番。

  新型HTML5引擎战火将烧起

标准的HTML5引擎并不能解决HTML5的所有问题,拥有大流量入口的互联网巨头,莫不在思考内嵌更优秀的增强引擎。腾讯推出了X5浏览器引 擎,就是看中这个机会。目前各路浏览器厂商、应用市场厂商、甚至rom厂商,都在努力整合更优质的浏览器引擎。假使微信内嵌的Webview可以运行更优 秀的canvas游戏、假使360手机助手可以发行即点即用的HTML5应用并且能力体验与原生一致、假使小米rom内置更强大的webview使得所有 HTML5应用在小米手机上运行的更流畅。

一个巨头开始行动,所有巨头都会闻风而动,没错,这场战役会是移动互联网世界的二次世界大战。

  应用发行市场将洗牌

由于超级App的巨大流量能轻易成为HTML5应用的入口,并且会形成大者更大的效应,传统的应用商店、甚至线下预装,这些流量不足和效率偏低的发行模式将被挤出市场主流。本身也是超级App的大流量应用商店,如果转型得当,也将以发行HTML5应用为主。

  广告和统计市场

原生的广告和统计SDK提供商会面临尬尴,Google、百度等基于网页的广告和统计服务会取得更大的优势。开发者不再需要打包SDK,引入一个Script即可。

开源技术将在移动互联网领域更加流行

HTML的开放性造就了大量的开源产品,也反向促进了HTML的繁荣。在Github上有大量的JS框架,而原生的开源代码数量相比甚少。而未来移动互联网世界将因为开源而发展的更迅速,这里也同样存在类Github厂商的机遇。

  开发工具的变化

早期HTML只需要记事本写几个Tag,中期的HTML、JS、CSS比较复杂,需要更高级的文本编辑器,但HTML5到来后,它的代码量、复 杂度、开发模型将与原生开发看齐,需要类似XCode、Eclipse等专业的IDE工具来解决开发、调试的问题。一些以会使用记事本写代码为荣的开发 者,将面临思路转换甚至被更高效的开发者淘汰。

  性能分析调优

目前很多针对原生应用的性能分析调优工具或服务,未来也面临转型,HTML5应用的性能分析调优是另一个世界。

  混淆与产权保护

HTML5是开放代码的,好处也带来弊端,有些东西开发者希望暴露,但有些东西开发者希望保护。混淆技术就变得更有商业机会。PC Web上Gmail的混淆就做的不错。除了JS混淆,离线数据加密相信也有不少空间。

  安全厂商的新机会

HTML5的强大会引发很多安全问题,并且解决思路与原生不一样,业内有可能会出现新的安全厂商领导者。

熟知历史才能预知未来,让我们来看看HTML5为什么诞生、这8年是怎么过来的。

  HTML5的诞生

自W3C于1999年发布HTML4后,Web世界快速发展,一片繁荣。人们一度认为HTML标准不需要升级了。一些致力于发展Web App的公司另行成立了WHATWG组织,直到2007年,W3C从WHATWG接手相关工作,重新开始发展HTML5。

HTML5的发展史,有用户的需求在推动,有技术开发者的需求在推动,更有巨大的商业利益在推动。

在互联网的早期,对用户而言,能打开浏览器接入到互联网世界就是一个神奇的事情,但互联网发展到2005年前后,开始出现下一个变化,就是宽带互联。

随着宽带的普及和电脑性能的增强,人们不再满足于单纯的通过互联网看新闻、收发邮件,消耗更高带宽的娱乐产品开始出现,就是流视频和网页游戏。 其实视频和游戏是古老的需求,在互联网不普及的时候,需求的满足方式是离线传输的VCD和游戏光盘;后来互联网逐渐普及,人们更改了使用方式,通过下载软 件+本地媒体播放器来看视频,下载体积较大的端游玩游戏。

但是对消费者体验更好的新方式还是出现并颠覆了以前的一切,那就是流媒体和网页游戏。Youtube等公司把握住潮流飞速崛起,各种页游公司也如雨后春笋。

但是HTML标准没有把握住产业的变化及时演进,浏览器产品也未升级,这块新需求被浏览器插件满足了,那就是Flash。这个部署在亿万浏览器 里的商业插件俨然成为事实标准。2005年Adobe巨资收购Macromedia,把Flash收归旗下,紧接着大幅推广FLV流媒体和action script语言,很明显这桩收购可以列为IT并购的经典案例,FLV流媒体和Flash游戏风靡互联网,Adobe在新的产业升级中攫取了大量的利润。

除了Flash这个商业产品成为了事实标准,W3C还面临一个尴尬,就是另一个私有扩展协议的制造者—IE。IE当时在桌面浏览器占有垄断地 位,并且扩展了大量的IE Only语法,开发者完全不知道这些语言是谁定义的。整个web世界,就被两家公司微软+Adobe绑架了。

很多IT巨头都坐不住了,尤其是苹果和Google。PC操作系统的世界难有突破,Web浏览器被苹果寄予厚望,而且第一代iPhone只支持 网页,那时还没有Appstore,Safari是乔布斯非常看重的产品;新贵Google虽然大量赞助Mozilla,但并未对IE的地位产生实质影 响,收购了YouTube后发现底层被Adobe控制,也是非常难过,而且Google每年给IE的搜索框和Adoble FLV缴纳的费用真不是小数目。

既然大家都是W3C的主席单位,好吧,我们重新开始做HTML5吧。

是的,HTML5其实就是这么诞生的。那是2007年,IE和Flash由盛转衰的转折点。

  HTML5第一阶段: Web 增强与破垄断

自HTML5诞生以来,一共经历了两个阶段,分别是Web增强和移动互联网。我们先从Web 增强说起。

web体验的丰富增强主要表现在:1. webapp,比如gmail;2. 流媒体;3. 游戏。我们就这3个方面来讲HTML5做了什么。

  1. webApp

HTML5新增了离线存储、更丰富的表单(比如Input type=date)、js线程、socket王乐、标准扩展embed、以及很多css3新语法…

  2. 流媒体

HTML5新增了audio、video

  3. 游戏

  HTML5新增了canvas、webgl

当然还有Google努力在HTML5中推进Header和Section等标签,以利于搜索引擎分析,这些不多述。

HTML5补充流媒体和游戏能力后,加上苹果强势拒绝在iOS上引入Flash,成功的遏制了Flash的发展,然后就该遏制IE私有语法了。

在HTML5标准的升级过程中,苹果和Google同时也看到了浏览器市场重新洗牌的机会,他们一方面参与HTML5的规范,一边在浏览器产品 上发力。Apple首先开始大力发展Safari,建立WebKit开源项目,Mac、iOS、Windows多平台齐发力;Google起初是赞助 Mozilla开发Firefox,后来自己开发了v8引擎,合并WebKit,于2008年正式推出Chrome。“IE的私有规范+Flash不是标 准,我们才是标准”这样的口号在新一代浏览器大战中打响,IE瞬间成为千夫所指的垄断代表,甚至成了阻碍Web发展的罪人(当时IE6已数年未更新,并且 丝毫不惧Firefox的发展)。

偏偏微软此时也出了晕招,推出了一系列即不完整支持规范又互相不兼容的IE7、8、9、10,彻底失去了开发者的心。

Adobe的Flash被遏制,与Web霸主的位子擦肩而过;IE的私有标准被遏制,并且造成IE市场份额不停下滑,直到IE最新的移动版本反过来开始支持WebKit私有语法,真是令人唏嘘。不知道HTML6是不是该打倒WebKit垄断了。

  HTML5第二阶段: 移动互联网

随着Chrome和Safari的高歌猛进,以及IE+Flash的衰落,HTML5告一段落,进入了下一个时代——移动互联网。HTML5的 跨平台优势在移动互联网时代被进一步凸显。HTML5是唯一一个通吃PC、Mac、iPhone、iPad、Android、Windows Phone等主流平台的跨平台语言。Java和Flash都曾梦想这个位置,但梦断于iOS。此时人们纷纷开始研究基于HTML5开发跨平台手机应用。很 多人当时认为,原生应用只是过渡,就像当年从C/S结构转变为B/S结构一样。而且学习Objective-C和Java很费劲,我既然会网页开发,为何 不试试HTML5。

W3C此时成立了Device API工作组,为HTML5扩展了Camera、GPS等手机特有的API,然而麻烦的是,移动互联网初期的迭代太快了,手机OS在不停的扩展硬件 API,陀螺仪、距离感应器、气压计。。。每年手机OS都有大版本更新。而W3C作为一个数百家会员单位共同决策的组织,从标准草案的提出到达成一致是非 常复杂的过程,跟不上移动互联网初期的快速迭代。

PhoneGap的出现,给开发者打开了一扇窗。很多人期待PhoneGap不停扩展API,来补充浏览器的不足。Adobe看到 PhoneGap仿佛看到了重振江湖地位的希望,但在Adobe收购PhoneGap后,又发现这个东西可商用性不足,而且开源使得Adobe无法像 Flash那样获取商业利益,于是就把PhoneGap捐给了Apache,改名为Cordova。

因为各种原因,Cordova的定位最终没有成为浏览器的强化,而走向了混合式开发。基于当时的背景,他们认为原生是不可替代的,“原生+HTML5”的混合模式更有意义。所以现在Cordova的使用模型是“原生工程师+HTML5工程师”一起协作完成App。

这时Facebook加入了W3C,牵头成立了Mobile Web工作组。Facebook是混Web圈的,并且在手机OS上没有自己的领地,他不喜欢被苹果和Google掌控的原生应用生态系统。Mobile Web这个工作组的重要目标就是让HTML5开发的网页应用达到原生应用的体验。然而,事与愿违,它不努力也就算了,结果是努力了却失败了。2012 年,Facebook放弃了HTML5的新闻充斥了全世界的IT媒体,HTML5瞬间被打入冷宫。

Facebook为何放弃HTML5?核心是当时基于HTML5真的做不出好的移动App。对比Twritter等竞争对手的原生 App,Facebook的HTML5版本实在无法让用户满意。比如Push功能,到现在HTML5的推送和原生的推送体验差距依然巨大,更不用说 HTML5应用的页面切换白屏、下拉刷新/侧滑菜单不流畅等众多问题。看着原生工程师轻松实现摇一摇、二维码、语音输入、分享到朋友圈等功能,更是让 HTML5工程师感觉自己站错了队。

即使Facebook不喜欢被控制,也不能拿被用户抛弃来冒险。而且Facebook并没有掌握关键点—手机浏览器内核。如果浏览器不跟上,徒然定一堆标准草案落不了地。

而浏览器在手机上的表现是什么呢?先看Google,Chrome性能虽高,但Android上的浏览器却并非Chrome,而是WebKit 改出来的一个蹩脚的Android浏览器;再看苹果,iOS上不允许其他浏览器引擎上架App Store,而且其他使用Safari引擎的应用也无法调用苹果自己的JavaScript加速引擎Nitro。结果是苹果和Google不但不在浏览器 上积极实现HTML5关于移动App所需的规范,反而对HTML5做出种种限制。

不管是当时硬件能力不足,还是手机OS厂商的故意限制,总之结果就是:在移动互联网的初期,一定是原生应用生态系统的天下,iOS和Android首先自己的地盘稳固后,产业才会向下个阶段升级。

Facebook也好,PhoneGap也好,想在移动互联网初期就分一杯羹是分不到的,但坚持下来,机会往往会出现。

  HTML5这回真的来了

终于,在2014年10月底,W3C宣布HTML5正式定稿。这个时间,不晚不早,硬件性能更强、手机OS迭代速度下降。

随着HTML5标准定稿,一切纷争将告一段落,现在,属于HTML5的时代到来了。

有人说,光标准定稿没用啊,配套起来了吗?HTML5做的应用究竟能否匹敌原生App?答案是,HTML5不但可以匹敌原生App,甚至它天然的很多特性超越了原生App。

我们先谈谈HTML5原来不如原生应用的地方,业内俗称HTML5有“性工能”障碍。即HTML5性能不如原生、开发工具不如原生、能力调用不如原生。

 

这几个问题导致开发者无法使用HTML5做出与原生一样的App。然而,不管是硬件升级还是OS厂商策略变化,以及相关软件技术的成熟,已解决了HTML5的“性工能”障碍。

  1. 硬件升级

2011年,iPhone 4s的CPU是A5,现在iPhone 6是A8,按苹果的历次发布会的说法,速度共提升了7.5倍。这3年间7.5倍的速度提升,抹平了太多HTML5的性能问题。

  2. 苹果、Google的策略变化

Google在2013年底发布的Android 4.4,内置的Webview不再是蹩脚的Android WebKit浏览器,而是Chromium,性能大幅提升。从最新的Android5.0开始,Webview可以通过Google Play Store实时更新,和Chrome的升级保持一致,用户就可以不刷机享受到最新的浏览器引擎;再看Apple方面,2012年iPhone 5发布后,HTML5在iOS上的表现已令人满意,Safari独家的JavaScript加速引擎Nitro不再那么重要,不过在iOS 8发布后,苹果还是很识趣地取消了三方程序调用Nitro的限制,现在任意浏览器或应用调用iOS的UIWebview都可以利用Nitro加速,这样在 前端使用JS做大型运算也成为可能。两大手机操作系统霸主和浏览器巨头的态度发生了变化,使得HTML5在手机上的发展不再受限,而且这个变化不可逆只能 继续向前,这种变化势必会产生深远的影响。

  3. 软件技术的成熟

PhoneGap的发展虽然放缓了,但其他产品技术却成熟了。2014年的iWeb大会上,众多厂商的产品提供了面向开发者免费或开源的HTML5性工能障碍的解决方案。

(注:编者作为从业人员,也会在分析各种方案时提到我们公司的方案,但编者会客观不夸张的陈述方案,而且该方案是纯免费的,没有商业销售嫌疑。)

DCloud公司在iWeb大会上发布了系统的HTML5“性工能缺失”的解决方案,包括:

a) 性能:提升HTML5性能的手机端引擎,让侧滑菜单、下拉刷新等动态交互卡顿的问题得以解决;

b) 工具:HTML5开发IDE产品HBuilder, 超快的编程利器;

c) 能力:把40万原生API封装成JavaScript对象,以解决HTML5能力不足问题的Native.js技术;

d) 最接近原生体验的高性能框架:MUI框架,体积只有几十K,加载、运行远快于一般框架。

基于该方案开发的HTML5应用完全可以达到原生App的功能和体验。

 

  使用HBuilder开发HTML5应用

英特尔公司发布了Crosswalk引擎,可以让Android 4.0-4.3的手机上的应用打包Chromium引擎而不是Android WebKit。毕竟目前市场上存在大量Android 4.0-4.3的手机,同时统一的webview也避免了兼容性的烦恼。

在专业方向上很多公司也做出了不错的成绩。触控的Cocos2d-html5、Egret runtime和Ludei CocoonJS强化了Canvas的表现,让HTML5游戏体验更好;UC、猎豹等手机浏览器都强化了音视频播放的表现。

不管是硬件升级、软件成熟,还是操作系统厂商策略变化,都在强力推动HTML5的爆发。

不过要注意,我说的HTML5爆发,不是指手机浏览器会替代桌面成为应用入口。有人说HTML5不好,因为用户讨厌打开浏览器输入URL的过 程。我想说这种想法是对HTML5的片面理解。HTML5!=传统浏览器,虽然编程语言还是HTML、Javascript、CSS,但发行方式绝不是传 统网站那么简单。HTML5应用的入口,反而很少是启动浏览器输入URL,它可以是存在于手机桌面的图标、也可以来自超级App(如微信朋友圈)、以及搜 索引擎、应用市场、广告联盟。。。到处都是它的入口。它的入口,比原生App更多。

  原生App的颠覆

HTML5的“性工能”障碍得到解决,可以接近原生App的效果,所以它就可以替代原生App吗?很多人认为,即使HTML5会发展的比现在好,也将是与原生App各占一部分市场的格局,要求不高的长尾应用会使用HTML5,而主流应用仍是原生App的天下。

但我认为这样的想法很危险,就像Apple成立前,HP的高层告诉沃兹:谁会在家里摆一台电脑呢?未来HTML5肯定会颠覆原生App。

  结语

其实未来如何发展是没人能准确预测的,变量非常多。但我想让用户和开发者都更方便的趋势是不会错的。

我在这里抛砖引玉,欢迎大家一起讨论,但我希望我们能理智的分析,在争议中提炼真知,而不是未经思考或验证仅因为害怕被颠覆而无谓的乱喷。也祝愿大家在HTML5的浪潮中,把握住机遇,享受下坐在风口当猪的感觉。

互联网+下的“一线城市应用”很尴尬

mikel阅读(1289)

原文《你的手机上有多少“一线城市应用”》摘要

出自新浪微博CEO王高飞。他说,为了挖掘二三线城市用户,去年,微博专门派出两支团队,在四川宜宾与江西九江这两个微博用户占比较低的三线城市待了半年,有了一些有意思的发现。

“大家都在说移动互联网起来了,或者已经结束了,后来发现差好多。”王高飞说。宜宾大约450万人口,运营商的话费用户大概在400万左右,确实已经饱和了,90%的人都有手机了,但是每个月流量超过1M的不到50万人,也就是说300多万人是有手机不上网。

还有多少app是只在一线城市待得很舒服,但下沉不到二、三线城市,乃至农村的?我想给它们起个名字,就叫“一线城市应用”

在一线城市玩得很high的应用,让二、三线城市怎么看?!的确是个很尴尬的问题,昨天《西祠胡同被艺龙卖了》昭示着论坛时代的结束,让人大喊移动互联网革命来了!可对于网络基础设施不健全,网速还停留在2G时代的二三线城市互联网+不起来了!过去“要想富先修路”的口号不光喊,还真实的落地修路了,可互联网4G从喊出来到普及还有多长时间,从3G的普及情况就看国家怎么让老百姓多长时间触网了,没有基础流量互联网就是个零,一切都是建立在网络的基础上。

再说说“一线城市应用”,在一线城市玩儿high了,然后下沉到二三线城市的战略从互联网网站开始就开始了,可大多都是水土不服,全国人民在玩微信也只局限在wifi和3G覆盖的情况下,要想占领更多的城市,就要个性化,O2O不是生拉硬套,要入乡随俗。

西祠胡同被艺龙卖了

mikel阅读(1247)

西祠胡同被艺龙卖了,曾经鼎盛一时的BBS时代终结了?从康盛创想被腾讯收购后,BBS就开始走下坡路了,很多地方级门户论坛都纷纷进行转型,可是在连卖煎饼的大妈都在用微信卖煎饼的时候,BBS时代就被革命了!从O2O的本地化被BAT各家大佬盯上了的时候,更加重了各家本地门户的压力,不变革是等死,用户有了手机后,谁还有那么多时间去本地论坛去泡?!各家还在指着本地广告服务和搞活动盈利的时候,却不知曾经稳稳占据的本地商家广告和活动这家肥肉,已经被美团等疯狂发力的进行了蚕食,更何况还有百度贴吧这种不伦不类的大家伙从互联网到手机的流量压力下,又有多少本地论坛门户能滋润的活着可想而知了!

怎么转型?无疑成了本地论坛门户的首要问题,可是看看那些论坛手机端,就可以看出有多迷茫了,简单粗暴的对接论坛的功能,毫无新意,有了微信还有谁再安装其他手机端,特别是社交类的应用呢?!一个公众号流量就能顶几个地方论坛的时代,BBS时代不终结都不行!好不容易得到了本地商家的认可,靠着进行本地线下活动为商家从线上引流了,可面对着只有铁杆的论坛用户之外,再无新用户参与的时候,商家也觉得鸡肋,纷纷投入了简单直接的团购的怀抱,现实就是这么残酷。

O2O最应该占据先机的应该是这些本地论坛门户,可恰恰是这些本地论坛丧失了先机,从而沦为鸡肋的下场,连电商都成了传统企业的时代,还想着不改变就能生存真得很难!要想在夹缝中生存,本地论坛就应该踏踏实实精细化本地服务这块,利用“地头蛇”的优势,将本地贴近老百姓的实际需求做到位,不要再大而全的漫无目的的撒网,那只能被淘汰,深耕本地化服务,深度服务好一亩三分地儿上的老百姓和商家,别怕脏怕累了,能够有机会干点儿脏活累活儿已经不错了,要啥自行车啊!

[转载]CSRF漏洞详细说明 - 网站安全 - 红黑联盟

mikel阅读(942)

[转载]CSRF漏洞详细说明 – 网站安全 – 红黑联盟.

Cross-Site Request Forgery(CSRF),中文一般译作跨站请求伪造。经常入选owasp漏洞列表Top10,在当前web漏洞排行中,与XSS和SQL注入并列前三。与前两者相比,CSRF相对来说受到的关注要小很多,但是危害却非常大。

通常情况下,有三种方法被广泛用来防御CSRF攻击:验证token,验证HTTP请求的Referer,还有验证XMLHttpRequests里的自定义header。鉴于种种原因,这三种方法都不是那么完美,各有利弊。

 二 CSRF的分类

在跨站请求伪造(CSRF)攻击里面,攻击者通过用户的浏览器来注入额外的网络请求,来破坏一个网站会话的完整性。而浏览器的安全策略是允许当前页 面发送到任何地址的请求,因此也就意味着当用户在浏览他/她无法控制的资源时,攻击者可以控制页面的内容来控制浏览器发送它精心构造的请求。

1、网络连接。例如,如果攻击者无法直接访问防火墙内的资源,他可以利用防火墙内用户的浏览器间接的对他所想访问的资源发送网络请求。甚至还有这样一种情况,攻击者为了绕过基于IP地址的验证策略,利用受害者的IP地址来发起他想发起的请求。

2、获知浏览器的状态。当浏览器发送请求时,通常情况下,网络协议里包含了浏览器的状态。这其中包括很多,比如cookie,客户端证书或基于身份 验证的header。因此,当攻击者借助浏览器向需要上述这些cookie,证书和header等作验证的站点发送请求的时候,站点则无法区分真实用户和 攻击者。

3、改变浏览器的状态。当攻击者借助浏览器发起一个请求的时候,浏览器也会分析并相应服务端的response。举个例子,如果服务端的 response里包含有一个Set-Cookie的header,浏览器会相应这个Set-Cookie,并修改存储在本地的cookie。这些改动都 会导致很微妙的攻击,我们将在第三部分描述。

作用范围内的威胁:我们按照产生危害的大小将此部分分成三种不同的危害模型。

1、论坛可 交互的地方。很多网站,比如论坛允许用户自定义有限种类的内容。举例来说,通常情况下,网站允许用户提交一些被动的如图像或链接等内容。如果攻击者让图像 的url指向一个恶意的地址,那么本次网络请求很有可能导致CSRF攻击。这些地方都可以发起请求,但这些请求不能自定义HTTP header,而且必 须使用GET方法。尽管HTTP协议规范要求请求不能带有危害,但是很多网站并不符合这一要求。

2、Web攻击者。在这里web攻击者的定义是指有自己的独立域名的恶意代理,比如attacker.com,并且拥有attacker.com的 HTTPS证书和web服务器。所有的这些功能只需要花10美元即可以做到。一旦用户访问attacker.com,攻击者就可以同时用GET和POST 方法发起跨站请求,即为CSRF攻击。

3、网络攻击者。这里的网络攻击者指的是能控制用户网络连接的恶意代理。比如,攻击者可以通过控制无线路由器或者DNS服务器来控制用户的网络连接。这种攻击比web攻击需要更多的资源和准备,但我们认为这对HTTPS站点也有威胁。因为HTTPS站点只能防护有源网络。

 

作用范围外的威胁:下面我们还列出了一些不在本论文讨论范围的相关危害模型。对这些危害的防御措施可以与CSRF的防御措施形成很好的互补。

1、跨站脚本(XSS)。如果攻击者能够向网站注入脚本,那么攻击者就会破坏该网站用户会话的完整性和保密性。有些XSS攻击需要发起网络请求,比 如将用户银行账户里的钱转移到攻击者的账户里,但是通常情况下,对CSRF的防御并没有考虑到这些情况。考虑到更安全的做法,网站必须实现对XSS和 CSRF的同时防御。

2、恶意软件。如果攻击者能够在用户的电脑上运行恶意软件,那么攻击者就可以控制用户的浏览器向那些可信的网站注入脚本。这时候基于浏览器的防御策略将会失效,因为攻击者可以用含有恶意插件的浏览器来替换用户的浏览器。

3、DNS的重新绑定。像CSRF一样,DNS重新绑定可以使用用户的IP地址来连接攻击者指定的服务器。处在防火墙保护内的服务器或者那些基于 IP地址验证的服务器需要一个对抗DNS重新绑定的防御方案。尽管DNS重新绑定的攻击和CSRF攻击的意图非常相似,但是他们还是需要各自不同的解决方 案。一个简单的解决DNS重新绑定攻击的方案就是要验证主机的HTTP请求header,确保包含有预期值。还有一个替代方案就是过滤DNS流量,防止将 外部的DNS名称解析成内部私有地址。

4、证书错误。如果用户在出现HTTPS证书错误的时候还愿意继续点击访问,那么HTTPS能够提供的很多安全保护就没有意义。有一些安全研究者指出了针对这一种情况的威害,但是在本文中,我们假设用户不会在出现了HTTPS证书错误之后继续点击访问。

5、钓鱼。当用户在访问钓鱼网站的时候,在身份验证的时候输入个人信息,钓鱼攻击就发生了。钓鱼攻击现今非常普遍也很有效,因为用户有的时候真的很难区分钓鱼网站和真正的网站。

6、用户跟踪。一些合作网站会利用跨站请求来对用户的浏览习惯建立一个关联行为库。大多数浏览器都通过组织第三方cookie发送来阻止类似的跟踪,但是利用挂站请求,浏览器的这一特性可以被绕过。

三 登录CSRF

无论是利用浏览器的网络连接还是利用浏览器的状态,大多数对CSRF的讨论都集中在能改变服务端状态的请求上面。尽管CSRF攻击能通过改变浏览器 的状态来对用户在访问可信网站时候造成危害,但是对它的重视程度还是不够。再登陆CSRF攻击里面,攻击者利用用户在可信网站的用户名和密码来对网站发起 一个伪造请求。一旦请求成功,服务器端就会响应一个Set-Cookie的header,浏览器接收到以后就会建立一个session cookie,并 记录用户的登陆状态。这个session cookie被用作绑定后续的请求,因而也可被攻击者用来作为身份验证。依据不同的网站,登陆CSRF攻击还可 以造成很严重的后果。

 

搜索记录:包括谷歌和雅虎等很多搜索引擎允许他们的用户选择是否同意保存他们的搜索记录,并且为用户提供一个接口来查看他们自己的私人搜索记录。搜 索请求里面包含了用户的行为习惯和兴趣的一些敏感细节,攻击者可以利用这些细节来欺骗用户,盗窃用户的身份或者窥探用户。当攻击者以用户身份登陆到搜索引 擎里,就可以看到用户的搜索记录。如图1. 这样,用户的搜索查询记录就被存储到了攻击者的搜索记录里,攻击者就可以登陆自己的账户随便查询用户的搜索记 录。

图1. 登陆CSRF攻击事件的跟踪图。受害人访问攻击者的网站,攻击者向谷歌伪造一个跨站点请求的登陆框,造成受害者被攻击者登陆到谷歌。随后,受害者使用搜索的时候,搜索记录就被攻击者记录下来。

 

 

PayPal:PayPal允许它的用户相互之间任意转移资金。转移资金的时候,用户要注册信用卡或者银行账户。攻击者可以利用登陆CSRF来发起以下攻击:

1、受害者访问了恶意商家的网站,并选择使用PayPal支付。

2、受害者被重定向到PayPal并且要求登陆他/她的账户。

3、网站等待用户登陆他/她的PayPal账户。

4、付款的时候,受害者先是登记自己的信用卡,但是信用卡实际上已经被添加到恶意商家的PayPal账户。

 

iGoogle:用户可以通过使用iGoogle来定制自己的谷歌主页,也包括一些插件。为了易用性,这些插件是“嵌入到iGoogle的”,这也 就意味着他们将影响到iGoogle的安全。通常情况下,iGoogle在添加新插件的时候,都会询问用户做出信任决定。但是攻击者可以通过登录CSRF 攻击来帮助用户做出决定,从而安装任意的插件。

 

1、攻击者通过用户的浏览器授权安装一个iGoogle插件(含有恶意脚本),并将插件添加到用户的定制化iGoogle主页。

2、攻击者使用户登陆谷歌,并开一个到iGoogle的框架。

3、谷歌认为受害者就是攻击者,并将攻击者的插件推送给受害者,而且允许攻击者在https://www.google.com域下运行脚本。

4、攻击者现在可以:(a)在正确的URL页面构造一个登陆框(b)盗取用户自动填充的密码(c)在另一个窗口等待用户登陆并读取document.cookie。

 

我们已经将上述漏洞告知了谷歌,他们已经在两方面来减缓漏洞带来的危害。首先,谷歌已经弃用内嵌的插件并禁止开发者开发类似的插件,只允许少部分比 较受欢迎的内嵌插件。其次,谷歌已经开发了私密token策略来防御登陆CSRF(下面将会讨论),但是这个策略只对登陆了的用户才有效。我们预计,谷歌 一旦充分测试了他们的防御方案并觉得有效之后,会否认他们的登陆CSRF漏洞。

 四 现有的CSRF防御方案

一般网站有三种防御CSRF攻击的方案。(1)验证token值。(2)验证HTTP头的Referer。(3)用XMLHttpRequest附加在header里。以上三种方法都在广泛使用,但是他们的效果都不是那么的令人满意。

 4.2 Token验证

在每个HTTP请求里附加一部分信息是一个防御CSRF攻击的很好的方法,因为这样可以判断请求是否已经授权。这个“验证token”应该不能轻易的被未登录的用户猜测出来。如果请求里面没有这个验证token或者token不能匹配的话,服务器应该拒绝这个请求。

Token验证的方法可以用来防御登陆CSRF,但是开发者往往会忘记验证,因为如果没有登陆,就不能通过session来绑定 CSRF token。网站要想用验证token的方式来防御登陆CSRF攻击的话,就必须先创建一个“前session”,这样才能部署CSRF的防御 方案,在验证通过了之后,再创建一个真正的session。

Token的设计。有很多技术可以生成验证token。

 

• session标识符。浏览器的cookie存储方式就是为了防止不同域之间互相访问cookie。一个普遍的做法是直接利用用户的 session标识符来作为验证token。服务器在处理每一个请求时,都将用户的token与session标识符来匹配。如果攻击者能够猜测出用户的 token,那么他就能登录用户的账户。而且这样做有个不好的地方在于,偶尔用户正在浏览的内容会发送给第三方,比如通过电子邮件直接上网页内容上传到浏 览器厂商的bug跟踪数据库。如果正好这个页面包含有用户的session标识符,任何能看到这个页面的人都能模拟用户登陆到网站,直到会话过期。

 

• 独立session随机数。与直接使用用户的session标识符不一样的是,当用户第一次登陆网站的时候,服务器可以产生一个随机数并将它存 储在用户的cookie里面。对于每一个请求,服务器都会将token与存储在cookie里的值匹配。例如,广泛使用的Trac问题跟踪系统就是用的此 技术。但是这个方法不能防御主动的网络攻击,即使是整个web应用都使用的是HTTPS协议。因为攻击者可以使用他自己的CSRF token来覆盖来覆 盖这个独立session随机数,进而可以使用一个匹配的token来伪造一个跨站请求。

 

• 依赖session随机数。有一个改进产生随机数的方法是将用户的session标识符与CSRF token建立对应关系后存储在服务端。服 务器在处理请求的时候,验证请求中的token是否与session标识符匹配。这个方法有个不好的地方就是服务端必须要维护一个很大的对应关系表(哈希 表)。

 

• session标识符的HMAC。有一种方法不需要服务端来维护哈希表,就是可以对用户的session token做一个加密后用作 CSRF 的token。例如, Ruby on Rails的web程序一般都是使用的这种方法,而且他们是使用session标识符的HMAC来作为 CSRF token的。只要所有的网站服务器都共享了HMAC密钥,那么每个服务器都可以验证请求里的CSRF token 是否与session标识 符匹配。HMAC的特性能确保即使攻击者知道用户的CSRF token,也不能推断出用户的session标识符。

 

鉴于有充足的资源,网站都可以使用HMAC方法来防御CSRF攻击。但是,很多网站和一些CSRF的防御框架(比如 NoForge, CSRFx 和CSRFGuard)都不能正确的实现比较隐秘的token防御。一个常见的错误就是在处理跨站请求的时候暴露了 CSRF token。举个例子,一个可信的网站在对另一个网站发起请求的时候附加上了CSRF token,那么那个网站就可以对这个可信的网站伪造一 个跨站请求。

 

案例研究:NoForge.NoForge就是使用服务端保存哈希表的方式来验证用户的CSRF token。它在所有链接和表单提交的时候会附加一个CSRF token,造成这种技术不太完善的原因有以下三个:

 

1、HTML是在浏览器里动态创建的,而不会被重新加上CSRF token。有些网站是在客户端创建HTML的。比如Gmail, Flickr, 和 Digg都是用JavaScript 来创建表单,而这些表单正是需要CSRF防御措施的。

2、NoForge并没有对指向本站和外站的超链接作区分。如果有一个指向外站的超链接,那么外站可以用请求里面获取到用户的 CSRF token。比如,如果phpBB部署了NoForge,那么一旦用户点击了一个连接,连接的站点就可以获取到用户的CSRF token,即 使NoForge区分了是本站的链接还是外站的链接,因为Referer 还是会暴露用户的CSRF token。

3、NoForge对登陆CSRF并没有什么效果,因为如果用户已经有了session标识符(登陆了),那么NoForge只会验证CSRF token。尽管这种缺陷是可以修复,但是这也说明了要想正确的实施token验证策略并不是一件很容易的事情。

 

虽然上述三个原因都是可以修复的,但是这些缺陷都说明了要想正确地实施token验证策略,是很复杂的一件事情。CSRFx 和 CSRFGuard,还有很多网站都说明了这一问题。

 4.2 Referer

大多数情况下,当浏览器发起一个HTTP请求,其中的Referer标识了请求是从哪里发起的。如果HTTP头里包含有Referer的时候,我们 可以区分请求是同域下还是跨站发起的,因为Referer离标明了发起请求的URL。网站也可以通过判断有问题的请求是否是同域下发起的来防御CSRF攻 击。

不幸的是,通常Referer会包含有一些敏感信息,可能会侵犯用户的隐私。比如,Referer可以显示用户对某个私密网站的搜索和查询。尽管这些内容对私密网站站长来说是好事,因为他们可以通过这些内容来优化搜索引擎排名,但是一些用户还是认为侵犯了他们的隐私。另外,许多组织也很担忧Referer可能会将内网的一些机密信息泄露出去。

 

漏洞。从历史上来看,浏览器的 一些漏洞使得一些恶意网站有欺骗Referer的价值,尤其是在使用代理服务器的时候。很多对Referer欺骗的讨论都标明浏览器允许Referer可 以伪造。Mozilla在Fire-fox 1.0.7里面已经修复了Referer欺骗的漏洞。目前的IE则还有这方面的漏洞,但是这些漏洞只能影响 XMLHttpRequest,并且只能用来伪造Referer跳转到攻击者自己的网站。

尺度。如果网站选择使用Referer来防御CSRF攻击的话,那么网站的开发人员就需要决定到底是使用比较宽松还是比较严格的Referer验证 策略。如果采用宽松的Referer验证策略,网站就应该阻止Referer值不对的请求。如果请求里面没有Referer,就接收请求。尽管这个方法用 的很普遍,但是它很容易被绕过。因为攻击者可以在header里面去掉Referer。例如,FTP和数据URL发起的请求里面就不包含Referer。 如果使用严格的Referer验证策略,网站还要阻止没有Referer的请求。这样做主要是为了防止恶意网站主动隐藏Referer,但也会带来兼容性 问题,比如会误杀一部分合法的请求,因为有些浏览器和网络的设置默认就是不含有Referer的。所以说这个度一定要掌握好,很多时候取决于经验。我们还 会在4.2.1里讨论这个问题。

 

个案研究:Facebook。纵观Facebook的大部分网站都是使用token认证的方式来防御CSRF攻击的。但是,在Facebook的登 陆框部分则使用的是宽松的Referer验证策略。这种方法在面对登陆CSRF的攻击时没有什么作用。举例来说,攻击者可以讲用户从 http://attacker.com/重定向到ftp://attacker.com/index.html ,然后再对Facebook发起一个跨 站的登陆请求。因为请求来自FTP URL,所以大多数浏览器都不会在请求里包含Referer。

 

4.2.1 实验

为了评估严格的Referer验证策略的兼容性,我们进行了一项实验来衡量到底有多大概率以及在什么情况下,合法的请求里面不含有Referer。

设计。广告是一个很方便测量浏览器和网络特征的渠道,因此我们可以利用广告作为实验平台。在2008年4月5日到4月8日期间,我们从 163,767个独立IP购买了283,945 个广告,分别是两个不同的广告渠道。在渠道A,我们以每千次展示0.50美元的价格购买了网络旗帜广告, 关键字为“火狐”,“游戏”,“IE”,“视频”,“YouTube”。在渠道B,我们以每千次展示5美元的价格的间隙广告,关键字为“芭蕾”,“金融 “,“花”,“食品”和“园艺”。我们在每个广告渠道上花了100美元,渠道A有241,483点击量(146,310个独立IP),渠道B有 42,406点击量(18,314个独立IP)。

广告服务是由我们实验室里的两台主机提供,两个独立的域名是从不同的注册商处购买。每当显示广告时,广告会在接下来的每个请求里面生成一个特定的标 识符,并随机选择一台主机作为主服务器。主服务器通过HTTP或者HTTPS协议将客户端HTML发送到我们的服务器,这些HTML能发起一个GET或者 POST请求。其中,请求包括提交表单,图像请求和XMLHttpRequests。请求的顺序是随机的并且跟用户的操作无关。当广告通过了浏览器的安全 策略之后,就向主服务器发起一个同域的请求,同时向次服务器发起一个跨域请求。每个服务器的成本是400美元,域名是7美元,从一个合法的证书颁发机构获 得的90天域验证的HTTPS证书是免费的。服务器根据接收到的网络请求来记录请求参数,包括Referer,User-Agent头,日期,客户端的C 类网络,会话标识符。服务器还通过DOM API记录了document.referrer的值,但是不记录客户端的IP地址。为了统计独立的IP地址, 服务器利用一个随机产生的KEY而不是记录HMAC的方式,这个KEY会被丢弃。服务器记录的信息不足以单独确定广告的浏览者到底有多少。

伦理。实验的设计遵守两个广告渠道的规则。实验中的行为基本上都是web广告每天的行为,所以都能正常的从广告商那里请求额外的资源,比如图片,音 频和视频。尽管我们的广告产生的HTTP请求数目远大于普通的广告,但是我们需要的带宽明显比一个视频广告需要的带宽要小。我们的服务器也像广告商一样, 只记录他们所记录的信息。实际上我们的服务器记录的信息明显要比商业的广告商要少,因为我们并不记录客户端的IP地址。

 

结果。我们已经将结果在图2和图3里总结出来了,我们还发现以下结果只有95%的可信度。

 

• HTTP方法里, 跨域请求比同域请求不包含Referer头的情况更普遍,而在POST方法(卡方系数= 2130, p值< 0.001) 和GET方法(卡方系数= 2175, p值<0.001) 里比较,前者不包含Referer头的情况更为普遍。

• 在不包含Referer头的统计中,HTTP比HTTPS更为普遍,包括跨域POST(卡方系数= 6754, p值<0.001)请 求,跨域GET(卡方系数= 6940, p值<0.001)请求,同域POST(卡方系数= 2286, p值<0.001)请求和同域 GET请求(卡方系数= 2377, p值<0.001)。

• 在不包含Referer头的统计中,广告渠道B所有形式的请求都比A要更普遍。这些请求形式包括:HTTP跨域POST(卡方系 数= 3060, p值<0.001),HTTP同域POST(卡方系数= 6537, p值<0.001),HTTPS跨域POST(卡方 系数= 49.13, p值<0.001)和HTTPS同域POST(卡方系数= 44.52, p值<0.001)请求。

• 我们还统计了自定义的header X-Requested-By(参见4.3节)和Origin(见第5章),X-Requested-By 大概有0.029%到0.047%的HTTP POST请求,0.084%到0.112%的HTTP GET请求,0.008%到0.018%的 HTTPS POST请求和 0.009%到0.020%的HTTPS GET请求里不包含有Referer头。Origin则在与上述相同的请求里都不 包含Referer头。

 

图2. 不包含Referer和Referer不正确的请求(283,945 个结果)。x和y分别代表主服务器和次服务器的域名

 

讨论。下面有两个有力的证据可以表明在不包含Referer的请求里,通常是来自网络(攻击)而不是浏览器。

 

1、HTTP请求比HTTPS请求不包含Referer更为普遍是因为,网络代理可以删除HTTP请求里的header,但是不能删除HTTPS请 求里的header。当然,在一些企业的网络里,一些HTTPS的终端就是一个网络代理,这种情况下代理可以修改HTTPS请求,但是这种情况是比较罕见 的。

2、浏览器在去掉Referer的时候也会去掉document.referrer的值,但是如果Referer是在网络里去掉的 话,document.referrer却还在。但是我们发现,Referer去掉的情况比document.referrer去掉的情况要更为普遍。

 

实际上,在实验中,document.referrer值被去掉主要是因为两种特殊的浏览器:PlayStation 3 浏览器不支持 document.referrer,Opera去掉document.referrer(但是并不去掉Referer)是为了跨站HTTPS请求。 XMLHttpRequest中的Referer被去掉的比例较高是由于Firefox 1.0和1.5中的bug引起的。所有的这些结果都表明只有极少 数的浏览器被配置成不发送Referer。

也有证据表明,Referer被去掉是由于涉及到隐私问题,当浏览器把Referer从网站A发送到网站B时,用户的隐私也在被暴露,因为网站B可 以通过Referer来收集用户在网站A的浏览行为。相比之下,在同域下发送Referer则不会引起隐私问题,因为网站完全可以通过cookie来收集 用户的隐私(也就是完全没有必要通过Referer来收集)。我们还发现,跨站请求比同站请求要更多的阻止Referer,说明由于考虑到隐私的问题,所 以才会人为的阻止Referer发送。

 

由此,我们得出两个主要的结论:

1、通过HTTPS来防御CSRF。在HTTPS请求里,Referer可以被用来防御CSRF。为了实施用Referer来防御CSRF的策略, 网站必须拒绝那些没有Referer的请求,因为攻击者可以控制浏览器来去掉Referer。而在HTTP里,网站则不能一味的拒绝没有Referer的 请求,因为考虑到兼容性,可能有相当大一部分 (大约 3–11%)用户可能就访问不了网站了。不同的是在HTTPS里,则可以执行严格的Referer 验证策略,因为只有很小的一部分(0.05–0.22%)浏览器会去掉Referer。特别需要指出的是,严格的Referer验证策略非常适合用来防御 登陆CSRF,因为通常情况下,登陆请求都是通过HTTPS协议发起的。

2、隐私问题。严格的Referer策略是很好的CSRF的防御方案,因为它实施起来很简单。不幸的是,隐私策略可能会阻止此方案的流行。因此,浏览器新的安全性能和新的CSRF防御机制都必须要先解决好隐私问题,才能大规模的部署。

 

图3. 广告渠道A中不包含Referer和Referer不正确的请求(241,483 个结果)。Opera阻止了跨站的 HTTPS document.referrer,Firefox 1.0和1.5由于bug在XMLHttpRequest的时候不发送 Referer,PlayStation 3(图中即为PS)不支持document.referrer。

4.3 自定义HTTP header

我们也可以用自定义HTTP头的方法来防御CSRF攻击,因为虽然浏览器会阻止向外站发送自定义的HTTP头,但是允许向本站通过 XMLHttpRequest的方式发送自定义HTTP头。比如,prototype.js这个JavaScript库就是使用这种方法,并且增加 了 X-Requested-By头到XMLHttpRequest里面 。Google Web Toolkit 也建议开发者用在 XMLHttpRequest里增加一个X-XSRF-Cookie头的方法来防御CSRF攻击,其中XMLHttpRequets包含有cookie的 值。当然XMLHttpRequets里面的cookie并不需要用来防御CSRF,因为只需要有头部分就足够了。

在使用这种方法来防御CSRF攻击的时候,网站必须在所有的请求里使用XMLHttpRequest并附加一个自定义头(比如X- Requested-By),并且拒绝所有没有自定义头的的请求。例如,为了防御登陆CSRF的攻击,网站必须通过XMLHttpRequest的方式发 送用户的身份验证信息到服务器。在我们的实验里,在服务器接收到的请求里面,大约有99.90–99.99%的请求是含有X-Requested-By头 的,这表明这一方法适用于绝大多数的用户。

五 建议:Origin字段

为了防止CSRF的攻击,我们建议修改浏览器在发送POST请求的时候加上一个Origin字段,这个Origin字段主要是用来标识出最初请求是从哪里发起的。如果浏览器不能确定源在哪里,那么在发送的请求里面Origin字段的值就为空。

隐私方面:这种Origin字段的方式比Referer更人性化,因为它尊重了用户的隐私。

1、Origin字段里只包含是谁发起的请求,并没有其他信息 (通常情况下是方案,主机和活动文档URL的端口)。跟Referer不一样的是,Origin字段并没有包含涉及到用户隐私的URL路径和请求内容,这个尤其重要。

2、Origin字段只存在于POST请求,而Referer则存在于所有类型的请求。

随便点击一个超链接(比如从搜索列表里或者企业intranet),并不会发送Origin字段,这样可以防止敏感信息的以外泄露。

在应对隐私问题方面,Origin字段的方法可能更能迎合用户的口味。

服务端要做的:用Origin字段的方法来防御CSRF攻击的时候,网站需要做到以下几点:

1、在所有能改变状态的请求里,包括登陆请求,都必须使用POST方法。对于一些特定的能改变状态的GET请求必须要拒绝,这是为了对抗上文中提到过的论坛张贴的那种危害类型。

2、对于那些有Origin字段但是值并不是我们希望的(包括值为空)请求,服务器要一律拒绝。比如,服务器可以拒绝一切Origin字段为外站的请求。

安全性分析:虽然Origin字段的设计非常简单,但是用它来防御CSRF攻击可以起到很好的作用。

1、去掉Origin字段。由于支持这种方法的浏览器在每次POST请求的时候都会带上源header,那么网站就可以通过查看是否存在这种 Origin字段来确定请求是否是由支持这种方法的浏览器发起的。这种设计能有效防止攻击者将一个支持这种方法的浏览器改变成不支持这种方法的浏览器,因 为即使你改变浏览器去掉了Origin字段,Origin字段还是存在,只不过值变为空了。这跟Referer很不一样,因为Referer 只要是在请 求里去掉了,那服务器就探测不到了。

2、DNS重新绑定。在现有的浏览器里面,对于同站的XMLHttpRequests,Origin字段可以被伪造。只依赖网络连接进行身份验证的 网站应当使用在第2章里提到的DNS重新绑定的方法,比如验证header里的Host字段。在使用Origin字段来防御CSRF攻击的时候,也需要用 到DNS重新绑定的方法,他们是相辅相成的。当然对于在第四章里提到的CSRF防御方法,也需要用到DNS重新绑定的方法。

3、插件。如果网站根据crossdomain.xml准备接受一个跨站HTTP请求的时候,攻击者可以在请求里用Flash Player来设置 Origin字段。在处理跨站请求的时候,token验证的方法处理的不好,因为token会暴露。为了应对这些攻击,网站不应当接受不可信来源的跨站请 求。

4、应用。Origin字段跟以下四个用来确定请求来源的建议非常类似。Origin字段以下四个建议的基础上统一并改进了,目前已经有几个组织采用了Origin字段的方法建议。

 

• Cross-Site XMLHttp Request。Cross-Site XMLHttp Request的方法规定了一个 Access-Control-Origin 字段,用来确定请求来源。这个字段存在于所有的HTTP方法,但是它只在XMLHttpRequests请 求的时候才会带上。我们对Origin字段的设想就是来源于这个建议,而且Cross-Site XMLHttp Request工作组已经接受我们的建 议愿意将字段统一命名为Origin。

•XDomainRequest。在Internet Explorer 8 Beta 1里有XDomainRequest的API,它在发送 HTTP请求的时候将Referer里的路径和请求内容删掉了。被缩减后的Referer字段可以标识请求的来源。我们的实验结果表明这种删减的 Referer字段经常会被拒绝,而我们的Origin字段却不会。微软已经发表声明将会采用我们的建议将XDomainRequest里的删减 Referer更改为Origin字段。

• JSONRequest。在JSONRequest这种设计里,包含有一个Domain字段用来标识发起请求的主机名。相比之下,我们的 Origin字段方法不仅包含有主机,还包含请求的方案和端口。JSONRequest规范的设计者已经接受我们的建议愿意将Domain字段更改为 Origin字段,以用来防止网络攻击。

• Cross-Document Messaging。在HTML5规范里提出了一个建议,就是建立一个新的浏览器API,用来验证客户端在 HTML文件之间链接。这种设计里面包含一个不能被覆盖的origin属性,如果不是在客户端的话,在服务端验证这种origin属性的过程与我们验证 origin字段的过程其实是一样的。

 

具体实施:我们在服务器和浏览器端都实现了利用origin字段的方法来防止CSRF攻击。在浏览器端我们的实现origin字段方式是,在 WebKit添加一个8行代码的补丁,Safari里有我们的开源组件,Firefox里有一个466行代码的插件。在服务器端我们实现origin字段 的方式是,在ModSecurity应用防火墙里我们只用3行代码,在Apache里添加一个应用防火墙语言(见图4)。这些规则在POST请求里能验证 Host字段和具有合法值的origin字段。在实现这些规则来防御CSRF攻击的时候,网站并不需要做出什么改变,而且这些规则还能确保GET请求没有 任何攻击性(前提是浏览器端已经实现了origin字段方法)。

图4. 在ModSecurity里实现origin字段方法来防御CSRF攻击

 六 session初始化

在session初始化的时候,登陆CSRF只是其中一个很普遍的漏洞。在session初始化了之后,web服务器通常会将用户的身份与 session标识符绑定起来。因此有两种类型的session初始化漏洞,一种是服务器将可信用户的身份与新初始化的session绑定到了一起,另一 种是服务器将攻击者的身份与session绑定到了一起。

• 作为可信用户的验证。在某些特定的情况下,攻击者可以使用一个可预见的session标识符强制网站开启一个新的session。这一类型的漏 洞一般都被称为session定位漏洞。当用户提供他们的身份信息给一个可信网站来验证后,网站会将用户的身份与一个可预见的session标识符绑定到 一起。攻击者此时就可以通过这个session标识符来扮演用户的身份登录网站。

• 作为攻击者的验证。攻击者也可以通过用户的浏览器强制网站开始一个新的session,并且强制session与攻击者的身份绑定到一起(第3 章已经说明了攻击是怎么完成的)。登录CSRF攻击只是这一类型中的最简单漏洞,但是攻击者还可以有其他的方法强制通过用户的浏览器将session与自 己绑定到一起。

6.1 HTTP请求

OpenID:像LiveJournal、Movable Type和WordPress等很多网站都在使用OpenID 协议,建议这些可以使用 自签名随机数的方式来对抗回复攻击,但不要将OpenID session与用户的浏览器绑定到一起,因为攻击者可以强制用户的浏览器初始化一个 session然后将session与自己绑定到一起。规范中声明了: return_to 这个URL可能被委托方用来在用户的验证请求与验证答复之间 建立联系。但是LiveJournal, Movable Type和WordPress都认为这不是必须的,也没有实施它。为了对抗这种攻击,在协议初 始化的时候委托方应该生成一个新的随机数,并将它与浏览器的cookie存储到一起,将它包含到return_to参数里。委托方会将在cookie里的 随机数与return_to参数里的随机数匹配。这种方法其实与token验证的方法很类似,并且确保了从一开始OpenID 协议的session就能 在同一个浏览器上完成。

 

PHP cookieless(不 用cookie的)验证:这种方法被Hushmail 等网站用来防止用户的电脑上还保留有cookie。Cookieless 验证方法是将用户的 session标识符存储在请求的参数里面。但是这个方法不能将session与用户的浏览器绑定到一起,因此攻击者可以强制用户的浏览器初始化一个 session与攻击者绑定到一起。为了防止这种攻击,网站必须使用另外的方法将session标识符与用户的浏览器绑定到一起。例如,网站可以构造一个 长时间的frame,其中包含有session标识符。这种方式是通过将session标识符保存在内存里来将用户的浏览器与session绑定。使用 PHP cookieless验证方法的网站通常也会存在session初始化漏洞,会让攻击者可以模仿一个可信的用户。当然,类似的session定位 漏洞有很多标准的防御方法,例如,当用户登陆后,网站可以再次生成一个session标识符。

6.2 Cookie重写

漏洞。服务器可以在Set-Cookie字段里用一个Secure flag方式告诉浏览器此cookie只能通过HTTPS协议发送。现金的浏览 器都支持这个特性,并且在一些对安全性要求比较高的网站,这个特性通常被用来保护session。但是,这个Secure flag并不能保证完整性。攻 击者可以模仿网站通过HTTP向同一个主机发送Set-Cookie字段,并在主机上设立了cookie。当浏览器通过HTTPS向网站发送cookie 的时候,网站并没有一个机制来确定cookie是否被攻击者重写。如果这个cookie里面包含有用户的session标识符,攻击者就可以很容易的通过 重写用户的cookie来发起一个session初始化攻击。基本上没有网站能够防御这种攻击,因为他们需要客户端提供一个cookie来作完整性验证。 但是,有人建议使用浏览器的特性,比如localStorage,它可以弥补这一不足。换句话说,如果网站声称它的应用层session的验证完全跟基于 cookie的HTTP层的session无关的话,攻击者可以在验证之前就重写用户的cookie,然后扮演用户登陆网站。尽管安全人员很多年前就知道 攻击者可以重写cookie,但是浏览器厂商并没有什么好的对抗办法。厂商考虑到了通过拒绝HTTP请求的方式来对抗cookie重写的攻击,但是这一做 法显然不太合理。更糟糕的是,这一方法并不能提供cookie的完整性,因为Cookie 字段本身并不能区分cookie 里是否含有 Secure flag。

防御方法。为了不改变现有的cookie字段而就能保护cookie的完整性(是否包含有Secure flag),我们建议浏览器可以在 HTTPS请求里面新加一个Cookie-Integrity字段,专门用来检测cookie的完整性状态。这样也是考虑了兼容以前策略的做法。例如

Cookie: SID=DQAAAHQA…; pref=ac81a9…; TM=1203…

Cookie-Integrity: 0, 2

当cookie被设置成使用HTTPS协议发送的时候,Cookie-Integrity字段可以在请求里面用来描述cookie字段的索引。如果 请求里面的cookie都没有被设置成HTTPS,那么Cookie-Integrity字段的值就为空。对Cookie-Integrity字段的完整 性的保护与Secure flag能提供的机密是相辅相成的,并且这样做也具备很好的兼容性,因为服务器会忽略具有无法识别的header的请求。下面是 几个设计的建议:

带宽。在每一个HTTP请求中添加内容必然会增加所有网络的延迟,为了节省带宽,我们只在cookie字段里添加cookie的索引值。还有一个建议做法就是添加一个类似cookie字段的副本,命名为cookie2。

多样性。当主机准备建立一个与已有cookie同名的cookie,那么cookie完全可以包含两个同名的cookie。因为在此种情况下,也许 Cookie-Integrity字段不能根据cookie名来分辨它们,但是我们可以在cookie字段里面通过索引值来区别它们。

Rollback。在HTTPS请求里面加入Cookie-Integrity字段可以有效的防止rollback攻击。 如果没有Cookie- Integrity字段,并且在不能保证cookie完整性的时候,那么服务器此时也不能确定请求里面的cookie是否具备完整性(假设请求是从一个低 版本的主机发出的,即不支持Cookie-Integrity字段)。

同胞域。假设有这样一种情况,example.com分别包含有一个可信的和一个不可信的子 域,www.example.com 和 users.example.com。在对example.com设置cookie的时候,不可信的子域就可以 注入可信子域的cookie字段。Cookie-Integrity字段并不能防止这种攻击,但是我们可以通过增加一个字段来标识每个cookie的来源 (当然这要取决于对带宽和复杂性的考虑)。

我们在Firefox里用202行JavaScript代码添加实现了Cookie-Integrity字段,并增加了一个Integrity flag存储到cookie里面,主要用来记录这个cookie是否被设置成使用HTTPS传输。

 七 总结和建议

CSRF是当今一个被利用的非常广泛的漏洞。很多网站修复了他们的包括登陆CSRF漏洞在内的CSRF漏洞。基于这篇文章中提到的实验和分析,我们建议网站在不同的情况下使用不同的CSRF防御策略。

• 登陆CSRF。我们建议使用严格的Referer验证策略来防御登陆CSRF,因为登陆的表单一般都是通过HTTPS发送,在合法请求里面的Referer都是真实可靠的。如果碰到没有Referer字段的登陆请求,那么网站应该直接拒绝以防御这种恶意的修改。

 

• HTTPS。对于那些专门使用HTTPS协议的网站,比如银行类,我们也建议使用严格的Referer验证策略来防御CSRF攻击。对于那些有特定跨站需求的请求,网站应该建立一份白名单,比如主页等。

 

• 第三方内容。如果网站纳入了第三方的内容,比如图像外链和超链接,网站应该使用一个正确的验证token 的框架,比如 Ruby-on- Rails。如果这样的一个框架效果不好的话,网站就应该花时间来设计更好的token 验证策略,可以用HMAC方法将用户的session与 token 绑定到一起。

 

对于更长远的建议,我们希望能用Origin字段来替代Referer,因为这样既保留了既有效果,又尊重了用户的隐私。最终要废除利用token来防御CSRF的方式,因为这样网站就可以更好的保护无论是HTTP还是HTTPS请求,而不用担心token是否会泄露。

 

未来的工作。如果使用Origin字段的方法来防御CSRF攻击,网站要注意在处理GET请求的时候不要有什么副作用。尽管HTTP规范里已经这样要求,但是很多网站并没有很好的遵守这一要求。让网站都执行这一要求正是我们未来的工作重点。

 

CSRF攻击还兴起了一个变种,即攻击者在一个可信的网站嵌入一个frame并引诱用户点击(点击劫持)。尽管从我们的定义上讲,这个并不能算是 CSRF攻击,但是他们有一个很相似的地方就在于,攻击者都是利用用户的浏览器来对他信任的网站发起一个请求。防御这种攻击的传统办法都是 frame busting,但是这种方法有个问题就是它依赖JavaScript,而JavaScript很有可能会被用户或者攻击者禁用。在这里我们有个建议是,可以在Origin字段里添加一些内容用来描述frame的来源,也就是frame里面的超链接,这样受信任的网站就可以根据frame的来源来决定是拒绝还是接受这个请求。

翻译者:Fireweed

原文链接:http://seclab.stanford.edu/websec/

Fireweed’s blog:http://www.goitcn.com

翻译自国外网站转载请注明出处

[转载]浅谈CSRF攻击方式 - hyddd - 博客园

mikel阅读(892)

[转载]浅谈CSRF攻击方式 – hyddd – 博客园.

一.CSRF是什么?

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

二.CSRF可以做什么?

你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。

三.CSRF漏洞现状

CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别 爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI……而 现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”。

四.CSRF的原理

下图简单阐述了CSRF攻击的思想:

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤

1.登录受信任网站A,并在本地生成Cookie

2.在不登出A的情况下,访问危险网站B

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。

2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)

3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

 

上面大概地讲了一下CSRF攻击的思想,下面我将用几个例子详细说说具体的CSRF攻击,这里我以一个银行转账的操作作为例子(仅仅是例子,真实的银行网站没这么傻:>)

  示例1:

银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000

危险网站B,它里面有一段HTML的代码如下:

  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块……

为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中 的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏 览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com /Transfer.php?toBankId=11&money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账 操作),所以就立刻进行转账操作……

示例2:

为了杜绝上面的问题,银行决定改用POST请求完成转账操作。

银行网站A的WEB表单如下:

  <form action=”Transfer.php” method=”POST”>
    <p>ToBankId: <input type=”text” name=”toBankId” /></p>
    <p>Money: <input type=”text” name=”money” /></p>
    <p><input type=”submit” value=”Transfer /></p>
  </form>

后台处理页面Transfer.php如下:

复制代码

  <?php
    session_start();
    if (isset($_REQUEST[toBankId&& isset($_REQUEST[money]))
{
buy_stocks(
$_REQUEST[toBankId], $_REQUEST[money]);
}
  ?>

复制代码

危险网站B,仍然只是包含那句HTML代码:

  <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

和示例1中的操作一样,你首先登录了银行网站A,然后访问危险网站B,结果…..和示例1一样,你再次没了1000块~T_T,这次事故的 原因是:银行后台使用了$_REQUEST去获取请求的数据,而$_REQUEST既可以获取GET请求的数据,也可以获取POST请求的数据,这就造成 了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。在PHP中,可以使用$_GET和$_POST分别获取GET请求和POST 请求的数据。在JAVA中,用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。

示例3:

经过前面2个惨痛的教训,银行决定把获取请求数据的方法也改了,改用$_POST,只获取POST请求的数据,后台处理页面Transfer.php代码如下:

复制代码

  <?php
session_start();
if (isset($_POST[toBankId&& isset($_POST[money]))
{
buy_stocks(
$_POST[toBankId], $_POST[money]);
}
?>

复制代码

然而,危险网站B与时俱进,它改了一下代码:

复制代码

<html>
  <head>
    <script type=”text/JavaScript>
      function steal()
{
iframe 
= document.frames[steal];
iframe.document.Submit(
transfer);
}
    </script>
  </head>

<body onload=”steal()”>
    <iframe name=”steal” display=”none”>
      <form method=”POST” name=”transfer” action=”http://www.myBank.com/Transfer.php”>
<input type=”hidden” name=”toBankId” value=”11″>
<input type=”hidden” name=”money” value=”1000″>
</form>
    </iframe>
  </body>
</html>

复制代码

如果用户仍是继续上面的操作,很不幸,结果将会是再次不见1000块……因为这里危险网站B暗地里发送了POST请求到银行!

总结一下上面3个例子,CSRF主要的攻击模式基本上是以上的3种,其中以第1,2种最为严重,因为触发条件很简单,一 个<img>就可以了,而第3种比较麻烦,需要使用JavaScript,所以使用的机会会比前面的少很多,但无论是哪种情况,只要触发了 CSRF攻击,后果都有可能很严重。

理解上面的3种攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的

五.CSRF的防御

我总结了一下看到的资料,CSRF的防御可以从服务端客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。

1.服务端进行CSRF防御

服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数

(1).Cookie Hashing(所有表单都包含同一个伪随机值):

这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>

  <?php
    //构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie”, $value, time()+3600);
  ?>

在表单里增加Hash值,以认证这确实是用户发送的请求。

复制代码

  <?php
    $hash = md5($_COOKIE[cookie]);
  ?>
  <form method=”POST” action=”transfer.php”>
    <input type=”text” name=”toBankId”>
    <input type=”text” name=”money”>
    <input type=”hidden” name=”hash” value=<?=$hash;?>>
    <input type=”submit” name=”submit” value=”Submit”>
  </form>

复制代码

然后在服务器端进行Hash值验证

复制代码

      <?php
        if(isset($_POST[check])) {
$hash = md5($_COOKIE[cookie]);
             if($_POST[check== $hash) {
doJob();
else {
//…

}
else {
//…

}
?>

复制代码

这个方法个人觉得已经可以杜绝99%的CSRF攻击了,那还有1%呢….由于用户的Cookie很容易由于网站的XSS漏洞而被盗取,这就 另外的1%。一般的攻击者看到有需要算Hash值,基本都会放弃了,某些除外,所以如果需要100%的杜绝,这个不是最好的方法。
(2).验证码

这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,厄….这个方案可以完全解决CSRF,但个人觉得在易用性方面似乎不是太好,还有听闻是验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

(3).One-Time Tokens(不同的表单包含一个不同的伪随机值)

在实现One-Time Tokens时,需要注意一点:就是“并行会话的兼容”。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提 交。考虑一下如果每次表单被装入时站点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单 都含有非法的伪随机值。必须小心操作以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。

以下我的实现:

1).先是令牌生成函数(gen_token()):

复制代码

     <?php
     function gen_token() {
    //这里我是贪方便,实际上单使用Rand()得出的随机数作为令牌,也是不安全的。
//这个可以参考我写的Findbugs笔记中的《Random object created and used only once》
          $token = md5(uniqid(rand(), true));
return $token;
}

复制代码

2).然后是Session令牌生成函数(gen_stoken()):

复制代码

     <?php
  function gen_stoken() {
      $pToken = “”;
      if($_SESSION[STOKEN_NAME]  == $pToken){
//没有值,赋新值
  $_SESSION[STOKEN_NAME] = gen_token();
      }
else{
//继续使用旧的值
}

}
?>

复制代码

3).WEB表单生成隐藏输入域的函数:

复制代码

     <?php
function gen_input() {
gen_stoken();
echo “<input type=\”hidden\” name=\”” . FTOKEN_NAME . “\”
value=\”” . $_SESSION[STOKEN_NAME] . “\”> “;
}
?>

复制代码

4).WEB表单结构:

复制代码

     <?php
session_start();
include(”functions.php”);
?>
<form method=”POST” action=”transfer.php”>
<input type=”text” name=”toBankId”>
<input type=”text” name=”money”>
<? gen_input(); ?>
<input type=”submit” name=”submit” value=”Submit”>
</FORM>

复制代码

5).服务端核对令牌:

这个很简单,这里就不再啰嗦了。

上面这个其实不完全符合“并行会话的兼容”的规则,大家可以在此基础上修改。

 

其实还有很多想写,无奈精力有限,暂且打住,日后补充,如果错漏,请指出:>

PS:今天下午写这篇文档的时候FF崩溃了一次,写了一半文章的全没了,郁闷好久T_T…….

转载请说明出处,谢谢[hyddd(http://www.cnblogs.com/hyddd/)]

六.参考文献

[1].Preventing CSRF

[2].Security Corner: Cross-Site Request Forgeries

[3].《深入解析跨站请求伪造漏洞:原理剖析》

[4].《Web安全测试之跨站请求伪造(CSRF)》

[5].《深入解析跨站请求伪造漏洞:实例讲解》

[6].http://baike.baidu.com/view/1609487.htm

[转载]Android开源框架之SwipeListView导入及模拟QQ侧滑 - 指尖的舞客 - 博客园

mikel阅读(1104)

[转载]Android开源框架之SwipeListView导入及模拟QQ侧滑 – 指尖的舞客 – 博客园.  SwipeListView是Github上的一个开源框架,地址:https://github.com/47deg/Android-swipelistview

SwipeListView was born out of the need to add swipe gestures to ListView on Android.

因为开发需要整一个类似QQ侧滑删除的ListView,一开始准备自己写一个自定义layout作为item布局,依稀记得有个叫swipelistview的开源框架,结果还真可以拿来用,效果略有差别,但也满足项目要求了。那么,问题也来了,Github上最后的push的SwipelistView使用的是Gradle来构建,无奈鄙人几个月来一直在用es开始开发,考虑到可能要查看或者修改它的源码,就只好手工转为ecplise下的工程。下面先上Demo说明基本使用方法,方法都很简单,主要是网上搜索的资料都不是很完整,自己写一篇备忘,也供新手朋友们参考,再说说Gradle构建的swipelistview Module如何导入eclipse工程。

一、引用swipelistview库开发带侧滑+按钮的ListView

swipelistview的使用同listview的使用方法差不多,因为swipelistview是直接继承于ListView的,只是扩展了一些方法。

官方给出了再XML布局文件中的基本写法:


各属性说明如下:

swipeFrontView - Required - front view id.
swipeBackView - Required - back view id.
swipeActionLeft - Optional - left swipe action Default: 'reveal'
swipeActionRight - Optional - right swipe action Default: 'reveal'
swipeMode - Gestures to enable or 'none'. Default: 'both'
swipeCloseAllItemsWhenMoveList - Close revealed items on list motion. Default: 'true'
swipeOpenOnLongPress - Reveal on long press Default: 'true'
swipeAnimationTime - item drop animation time. Default: android configuration
swipeOffsetLeft - left offset
swipeOffsetRight - right offset

 

Demo地址,效果图:

我们自己定义swipelistview的item布局:

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

&nbsp;

&nbsp;

&nbsp;

&nbsp;

<button>
</button>

&nbsp;

&nbsp;

在布局swipeview所在布局文件中的定义


&nbsp;

 使用注意点:

为了让每次显示滑动一条数据,需要在你自己实现的BaseSwipeListViewListener中重写onStartOpen方法,在里面调用mSwipeListView.cloSEOpenedItems()。

二、导入swipelistview到eclipse工程

也许有人一看是gradle构建的android项目就不知道怎么办了,以为as构建的项目是不能之间导入eclipse工程的。幸运的是,swipelistview工程极其简洁,手工导入eclipse也是比较的容易的。

1. 新建一个android工程,勾选标记为libraray,且不用创建activity。

2. 将下载下来的android-swipelistview-master工程中\android-swipelistview-master\swipelistview\src\main\java下的com文件下直接粘贴到新建工程的src目录下。

同时把\android-swipelistview-master\swipelistview\src\main目录下的res资源放到eclipse下新建的Android库工程对应目录下。

3. 做完上面两部还没有完,因为swipelistview依赖nineoldandroids库,且目前的swipelistview版本依赖 nineoldandroids-2.4.0+,下载地址https://github.com/JakeWharton /NineOldAndroids,可以只下载

nineoldandroids-2.4.0.jar,直接放在新建android库工程的libs目录下即可。至此导入工作完成。

[转载]Lucene.net站内搜索—2、Lucene.Net简介和分词 - 邹琼俊 - 博客园

mikel阅读(1091)

[转载]Lucene.net站内搜索—2、Lucene.Net简介和分词 – 邹琼俊 – 博客园.

Lucene.Net是由Java版本的Lucene(卢思银)移植过来的,所有的类、方法都几乎和Lucene一模一样,因此使用时参考 Lucene 即可。

Lucene.Net只是一个全文检索开发包(就像ADO.Net和管理系统的关系),不是一个成型的搜索引擎,它的功能就是:把数据扔给 Lucene.Net ,查询数据的时候从Lucene.Net 查询数据,可以看做是提供了全文检索功能的一个数据库。SQLServer中和Lucene.Net各存一份,目的不一样。Lucene.Net不管文本 数据怎么来的。用户可以基于Lucene.Net开发满足自己需求的搜索引擎。

Lucene.Net只能对文本信息进行检索。如果不是文本信息,要转换为文本信息,比如要检索Excel文件,就要用NPOI把Excel读取成字符 串,然后把字符串扔给Lucene.Net。Lucene.Net会把扔给它的文本切词保存,加快检索速度。midomi.com。因为是保存的时候分词 (切词),所以搜索速度非常快!索引库默认保存的是“词的目录”

要快速的从《红楼梦》中找出词,可以先遍历这本书建一个词和页数的对应目录。第一次“找词”非常慢,但是搜索就快了。

分词

分词是核心的算法,搜索引擎内部保存的就是一个个的“词(Word)”。英文分词很简单,按照空格分隔就可以。中文则麻烦,把“北京,Hi欢迎你们大家” 拆成“北京 Hi 欢迎 你们大家”。

“the”,“,”,“和”,“啊”,“的”等对于搜索来说无意义的词一般都属于不参与分词的无意义单词(noise word)。

Lucene.Net中不同的分词算法就是不同的类。所有分词算法类都从Analyzer类继承,不同的分词算法有不同的优缺点。

(*)内置的StandardAnalyzer是将英文按照空格、标点符号等进行分词,将中文按照单个字进行分词,一个汉字算一个词。代码见备注

(*)二元分词算法,每两个汉字算一个单词,“欢迎你们大家”会分词为“欢迎   迎你  你们 们大  大家”,网上找到的一个二元分词算法CJKAnalyzer。面试的时候能说出不同的分词算法的差异。

无论是一元分词还是二元分词,分词效率比较高,但是分出无用词,因此索引库大。查询效率低。

基于词库的分词算法,基于一个词库进行分词,可以提高分词的成功率。有庖丁解牛、盘古分词等。效率低。

1、 StandardAnalyzer示例(不用背代码,拷过来知道改哪里即可,我复制粘贴的代码你也一样复制粘贴)

Analyzer analyzer = new StandardAnalyzer();

TokenStream tokenStream = analyzer.TokenStream(“”,newStringReader(“我是真的爱你”));

Lucene.Net.Analysis.Token token = null;

while ((token =tokenStream.Next()) != null)

{

Console.WriteLine(token.TermText());

}

盘古分词算法使用

具体用法参考《PanguMannual.pdf》

打开PanGu4Lucene\WebDemo\Bin,添加对PanGu.dll(同目录下不要有Pangu.xml,那个默认的配置文件的选项对于分词结果有很多无用信息)、PanGu.Lucene.Analyzer.dll的引用

把上面代码的Analyzer用PanGuAnalyzer代替

运行发现提示需要dct文件,因为不能把词库写死在dll中,因此需要提供单独的词库文件,根据报错放到合适的路径中。

通用技巧:把Dict目录下的文件“复制到输出目录”设定为“如果较新则复制”,每次生成的时候都会自动把文件拷到bin\Debug 下,非常方便。(只有Web应用程序有那个选项,网站没有。)永远不要对bing\Debug下的东西做直接的修改,要改“源文件”。

词库的编辑,使用DictManage.exe,对单词编辑的时候要先查找。工作的项目中要将行业单词添加到词库中,比如餐饮搜索、租房搜索、视频搜索等。

注:出现Dict路径的问题,没有找到配置文件,默认就是Dict目录,设定Pangu.xml的复制到输出设置为“如果较新则复制”即可。或者词典目录就命名为Dict,不要配置文件。

Demo:

一元分词

1、  新建项目——ASP.NET Web应用程序SearchDemo

2、  新建文件夹lib,存放dll文件Lucene.Net.dll

3、  添加Lucene.Net.dll引用

二元分词

1、拷贝两个类到根目录下

盘古分词

1、  拷贝两个dll PanGu.dll和PanGu.Lucene.Analyzer.dll到lib目录下

2、  添加这两个dll的引用

3、  添加Dict词库目录和词库文件

4、  修改分词代码

5、  如果出现如下错误

把Dict目录下的文件“复制到输出目录”设定为“如果较新则复制”

分词代码如下:


     <form id="form1" runat="server">  
        <div>  
            <asp:TextBox ID="txtContent" runat="server" Height="62px" TextMode="MultiLine"   
                Width="191px"></asp:TextBox>  
            <asp:Button ID="btnOnePartWord"  
                runat="server" Text="一元分词" onclick="btnOnePartWord_Click" />  
            <asp:Button ID="btnTwoPartWord" runat="server" Text="二元分词"   
                onclick="btnTwoPartWord_Click" />  
    <asp:Button ID="btnPanGu" runat="server" Text="盘古分词" onclick="btnPanGu_Click" />  
                <asp:ListBox ID="lstWord" runat="server" Width="112px"></asp:ListBox>  
        </div>  
    </form>  

cs:


    using Lucene.Net.Analysis;  
    using System.IO;  
    using Lucene.Net.Analysis.Standard;  
    using NSharp.SearchEngine.Lucene.Analysis.Cjk;  
    using Lucene.Net.Analysis.PanGu;  
      
    namespace SearchDemo.Pages  
    {  
        public partial class 分词算法 : System.Web.UI.Page  
        {  
            protected void Page_Load(object sender, EventArgs e)  
            {  
      
            }  
      
            protected void btnOnePartWord_Click(object sender, EventArgs e)  
            {  
                Analyzer oneAnalyzer = new StandardAnalyzer(); //一元分词  
                PartWordMethod(oneAnalyzer);  
            }  
      
            private void PartWordMethod(Analyzer analyzer)  
            {  
                lstWord.Items.Clear();  
                //Analyzer analyzer = new PanGuAnalyzer();  
                TokenStream tokenStream = analyzer.TokenStream("", new StringReader(txtContent.Text));  
                Lucene.Net.Analysis.Token token = null;  
      
                while ((token = tokenStream.Next()) != null)  
                {  
                    string word = token.TermText();  
                    lstWord.Items.Add(word);  
                }  
            }  
      
            protected void btnTwoPartWord_Click(object sender, EventArgs e)  
            {  
                Analyzer oneAnalyzer = new CJKAnalyzer(); //二元分词  
                PartWordMethod(oneAnalyzer);  
            }  
            protected void btnPanGu_Click(object sender, EventArgs e)  
            {  
                Analyzer oneAnalyzer = new PanGuAnalyzer(); //盘古分词  
                PartWordMethod(oneAnalyzer);  
            }  
        }  
    } 

[转载]ASP.NET MVC使用Bootstrap系列(1)——开始使用Bootstrap - 木宛城主 - 博客园

mikel阅读(1071)

[转载]ASP.NET MVC使用Bootstrap系列(1)——开始使用Bootstrap – 木宛城主 – 博客园.

作为一名Web开发者而言,如果不借助任何前端框架,从零开始使用HTMLCSS来构建友好的页面是非常困难的。特别是对于Windows Form的开发者而言,更是难上加难。

正是由于这样的原因,Bootstrap诞生了。Twitter Bootstrap为开发者提供了丰富的CSS样式、组件、插件、响应式布局等。同时微软已经完全集成在ASP.NET MVC 模板中。

Bootstrap结构介绍

你可以通过http://getbootstrap.com.来下载最新版本的Bootstrap

解压文件夹后,可以看到Bootstrap的文件分布结构如下,包含3个文件夹:

  • css
  • fonts
  • js    

css文件夹中包含了4.css文件和2.map文件。我们只需要将bootstrap.css文件包含到项目里这样就能将Bootstrap应用到我们的页面中了。bootstrap.min.css即为上述css的压缩版本。

.map文件不必包含到项目里,你可以将其忽略。这些文件被用来作为调试符号(类似于Visual Studio中的.pdb文件),最终能让开发人员在线编辑预处理文件。

Bootstrap使用Font Awesome(一个字体文件包含了所有的字形图标,只为Bootstrap设计)来显示不同的图标和符号,fonts文件夹包含了4类的不同格式的字体文件:

  • Embedded OpenType (glyphicons-halflings-regular.eot)
  • Scalable Vector Graphics (glyphicons-halflings-regular.svg)
  • TrueType font (glyphicons-halflings-regular.ttf)
  • Web Open Font Format (glyphicons-halflings-regular.woff)

建议将所有的字体文件包含在你的Web应用程序中,因为这能让你的站点在不同的浏览器中显示正确的字体。

EOT字体格式文件需要IE9及以上浏览器支持,TTF是传统的旧字体格式文件,WOFF是从TTF中压缩得到的字体格式文件。如果你只需要支持IE8之后的浏览器、iOS 4以上版本、同时支持Android,那么你只需要包含WOFF字体即可。

js文件夹包含了3个文件,所有的Bootstrap插件被包含在boostrap.js文件中,bootstrap.min.js即上述js的压缩版本,npm.js通过项目构建工具Grunt自动生成。

在引用boostrap.js文件之前,请确保你已经引用了JQuery库因为所有的Bootstrap插件需要JQuery

ASP.NET MVC 项目中添加Bootstrap文件

打开Visual Studio 2013,创建标准的ASP.NET MVC项目,默认情况下已经自动添加了Bootstrap的所有文件,如下所示:

说明微软对于Bootstrap是非常认可的,高度集成在Visual Studio中。

值得注意的是,在Scripts文件中添加了一个名为_references.js的文件,这是一个非常有用的功能,当我们在使用Bootstrap等一些前端库时,它可以帮助Visual Studio启用智能提示。

当然我们也可以创建一个空的ASP.NET MVC项目手动去添加这些依赖文件,正如下图所示这样,选择空的模板:

对于新创建的空白ASP.NET MVC项目来说,没用ContentFontsScripts文件夹——我们必须手动去创建他们,如下所示:

当然,也可以用Nuget来自动添加Bootstrap资源文件。如果使用图形界面来添加Bootstrap Nuget Package,则直接搜索Bootstrap即可;如果使用Package Manager Console来添加Bootstrap Nuget Package,则输入Install-Package bootstrap

网站创建Layout布局页

为了让我们的网站保持一致的风格,我将使用Bootstrap来构建Layout布局页。在Views文件夹创建MVC Layout Page(Razor)布局文件,如下图所示:

在新创建的Layout布局页中,使用如下代码来引用Bootstrap资源文件。

<link href=”@Url.Content(“~/css/bootstrap.css”) rel=”stylesheet”>

<script src=”@Url.Content(“~/js/bootstrap.js”)“></script>

其中使用 @Url.Content 会将虚拟或者相对路径转换为绝对路径,这样确保Bootstrap资源文件被引用。

新建一个名为HomeController,并且添加默认Index的视图,使其套用上述的Layout布局页面,如下所示:

使用捆绑打包和压缩来提升网站性能

捆绑打包(bundling)和压缩(minification)ASP.NET中的一项新功能,允许你提升网站加载速度,这是通过限制请求CSSJavaScript文件的次数来完成的。本质上是将这类文件结合到一个大文件以及删除所有不必要的字符(比如:注释、空格、换行)。

对于大多数现代浏览器访问一个主机名都有6个并发连接的极限,这意味着如果你在一张页面上引用了6个以上的CSS、JavaScript文件,浏览器一次只会下载6个文件。所以限制资源文件的个数是个好办法,真正意义上的使命必达,而不是浪费在加载资源上。

Bootstrap项目中使用捆绑打包

因为我们创建的是空的ASP.NET MVC项目,所以并没有自动引用与打包相关的程序集。打开Nuget Package Manager Console来完成对Package的安装,使用如下PowerShell命令:

install-package Microsoft.AspNet.Web.Optimization 来安装Microsoft.AspNet.Web.Optimization NuGet package以及它依赖的Package,如下所示:

在安装完成后,在App_Start中添加 BundleConfig类:

复制代码
public static void RegisterBundles(BundleCollection bundles)
{
   bundles.Add(new ScriptBundle("~/bootstrap/js").Include(
   "~/js/bootstrap.js",
   "~/js/site.js"));
   bundles.Add(new StyleBundle("~/bootstrap/css").Include(
   "~/css/bootstrap.css",
   "~/css/site.css"));
}
复制代码

ScriptBundleStyleBundle对象实例化时接受一个参数用来代表打包文件的虚拟路径,Include顾名思义将你需要的文件包含到其中。

然后在Application_Start方法中注册它:

复制代码
protected void Application_Start()
{
   AreaRegistration.RegisterAllAreas();
   RouteConfig.RegisterRoutes(RouteTable.Routes);
   BundleConfig.RegisterBundles(BundleTable.Bundles);
   BundleTable.EnableOptimizations = true;
}
复制代码

记住,不要去包含.min类型的文件到打包文件中,比如bootstrap.min.cssbootstrap.min.js,编译器会忽略这些文件因为他们已经被压缩过了。

ASP.NET MVC 布局页使用@Styles.Render(“~/bootstrap/css”)@Scripts.Render(“~/bootstrap/js”)来添加对打包文件的引用。

如果Visual Studio HTML编辑器表明无法找到StylesScripts对象,那就意味着你缺少了命名空间的引用,你可以手动在布局页的顶部添加System.Web.Optimization 命名空间,如下代码所示:

复制代码
@using System.Web.Optimization
<!DOCTYPE html>
<html>
 <head>
  <meta name="viewport" content="width=device-width" />
  <title>@ViewBag.Title</title>
  @*<link href="@Url.Content("~/css/bootstrap.css")" rel="stylesheet">
  <script src="@Url.Content("~/js/bootstrap.js")"></script>*@
  @Scripts.Render("~/bootstrap/js")
  @Styles.Render("~/bootstrap/css")
 </head>
 <body>
  <div>
   @*@RenderBody()*@
 </div>
</body>
</html>
复制代码

当然为了通用性,最佳的实践是在Views文件夹的web.config中添加System.Web.Optimization名称空间的引用,如下所示:

复制代码
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="Bootstrap.Web" />
<add namespace="System.Web.Optimization" />
</namespaces>
复制代码

测试打包和压缩

为了使用打包和压缩,打开网站根目录下的web.config文件,并且更改compilation元素的dubug属性为false,即为release

<system.web>

<compilation Debug=”false” targetFramework=”4.5″ />

<httpRuntime targetFramework=”4.5″ />

</system.web>

当然你可以在Application_Start方法中设置BundleTable.EnableOptimizations = true来同样达到上述效果(它会override web.config中的设置,即使Debug属性为true)。

最后浏览网页,查看源代码,可以清楚看到打包文件的路径是之前定义过的相对路径,点击这个链接,浏览器为我们打开了经过压缩处理过后的打包文件,如下图所示:

小结

在这一章节中,简单为大家梳理了Bootstrap的体系结构,然后怎样在ASP.NET MVC项目中添加Bootstrap,最后使用了打包和压缩技术来实现对资源文件的打包,从而提高了网站的性能。

 

本博客为木宛城主原创,基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。