gleamwang


  • Startseite

  • Archiv

  • Tags
gleamwang

【译】MacOS 的安全和隐私指南

Veröffentlicht am 2016-12-17 |

MacOS 的安全和隐私指南

  • 原文地址:macOS Security and Privacy Guide
  • 原文作者:drduh
  • 译文出自:掘金翻译计划
  • 译者:Nicolas(Yifei) Li, MAYDAY1993, DeadLion
  • 校对者:lovelyCiTY, sqrthree

这里汇集了一些想法,它们是有关如何保护运行了 macOS 10.12 “Sierra” 操作系统(以前是 OS X)的现代化苹果 Mac 电脑,也包含了一些提高个人网络隐私的小贴士。

这份指南的目标读者是那些希望采用企业级安全标准的”高级用户”,但是也适用于那些想在 Mac 上提高个人隐私和安全性的初级用户们。

一个系统的安全与否完全取决于管理员的能力。没有一个单独的技术、软件,或者任何一个科技能保证计算机完全安全;现代的计算机和操作系统都是非常复杂的,并且需要大量的增量修改才能获得在安全性和隐私性上真正意义的提高。

免责声明:若按照以下操作后对您的 Mac 电脑造成损伤,望您自行负责。

如果你发现了本文中的错误或者有待改进的内容,请提交 pull request 或者 创建一个 issue.

  • 基础知识
  • 固件
  • 准备和安装 macOS
    • 虚拟机
  • 首次启动
  • 管理员和普通用户账号
  • 对整个磁盘进行数据加密
  • 防火墙
    • 应用程序层的防火墙
    • 第三方防火墙
    • 内核级的数据包过滤
  • 系统服务
  • Spotlight 建议
  • Homebrew
  • DNS
    • Hosts 文件
    • Dnsmasq
      • 检测 DNSSEC 验证
    • DNSCrypt
  • Captive portal
  • 证书授权
  • OpenSSL
  • Curl
  • Web
    • 代理
    • 浏览器
    • 插件
  • PGP/GPG
  • OTR
  • Tor
  • VPN
  • 病毒和恶意软件
  • 系统完整性保护
  • Gatekeeper 和 XProtect
  • 密码
  • 备份
  • Wi-Fi
  • SSH
  • 物理访问
  • 系统监控
    • OpenBSM 监测
    • DTrace
    • 运行
    • 网络
  • 二进制白名单
  • 其它
  • 相关软件
  • 其它资源

基础知识

安全标准的最佳实践适用于以下几点:

  • 创建一个威胁模型

    • 考虑下什么是你需要保护的,避免谁的侵害?你的对手会是一个 TLA 机构么?(如果是的,你需要考虑替换使用 OpenBSD),或者是一个在网络上好管闲事的偷听者,还是一起针对你精心策划的 apt 网络攻击?
    • 研究并识别出那些威胁,想一想如何减少被攻击的面。
  • 保持系统更新

    • 请为你的系统和软件持续更新补丁!更新补丁!更新补丁!(重要的事情说三遍)。
    • 可以使用 App Store 应用程序来完成对 macOS 系统的更新,或者使用命令行工具 softwareupdate,这两个都不需要注册苹果账号。
    • 请为那些你经常使用的程序,订阅公告邮件列表(例如,Apple 安全公告)。
  • 对敏感数据进行加密

    • 除了对整个磁盘加密之外,创建一个或者多个加密的容器,用它们来保存一些你的密码、秘钥、那些个人文件和余下的其他数据。
    • 这有助于减少数据泄露造成的危害。
  • 经常备份数据

    • 定期创建数据备份,并且做好遇到危机时候的数据恢复工作。
    • 在拷贝数据备份到外部存储介质或者 “云” 系统中之前,始终对它们进行加密。
    • 定期对备份进行测试,验证它们是可以工作的。例如,访问某一部分文件或者对比哈希校验值。
  • 注意钓鱼网站

    • 最后,具有高安全意识的管理员能大大降低系统的安全风险。
    • 在安装新软件的时候,请加倍小心。始终选择免费的软件和开源的软件(当然了,macOS 不是开源的)

固件

为固件设定一个密码,它能阻止除了你的启动盘之外的任何其它设备启动你的 Mac 电脑。它也能设定成每次启动时为必选项。

当你的计算机被盗的时候,这个功能是非常有用的,因为唯一能重置固件密码的方式是通过 Apple Store,或者使用一个 SPI 程序,例如 Bus Pirate 或者其它刷新电路的程序。

  1. 开始时,按下 Command 和 R 键来启动恢复模式 / Recovery Mode。

  2. 当出现了恢复模式的界面,从 Utilities / 工具 菜单中选择 Firmware Password Utility / 固件密码实用工具。

  3. 在固件工具窗口中,选择 Turn On Firmware Password / 打开固件密码。

  4. 输入一个新的密码,之后在 Verify / 验证 处再次输入一样的密码。

  5. 选择 Set Password / 设定密码。

  6. 选择 Quit Firmware Utility / 退出固件工具 关闭固件密码实用工具。

  7. 选择 Apple 菜单,并且选择重新启动或者关闭计算机。

这个固件密码会在下一次启动后激活。为了验证这个密码,在启动过程中按住 Alt 键 - 按照提示输入密码。

当启动进操作系统以后。固件密码也能通过 firmwarepasswd 工具管理。

Using a Dediprog SF600 to dump and flash a 2013 MacBook SPI Flash chip to remove a firmware password, sans Apple

在没有 Apple 技术支持下,使用 Dediprog SF600 来输出并且烧录一个 2013 款的 MacBook SPI 闪存芯片,或者移除一个固件密码

可参考 HT204455, LongSoft/UEFITool 或者 chipsec/chipsec 了解更多信息。

准备和安装 macOS

有很多种方式来安装一个全新的 macOS 副本。

最简单的方式是在启动过程中按住 Command 和 R 键进入 Recovery Mode / 恢复模式。系统镜像文件能够直接从 Apple 官网上下载并且使用。然而,这样的方式会以明文形式直接在网络上暴露出你的机器识别码和其它的识别信息。

PII is transmitted to Apple in plaintext when using macOS Recovery

在 macOS 恢复过程中,捕获到未加密的 HTTP 会话包

另一种方式是,从 App Store 或者其他地方下载 macOS Sierra 安装程序,之后创建一个自定义可安装的系统镜像。

这个 macOS Sierra 安装应用程序是经过代码签名的,它可以使用 code sign 命令来验证并确保你接收到的是一个正版文件的拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ codesign -dvv /Applications/Install\ macOS\ Sierra.app
Executable=/Applications/Install macOS Sierra.app/Contents/MacOS/InstallAssistant
Identifier=com.apple.InstallAssistant.Sierra
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=297 flags=0x200(kill) hashes=5+5 location=embedded
Signature size=4167
Authority=Apple Mac OS Application Signing
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Info.plist entries=30
TeamIdentifier=K36BKF7T3D
Sealed Resources version=2 rules=7 files=137
Internal requirements count=1 size=124

macOS 安装程序也可以由 createinstallmedia 工具制作,它在 Install macOS Sierra.app/Contents/Resources/ 文件路径中。请参考为 macOS 制作一个启动安装程序,或者直接运行这个命令(不需要输入任何参数),看看它是如何工作的。

注意 Apple 的安装程序并不能跨版本工作。如果你想要创造一个 10.12 的镜像,例如,以下指令也必须要在 10.12 的机器上运行!

为了创建一个 macOS USB 启动安装程序,需要挂载一个 USB 驱动器,清空它的内容、进行重新分区,之后使用 createinstallmedia 工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ diskutil list
[Find disk matching correct size, usually "disk2"]
$ diskutil unmountDisk /dev/disk2
$ diskutil partitionDisk /dev/disk2 1 JHFS+ Installer 100%
$ cd /Applications/Install\ macOS\ Sierra.app
$ sudo ./Contents/Resources/createinstallmedia --volume /Volumes/Installer --applicationpath /Applications/Install\ macOS\ Sierra.app --nointeraction
Erasing Disk: 0%... 10%... 20%... 30%... 100%...
Copying installer files to disk...
Copy complete.
Making disk bootable...
Copying boot files...
Copy complete.
Done.

为了创建一个自定义、可安装的镜像,能用它恢复一台 Mac 电脑,你需要找到 InstallESD.dmg,这个文件也包含在 Install macOS Sierra.app 中。

通过 Finder 找到,并在这个应用程序图标上点击鼠标右键,选择 Show Package Contents / 显示包内容,之后从 Contents / 内容 进入到 SharedSupport / 共享支持,找到 InstallESD.dmg 文件。

你能通过 openssl sha1 InstallESD.dmg 、shasum -a 1 InstallESD.dmg 或者 shasum -a 256 InstallESD.dmg 得到的加密过的哈希值验证来确保你得到的是同一份正版拷贝(在 Finder 中,你能把文件直接拷贝到终端中,它能提供这个文件的完整路径地址)。

可以参考 HT204319,它能确定你最初采购来的计算机使用了哪个版本的 macOS,或者哪个版本适合你的计算机。

可以参考 InstallESD_Hashes.csv 这个在我代码仓库中的文件,它是现在和之前该版本文件的哈希值。你也可以使用 Google 搜索这些加密的哈希值,确保这个文件是正版且没有被修改过的。

可以使用 MagerValp/AutoDMG 来创建这个镜像文件,或者手动创建、挂载和安装这个操作系统到一个临时镜像中:

$ hdiutil attach -mountpoint /tmp/install_esd ./InstallESD.dmg

$ hdiutil create -size 32g -type SPARSE -fs HFS+J -volname "macOS" -uid 0 -gid 80 -mode 1775 /tmp/output.sparseimage

$ hdiutil attach -mountpoint /tmp/os -owners on /tmp/output.sparseimage

$ sudo installer -pkg /tmp/install_esd/Packages/OSInstall.mpkg -tgt /tmp/os -verbose

这一步需要花费一些时间,请耐心等待。你能使用 tail -F /var/log/install.log 命令在另一个终端的窗口内查看进度。

(可选项) 安装额外的软件,例如,Wireshark:

$ hdiutil attach Wireshark\ 2.2.0\ Intel\ 64.dmg

$ sudo installer -pkg /Volumes/Wireshark/Wireshark\ 2.2.0\ Intel\ 64.pkg -tgt /tmp/os

$ hdiutil unmount /Volumes/Wireshark

遇到安装错误时,请参考 MagerValp/AutoDMG/wiki/Packages-Suitable-for-Deployment,使用 chilcote/outset 来替代解决首次启动时候的包和脚本。

当你完成的时候,分离、转换并且验证这个镜像:

$ hdiutil detach /tmp/os

$ hdiutil detach /tmp/install_esd

$ hdiutil convert -format UDZO /tmp/output.sparseimage -o ~/sierra.dmg

$ asr imagescan --source ~/sierra.dmg

现在,sierra.dmg 已经可以被用在一个或者多个 Mac 电脑上了。它能继续自定义化这个镜像,比如包含预先定义的用户、应用程序、预置参数等。

这个镜像能使用另一个在 Target Disk Mode / 目标磁盘模式 下的 Mac 进行安装,或者从 USB 启动安装盘安装。

为了使用 Target Disk Mode / 目标磁盘模式,按住 T 键的同时启动 Mac 电脑,并且通过 Firewire 接口,Thunderbolt 接口或者 USB-C 线连接另外一台 Mac 电脑。

如果你没有其它 Mac 电脑,通过启动的时候,按住 Option 键用 USB 安装盘启动,把 sierra.dmg 和其它需要的文件拷贝到里面。

执行 diskutil list 来识别连接着的 Mac 磁盘,通常是 /dev/disk2

(可选项) 一次性安全清除磁盘(如果之前通过 FileVault 加密,该磁盘必须先要解锁,并且装载在 /dev/disk3s2):

$ sudo diskutil secureErase freespace 1 /dev/disk3s2

把磁盘分区改成 Journaled HFS+ 格式:

$ sudo diskutil unmountDisk /dev/disk2

$ sudo diskutil partitionDisk /dev/disk2 1 JHFS+ macOS 100%

把该镜像还原到新的卷中:

$ sudo asr restore --source ~/sierra.dmg --target /Volumes/macOS --erase --buffersize 4m

你也能使用 Disk Utility / 磁盘工具 应用程序来清除连接着的 Mac 磁盘,之后将 sierra.dmg 还原到新创建的分区中。

如果你正确按照这些步骤执行,该目标 Mac 电脑应该安装了新的 macOS Sierra 了。

如果你想传送一些文件,把它们拷贝到一个共享文件夹,例如在挂载磁盘的镜像中, /Users/Shared,例如,cp Xcode_8.0.dmg /Volumes/macOS/Users/Shared

Finished restore install from USB recovery boot

完成从 USB 启动的还原安装

这里还没有大功告成!除非你使用 AutoDMG 创建了镜像,或者把 macOS 安装在你 Mac 上的其它分区内,你需要创建一块还原分区(为了使用对整个磁盘加密的功能)。你能使用 MagerValp/Create-Recovery-Partition-Installer 或者按照以下步骤:

请下载 RecoveryHDUpdate.dmg 这个文件。

1
2
3
RecoveryHDUpdate.dmg
SHA-256: f6a4f8ac25eaa6163aa33ac46d40f223f40e58ec0b6b9bf6ad96bdbfc771e12c
SHA-1: 1ac3b7059ae0fcb2877d22375121d4e6920ae5ba

添加并且扩展这个安装程序,之后执行以下命令:

1
2
3
4
5
6
7
$ hdiutil attach RecoveryHDUpdate.dmg
$ pkgutil --expand /Volumes/Mac\ OS\ X\ Lion\ Recovery\ HD\ Update/RecoveryHDUpdate.pkg /tmp/recovery
$ hdiutil attach /tmp/recovery/RecoveryHDUpdate.pkg/RecoveryHDMeta.dmg
$ /tmp/recovery/RecoveryHDUpdate.pkg/Scripts/Tools/dmtest ensureRecoveryPartition /Volumes/macOS/ /Volumes/Recovery\ HD\ Update/BaseSystem.dmg 0 0 /Volumes/Recovery\ HD\ Update/BaseSystem.chunklist

必要的时候把 /Volumes/macOS 替换成以目标磁盘启动的 Mac 的路径。

这个步骤需要花几分钟才能完成。再次执行 diskutil list 来确保 Recovery HD 已经存在 /dev/disk2 或者相似的路径下。

一旦你完成了这些,执行 hdituil unmount /Volumes/macOS 命令弹出磁盘,之后关闭以目标磁盘模式启动的 Mac 电脑。

虚拟机

在虚拟机内安装 macOS,可以使用 VMware Fusion 工具,按照上文中的说明来创建一个镜像。你不需要再下载,也不需要手动创建还原分区。

1
2
3
VMware-Fusion-8.5.2-4635224.dmg
SHA-256: f6c54b98c9788d1df94d470661eedff3e5d24ca4fb8962fac5eb5dc56de63b77
SHA-1: 37ec465673ab802a3f62388d119399cb94b05408

选择 Install OS X from the recovery parition 这个安装方法。可自定义配置任意的内存和 CPU,之后完成设置。默认情况下,这个虚拟机应该进入 Recovery Mode / 还原模式。

在还原模式中,选择一个语言,之后在菜单条中由 Utilities 打开 Terminal。

在虚拟机内,输入 ifconfig | grep inet — 你应该能看到一个私有地址,比如 172.16.34.129

在 Mac 宿主机内,输入 ifconfig | grep inet — 你应该能看到一个私有地址,比如 172.16.34.1

通过修改 Mac 宿主机内的文件让可安装镜像对虚拟器起作用,比如,修改 /etc/apache2/htpd.conf 并且在该文件最上部增加以下内容:(使用网关分配给 Mac 宿主机的地址和端口号 80):

Listen 172.16.34.1:80

在 Mac 宿主机上,把镜像链接到 Apache 网络服务器目录:

$ sudo ln ~/sierra.dmg /Library/WebServer/Documents

在 Mac 宿主机的前台运行 Apache:

$ sudo httpd -X

在虚拟机上通过本地网络命令 asr,安装镜像文件到卷分区内:

1
2
3
4
5
6
7
8
9
-bash-3.2# asr restore --source http://172.16.34.1/sierra.dmg --target /Volumes/Macintosh\ HD/ --erase --buffersize 4m
Validating target...done
Validating source...done
Erase contents of /dev/disk0s2 (/Volumes/Macintosh HD)? [ny]: y
Retrieving scan information...done
Validating sizes...done
Restoring ....10....20....30....40....50....60....70....80....90....100
Verifying ....10....20....30....40....50....60....70....80....90....100
Remounting target volume...done

完成后,在 sudo httpd -X 窗口内通过 Control 和 C 组合键停止在宿主机 Mac 上运行的 Apache 网络服务器服务,并且通过命令 sudo rm /Library/WebServer/Documents/sierra.dmg 删除镜像备份文件。

在虚拟机内,在左上角 Apple 菜单中选择 Startup Disk,选择硬件驱动器并重启你的电脑。你可能想在初始化虚拟机启动的时候禁用网络适配器。

例如,在访问某些有风险的网站之前保存虚拟机的快照,并在之后用它还原该虚拟机。或者使用一个虚拟机来安装和使用有潜在问题的软件。

首次启动

注意 在设置 macOS 之前,请先断开网络连接并且配置一个防火墙。然而,装备有触摸条(Touch Bar)的 2016 最新款 MacBook,它需要在线激活系统.

在首次启动时,按住 Command Option P R 键位组合,它用于清除 NVRAM。

当 macOS 首次启动时,你会看到 Setup Assistant / 设置助手 的欢迎画面。

请在创建你个人账户的时候,使用一个没有任何提示的高安全性密码。

如果你在设置账户的过程中使用了真实的名字,你得意识到,你的计算机的名字和局域网的主机名将会因为这个名字而泄露 (例如,John Applesseed’s MacBook),所以这个名字会显示在局域网络和一些配置文件中。这两个名字都能在 System Preferences / 系统配置 > Sharing / 共享 菜单中或者以下命令来改变:

$ sudo scutil --set ComputerName your_computer_name

$ sudo scutil --set LocalHostName your_hostname

管理员和普通用户账号

管理员账户始终是第一个账户。管理员账户是管理组中的成员并且有访问 sudo 的能力,允许它们修改其它账户,特别是 root,赋予它们对系统更高效的控制权。管理员执行的任何程序也有可能获得一样的权限,这就造成了一个安全风险。类似于 sudo 这样的工具都有一些能被利用的弱点,例如在默认管理员账户运行的情况下,并行打开的程序或者很多系统的设定都是处于解锁的状态 [p. 61–62]。Apple 提供了一个最佳实践和其它一些方案 [p. 41–42],例如,为每天基本的工作建立一个单独的账号,使用管理员账号仅为了安装软件和配置系统。

每一次都通过 macOS 登录界面进入管理员帐号并不是必须的。系统会在需要认证许可的时候弹出提示框,之后交给终端就行了。为了达到这个目的,Apple 为隐藏管理员账户和它的根目录提供了一些建议。这对避免显示一个可见的 影子 账户来说是一个好办法。管理员账户也能从 FileVault 里移除。

错误警告

  1. 只有管理员账户才能把应用程序安装在 /Applications 路径下 (本地目录)。Finder 和安装程序将为普通用户弹出一个许可对话框。然而,许多应用程序都能安装在 ~/Applications (该目录能被手动创建) 路径下。经验之谈: 那些不需要管理员权限的应用程序 — 或者在不在 /Applications 目录下都没关系的应用程序 — 都应该安装在用户目录内,其它的应安装在本地目录。Mac App Store 上的应用程序仍然会安装在 /Applications 并且不需要额外的管理员认证。

  2. sudo 无法在普通用户的 shell 内使用,它需要使用 su 或者 login 在 shell 内输入一个管理员账户。这需要很多技巧和一些命令行界面操作的经验。

  3. 系统配置和一些系统工具 (比如 Wi-Fi 诊断器) 为了所有的功能都能执行,它会需要 root 权限。在系统配置界面中的一些面板都是上锁的,所以需要单独的解锁按钮。一些应用程序在打开的时候会提示认证对话框,其它一些则需要通过一个管理员账号直接打开才能获得全部功能的权限。(例如 Console)

  4. 有些第三方应用程序无法正确运行,因为它们假设当前的用户是管理员账户。这些程序只能在登录管理员账户的情况下才能被执行,或者使用 open 工具。

设置

账户能在系统设置中创建和管理。在一个已经建立的系统中,通常很容易就能创建第二个管理员账号并且把之前的管理员帐号降级。这就避免了数据迁移的问题。新安装的系统都能增加普通账号。对一个账号降级能通过新建立的管理员帐号中的系统设置 — 当然那个管理员账号必须已经注销 — 或者执行这些命令(这两个指令可能没有必要都执行,可以参考issue #179):

1
2
3
$ sudo dscl . -delete /Groups/admin GroupMembership <username>
$ sudo dscl . -delete /Groups/admin GroupMembers <GeneratedUID>

通过以下指令,你就能发现你账号的 “GeneratedUID”:

1
$ dscl . -read /Users/<username> GeneratedUID

也可以参考这篇文章,它能带给你有关更多 macOS 是如何确定组成员的内容。

对整个磁盘进行数据加密

FileVault 提供了在 macOS 上对整个磁盘加密的能力(技术上来说,是整个卷宗。)

FileVault 加密将在休眠的时候保护数据,并且阻止其它人通过物理访问形式偷取数据或者使用你的 Mac 修改数据。

因为大部分的加密操作都高效地运作在硬件上,性能上的损失对 FireVault 来说并不凸显。

FileVault 的安全性依赖于伪随机数生成器 (PRNG)。

这个随机设备实现了 Yarrow 伪随机数生成器算法并且维护着它自己的熵池。额外的熵值通常由守护进程 SecurityServer 提供,它由内核测算得到的随机抖动决定。

SecurityServer 也常常负责定期保存一些熵值到磁盘,并且在启动的时候重新加载它们,把这些熵值提供给早期的系统使用。

参考 man 4 random 获得更多信息。

在开启 FileVault 之前,PRNG 也能通过写入 /dev/random 文件手动提供熵的种子。也就是说,在激活 FileVault 之前,我们能用这种方式撑一段时间。

在启用 FileVault 之前,手动配置种子熵:

$ cat > /dev/random
[Type random letters for a long while, then press Control-D]

通过 sudo fdsetup enable 启用 FileVault 或者通过 System Preferences > Security & Privacy 之后重启电脑。

如果你能记住你的密码,那就没有理由不保存一个还原秘钥。然而,如果你忘记了密码或者还原秘钥,那意味着你加密的数据将永久丢失了。

如果你想深入了解 FileVault 是如何工作得, 可以参考这篇论文 Infiltrate the Vault: Security Analysis and Decryption of Lion Full Disk Encryption (pdf) 和这篇相关的演讲文稿 (pdf)。也可以参阅 IEEE Std 1619-2007 “The XTS-AES Tweakable Block Cipher” (pdf).

你可能希望强制开启休眠并且从内存中删除 FileVault 的秘钥,而非一般情况下系统休眠对内存操作的处理方式:

$ sudo pmset -a destroyfvkeyonstandby 1
$ sudo pmset -a hibernatemode 25

所有计算机都有 EFI 或 BIOS 这类的固件,它们帮助发现其它硬件,最终使用所需的操作系统实例把计算机正确启动起来。以 Apple 硬件和 EFI 的使用来说,Apple 把有关的信息保存在 EFI 内,它辅助 macOS 的功能正确运行。举例来说,FileVault 的秘钥保存在 EFI 内,在待机模式的时候出现。

那些容易被高频攻击的部件,或者那些待机模式下,容易被暴露给所有设备访问的设备,它们都应该销毁在固件中的 FileVault 秘钥来减少这个风险。这么干并不会影响 FileVault 的正常使用,但是系统需要用户在每次跳出待机模式的时候输入这个密码。

如果你选择在待机模式下删除 FileVault 秘钥,你也应该修改待机模式的设置。否则,你的机器可能无法正常进入待机模式,会因为缺少 FileVault 秘钥而关机。参考 issue #124 获得更多信息。可以通过以下命令修改这些设置:

$ sudo pmset -a powernap 0
$ sudo pmset -a standby 0
$ sudo pmset -a standbydelay 0
$ sudo pmset -a autopoweroff 0

如果你想了解更多, 请参考 Best Practices for Deploying FileVault 2 (pdf) 和这篇论文 Lest We Remember: Cold Boot Attacks on Encryption Keys (pdf)

防火墙

在准备连接进入互联网之前,最好是先配置一个防火墙。

在 macOS 上有好几种防火墙。

应用程序层的防火墙

系统自带的那个基本的防火墙,它只阻止对内的连接。

注意,这个防火墙没有监控的能力,也没有阻止对外连接的能力。

它能在 System Preferences 中 Security & Privacy 标签中的 Firewall 控制,或者使用以下的命令。

开启防火墙:

$ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on

开启日志:

$ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setloggingmode on

你可能还想开启私密模式:

$ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on

计算机黑客会扫描网络,所以它们能标记计算机并且实施网络攻击。你能使用私密模式,避免你的计算机响应一些这样的恶意扫描。当开启了防火墙的私密模式后,你的计算机就不会响应 ICMP 请求,并且不响应那些已关闭的 TCP 或 UDP 端口的连接。这会让那些网络攻击者们很难发现你的计算机。

最后,你可能会想阻止系统自带的软件和经过代码签名,下载过的软件自动加入白名单:

$ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsigned off

$ sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsignedapp off

那些经过一个认证签名的应用程序会自动允许加入列表,而不是提示用户再对它们进行认证。包含在 OS X 内的应用程序都被 Apple 代码签名,并且都允许接对内的连接,当这个配置开启了。举例来说,因为 iTunes 已经被 Apple 代码签名,所以它能自动允许防火墙接收对内的连接。

如果你执行一个未签名的应用程序,它也没有被纳入防火墙白名单,此时一个带允许或者拒绝该连接选项的对话框会出现。如果你选择“允许连接”,macOS 对这个应用程序签名并且自动把它增加进防火墙的白名单。如果你选择“拒绝连接”,macOS 也会把它加入名单中,但是会拒绝对这个应用程序的对内连接。

在使用完 socketfilterfw 之后,你需要重新启动(或者结束)这个进程:

$ sudo pkill -HUP socketfilterfw

第三方防火墙

例如 Little Snitch, Hands Off, Radio Silence 和 Security Growler 这样的程序都提供了一个方便、易用且安全的防火墙。

Example of Little Snitch monitored session

以下是一段 Little Snitch 监控会话的例子

1
2
3
LittleSnitch-3.7.1.dmg
SHA-256: e6332ee70385f459d9803b0a582d5344bb9dab28bcd56e247ae69866cc321802
SHA-1: d5d602c0f76cd73051792dff0ac334bbdc66ae32

这些程序都具备有监控和阻拦对内和对外网络连接的能力。然而,它们可能会需要使用一个闭源的内核扩展。

如果过多的允许或者阻拦网络连接的选择让你不堪重负,使用配置过白名单的静谧模式,之后定期检查你设定项,来了解这么多应用程序都在干什么。

需要指出的是,这些防火墙都会被以 root 权限运行的程序绕过,或者通过 OS vulnerabilities (pdf),但是它们还是值得拥有的 — 只是不要期待完全的保护。然而,一些恶意软件实际上能自我删除,如果发现 Little Snitch 或者其他一些安全软件已经安装,它就根本不启动。

若想了解更多有关 Little Snitch 是如何工作的,可参考以下两篇文章:Network Kernel Extensions Programming Guide 和 Shut up snitch! – reverse engineering and exploiting a critical Little Snitch vulnerability.

内核级的数据包过滤

有一个高度可定制化、功能强大,但的确也是最复杂的防火墙存在内核中。它能通过 pfctl 或者很多配置文件控制。

pf 也能通过一个 GUI 应用程序控制,例如 IceFloor 或者 Murus。

有很多书和文章介绍 pf 防火墙。这里,我们只介绍一个有关通过 IP 地址阻拦访问的例子。

将以下内容增加到 pf.rules 文件中:

1
2
3
4
5
6
7
8
9
10
11
set block-policy drop
set fingerprints "/etc/pf.os"
set ruleset-optimization basic
set skip on lo0
scrub in all no-df
table <blocklist> persist
block in log
block in log quick from no-route to any
pass out proto tcp from any to any keep state
pass out proto udp from any to any keep state
block log on en0 from {<blocklist>} to any

使用以下命令:

  • sudo pfctl -e -f pf.rules — 开启防火墙
  • sudo pfctl -d — 禁用防火墙
  • sudo pfctl -t blocklist -T add 1.2.3.4 — 把某个主机加入阻止清单中
  • sudo pfctl -t blocklist -T show — 查看阻止清单
  • sudo ifconfig pflog0 create — 为某个接口创建日志
  • sudo tcpdump -ni pflog0 — 输出打印数据包

我不建议你花大量时间在如何配置 pf 上,除非你对数据包过滤器非常熟悉。比如说,如果你的 Mac 计算机连接在一个 NAT 后面,它存在于一个安全的家庭网络中,那以上操作是完全没有必要的。

可以参考 fix-macosx/net-monitor 来了解如何使用 pf 监控用户和系统级别对“背景连接通讯”的使用。

系统服务

在你连接到互联网之前,你不妨禁用一些系统服务,它们会使用一些资源或者后台连接通讯到 Apple。

可参考这三个代码仓库获得更多建议,fix-macosx/yosemite-phone-home, l1k/osxparanoia 和 karek314/macOS-home-call-drop。

在 macOS 上的系统服务都由 launchd 管理。可参考 launchd.info,也可以参考以下两个材料,Apple’s Daemons and Services Programming Guide 和 Technical Note TN2083。

你也可以运行 KnockKnock,它能展示出更多有关启动项的内容。

  • 使用 launchctl list 查看正在运行的用户代理
  • 使用 sudo launchctl list 查看正在运行的系统守护进程
  • 通过指定服务名称查看,例如,launchctl list com.apple.Maps.mapspushd
  • 使用 defaults read 来检查在 /System/Library/LaunchDaemons 和 /System/Library/LaunchAgents 工作中的 plist
  • 使用 man,strings 和 Google 来学习运行中的代理和守护进程是什么

举例来说,想要知道某个系统启动的守护进程或者代理干了什么,可以输入以下指令:

$ defaults read /System/Library/LaunchDaemons/com.apple.apsd.plist

看一看 Program 或者 ProgramArguments 这两个部分的内容,你就知道哪个二进制文件在运行,此处是 apsd。可以通过 man apsd 查看更多有关它的信息。

再举一个例子,如果你对 Apple Push Nofitications 不感兴趣,可以禁止这个服务:

$ sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.apsd.plist

注意 卸载某些服务可能造成某些应用程序无法使用。首先,请阅读手册或者使用 Google 检索确保你明白自己在干什么。

禁用那些你不理解的系统进程的时候一定要万分小心,因为它可能会让你的系统瘫痪无法启动。如果你弄坏了你的 Mac,可以使用单一用户模式来修复。

如果你觉得 Mac 持续升温,感觉卡顿或者常常表现出诡异的行为,可以使用 Console) 和 Activity Monitor 这两个应用程序,因为这可能是你不小心操作造成的。

以下指令可以查看现在已经禁用的服务:

$ find /var/db/com.apple.xpc.launchd/ -type f -print -exec defaults read {} \; 2>/dev/null

有详细注释的启动系统守护进程和代理的列表,各自运行的程序和程序的哈希校验值都包含在这个代码仓库中了。

(可选项) 运行 read_launch_plists.py 脚本,使用 diff 输出和你系统对比后产生的差异,例如:

$ diff <(python read_launch_plists.py) <(cat 16A323_launchd.csv)

你可以参考这篇 cirrusj.github.io/Yosemite-Stop-Launch,它对具体服务进行了一些解释, 也可以看看这篇 Provisioning OS X and Disabling Unnecessary Services,这篇是其它一些解释。

Spotlight 建议

在 Spotlight 偏好设置面板和 Safari 的搜索偏好设置中都禁用 Spotlight 建议,来避免你的搜索查询项会发送给 Apple。

在 Spotlight 偏好设置面板中也禁用必应 Web 搜索来避免你的搜索查询项会发送给 Microsoft。

查看 fix-macosx.com 获得更详细的信息。

如果你已经更新到 Mac OS X Yosemite(10.10)并且在用默认的设置,每一次你开始在 Spotlight (去打开一个应用或在你的电脑中搜索一个文件)中打字,你本地的搜索词和位置会被发送给 Apple 和第三方(包括 Microsoft )。

注意 这个网站和它的指导说明已不再适用于 macOS Sierra — 参考issue 164.

下载,查看并应用他们建议的补丁:

1
2
3
4
5
6
$ curl -O https://fix-macosx.com/fix-macosx.py
$ less fix-macosx.py
$ python fix-macosx.py
All done. Make sure to log out (and back in) for the changes to take effect.

谈到 Microsoft,你可能还想看看 https://fix10.isleaked.com/,挺有意思的。

Homebrew

考虑使用 Homebrew 来安装软件和更新用户工具(查看 Apple’s great GPL purge),这样更简单些。
注意如果你还没安装 Xcode 或命令行工具,可以用 xcode-select --install 来从 Apple 下载、安装。

要安装 Homebrew:

$ mkdir homebrew && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

在你的脚本或 rc 文件中编辑 PATH 来使用 ~/homebrew/bin 和 ~/homebrew/sbin。例如,先 echo 'PATH=$PATH:~/homebrew/sbin:~/homebrew/bin' >> .zshrc,然后用 chsh -s /bin/zsh 把登录脚本改为 Z shell,打开一个新的终端窗口并运行 brew update。

Homebrew 使用 SSL/TLS 与 GitHub 通信并验证下载包的校验,所以它是相当安全的。

记得定期在可信任的、安全的网络上运行 brew update 和 brew upgrade 来下载、安装软件更新。想在安装前得到关于一个包的信息,运行 brew info <package> 在线查看。

依据 Homebrew 匿名汇总用户行为分析,Homebrew 获取匿名的汇总的用户行为分析数据并把它们报告给 Google Analytics。

你可以在你的(shell)环境或 rc 文件中设置 export HOMEBREW_NO_ANALYTICS=1,或使用 brew analytics off 来退出 Homebrew 的分析。

可能你还希望启用额外的安全选项,例如 HOMEBREW_NO_INSECURE_REDIRECT=1 和 HOMEBREW_CASK_OPTS=--require-sha。

DNS

Hosts 文件

使用 Hosts 文件) 来屏蔽蔽已知的恶意软件、广告或那些不想访问的域名。

用 root 用户编辑 hosts 文件,例如用 sudo vi /etc/hosts。hosts 文件也能用可视化的应用 2ndalpha/gasmask 管理。

要屏蔽一个域名,在 /etc/hosts 中加上 0 example.com 或 0.0.0.0 example.com 或 127.0.0.1 example.com。

网上有很多可用的域名列表,你可以直接复制过来,要确保每一行以 0, 0.0.0.0, 127.0.0.1 开始,并且 127.0.0.1 localhost 这一行包含在内。

对于这些主机列表,可以查看 someonewhocares.org、l1k/osxparanoia/blob/master/hosts、StevenBlack/hosts 和 gorhill/uMatrix/hosts-files.json。

要添加一个新的列表:

1
2
3
4
5
6
7
8
9
$ curl "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" | sudo tee -a /etc/hosts
$ wc -l /etc/hosts
31998
$ egrep -ve "^#|^255.255.255|^0.0.0.0|^127.0.0.0|^0 " /etc/hosts
::1 localhost
fe80::1%lo0 localhost
[should not return any other IP addresses]

更多信息请查看 man hosts 和 FreeBSD 配置文件。

Dnsmasq

与其他特性相比,dnsmasq 能缓存请求,避免无资格名单中的查询数据上传和屏蔽所有的顶级域名。

另外,和 DNSCrypt 一起使用来加密输出的 DNS 流量。

如果你不想使用 DNSCrypt,再怎么滴也不要用 ISP 提供 的 DNS。两个流行的选择是 Google DNS 和 OpenDNS。

(可选) DNSSEC 是一系列 DNS 的扩展,为 DNS 客户端提供 DNS 数据的来源验证、否定存在验证和数据完整性检验。所有来自 DNSSEC 保护区域的应答都是数字签名的。签名的记录通过一个信任链授权,以一系列验证过的 DNS 根区域的公钥开头。当前的根区域信任锚点可能下载下来从 IANA 网站。关于 DNSSEC 有很多的资源,可能最好的一个是 dnssec.net 网站。

安装 Dnsmasq (DNSSEC 是可选的):

$ brew install dnsmasq --with-dnssec

$ cp ~/homebrew/opt/dnsmasq/dnsmasq.conf.example ~/homebrew/etc/dnsmasq.conf

编辑配置项:

$ vim ~/homebrew/etc/dnsmasq.conf

检查所有的选项。这有一些推荐启用的设置:

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
# Forward queries to DNSCrypt on localhost port 5355
server=127.0.0.1#5355
# Uncomment to forward queries to Google Public DNS
#server=8.8.8.8
# Never forward plain names
domain-needed
# Examples of blocking TLDs or subdomains
address=/.onion/0.0.0.0
address=/.local/0.0.0.0
address=/.mycoolnetwork/0.0.0.0
address=/.facebook.com/0.0.0.0
# Never forward addresses in the non-routed address spaces
bogus-priv
# Reject private addresses from upstream nameservers
stop-dns-rebind
# Query servers in order
strict-order
# Set the size of the cache
# The default is to keep 150 hostnames
cache-size=8192
# Optional logging directives
log-async
log-dhcp
log-facility=/var/log/dnsmasq.log
# Uncomment to log all queries
#log-queries
# Uncomment to enable DNSSEC
#dnssec
#trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
#dnssec-check-unsigned

安装并启动程序(sudo 需要绑定在 53 特权端口):

$ sudo brew services start dnsmasq

要设置 Dnsmasq 为本地的 DNS 服务器,打开系统偏好设置 > 网络并选择“高级”(译者注:原文为 ‘active interface’,实际上‘高级’),接着切换到 DNS 选项卡,选择 + 并 添加 127.0.0.1, 或使用:

$ sudo networksetup -setdnsservers "Wi-Fi" 127.0.0.1

确保 Dnsmasq 正确配置:

1
2
3
4
5
6
7
8
9
10
11
$ scutil --dns
DNS configuration
resolver #1
search domain[0] : whatever
nameserver[0] : 127.0.0.1
flags : Request A records, Request AAAA records
reach : Reachable, Local Address, Directly Reachable Address
$ networksetup -getdnsservers "Wi-Fi"
127.0.0.1

注意 一些 VPN 软件一链接会覆盖 DNS 设置。更多信息查看 issue #24。

检测 DNSSEC 验证

测试已签名区域的 DNSSEC(域名系统安全扩展协议)验证是否成功:

$ dig +dnssec icann.org

应答应该有NOERROR状态并包含ad。例如:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47039
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

不恰当签名的区域会导致检测 DNSSEC 验证的失败:

$ dig www.dnssec-failed.org

应答应该包含SERVFAIL状态。例如:

;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 15190
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

dnscrypt

使用 dnscrypt 在可选的范围内加密 DNS 流量(译者注:原文为 ‘the provider of choice’)。

如果你更喜欢一个 GUI 应用程序,看这里 alterstep/dnscrypt-osxclient。

从 Homebrew 安装 DNSCrypt:

$ brew install dnscrypt-proxy

如果要和 Dnsmasq 一起使用,找到这个文件homebrew.mxcl.dnscrypt-proxy.plist

1
2
$ find ~/homebrew -name homebrew.mxcl.dnscrypt-proxy.plist
/Users/drduh/homebrew/Cellar/dnscrypt-proxy/1.7.0/homebrew.mxcl.dnscrypt-proxy.plist

将下面一行编辑进去:

<string>--local-address=127.0.0.1:5355</string>

接着写:

<string>/usr/local/opt/dnscrypt-proxy/sbin/dnscrypt-proxy</string>

dnscrypt

添加一行本地地址来使用 DNScrypt,使用 53 以外的端口,比如 5355

用 Homebrew 也能实现上述过程,安装 gnu-sed 并使用gsed 命令行:

$ sudo gsed -i "/sbin\\/dnscrypt-proxy<\\/string>/a<string>--local-address=127.0.0.1:5355<\\/string>\n" $(find ~/homebrew -name homebrew.mxcl.dnscrypt-proxy.plist)

默认情况下,resolvers-list 将会指向 dnscrypt 版本特定的 resolvers 文件。当更新了 dnscrypt,这一版本将不再存在,若它存在,可能指向一个过期的文件。在 /Library/LaunchDaemons/homebrew.mxcl.dnscrypt-proxy.plist 中把 resolvers 文件改为 /usr/local/share 中的符号链接的版本,能解决上述问题:

<string>--resolvers-list=/usr/local/share/dnscrypt-proxy/dnscrypt-resolvers.csv</string>

启用 DNSCrypt:

$ brew services start dnscrypt-proxy

确保 DNSCrypt 在运行:

1
2
3
4
5
6
$ sudo lsof -Pni UDP:5355
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dnscrypt- 83 nobody 7u IPv4 0x1773f85ff9f8bbef 0t0 UDP 127.0.0.1:5355
$ ps A | grep '[d]nscrypt'
83 ?? Ss 0:00.27 /Users/drduh/homebrew/opt/dnscrypt-proxy/sbin/dnscrypt-proxy --local-address=127.0.0.1:5355 --ephemeral-keys --resolvers-list=/Users/drduh/homebrew/opt/dnscrypt-proxy/share/dnscrypt-proxy/dnscrypt-resolvers.csv --resolver-name=dnscrypt.eu-dk --user=nobody

默认情况下,dnscrypt-proxy 运行在本地 (127.0.0.1) ,53 端口,并且 “nobody” 身份使用dnscrypt.eu-dk DNSCrypt-enabled
resolver。如果你想改变这些设置,你得编辑 plist 文件 (例如, –resolver-address, –provider-name, –provider-key, 等。)

通过编辑 homebrew.mxcl.dnscrypt-proxy.plist 也能完成

你能从一个信任的位置或使用 public servers 中的一个运行你自己的 dnscrypt server(也可以参考 drduh/Debian-Privacy-Server-Guide#dnscrypt)

确保输出的 DNS 流量已加密:

1
2
3
4
5
6
$ sudo tcpdump -qtni en0
IP 10.8.8.8.59636 > 77.66.84.233.443: UDP, length 512
IP 77.66.84.233.443 > 10.8.8.8.59636: UDP, length 368
$ dig +short -x 77.66.84.233
resolver2.dnscrypt.eu

你也可以阅读 What is a DNS leak,mDNSResponder manual page 和 ipv6-test.com。

Captive portal

当 macOS 连接到新的网络,它会检测网络,如果连接没有被接通,则会启动 Captive Portal assistant 功能。

一个攻击者能触发这一功能,无需用户交互就将一台电脑定向到有恶意软件的网站,最好禁用这个功能并用你经常用的浏览器登录 captive portals, 前提是你必须首先禁用了任何的客户端 / 代理设置。

$ sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.captive.control Active -bool false

也可以看看 Apple OS X Lion Security: Captive Portal Hijacking Attack,Apple’s secret “wispr” request,How to disable the captive portal window in Mac OS Lion,和 An undocumented change to Captive Network Assistant settings in OS X 10.10 Yosemite。

证书授权

macOS 上有从像 Apple、Verisign、Thawte、Digicert 这样的营利性公司和来自中国、日本、荷兰、美国等等的政府机关安装的超过 200 个可信任的根证书。这些证书授权(CAs)能够针对任一域名处理 SSL/TLS 认证,代码签名证书等等。

想要了解更多,可以看看 Certification Authority Trust Tracker、Analysis of the HTTPS certificate ecosystem(pdf) 和 You Won’t Be Needing These Any More: On Removing Unused Certificates From Trust Stores(pdf)。

你可以在钥匙串访问中的系统根证书选项卡下检查系统根证书,或者使用 security 命令行工具和 /System/Library/Keychains/SystemRootCertificates.keychain 文件。

你可以通过钥匙串访问将它们标记为永不信任禁用证书授权并关闭窗口:

A certificate authority certificate

被你的系统信任的被迫或妥协的证书授权产生一个假的 / 欺骗的 SSL 证书,这样的一个中间人攻击的风险很低,但仍然是可能的。

OpenSSL

在 Sierra 中 OpenSSL 的版本是0.9.8zh,这不是最新的。它不支持 TLS 1.1 或新的版本,elliptic curve ciphers,还有更多。

Apple 在他们的 Cryptographic Services 指南文档中宣布弃用 OpenSSL。他们的版本也有补丁,可能会带来惊喜喔。

如果你要在你的 Mac 上用 OpenSSL,用 brew install openssl 下载并安装一个 OpenSSL 最近的版本。注意,brew 已经链接了 /usr/bin/openssl ,可能和构建软件冲突。查看 issue #39。

在 homebrew 版本和 OpenSSL 系统版本之间比较 TLS 协议和密码:

1
2
3
4
5
6
7
8
9
10
11
$ ~/homebrew/bin/openssl version; echo | ~/homebrew/bin openssl s_client -connect github.com:443 2>&1 | grep -A2 SSL-Session
OpenSSL 1.0.2j 26 Sep 2016
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
$ /usr/bin/openssl version; echo | /usr/bin/openssl s_client -connect github.com:443 2>&1 | grep -A2 SSL-Session
OpenSSL 0.9.8zh 14 Jan 2016
SSL-Session:
Protocol : TLSv1
Cipher : AES128-SHA

阅读 Comparison of TLS implementations,How’s My SSL,Qualys SSL Labs Tools 了解更多,查看更详细的解释和最新的漏洞测试请看 ssl-checker.online-domain-tools.com。

Curl

macOS 中 Curl 的版本针对 SSL/TLS 验证使用安全传输。

如果你更愿意使用 OpenSSL,用 brew install curl --with-openssl 安装并通过 brew link --force curl 确保它是默认的。

这里推荐几个向 ~/.curlrc 中添加的可选项(更多请查看 man curl):

1
2
3
4
5
6
7
8
9
user-agent = "Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0"
referer = ";auto"
connect-timeout = 10
progress-bar
max-time = 90
verbose
show-error
remote-time
ipv4

Web

代理

考虑使用 Privoxy 作为本地代理来过滤网络浏览内容。

一个已签名的 privoxy 安装包能从 silvester.org.uk 或 Sourceforge 下载。签过名的包比 Homebrew 版本更安全,而且能得到 Privoxy 项目全面的支持。

另外,用 Homebrew 安装、启动 privoxy:

$ brew install privoxy

$ brew services start privoxy

默认情况下,privoxy 监听本地的 8118 端口。

为你的网络接口设置系统 http 代理为127.0.0.1 和 8118(可以通过 系统偏好设置 > 网络 > 高级 > 代理):

$ sudo networksetup -setwebproxy "Wi-Fi" 127.0.0.1 8118

(可选) 用下述方法设置系统 https 代理,这仍提供了域名过滤功能:

$ sudo networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 8118

确保代理设置好了:

1
2
3
4
5
6
7
8
9
10
11
$ scutil --proxy
<dictionary> {
ExceptionsList : <array> {
0 : *.local
1 : 169.254/16
}
FTPPassive : 1
HTTPEnable : 1
HTTPPort : 8118
HTTPProxy : 127.0.0.1
}

在一个浏览器里访问 http://p.p/,或用 Curl 访问:

1
2
3
4
5
$ ALL_PROXY=127.0.0.1:8118 curl -I http://p.p/
HTTP/1.1 200 OK
Content-Length: 2401
Content-Type: text/html
Cache-Control: no-cache

代理已经有很多好的规则,你也能自己定义。

编辑 ~/homebrew/etc/privoxy/user.action 用域名或正则表达式来过滤。

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{ +block{social networking} }
www.facebook.com/(extern|plugins)/(login_status|like(box)?|activity|fan)\.php
.facebook.com
{ +block{unwanted images} +handle-as-image }
.com/ads/
/.*1x1.gif
/.*fb-icon.[jpg|gif|png]
/assets/social-.*
/cleardot.gif
/img/social.*
ads.*.co.*/
ads.*.com/
{ +redirect{s@http://@https://@} }
.google.com
.wikipedia.org
code.jquery.com
imgur.com

验证 Privoxy 能够拦截和重定向:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ALL_PROXY=127.0.0.1:8118 curl ads.foo.com/ -IL
HTTP/1.1 403 Request blocked by Privoxy
Content-Type: image/gif
Content-Length: 64
Cache-Control: no-cache
$ ALL_PROXY=127.0.0.1:8118 curl imgur.com/ -IL
HTTP/1.1 302 Local Redirect from Privoxy
Location: https://imgur.com/
Content-Length: 0
Date: Sun, 09 Oct 2016 18:48:19 GMT
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

你能用小猫的图片来代替广告图片,例如,通过启动一个本地的 Web 服务器然后重定向屏蔽的请求到本地。

浏览器

Web 浏览器引发最大的安全和隐私风险,因为它基本的工作是从因特网上下载和运行未信任的代码。

对于你的大部分浏览请使用 Google Chrome。它提供了独立的配置文件,好的沙盒处理,经常更新(包括 Flash,尽管你应该禁用它 —— 原因看下面),并且自带牛哄哄的资格证书。

Chrome 也有一个很好的 PDF 阅读器。

如果你不想用 Chrome,Firefox 也是一个很好的浏览器。或两个都用。看这里的讨论 #2,#90。

如果用 Firefox,查看 TheCreeper/PrivacyFox 里推荐的隐私偏好设置。也要确保为基于 Mozilla 的浏览器检查 NoScript,它允许基于白名单预先阻止脚本。

创建至少三个配置文件,一个用来浏览可信任的网站 (邮箱,银行),另一个为了大部分是可信的 网站(聚合类,新闻类站点),第三个是针对完全无 cookie 和无脚本的网站浏览。

  • 一个启用了 无 cookies 和 Javascript(例如, 在 chrome://settings/content中被关掉)的配置文件就应该用来访问未信任的网站。然而,如果不启用 Javascript,很多页面根本不会加载。

  • 一个有 uMatrix 或 uBlock Origin(或两个都有)的配置文件。用这个文件来访问大部分是可信的网站。花时间了解防火墙扩展程序是怎么工作的。其他经常被推荐的扩展程序是 Privacy Badger、HTTPSEverywhere 和 CertPatrol(仅限 Firefox)。

  • 一个或更多的配置文件用来满足安全和可信任的浏览需求,例如仅限于银行和邮件。

想法是分隔并划分数据,那么如果一个“会话”出现漏洞或泄露隐私并不一定会影响其它数据。

在每一个文件里,访问 chrome://plugins/ 并禁用 Adobe Flash Player。如果你一定要用 Flash,访问 chrome://settings/contents,在插件部分,启用在让我自行选择何时运行插件内容(也叫做 click-to-play)。

花时间阅读 Chromium 安全和 Chromium 隐私。

例如你可能希望禁用 DNS prefetching(也可以阅读 DNS Prefetching and Its Privacy Implications)。

你也应该知道 WebRTC,它能获取你本地或外网的(如果连到 VPN)IP 地址。这可以用诸如 uBlock Origin 和 rentamob/WebRTC-Leak-Prevent 这样的扩展程序禁用掉。

很多源于 Chromium 的浏览器本文是不推荐的。它们通常不开源,维护性差,有很多 bug,而且对保护隐私有可疑的声明。阅读 The Private Life of Chromium Browsers。

也不推荐 Safari。代码一团糟而且安全问题漏洞经常发生,并且打补丁很慢(阅读 Hacker News 上的讨论)。安全并不是 Safari 的一个优点。如果你硬要使用它,至少在偏好设置里禁用下载后打开”安全的文件,也要了解其他的隐私差别。

其他乱七八糟的浏览器,例如 Brave,在这个指南里没有评估,所以既不推荐也不反对使用。

想浏览更多安全方面的问题,请阅读 HowTo: Privacy & Security Conscious Browsing,browserleaks.com 和 EFF Panopticlick。

插件

Adobe Flash, Oracle Java, Adobe Reader, Microsoft Silverlight(Netflix 现在使用了 HTML5) 和其他的插件有安全风险,不应该安装。

如果它们是必须的,只在一个虚拟机里安装它们并且订阅安全通知以便确保你总能及时修补漏洞。

阅读 Hacking Team Flash Zero-Day、Java Trojan BackDoor.Flashback、Acrobat Reader: Security Vulnerabilities 和 Angling for Silverlight Exploits。

PGP/GPG

PGP 是一个端对端邮件加密标准。这意味着只是选中的接收者能解密一条消息,不像通常的邮件被提供者永久阅读和保存。

GPG 或 GNU Privacy Guard,是一个符合标准的 GPL 协议项目。

GPG 被用来验证你下载和安装的软件签名,既可以对称也可以非对称的加密文件和文本。

从 Homebrew 上用 brew install gnupg2 安装。

如果你更喜欢图形化的应用,下载安装 GPG Suite。

这有几个往 ~/.gnupg/gpg.conf 中添加的推荐选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
auto-key-locate keyserver
keyserver hkps://hkps.pool.sks-keyservers.net
keyserver-options no-honor-keyserver-url
keyserver-options ca-cert-file=/etc/sks-keyservers.netCA.pem
keyserver-options no-honor-keyserver-url
keyserver-options debug
keyserver-options verbose
personal-cipher-preferences AES256 AES192 AES CAST5
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
cert-digest-algo SHA512
s2k-digest-algo SHA512
s2k-cipher-algo AES256
charset utf-8
fixed-list-mode
no-comments
no-emit-version
keyid-format 0xlong
list-options show-uid-validity
verify-options show-uid-validity
with-fingerprint

安装 keyservers CA 认证:

$ curl -O https://sks-keyservers.net/sks-keyservers.netCA.pem

$ sudo mv sks-keyservers.netCA.pem /etc

这些设置将配置 GnuPG 在获取新密钥和想用强加密原语时使用 SSL。

请阅读 ioerror/duraconf/configs/gnupg/gpg.conf。你也应该花时间读读 OpenPGP Best Practices。

如果你没有一个密钥对,可以用 gpg --gen-key 创建一个。也可以阅读 drduh/YubiKey-Guide。

读在线的指南并练习给你自己和朋友们加密解密邮件。让他们也对这篇文章感兴趣吧!

OTR

OTR 代表 off-the-record 并且是一个针对即时消息对话加密和授权的密码协议。

你能在任何一个已存在的 XMPP 聊天服务中使用 OTR,甚至是 Google Hangouts(它只在使用 TLS 的用户和服务器之间加密对话)。

你和某人第一次开始一段对话,你将被要求去验证他们的公钥指纹。确保是本人亲自操作或通过其它一些安全的方式(例如 GPG 加密过的邮件)。
针对 XMPP 和其他的聊天协议,有一个流行的 macOS GUI 客户端是 Adium。

考虑下载一个 beta 版本,使用 OAuth2 验证,确保登录谷歌账号更安全。

1
2
3
Adium_1.5.11b3.dmg
SHA-256: 999e1931a52dc327b3a6e8492ffa9df724a837c88ad9637a501be2e3b6710078
SHA-1: ca804389412f9aeb7971ade6812f33ac739140e6

记住对于 Adium 的 OTR 聊天禁用登录。

一个好的基于控制台的 XMPP 客户端是 profanity,它能用 brew install profanity 安装。

想增加匿名性的话,查看 Tor Messenger,尽管它还在测试中,Ricochet(它最近接受了一个彻底的安全审查)也是,这两个都使用 Tor 网络而不是依赖于消息服务器。

如果你想了解 OTR 是如何工作的,可以阅读这篇论文 Off-the-Record Communication, or, Why Not To Use PGP

Tor

Tor 是一个用来浏览网页的匿名代理。

从官方 Tor 项目网站下载 Tor 浏览器。

不要尝试配置其他的浏览器或应用程序来使用 Tor,因为你可能会导致一个错误,危及你的匿名信息。

下载 dmg 和 asc 签名文件,然后验证已经被 Tor 开发者签过名的磁盘镜像:

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
$ cd Downloads
$ file Tor*
TorBrowser-6.0.5-osx64_en-US.dmg: bzip2 compressed data, block size = 900k
TorBrowser-6.0.5-osx64_en-US.dmg.asc: PGP signature Signature (old)
$ gpg Tor*asc
gpg: assuming signed data in `TorBrowser-6.0.5-osx64_en-US.dmg'
gpg: Signature made Fri Sep 16 07:51:52 2016 EDT using RSA key ID D40814E0
gpg: Can't check signature: public key not found
$ gpg --recv 0xD40814E0
gpg: requesting key D40814E0 from hkp server keys.gnupg.net
gpg: key 93298290: public key "Tor Browser Developers (signing key) <torbrowser@torproject.org>" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
$ gpg Tor*asc
gpg: assuming signed data in 'TorBrowser-6.0.5-osx64_en-US.dmg'
gpg: Signature made Fri Sep 16 07:51:52 2016 EDT using RSA key ID D40814E0
gpg: Good signature from "Tor Browser Developers (signing key) <torbrowser@torproject.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: EF6E 286D DA85 EA2A 4BA7 DE68 4E2C 6E87 9329 8290
Subkey fingerprint: BA1E E421 BBB4 5263 180E 1FC7 2E1A C68E D408 14E0

确保 Good signature from "Tor Browser Developers (signing key) <torbrowser@torproject.org>"出现在输出结果中。关于密钥没被认证的警告没有危害的,因为它还没被手动分配信任。

看 How to verify signatures for packages 获得更多信息。

要完成安装 Tor 浏览器,打开磁盘镜像,拖动它到应用文件夹里,或者这样:

1
2
3
$ hdiutil mount TorBrowser-6.0.5-osx64_en-US.dmg
$ cp -rv /Volumes/Tor\ Browser/TorBrowser.app /Applications

也可以验证是否这个 Tor 应用程序是由名为 MADPSAYN6T 的 Apple 开发者账号进行签名编译的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ codesign -dvv /Applications/TorBrowser.app
Executable=/Applications/TorBrowser.app/Contents/MacOS/firefox
Identifier=org.mozilla.tor browser
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20200 size=247 flags=0x0(none) hashes=5+3 location=embedded
Library validation warning=OS X SDK version before 10.9 does not support Library Validation
Signature size=4247
Authority=Developer ID Application: The Tor Project, Inc (MADPSAYN6T)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Signed Time=Nov 30, 2016, 10:40:34 AM
Info.plist entries=21
TeamIdentifier=MADPSAYN6T
Sealed Resources version=2 rules=12 files=130
Internal requirements count=1 size=184

为了查看证书的详细内容,可以使用 codesign 提取并且使用 openssl 对它进行解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ codesign -d --extract-certificates /Applications/TorBrowser.app
Executable=/Applications/TorBrowser.app/Contents/MacOS/firefox
$ file codesign*
codesign0: data
codesign1: data
codesign2: data
$ openssl x509 -inform der -in codesign0 -subject -issuer -startdate -enddate -noout
subject= /UID=MADPSAYN6T/CN=Developer ID Application: The Tor Project, Inc (MADPSAYN6T)/OU=MADPSAYN6T/O=The Tor Project, Inc/C=US
issuer= /CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US
notBefore=Apr 12 22:40:13 2016 GMT
notAfter=Apr 13 22:40:13 2021 GMT
$ openssl x509 -inform der -in codesign0 -fingerprint -noout
SHA1 Fingerprint=95:80:54:F1:54:66:F3:9C:C2:D8:27:7A:29:21:D9:61:11:93:B3:E8
$ openssl x509 -inform der -in codesign0 -fingerprint -sha256 -noout
SHA256 Fingerprint=B5:0D:47:F0:3E:CB:42:B6:68:1C:6F:38:06:2B:C2:9F:41:FA:D6:54:F1:29:D3:E4:DD:9C:C7:49:35:FF:F5:D9

Tor 流量对于出口节点(不能被一个网络窃听者读取)是加密的, Tor 是可以被发现的- 例如,TLS 握手“主机名”将会以明文显示:

1
2
3
4
5
$ sudo tcpdump -An "tcp" | grep "www"
listening on pktap, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
.............". ...www.odezz26nvv7jeqz1xghzs.com.........
.............#.!...www.bxbko3qi7vacgwyk4ggulh.com.........
.6....m.....>...:.........|../* Z....W....X=..6...C../....................................0...0..0.......'....F./0.. *.H........0%1#0!..U....www.b6zazzahl3h3faf4x2.com0...160402000000Z..170317000000Z0'1%0#..U....www.tm3ddrghe22wgqna5u8g.net0..0..

查看 Tor Protocol Specification 和 Tor/TLSHistory 获得更多信息。

另外,你可能也希望使用一个 pluggable transport,例如 Yawning/obfs4proxy 或 SRI-CSL/stegotorus 来混淆 Tor 流量。

这能通过建立你自己的 Tor relay 或找到一个已存在的私有或公用的 bridge 来作为一个混淆入口节点来实现。

对于额外的安全性,在 VirtualBox 或 VMware,可视化的 GNU/Linux 或 BSD 机器里用 Tor。

最后,记得 Tor 网络提供了匿名,这并不等于隐私。Tor 网络不一定能防止一个全球的窃听者能获得流量统计和相关性。你也可以阅读 Seeking Anonymity in an Internet Panopticon 和 Traffic Correlation on Tor by Realistic Adversaries。

阅读 Invisible Internet Project (I2P) 和它的 Tor 对比。

VPN

如果你在未信任的网络使用 Mac - 机场,咖啡厅等 - 你的网络流量会被监控并可能被篡改。

用一个 VPN 是个好想法,它能用一个你信任的提供商加密所有输出的网络流量。举例说如何建立并拥有自己的 VPN,阅读 drduh/Debian-Privacy-Server-Guide。

不要盲目地还没理解整个流程和流量将如何被传输就为一个 VPN 服务签名。如果你不理解 VPN 是怎样工作的或不熟悉软件的使用,你就最好别用它。

当选择一个 VPN 服务或建立你自己的服务时,确保研究过协议,密钥交换算法,认证机制和使用的加密类型。诸如 PPTP 这样的一些协议,应该避免支持 OpenVPN。

当 VPN 被中断或失去连接时,一些客户端可能通过下一个可用的接口发送流量。查看 scy/8122924 研究下如何允许流量只通过 VPN。

另一些脚本会关闭系统,所以只能通过 VPN 访问网络,这就是 the Voodoo Privacy project - sarfata/voodooprivacy 的一部分,有一个更新的指南用来在一个虚拟机上(hwdsl2/setup-ipsec-vpn)或一个 docker 容器(hwdsl2/docker-ipsec-vpn-server)上建立一个 IPSec VPN。

病毒和恶意软件

面对日益增长的恶意软件,Mac 还无法很好的防御这些病毒和恶意软件!

一些恶意软件捆绑在正版软件上,比如 Java bundling Ask Toolbar,还有 Mac.BackDoor.iWorm 这种和盗版软件捆绑到一块的。 Malwarebytes Anti-Malware for Mac 是一款超棒的应用,它可以帮你摆脱种类繁多的垃圾软件和其他恶意程序的困扰。

看看恶意软件驻留在 Mac OS X 的方法 (pdf) 和恶意软件在 OS X Yosemite 后台运行了解各种恶意软件的功能和危害。

你可以定期运行 Knock Knock 这样的工具来检查在持续运行的应用(比如脚本,二进制程序)。但这种方法可能已经过时了。Block Block 和 Ostiarius 这样的应用可能还有些帮助。可以在 issue #90 中查看相关警告。除此之外,使用 Little Flocker 也能保护部分文件系统免遭非法写入,类似 Little Snitch 保护网络 (注意,该软件目前是 beat 版本,谨慎使用)。

反病毒软件是把双刃剑 – 对于高级用户没什么用,却可能面临更多复杂攻击的威胁。然而对于 Mac 新手用户可能是有用的,可以检测到“各种”恶意软件。不过也要考到额外的处理开销。

看看 Sophail: Applied attacks against Antivirus (pdf), Analysis and Exploitation of an ESET Vulnerability, a trivial Avast RCE, Popular Security Software Came Under Relentless NSA and GCHQ Attacks, 和 AVG: “Web TuneUP” extension multiple critical vulnerabilities.

因此,最好的防病毒方式是日常地防范。看看 issue #44 中的讨论。

macOS 上有很多本地提权漏洞,所以要小心那些从第三方网站或 HTTP(案例)下载且运行受信或不受信的程序。

看看 The Safe Mac 上过去和目前的 Mac 安全新闻。

也检查下 Hacking Team 为 Mac OS 开发的恶意软件:root installation for MacOS、 Support driver for Mac Agent 和 RCS Agent for Mac,这是一个很好的示例,一些高级的恶意程序是如何在用户空间隐藏自己的(例如 ps、ls)。想了解更多的话,看看 A Brief Analysis of an RCS Implant Installer 和 reverse.put.as。

系统完整性保护

System Integrity Protection (SIP) 这个安全特性源于 OS X 10.11 “El Capitan”。默认是开启的,不过可以禁用,这可能需要更改某些系统设置,如删除根证书颁发机构或卸载某些启动守护进程。保持这项功能默认开启状态。

摘取自 OS X 10.11 新增功能:

一项新的安全政策,应用于每个正在运行的进程,包括特权代码和非沙盒中运行的代码。该策略对磁盘上和运行时的组件增加了额外的保护,只允许系统安装程序和软件更新修改系统二进制文件。不再允许代码注入和运行时附加系统二进制文件。

阅读 What is the “rootless” feature in El Capitan, really?

禁用 SIP 的一些 MacBook 已经售出。要验证 SIP 是否已启用,请使用命令 csrutil status,该命令应返回:System Integrity Protection status: enabled.。否则,通过恢复模式启用 SIP。

Gatekeeper 和 XProtect

Gatekeeper 和 quarantine 系统试图阻止运行(打开)未签名或恶意程序及文件。

XProtect 防止执行已知的坏文件和过时的版本插件,但并不能清除或停止现有的恶意软件。

两者都提供了对常见风险的一些保护,默认设置就好。

你也可以阅读 Mac Malware Guide : How does Mac OS X protect me? 和 Gatekeeper, XProtect and the Quarantine attribute。

注意 Quarantine 会将下载的文件信息存储在 ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2,这可能会造成隐私泄露的风险。简单的使用 strings 或下面的命令来检查文件:

$ echo 'SELECT datetime(LSQuarantineTimeStamp + 978307200, "unixepoch") as LSQuarantineTimeStamp, LSQuarantineAgentName, LSQuarantineOriginURLString, LSQuarantineDataURLString from LSQuarantineEvent;' | sqlite3 /Users/$USER/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2

阅读这篇文章了解更多信息。

想永久禁用此项功能,清除文件和让它不可更改:

$ :>~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2

$ sudo chflags schg ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2

此外,macOS 附加元数据(HFS+ extended attributes)来下载文件,能通过 mdls 和 xattr 指令来观察:

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
$ ls -l@ ~/Downloads/TorBrowser-6.0.8-osx64_en-US.dmg
-rw-r--r--@ 1 drduh staff 59322237 Dec 1 12:00 TorBrowser-6.0.8-osx64_en-US.dmg
com.apple.metadata:kMDItemWhereFroms 186
com.apple.quarantine 68
$ mdls ~/Downloads/TorBrowser-6.0.8-osx64_en-US.dmg
_kMDItemOwnerUserID = 501
kMDItemContentCreationDate = 2016-12-01 12:00:00 +0000
kMDItemContentModificationDate = 2016-12-01 12:00:00 +0000
kMDItemContentType = "com.apple.disk-image-udif"
kMDItemContentTypeTree = (
"public.archive",
"public.item",
"public.data",
"public.disk-image",
"com.apple.disk-image",
"com.apple.disk-image-udif"
)
kMDItemDateAdded = 2016-12-01 12:00:00 +0000
kMDItemDisplayName = "TorBrowser-6.0.8-osx64_en-US.dmg"
kMDItemFSContentChangeDate = 2016-12-01 12:00:00 +0000
kMDItemFSCreationDate = 2016-12-01 12:00:00 +0000
kMDItemFSCreatorCode = ""
kMDItemFSFinderFlags = 0
kMDItemFSHasCustomIcon = (null)
kMDItemFSInvisible = 0
kMDItemFSIsExtensionHidden = 0
kMDItemFSIsStationery = (null)
kMDItemFSLabel = 0
kMDItemFSName = "TorBrowser-6.0.8-osx64_en-US.dmg"
kMDItemFSNodeCount = (null)
kMDItemFSOwnerGroupID = 5000
kMDItemFSOwnerUserID = 501
kMDItemFSSize = 60273898
kMDItemFSTypeCode = ""
kMDItemKind = "Disk Image"
kMDItemLogicalSize = 60273898
kMDItemPhysicalSize = 60276736
kMDItemWhereFroms = (
"https://dist.torproject.org/torbrowser/6.0.8/TorBrowser-6.0.8-osx64_en-US.dmg",
"https://www.torproject.org/projects/torbrowser.html.en"
)
$ xattr -l TorBrowser-6.0.8-osx64_en-US.dmg
com.apple.metadata:kMDItemWhereFroms:
00000000  62 70 6C 69 73 74 30 30 A2 01 02 5F 10 4D 68 74  |bplist00..._.Mht|
00000010  74 70 73 3A 2F 2F 64 69 73 74 2E 74 6F 72 70 72  |tps://dist.torpr|
00000020  6F 6A 65 63 74 2E 6F 72 67 2F 74 6F 72 62 72 6F  |oject.org/torbro|
00000030  77 73 65 72 2F 36 2E 30 2E 38 2F 54 6F 72 42 72  |wser/6.0.8/TorBr|
00000040  6F 77 73 65 72 2D 36 2E 30 2E 38 2D 6F 73 78 36  |owser-6.0.8-osx6|
00000050  34 5F 65 6E 2D 55 53 2E 64 6D 67 5F 10 36 68 74  |4_en-US.dmg_.6ht|
00000060  74 70 73 3A 2F 2F 77 77 77 2E 74 6F 72 70 72 6F  |tps://www.torpro|
00000070  6A 65 63 74 2E 6F 72 67 2F 70 72 6F 6A 65 63 74  |ject.org/project|
00000080  73 2F 74 6F 72 62 72 6F 77 73 65 72 2E 68 74 6D  |s/torbrowser.htm|
00000090  6C 2E 65 6E 08 0B 5B 00 00 00 00 00 00 01 01 00  |l.en..[.........|
000000A0  00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00  |................|
000000B0  00 00 00 00 00 00 94                             |.......|
000000b7
com.apple.quarantine: 0081;58519ffa;Google Chrome.app;1F032CAB-F5A1-4D92-84EB-CBECA971B7BC

可以使用 -d 指令标志移除原数据属性:

1
2
3
4
5
6
$ xattr -d com.apple.metadata:kMDItemWhereFroms ~/Downloads/TorBrowser-6.0.5-osx64_en-US.dmg
$ xattr -d com.apple.quarantine ~/Downloads/TorBrowser-6.0.5-osx64_en-US.dmg
$ xattr -l ~/Downloads/TorBrowser-6.0.5-osx64_en-US.dmg
[No output after removal.]

密码

你可以使用 OpenSSL 生成强密码:

$ openssl rand -base64 30
LK9xkjUEAemc1gV2Ux5xqku+PDmMmCbSTmwfiMRI

或者 GPG:

$ gpg --gen-random -a 0 30
4/bGZL+yUEe8fOqQhF5V01HpGwFSpUPwFcU3aOWQ

或 /dev/urandom 输出:

$ dd if=/dev/urandom bs=1 count=30 2>/dev/null | base64
CbRGKASFI4eTa96NMrgyamj8dLZdFYBaqtWUSxKe

还可以控制字符集:

$ LANG=C tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 40 | head -n 1
jm0iKn7ngQST8I0mMMCbbi6SKPcoUWwCb5lWEjxK

$ LANG=C tr -dc 'DrDuh0-9' < /dev/urandom | fold -w 40 | head -n 1
686672u2Dh7r754209uD312hhh23uD7u41h3875D

你也可以用 Keychain Access(钥匙串访问)生成一个令人难忘的密码,或者用 anders/pwgen 这样的命令行生成。

钥匙串使用 PBKDF2 派生密钥加密,是个非常安全存储凭据的地方。看看 Breaking into the OS X keychain。还要注意钥匙串不加密的密码对应密码输入的名称。

或者,可以自己用 GnuPG (基于 drduh/pwd.sh 密码管理脚本的一个插件)管理一个加密的密码文件。

除密码外,确保像 GitHub、 Google 账号、银行账户这些网上的账户,开启两步验证。

看看 Yubikey 的两因素和私钥(如:ssh、gpg)硬件令牌。 阅读 drduh/YubiKey-Guide 和 trmm.net/Yubikey。两个 Yubikey 的插槽之一可以通过编程来生成一个长的静态密码(例如可以与短的,记住的密码结合使用)。

备份

备份到外部介质或在线服务之前,总是先对本地文件进行加密。

一种方法是使用 GPG 对称加密,你选择一个密码。

加密一个文件夹:

$ tar zcvf - ~/Downloads | gpg -c > ~/Desktop/backup-$(date +%F-%H%M).tar.gz.gpg

解密文档:

$ gpg -o ~/Desktop/decrypted-backup.tar.gz -d ~/Desktop/backup-2015-01-01-0000.tar.gz.gpg && \
  tar zxvf ~/Desktop/decrypted-backup.tar.gz

你也可以用 Disk Utility 或 hdiutil 创建加密卷:

$ hdiutil create ~/Desktop/encrypted.dmg -encryption -size 1g -volname "Name" -fs JHFS+

也可以考虑使用下面的应用和服务:SpiderOak、Arq、Espionage 和 restic。

Wi-Fi

macOS 会记住它连接过的接入点。比如所有无线设备,每次搜寻网络的时候,Mac 将会显示所有它记住的接入点名称(如 MyHomeNetwork) ,比如每次从休眠状态唤醒设备的时候。

这就有泄漏隐私的风险,所以当不再需要的时候最好从列表中移除这些连接过的网络, 在 System Preferences > Network > Advanced 。

看看 Signals from the Crowd: Uncovering Social Relationships through Smartphone Probes (pdf) 和 Wi-Fi told me everything about you (pdf)。

保存的 Wi-Fi 信息 (SSID、最后一次连接等)可以在 /Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist 中找到。

你可能希望在连接到新的和不可信的无线网络之前伪造网卡 MAC 地址,以减少被动特征探测:

$ sudo ifconfig en0 ether $(openssl rand -hex 6 | sed 's%\(..\)%\1:%g; s%.$%%')

注意每次启动,MAC 地址将重置为硬件默认地址。

了解下 feross/SpoofMAC.

最后,WEP 保护在无线网络是不安全的,你应该尽量选择连接 WPA2 保护网络,可以减少被窃听的风险。

SSH

对于向外的 ssh 连接,使用硬件或密码保护的秘钥,设置远程 hosts 并考虑对它们进行哈希,以增强安全性。

将这几个配置项加到 ~/.ssh/config:

Host *
  PasswordAuthentication no
  ChallengeResponseAuthentication no
  HashKnownHosts yes

注意 macOS Sierra 默认永久记住 SSH 秘钥密码。添加配置 UseKeyChain no 来关闭这项功能。

你也可以用 ssh 创建一个加密隧道来发送数据,这有点类似于 VPN。

例如,在一个远程主机上使用 Privoxy:

$ ssh -C -L 5555:127.0.0.1:8118 you@remote-host.tld

$ sudo networksetup -setwebproxy "Wi-Fi" 127.0.0.1 5555

$ sudo networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 5555

或者使用 ssh 连接作为 SOCKS 代理:

$ ssh -NCD 3000 you@remote-host.tld

默认情况下, macOS 没有 sshd ,也不允许远程登陆。

启用 sshd 且允许进入的 ssh 连接:

$ sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

或者设置 System Preferences > Sharing 菜单。

如果你准备使用 sshd,至少禁用密码身份验证并考虑进一步强化配置。

找到 /etc/sshd_config,添加:

1
2
3
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

确认 sshd 是否启用:

$ sudo lsof -Pni TCP:22

物理访问

时刻保证 Mac 物理安全。不要将 Mac 留在无人照看的酒店之类的地方。

有一种攻击就是通过物理访问,通过注入引导 ROM 来安装键盘记录器,偷走你的密码。看看这个案例 Thunderstrike。

有个工具 usbkill 可以帮助你,这是“一个反监视断路开关,一旦发现 USB 端口发生改变就会关闭你的计算机”。

考虑购买屏幕隐私过滤器防止别人偷瞄。

系统监控

OpenBSM 监测

macOS 具有强大的 OpenBSM 审计功能。你可以使用它来监视进程执行、网络活动等等。

跟踪监测日志,使用 praudit 工具:

1
2
3
4
$ sudo praudit -l /dev/auditpipe
header,201,11,execve(2),0,Thu Sep 1 12:00:00 2015, + 195 msec,exec arg,/Applications/.evilapp/rootkit,path,/Applications/.evilapp/rootkit,path,/Applications/.evilapp/rootkit,attribute,100755,root,wheel,16777220,986535,0,subject,drduh,root,wheel,root,wheel,412,100005,50511731,0.0.0.0,return,success,0,trailer,201,
header,88,11,connect(2),0,Thu Sep 1 12:00:00 2015, + 238 msec,argument,1,0x5,fd,socket-inet,2,443,173.194.74.104,subject,drduh,root,wheel,root,wheel,326,100005,50331650,0.0.0.0,return,failure : Operation now in progress,4354967105,trailer,88
header,111,11,OpenSSH login,0,Thu Sep 1 12:00:00 2015, + 16 msec,subject_ex,drduh,drduh,staff,drduh,staff,404,404,49271,::1,text,successful login drduh,return,success,0,trailer,111,

看看 audit、praudit、audit_control 的操作手册,其它文件在 /etc/security目录下。

注意虽然 audit 手册 上说 -s 标签会立即同步到配置中,实际上需要重启才能生效。

更多信息请看 ilostmynotes.blogspot.com 和 derflounder.wordpress.com 上的文章。

DTrace

iosnoop 监控磁盘 I/O

opensnoop 监控文件打开

execsnoop 监控进程执行

errinfo 监控失败的系统调用

dtruss 监控所有系统调用

运行命令 man -k dtrace 去了解更多信息。

注意系统完整性保护和 DTrace 冲突,所以这些工具可能用不上了。

运行

ps -ef 列出所有正在运行的进程。

你也可以通过活动监视器来查看进程。

launchctl list 和 sudo launchctl list 分别列出用户运行和加载的程序、系统启动守护程序和代理。

网络

列出公开网络文件:

$ sudo lsof -Pni

列出各种网络相关的数据结构的内容:

$ sudo netstat -atln

你也可以通过命令行使用 Wireshark。

监控 DNS 查询和响应:

1
2
3
4
5
$ tshark -Y "dns.flags.response == 1" -Tfields \
-e frame.time_delta \
-e dns.qry.name \
-e dns.a \
-Eseparator=,

监控 HTTP 请求和响应:

1
2
3
4
5
6
7
$ tshark -Y "http.request or http.response" -Tfields \
-e ip.dst \
-e http.request.full_uri \
-e http.request.method \
-e http.response.code \
-e http.response.phrase \
-Eseparator=/s

监控 x509 证书:

1
2
3
4
5
6
7
8
$ tshark -Y "ssl.handshake.certificate" -Tfields \
-e ip.src \
-e x509sat.uTF8String \
-e x509sat.printableString \
-e x509sat.universalString \
-e x509sat.IA5String \
-e x509sat.teletexString \
-Eseparator=/s -Equote=d

也可以考虑简单的网络监控程序 BonzaiThePenguin/Loading。

二进制白名单

google/santa 是一款为 Google 公司 Macintosh 团队开发的一款安全软件,而且是开源的。

Santa 是 macOS 上一个二进制白名单/黑名单系统。它由多个部分组成,一个是监控执行程序的内核扩展,基于 SQLite 数据库内容进行执行决策的用户级守护进程,决定拦截的情况下通知用户的一个 GUI 代理,以及用于管理系统和数据库同步服务的命令行实用程序。

Santa 使用内核授权 API 来监视和允许/禁止在内核中执行二进制文件。二进制文件可以是经过唯一哈希或开发者证书签名的白/黑名单。Santa 可以用来只允许执行可信代码,或者阻止黑名单中已知恶意软件在 Mac 上运行,和 Windows 软件 Bit9 类似。

注意 Santa 目前还没有管理规则的用户图形界面。下面的教程是为高级用户准备的!

安装 Santa,先访问发布页面,下载最新的磁盘镜像,挂载然后安装相关软件包:

1
2
3
$ hdiutil mount ~/Downloads/santa-0.9.14.dmg
$ sudo installer -pkg /Volumes/santa-0.9.14/santa-0.9.14.pkg -tgt /

Santa 默认安装为 “Monitor” 模式 (不拦截,只记录),有两个规则:一条是为了 Apple 二进制,另一条是为了 Santa 软件本身。

验证 Santa 是否在运行,内核模块是否加载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ santactl status
>>> Daemon Info
Mode | Monitor
File Logging | No
Watchdog CPU Events | 0 (Peak: 0.00%)
Watchdog RAM Events | 0 (Peak: 0.00MB)
>>> Kernel Info
Kernel cache count | 0
>>> Database Info
Binary Rules | 0
Certificate Rules | 2
Events Pending Upload | 0
$ ps -ef | grep "[s]anta"
0 786 1 0 10:01AM ?? 0:00.39 /Library/Extensions/santa-driver.kext/Contents/MacOS/santad --syslog
$ kextstat | grep santa
119 0 0xffffff7f822ff000 0x6000 0x6000 com.google.santa-driver (0.9.14) 693D8E4D-3161-30E0-B83D-66A273CAE026 <5 4 3 1>

创建一个黑名单规则来阻止 iTunes 运行:

$ sudo santactl rule --blacklist --path /Applications/iTunes.app/
Added rule for SHA-256: e1365b51d2cb2c8562e7f1de36bfb3d5248de586f40b23a2ed641af2072225b3.

试试打开 iTunes ,它会被阻止运行。

$ open /Applications/iTunes.app/
LSOpenURLsWithRole() failed with error -10810 for the file /Applications/iTunes.app.

Santa block dialog when attempting to run a blacklisted program

移除规则:

$ sudo santactl rule --remove --path /Applications/iTunes.app/
Removed rule for SHA-256: e1365b51d2cb2c8562e7f1de36bfb3d5248de586f40b23a2ed641af2072225b3.

打开 iTunes:

$ open /Applications/iTunes.app/
[iTunes will open successfully]

创建一个新的 C 语言小程序:

1
2
3
4
$ cat <<EOF > foo.c
> #include <stdio.h>
> main() { printf("Hello World\n”); }
> EOF

用 GCC 编译该程序(需要安装 Xcode 或者命令行工具):

1
2
3
4
5
6
7
$ gcc -o foo foo.c
$ file foo
foo: Mach-O 64-bit executable x86_64
$ codesign -d foo
foo: code object is not signed at all

运行它:

1
2
$ ./foo
Hello World

将 Santa 切换为 “Lockdown” 模式,这种情况下只允许白名单内二进制程序运行:

$ sudo defaults write /var/db/santa/config.plist ClientMode -int 2

试试运行未签名的二进制:

1
2
3
4
5
6
7
8
9
10
11
$ ./foo
bash: ./foo: Operation not permitted
Santa
The following application has been blocked from executing
because its trustworthiness cannot be determined.
Path: /Users/demouser/foo
Identifier: 4e11da26feb48231d6e90b10c169b0f8ae1080f36c168ffe53b1616f7505baed
Parent: bash (701)

想要在白名单中添加一个指定的二进制,确定其 SHA-256 值:

1
2
3
4
5
6
7
$ santactl fileinfo /Users/demouser/foo
Path : /Users/demouser/foo
SHA-256 : 4e11da26feb48231d6e90b10c169b0f8ae1080f36c168ffe53b1616f7505baed
SHA-1 : 4506f3a8c0a5abe4cacb98e6267549a4d8734d82
Type : Executable (x86-64)
Code-signed : No
Rule : Blacklisted (Unknown)

增加一条白名单规则:

$ sudo santactl rule --whitelist --sha256 4e11da26feb48231d6e90b10c169b0f8ae1080f36c168ffe53b1616f7505baed
Added rule for SHA-256: 4e11da26feb48231d6e90b10c169b0f8ae1080f36c168ffe53b1616f7505baed.

运行它:

1
2
$ ./foo
Hello World

小程序没有被阻止,它成功的运行了。

应用程序也可以通过开发者签名来加到白名单中(这样每次更新应用程序的时候,新版本的二进制文件就不用手动加到白名单中了)。例如,下载运行 Google Chrome , 在 “Lockdown” 模式下 Santa 会阻止它运行:

1
2
3
4
5
6
7
8
$ curl -sO https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg
$ hdiutil mount googlechrome.dmg
$ cp -r /Volumes/Google\ Chrome/Google\ Chrome.app /Applications/
$ open /Applications/Google\ Chrome.app/
LSOpenURLsWithRole() failed with error -10810 for the file /Applications/Google Chrome.app.

通过它自己的开发者签名将应用加到白名单中(Signing Chain 中第一项):

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
$ santactl fileinfo /Applications/Google\ Chrome.app/
Path : /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
SHA-256 : 0eb08224d427fb1d87d2276d911bbb6c4326ec9f74448a4d9a3cfce0c3413810
SHA-1 : 9213cbc7dfaaf7580f3936a915faa56d40479f6a
Bundle Name : Google Chrome
Bundle Version : 2883.87
Bundle Version Str : 55.0.2883.87
Type : Executable (x86-64)
Code-signed : Yes
Rule : Blacklisted (Unknown)
Signing Chain:
1. SHA-256 : 15b8ce88e10f04c88a5542234fbdfc1487e9c2f64058a05027c7c34fc4201153
SHA-1 : 85cee8254216185620ddc8851c7a9fc4dfe120ef
Common Name : Developer ID Application: Google Inc.
Organization : Google Inc.
Organizational Unit : EQHXZ8M8AV
Valid From : 2012/04/26 07:10:10 -0700
Valid Until : 2017/04/27 07:10:10 -0700
2. SHA-256 : 7afc9d01a62f03a2de9637936d4afe68090d2de18d03f29c88cfb0b1ba63587f
SHA-1 : 3b166c3b7dc4b751c9fe2afab9135641e388e186
Common Name : Developer ID Certification Authority
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2012/02/01 14:12:15 -0800
Valid Until : 2027/02/01 14:12:15 -0800
3. SHA-256 : b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024
SHA-1 : 611e5b662c593a08ff58d14ae22452d198df6c60
Common Name : Apple Root CA
Organization : Apple Inc.
Organizational Unit : Apple Certification Authority
Valid From : 2006/04/25 14:40:36 -0700
Valid Until : 2035/02/09 13:40:36 -0800

这个例子中, 15b8ce88e10f04c88a5542234fbdfc1487e9c2f64058a05027c7c34fc4201153 是 Google’s Apple 开发者证书的 SHA-256 (team ID EQHXZ8M8AV)。 将它加到白名单中:

1
2
$ sudo santactl rule --whitelist --certificate --sha256 15b8ce88e10f04c88a5542234fbdfc1487e9c2f64058a05027c7c34fc4201153
Added rule for SHA-256: 15b8ce88e10f04c88a5542234fbdfc1487e9c2f64058a05027c7c34fc4201153.

Google Chrome 现在应该可以启动了,以后的更新也不会被阻止,除非签名证书修改了或过期了。

关闭 “Lockdown” 模式:

$ sudo defaults delete /var/db/santa/config.plist ClientMode

在 /var/log/santa.log 可以查看监控器允许和拒绝执行的决策记录。

注意 Python、Bash 和其它解释性语言是在白名单中的(因为它们是由苹果开发者证书签名的),所以 Santa 不会阻止这些脚本的运行。因此,要注意到 Santa 可能无法有效的拦截非二进制程序运行(这不算漏洞,因为它本身就这么设计的)。

其它

如果你想的话,禁用诊断与用量.

如果你想播放音乐或看视频,使用 VLC 播放器,这是免费且开源的。

如果你想用 torrents, 使用免费、开源的 Transmission(注意:所有软件都一样,即使是开源项目,恶意软件还是可能找到破解的方式)。你可能希望使用一个块列表来避免和那些已知的坏主机配对,了解下 Transmission 上最好的块列表 和 johntyree/3331662。

用 duti 管理默认文件处理,可以通过 brew install duti 来安装。管理扩展的原因之一是为了防止远程文件系统在 Finder 中自动挂载。 (保护自己免受 Sparkle 后门影响)。这里有几个推荐的管理指令:

1
2
3
4
5
6
7
$ duti -s com.apple.Safari afp
$ duti -s com.apple.Safari ftp
$ duti -s com.apple.Safari nfs
$ duti -s com.apple.Safari smb

使用控制台应用程序来监控系统日志,也可以用 syslog -w 或 log stream 命令。

在 macOS Sierra (10.12) 之前的系统,在 /etc/sudoers启用 tty_tickets flag 来阻止 sudo 会话在其它终端生效。使用命令 sudo visudo 然后添加一行 Defaults tty_tickets 就可以了。

设置进入休眠状态时马上启动屏幕保护程序:

$ defaults write com.apple.screensaver askForPassword -int 1

$ defaults write com.apple.screensaver askForPasswordDelay -int 0

在 Finder 中显示隐藏文件和文件夹:

$ defaults write com.apple.finder AppleShowAllFiles -bool true

$ chflags nohidden ~/Library

显示所有文件扩展名(这样 “Evil.jpg.app” 就无法轻易伪装了)。

$ defaults write NSGlobalDomain AppleShowAllExtensions -bool true

不要默认将文档保存到 iCloud:

$ defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false

在终端启用安全键盘输入(除非你用 YubiKey 或者像 TextExpander 这样的程序)。

禁用崩溃报告(就是那个在程序崩溃后,会出现提示将问题报告给苹果的提示框):

$ defaults write com.apple.CrashReporter DialogType none

禁用 Bonjour 多播广告/):

$ sudo defaults write /Library/Preferences/com.apple.mDNSResponder.plist NoMulticastAdvertisements -bool YES

如果用不上的话,禁用 Handoff 和蓝牙功能。

考虑 sandboxing 你的应用程序。 了解下 fG! Sandbox Guide (pdf) 和 s7ephen/OSX-Sandbox–Seatbelt–Profiles。

你知道苹果公司自 2006 后就不再出售带 TPM 的电脑了吗?

相关软件

Santa - macOS 上一个带二进制白名单/黑名单监控系统的软件。

kristovatlas/osx-config-check - 检查你的 OSX 设备各种硬件配置设置。

Lockdown - 审查和修正安全配置。

Dylib Hijack Scanner - 扫描那些容易被劫持或已经被黑的应用。

Little Flocker - “Little Snitch for files”, 防止应用程序访问文件。

facebook/osquery - 可以检索系统底层信息。用户可以编写 SQL 来查询系统信息。

google/grr - 事件响应框架侧重于远程现场取证。

yelp/osxcollector - 证据收集 & OS X 分析工具包。

jipegit/OSXAuditor - 分析运行系统时的部件,比如隔离的文件, Safari、 Chrome 和 Firefox 历史记录, 下载,HTML5 数据库和本地存储、社交媒体、电子邮件帐户、和 Wi-Fi 接入点的名称。

libyal/libfvde - 访问 FileVault Drive Encryption (FVDE) (或 FileVault2) 加密卷的库。

CISOfy/lynis - 跨平台安全审计工具,并协助合规性测试和系统强化。

其它资源

排名不分先后

MacOS Hardening Guide - Appendix of *OS Internals: Volume III - Security & Insecurity Internals (pdf)

Mac Developer Library: Secure Coding Guide

OS X Core Technologies Overview White Paper (pdf)

Reverse Engineering Mac OS X blog

Reverse Engineering Resources

Patrick Wardle’s Objective-See blog

Managing Macs at Google Scale (LISA ‘13)

OS X Hardening: Securing a Large Global Mac Fleet (LISA ‘13)

DoD Security Technical Implementation Guides for Mac OS

The EFI boot process

The Intel Mac boot process

Userland Persistence on Mac OS X

Developing Mac OSX kernel rootkits

IOKit kernel code execution exploit

Hidden backdoor API to root privileges in Apple OS X

IPv6 Hardening Guide for OS X

Harden the World: Mac OSX 10.11 El Capitan

Hacker News discussion

Hacker News discussion 2

Apple Open Source

OS X 10.10 Yosemite: The Ars Technica Review

CIS Apple OSX 10.10 Benchmark (pdf)

How to Switch to the Mac

Security Configuration For Mac OS X Version 10.6 Snow Leopard (pdf)

EFF Surveillance Self-Defense Guide

MacAdmins on Slack

iCloud security and privacy overview

Demystifying the DMG File Format

There’s a lot of vulnerable OS X applications out there (Sparkle Framework RCE)

iSeeYou: Disabling the MacBook Webcam Indicator LED

Mac OS X Forensics - Technical Report (pdf)

Mac Forensics: Mac OS X and the HFS+ File System (pdf)

Extracting FileVault 2 Keys with Volatility

Auditing and Exploiting Apple IPC

Mac OS X and iOS Internals: To the Apple’s Core by Jonathan Levin

Demystifying the i-Device NVMe NAND (New storage used by Apple)

gleamwang

上班吃什么

Veröffentlicht am 2016-12-15 |

坚果

整天很费脑力 平时又几乎不吃小零食

最近用宜家的瓶子 装剥好的坚果

想吃就吃

嗯 你不喜欢吃肉 你要多吃坚果

准备了核桃 夏威夷果 巴旦木 碧根果 枸杞 大枣 葡萄干和黑加仑干

每天中午吃完饭后 如果瓶子里快没了 就开始扒吧

把瓶子用多种坚果装满 很幸福

gleamwang

大连烤鱼片

Veröffentlicht am 2016-10-23 |

2016-10月下旬

大连的现烤鱼片 挺好吃的 可是为什么口味又咸又甜啊

找店家又买了点 找的圆通快递 路线是大连-无锡-上海 等了好久 差评

#关于快递

好不容易第三天上午开始派件 快递小哥默认周末不往公司派件

发了个短信说 我里面是生鲜 麻烦放配件箱里 等下我自己去拿

第二天早上 还是没派件

果断投诉

塞进去了

我去拿的时候 惊呆了

快递拿不出来 那个柜子很矮

于是我拽了五分钟后 拿出了变形的鱼干

第三次投诉

不关什么工作和职位 最起码说不会让人差评吧

不然 和咸鱼有什么区别(不是下面的咸鱼 人家很好吃 很尽力的遇到我 被我品尝 也值了)

#下面是图

下午吃一片 精神一整天 额 不是啦 还是略咸 口味变淡很久了

请忽略牌子 这和牌子没关系

烤得焦黄焦黄的 满满的幸福啊 (咽了下口水)

包装可以选正常或者真空的 可是真空的一压缩会硬 影响口感
保质期大概一个月 反正我应该能吃完 不会坏




#总结

生活很美好 需要你发现

gleamwang

你不爱吃肉 要多吃坚果

Veröffentlicht am 2016-10-23 |

2016-9 秋天到了

嗯 作为辛苦搬砖的人 要多吃坚果 补补脑

之前买的夏威夷果巴旦木碧根果什么的 没看口味 买到了什么奶油味啊 超咸 不好吃

于是这次 挑了很久 和客服妹妹再三确认 我这个是原味的啊 是椒盐味的么

#下面是图

碧根果超难剥 我的手啊 后来知乎了下 说是用剪刀剪

巴旦木很好剥 又好吃啦啦啦

嗯 弄好 装瓶 每天吃半瓶 补补脑

#总结

大神说过坚果的好

gleamwang

【译】在 Swift Playgrounds 中使用 Core Data 模型

Veröffentlicht am 2016-10-19 |
  • 原文链接 : using-a-core-data-model-in-swift-playgrounds
  • 原文作者 : Andrew Bancroft
  • 译文出自 : 掘金翻译计划
  • 译者 : MAYDAY1993
  • 校对者: siegeout [owenlyn] (https://github.com/owenlyn)

在 Swift Playgrounds 中使用 Core Data 模型

你能在 Xcode 的 Swift Playgrounds 中使用 Core Data 模型么?当然可以!

在2015年, http://www.learncoredata.com的作者 Jeremiah Jessel,写了篇文章 detailing how you can use the Core Data framework inside a playground。从建立 Core Data 堆栈到在代码中创建 NSManagedObjects,他向我们展示了如何处理这一过程中的所有事情。多么好的资料啊!
读完他的指南后,我开始思考:我很好奇你是否能拿到一个由 Xcode 的数据模型设计创建的 .xcdatamodeld 文件,并在某个背景使用这个文件…
简短的答案是不可以。你不能使用 .xcdatamodeld 文件(至少,我找不到可行的方法),但是你能用当你构建应用就生成的 “momd” 文件。

##局限性
当我了解这个概念的时候我遇到了至少两个局限性/或者说是需要注意的地方。

##没有 NSManagedObject 子类
尽管你能在模型中创建实体的实例,如果你已经为实体创建了 NSManagedObject 的子类,在 Swift Playgrounds 中你还不能使用这些实体。你得用 setValue(_: forKey:) 在 NSManagedObject 实例中设置属性来解决这一问题。
但是这只是一个很小的缺陷,尤其是如果你只想稍微了解。

##更新模型
你读过 walkthrough之后,将会知道如何在背景中引入模型。
总的说来是这样的:如果你曾经更改了模型,你需要操作必须的步骤来在资源文件夹中重新添加一个最新编译的模型。这是因为新加的资源是复制过来的,不是引用的。
我并不认为这是个很糟糕的缺点,尤其是你一旦了解怎么做的时候。
所以你要怎么做呢?看下面过程:

##攻略
在你的项目中加入一个数据模型,我们开始啦。如果你已经进行了一个使用 Core Data 的项目,在你的项目里可能已经有了一个 .xcdatamodeld 文件。如果你没有,这个 .xcdatamodeld 文件能从文件菜单中简单添加。

##添加数据模型文件(除非你已经有一个)
File -> New -> File…
New Data Model

用冒烟测试来看以上方法是否可行,我将模型名字设置为默认的值 “Model.xcdatamodeld”。

##添加带属性的实体
将数据模型添加到项目之后,我继续添加了一个带( 16 位的整数类型名字是 “attribute” )属性的(名字叫 “Entity” )实体:
Add an entity with an attribute.

##添加 playground
下一步,我往项目里加了一个新的 playground:
File -> New -> Playground…
Add new playground

##构建项目:定位 “momd” 文件
有一个 playground 并且一个数据模型结构化了,我构建了项目(CMD + B),因此 .xcdatamodeld 文件能被编译成一个 “momd” 文件。就是这个 “momd” 文件需要作为一个资源被添加到 playground 中。
要找到 “momd” 文件,在你的项目导航栏中展开 “Products”,右击 .app,单击 “Show in Finder”:
Show product in finder

##显示 .app 包的内容
在 finder 窗口,右击 .app 文件,然后单击 “Show package contents”:
Show package contents

##从 finder 中把 “momd” 文件拖拽到 playground 的资源文件夹
Locate

Drag

##写 Core Data 代码来使用模型
既然 “momd” 文件在 playground 的资源文件夹里,你能写代码了。你能插入 NSManagedObject 实例,运行 fetch requests 等等。下面是我写的一个例子:

Core Data Playground

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
import UIKit
import CoreData
// Core Data 堆栈存在内存中
public func createMainContext() -> NSManagedObjectContext {
//用你自己模型的名字替换 "Model"
let modelUrl = NSBundle.mainBundle().URLForResource("Model", withExtension: "momd")
guard let model = NSManagedObjectModel.init(contentsOfURL: modelUrl!) else { fatalError("model not found") }
let psc = NSPersistentStoreCoordinator(managedObjectModel: model)
try! psc.addPersistentStoreWithType(NSInMemoryStoreType, configuration: nil, URL: nil, options: nil)
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.persistentStoreCoordinator = psc
return context
}
let context = createMainContext()
//插入一个新实体
let ent = NSEntityDescription.insertNewObjectForEntityForName("Entity", inManagedObjectContext: context)
ent.setValue(42, forKey: "attribute")
try! context.save()
//运行一个 fetch request
let fr = NSFetchRequest(entityName: "Entity")
let result = try! context.executeFetchRequest(fr)
print(result)

Fetch request result

哇哦!这很酷啊。

别忘了 :如果你更新了模块,你需要重新构建你的应用,从 playground 的资源中删掉 “momd” 文件夹,再一次重新把新编译好的 “momd” 文件拖拽到 playground 中来运行最新版本的模型。

潜在的用处

除了“我想知道这是否可能”,另一个问的重要问题是“它是多么有用?”

  • 学习。 Playgrounds 本身作为一个学习工具有意义。能够搭建你在 Xcode 设计中思考的模块,把它导入一个 Playground ,并且把它当作一个学习练习来研究它,是多么酷啊!
  • 当你需要测试你的数据模块但是不想把它连到一个实际的用户交互的时候,也是有用的。在 playground 中抛掉所有用户交互复杂性,只研究数据模型!这似乎是一个比在控制台输出更优雅的解决方法
  • 有可能你需要为一个 fetch request 构建半复杂性的 NSPredicate 实例--为何不首先在 playground 中得到这个实例,然后把实例迁移到你的应用中呢?仅仅是个想法哦!
gleamwang

【译】你考虑清楚了吗就决定用 Bootstrap ?

Veröffentlicht am 2016-10-19 |
  • 原文地址:Bootstrap considered harmful
  • 原文作者:Hidde de Vries
  • 译文出自:掘金翻译计划
  • 译者: MAYDAY1993
  • 校对者: Kulbear hpoenixf

你考虑清楚了吗就决定用 Bootstrap ?

近年来,在前端项目中, Bootstrap 已经成为了一个非常受欢迎的工具。 Bootstrap 的确有很多优点,然而,如果你的团队中恰好有一个专职的前端工程师。那我推荐你们不要使用 Bootstrap ,因为在某些情况下, Bootstrap 弊大于利。

Bootstrap 对什么有好处

Bootstrap 带有栅格系统,也有针对很多组件的样式和脚本,包括表格,导航栏,进度条,分页,表单样式,模态框和提示框。在这篇文章中,谈论 ‘Bootstrap’,我的意思是包含所有组件的实践(与只选择包括一部分相反,例如, 只是栅格)。
对于需要把项目输出成标记语言,并且不想操心将结果样式化的后端开发工程师来讲, Bootstrap 是一个好的工具。如果因为某些原因,比如预算或其他因素,在一个团队里没有前端开发者或设计师, Bootstrap 适合用来填坑。

对于设计师来讲, Bootstrap 也有一席之地:它是一个很有价值的工具,用来从设计软件快速移动到浏览器,而不需要过度担心前端代码策略。
甚至对于主要和数据打交道很少关注 UI 和布局的前端开发者,让一个开发者关注于搭建应用本身, Bootstrap 在这一方面也很好。

什么时候你最好别用它

然而,如果你的团队里有一个前端开发工程师,使用 Bootstrap 会潜在地浪费他们宝贵的时间,并且将他们的注意力从解决实际的问题转移。 Bootstrap 恰恰做的是前端开发者擅长的,但是它以一种很普遍的方式来实现。你的网站或应用是很具体的,所以如果你用一个普遍的系统,它有可能不会起作用。这意味着你的代码将包含全部的可能性才有可能实现具体的需求。

当你需要很多代码来覆盖 Bootstrap 的样式

Bootstrap 是由 Twitter 的开发者开发来系统化他们网站应用的样式。当你的网站应用的样式和他们不一样,这意味着你不得不覆盖掉他们的样式来。
大多数网站的样式并不像 Twitter 那样。因此,如果他们安装 Bootstrap ,他们会覆盖掉很多样式。
在一些我参与的网站中,我发现多达十分之九的 Bootstrap 样式会被网站自己的样式覆盖掉。很坦率的讲,这是荒谬的。

当它让简单的事情复杂化

CSS 用来为网页增加一系列简单的在某些条件下会被代码覆盖的样式规则。当你的网站中有 Bootstrap 的样式,几乎网站内所有的东西都已经被一系列复杂的代码规则设置好了。任何例外都会超出这个框架所设置好的规则。而大多数网站所面临的问题正是它们的样式对于 Bootstrap 来说往往是例外。
Bootstrap 的样式是复杂的:你会有一个带有 12 列的栅格系统,这 12 列能以你想要的任何方式组合使用,有特殊的类来基于用户的视图尺寸设置不同的偏移量和列结构。很多网站是简单的:在小屏幕上没有列,在更大的屏幕会有一到两列。

当它产生了技术债务

一个前端代码库依赖 Bootstrap 的时间越长,纠缠的越多,并且它包含了更多只是用来覆盖掉 Bootstrap 代码的规则。这常常导致代码库陷于巨大的技术债务,尤其当前端代码以经常需要手动更新的方式整合在后端的时候。

当它引入可能不是你的应用的命名习惯

命名很难,而且想出有意义的属于你的团队和应用的命名习惯很花时间。对于组件名使用合适的名词,不要和一些名词的缩写像 ’btn’ 的类名混淆。

结论

在开发网站的过程中 Bootstrap 和朋友在各种各样的阶段是有好处的。然而它们不是一个能使任何事都简单的魔法:相反,会有很多能够通过让前端开发者关注于亲自开发 UI 来避免的缺点。

gleamwang

【译】在开发移动应用时你应该考虑的 「Empty State」

Veröffentlicht am 2016-10-18 |
  • 原文链接 : Empty State: Mobile App “Nice-to-Have” Essential
  • 原文作者 : Nick Babich
  • 译文出自 : 掘金翻译计划
  • 译者 : MAYDAY1993
  • 校对者: jiaowoyongqi shixinzhang

#

普通应用在安装后的前三天会失去 77% 的日活跃用户。更为严重的是:三十天内,大约 80% 的日活跃用户会流失.

这些低留存率是因为应用做的很烂么?并不总是这个原因。

用户试用了很多应用并且在最初的几天决定要删掉哪些。应用成功的关键是在关键时期吸引住用户。

你的任务是确保用户停留足够长的时间并有很多交互操作来享受应用。 但在这些好情况发生之前他们应该享受第一次使用。

通常我们设计一个很受欢迎的界面,布局里的每个元素看上去都安排的很好。空白状态界面通常是你最后设计的。事实上 empty state 对于吸引用户操作充满潜力。即使 empty state 只是一个临时的阶段,我们必须认真对待它带来的与用户交流的价值。

什么时候用户遇到 empty state?

  • 第一次使用:应用第一次启动

  • 错误:遇到一些问题

  • 用户删除内容:当用户删掉所有的应用内容

    empty state 的作用不仅仅是装饰的作用。除了通知用户页面上期待展示的内容, empty state 也具有优化首次使用体验的作用--他们告诉用户需要哪些明确的操作,所以应用才会有预期的功能。当用户遇到一个问题, empty state 也是极好(或坏)的。

一个成功 empty state 的完成下面三个目标:

  • 教育和帮助

  • 让用户愉悦

  • 提示用户进行操作

    empty state 的第一个目标是教人们怎么用你的应用。如果他们不理解功能,他们会离开。所以你应该通过建立起对未知的期待,让用户体验更好。

Invoice app  —双色插图的空白状态页,清晰地展示了如何快速地管理数据、查看销售业绩以及掌握客户动态的所有功能。

empty state 应该在出错的时候起作用。你需要在 empty state 的友好和有用间找到平衡。当显示错误的时候,向用户解释为什么他看不到任何东西以及如何解决这一问题:

不好的例子: Spotify 的 empty state 只有 ‘An error occurred’ 信息

Spotify’s 的错误提示并不像它本该的那样有用。

好的例子: Azendoo .感到迷茫和失连啦,像你在一个废弃的小岛上?听从建议,保持冷静,点把火,持续刷新就好啦。

Azendoo’s 的错误页面好玩又有用。

一个首次使用的好的 empty state 强调如下的时刻:

一个好的印象不仅仅是关于可用性,还关于个性化。如果你的第一个 empty state 页面看上去和相似的产品有一点不同,你已经向用户表明整个产品的体验也可能不同。对于 empty state 你的目标是给用户一个愉快的惊喜。

苹果上 Dubizzle 的没有喜欢的广告。

你能设计一些新鲜或惊喜的么?像是一个动态的 empty state :

Workmates  —动物在单独页面用可爱的hi和hello和你打招呼呢。

或者你可能编个笑话?

Cognito Brain Training —你会吃惊于看到一只鲨鱼,不管内容。

Aaron Walter 用人类需求的等级作为一个应用有成功的用户体验的一个解释;应用除了应该是有用的,可靠的、能用的,也应该是使人欢快的。所以设计下面的页面同理:

在 Line Play 里没有新闻结果。不管怎样,这体验很不好。

看你的手机里的首次使用页和其他应用的 empty state 体验。通过以下方法来取悦用户:

将一个 empty state 视为一个微型的登录页面。设计上保持微型的同时,一个成功的页面将会解释一个明确的特性并让用户有下一笔操作。

为了在一个 empty state 促使用户下一步操作,你应该这样:

  • 刺激用户:用适合用户的刺激性的语言和设计例如: “Learn more” 或 “Let’s get started.”

Dropbox iOS 应用

  • 说服用户:提醒他们当他们使用产品后将会获取的好处

Flipboard 移动端应用

  • 引导用户:向他们推荐并展示开始使用应用最好的方法。提供一个提示(或箭头)的按钮来引导用户采取必要的操作来关闭 empty state ,然后得到一个更有意义的页面“

箭头在第二张图提示操作。来源: Dribbble

  • 深入研究 empty state 因为它不是用户体验中一个暂时的或很小的部分。让用户在使用你的应用的时候很欢快并且能将个人感觉和产品特性联系起来。向用户介绍应用的好处,用户才能知道他们为什么要在意这个产品。

  • 视觉上保持简单的设计:通常来讲,简洁的页面,清晰的图标或插图和一个 CTA 按钮足够了。

  • 如果 empty state 是被用户的良好行为触发的,用一个愉快的信息来奖励用户。

  • 如果 empty state 是出错后出现的,解释清楚怎样解决这个问题和返回到之前的页面

    empty state 和其他设计组件一样重要,因为用户体验是所有能和谐地起作用的部分的总和。用户界面需要信息和操作之间精细的平衡。 empty state 将用户和设计完善的UI界面相连接起来,以此来保留用户的注意力。

Follow UX Planet: Twitter | Facebook

gleamwang

阳澄湖吃螃蟹

Veröffentlicht am 2016-10-15 |

2016-10-15 多云转晴 热

嗯 组团去吃螃蟹 天气还好 到那儿太阳就出来了 开始热了 很多人 很多车 很多蟹 哈哈哈

#下面是图

啦啦啦 到啦

记得去年绕淀山湖+阳澄湖 湖边有几条路也向下面这样 一溜儿都是卖螃蟹的

看到有个人牵着绳子遛螃蟹 觉得很好玩

静候

嗯 没来得及拍上桌的照片 我来的一个目的就是把吃完的壳再拼回去成完整的形状 啦啦啦 开心

蟹黄和膏都挺多的 都满了 很鲜 小钳子里面都是肉

不出意外 我又是最后一个吃完的人

嗯 战场

#总结

希望十一月份还有机会去吃肥肥哒

gleamwang

2016上海站尾场

Veröffentlicht am 2016-10-07 |

2016-10-07 小雨 上海体育场 写于21:50

(刚敷完面膜哦)

#两个半小时的录音

今天把十五段录音用imovie合成 找了半天上传音频的网站没找着合适的
点击收听或下载 (电脑端的话直接点 可以边听录音边看文章)
手机不能点 额 麻烦屈尊挪到电脑上打开听吧
百度云盘 链接: https://pan.baidu.com/s/1ge6LeuR
想直接点链接的 戳我 密码: 9ga5

里面喊最大声唱最大声 持续尖叫的人就是我啦

最近事儿多 各种talking各种黄段子啊 你们自己找 下面是歌单 反正就按时间顺序来

现在我开始边听演唱会录音边码字。。。

昨天的事儿 今天有空记录下 毕竟这辈子就这一次

*****图和录音明天传

# 买票准备

跟贴吧买的票 四张 和妹子一起去看 还好不是一个人

# 开场前一直纠结的问题
那就是看完咋回来啊 虽说4号和5号都十点半就结束了 可是十点半四号线也没有了啊 我还是不能坐地铁回来啊

又没有顺路的 一个人


  • 打车?不敢打啊 最近打车软件出了很多事儿 我害怕

  • 开车?女司机现在还不敢开啊

  • 住宿?一个人住外面我还是不敢啊

  • 算了 实在不行 就去什么网咖带到早上 坐地铁回来好了


开场前一直纠结 毕竟2016年的假期最后一天了 余额不足了 第二天还要上班啊 要不然通宵都行啊

毕竟年轻

后来遇到个小伙伴 给的建议就是 提早走 赶地铁 不然 打车的话 司机车开不进来 周边都得绕道 有可能还会要很多钱

“实在不行 就提前走吧 ”,这是打底儿的准备

# 演唱会准备

除了正常的官方荧光棒 由于五只代言了莫斯利安 而且把广告搬到了舞台上 会在演唱会上喝酸奶干杯 所以 想 我们能不能带酸奶进去 和大爷们一起干杯呢

后来 怕安检很严 莫斯利安只有杯装的 让试喝一口后也没多少了 就不带了

于是 我买了串香蕉哈哈哈 五个 和小伙伴么分了一下

五只一向有在con/通告/颁奖典礼中吃香蕉的传统

阿信说的 香蕉代表有福同享 雨伞代表有难同当 7号这天阿信打伞了哦 开心

# 关于演唱会时长及安排

说是7:00开始 这三天(前两天是听闻)都是‘宇宙人’出来唱到7:30 然后五只7:30再出来

结束差不多10:30 那就相当于五月天只唱了三个小时 还算安可

三个小时 你认为能嗨翻么 能尽兴么 虽然能值回票价 可是会差很多

相对于北京场 6:30开始 9:40结束 这还是在鸟巢对于时间是有限制的 所以结束的早

能看出差别了吧

所以上海场相对于北京场迟了一个小时才开场

我也就不多说什么的 可能有什么别的因素 也正常 只是没有说嗨到某个点而已

# 观看中
场外

每个座位都夹了一个扇子 好大的广告

由于自己前两天就很紧张 真的很紧张 “wc我等了四年呢啊啊啊啊啊啊” 对 就这种心情

背了一天歌词 嗯 参考4号和5号的歌单 划重点哈哈哈

所以从开场《do you ever shine?》 开始 就很嗨 唱很大声 蹦的也很频繁 就是那种兴奋的要跳起来

我全场录了音 除了有几个场景需要拍照 或者温柔的时候要打电话没有录到

阿信一开场打招呼的时候 声音就是哑的 没办法 就这样吧 这么多年过去了 嗓子也需要休息了

今晚五个四十岁男人的颜值都好高啊 好帅啊 就那种妹子都要去跪西装裤子冲动

阿信好像又变帅了呢 穿上西装好帅啊啊啊啊啊

果然怪兽最爱赤膊

知足最后一句 阿信还是没唱上去 哎 老了啊

少年 你能不能唱上去么 我嗓子都准备好呢

打招呼的时候 石头说今晚人变密了 阿信接下对观众说 “你们变密(便秘)了 需要疏通” 自己想啊 都笑喷了 后来 又解释说 “是人和人之间变密了 不是人自己” 怪兽接,“哦 不是人自己变紧了” 啊啊啊 什么鬼 不开黄腔就不能值回票价么啊喂

某次阿信又建议说 “不要总把荧光棒左右摇晃嘛 来 大家上下摆动看看” 额 反应了好久 大家都做出那个动作了 才反应过来说 阿信好污啊

说好的延伸台呢 之前的座位图有延伸台啊 骗纸

我们在16看台2层 偏角有点大 再远一点其实视野正好 因为看不到冠佑打鼓 只能通过大屏幕看

妹子说 看到了阿信打鼓 玛莎拉大提琴 如果今晚阿信再弹吉他 她今晚就死在这儿 事实证明 额 阿信最后真弹吉他了
后面 唱啥来着 不记得了 大信信换了件衣服 真是可爱的不要不要的 把妹子都迷倒了
图凑合着看吧

## 最爱玛甜甜

说下玛甜甜 头发好像又长了 百分之九十最先入镜的是他低着头飘逸的长发遮住脸 被风吹拂 在跳舞 画面太美


看到了玛莎拉大提琴 弹钢琴 因为真的很热 像我边蹦跶边唱 浑身是汗 刚开始他们还穿西装 更热 唱《诺亚方舟》的时候 有个镜头就是他抬起头 头发都粘在脸上了 心疼

“他怎么也不剪啊” 从开场 就蹦得很嗨 记得有一首歌 大家都坐在桌子旁 只有他一个人在后面跳舞晃头自嗨了一首歌 那飘逸的长发 帅呆了 好想去问问他用什么牌子的洗发水啊 (这个问题之前有人问过 他回答说 就一般的啊 )

又有一首歌 应该是《笑忘歌》 大家都左右摇晃荧光棒 啊 玛莎很可爱的举起了餐桌上的一整只烛台来左右晃 就这样晃了一整首歌 啊啊啊啊啊

#《温柔》
这个梗 该懂的人都懂啊

四年前 2012年7月19号 那时候 我大二 早早跟贴吧买了票 7月初就放暑假了 于是 我一个怕热的人硬是在学校多呆了半个月

和室友一起去看

之前也喜欢五月天一段时间了 知道温柔的梗 那时候还有我暗恋的人 从高二开始 一直没说出口 高考后 大家都考入了不同的学校 甚至不在一个省 也就放假见见 所以还是想让对方知道吧 于是 大晚上的给他打电话 因为现场 很多人 信号不好 就算打通了电话也听不清对方到底接没接通 接通了双方说什么能不能听得到 反正我听不到 所以 我心里也很忐忑 但是 没办法 这辈子可能就这一次机会来告白 勇敢一点吧(厚着脸皮一次好了)

于是 就打电话 因为不知道能不能接通就隔一分钟挂断 当时想的就是 我把要说的话说出来 让你听到 就可以了

嗯

第二天 那人给我打电话说 “你那么晚打电话啥事儿啊 喝多了吧 ”

我说 嗯 “我喝多了”

—-over—-

现在觉得说 我那时至少还有喜欢的人 默默的放在心里 那时候还用人人 qq空间

会悄悄的去看他的动态 好奇他的近况 会看他的访客互动 动态下留言 猜测他的心情。。。

暗恋就是这样啊 你不想让对方知道 你又怕对方不知道 很纠结 也很美好

咳咳 不讲故事了

为了圆打电话的愿望 (我觉得既然那个人没陪你来看演唱会 有一个能打给的人也很好)我厚着脸皮让老年人准备大晚上的接我电话 对 就是那个扛把子的 电话接通了 听到了 很高兴
# 关于门票

有很多人通过某些渠道 网上或是场外黄牛买到了假票 很多人都被骗了 所以你们要理智 啊 不会从五吧和纯真收票么 而且今年的票务方也是有脑子哦 一段段放票后 造成票子紧张的局面 抬高了价钱 上海首场黄牛255的票子卖500多 (其实对于黄牛党 我的观点就是 为了利益 加价可以接受 卖假票还有没有良心啦) 以至于后来票子卖不出去 十一前一个星期 永乐票务还有大量余票 一个朋友25号下单买了张555的票 收到的是票价755的 哈哈哈 吃惊

反正我只信任五吧和纯真 感谢这两个组织 不加价无假票 感谢默默付出的相关人员 尤其是团购相关的 五吧的座位一直都很好 这次555的座位已经很值了 离舞台超近 嗯 希望以后还能一起看演唱会

什么感动了你

## 行李箱
本来以为上海尾场人会变少 6:40进场 看人确实也不多 我们右边四个座位都是空的

后来慢慢的入座 内场也差不多坐满了 除了后区右侧 有一个正方形的区域 位子没几个人坐 很明晰

到开场的时候 差不多都坐满了 右边两个座位还是空的。。。。

后来 人来了 被惊到了 一个妹子拎着行李箱来的

(写到这儿 我都又感动了一下呢)

真爱啊 佩服

后来 出去的时候 又看到了几个行李箱 你们来得值 嗯 路上有多少汗水都值

安可时举的标语 平板和毯子

还记得么

“请让我们一起喊安可”

。。。。。
#图
很喜欢蓝海 也喜欢彩虹



# 结束后赶地铁

心中有不舍啊 因为不知道大爷们到底打算唱到几点啊

这是上海站尾场 加时很正常 而且演唱会过程中 冠佑透露 可能会多唱几首

12年诺亚方舟 十一点多才结束

所以今晚 如果唱到十一点多 那我十点多就走了 就有很多遗憾

由于从大爷们七点半开场就一直很嗨 跟唱 有时候激动的一直蹦达 跳起来 到了温柔唱出来 觉得也没什么遗憾了 就算少听了安可的歌 所以任性的决定先走吧 自己的生活还要继续

22:12听着倒数第四首歌《转眼》的时候果断收拾东西 和妹子抱了抱 边听转眼边跟着人群满满走出演唱会

出来的时候 拍了张照片 我来过 真好

跑去赶地铁 跑出去之后 天空下起了小雨 开始唱洋葱了 于是就边跑边唱摇着荧光棒唱洋葱 那场面 也是难忘

刚开始跑反了方向 到了一个十字路口 问了穿制服的 又往回跑

那时候只有几个妹子在跑 很多人都是正常走 嗯 可能是因为我们比较远吧

快跑到地铁口的时候 听到工作人员在喊 说 最后一班地铁快到了

于是 跑的人多了起来

超热 sr不是盖的 面料真不透气啊 蹦跶了三个小时+一路赶地铁狂奔 现在静下来 满头大汗

貌似还有几分钟到22:34分呢 于是 拿出了发的扇子 扇风 擦汗

这就意味着 我能坐地铁回去啦 不怕回不去啦啦啦啦

回到家都快十二点了 大雨

实际上 演唱会三首歌后结束 我也没什么可惜的了 还好
# 碎碎念
这三天朋友圈都说被刷屏 说可以通过朋友圈看直播哈哈哈哈

体育场一进去就各种周边 每个铺子都写着“五月天官方荧光棒摊位”也是醉了

而且 就算是官方买的荧光棒 质量好像也不太好 知道的两个妹子都坏了 还要去买新的 一个四十呢 不得不说 五只有头脑 演唱会的可控荧光棒数量可观呢

我不是脑残粉 只是一个喜欢了五年的迷妹

不是信仰 不是梦想 只是成长路上的背景音乐

还记得八十岁的约定 无论那是我在哪里 都会去的 一大家子人一起去

今早上班 找同事借充电器 同事说我 “咋春风得意的呢”

额 额 额 就是默默的爆发了下 觉得生活很美好 我有想要的 有期待的 有追求的 我就有努力的动力

--总结--

所以 下一场演唱会你还是会一个人么???

23:34 困了 演唱会录音明天再传吧。

gleamwang

奶奶牌炖排骨汤

Veröffentlicht am 2016-10-01 |

奶奶熬了四个多小时的排骨汤

#下面是图

油都浮上来了 没加什么其他佐料 越简单 味儿越纯

盛汤喝啦 通常一碰到什么骨头汤啊猪蹄汤啊牛肉汤啊鸭汤啊 我都不用吃饭了
先喝两碗汤暖暖胃 啃两块复杂的骨头 再喝两碗就饱啦

哇哦

其实 这时候的排骨没什么营养了 但是肉很嫩 对


#总结

有陪伴 才是温暖

1234…8
John Doe

John Doe

79 Artikel
13 Tags
RSS
© 2017 John Doe
Erstellt mit Hexo
Theme - NexT.Muse