用Bartender隐藏macOS通知栏的spotlight图标

一直用Bartender管理mac的通知栏,隐藏一些不常用的图标。但是从Mac OS X 10.11版开始,Spotlight的图标就无法被Bartender隐藏了。因为Mac OS默认会打开系统完整性保护(SIP)功能,拒绝其它程序修改Mac系统,所以Bartender无法修改Spotlight的显示状态。

想要隐藏spotlight图标需要先得把SIP暂时关闭:

  1. 重新启动电脑,在黑屏后,显示苹果标志前,按住键和R键,让Mac进入救援模式;
  2. 在救援模式的工具菜单中打开终端机,在终端中运行命令csrutil disable,关闭SIP;
  3. 退出终端重启电脑;
  4. 打开Bartender,现在可以设置Spotlight的隐藏设置了;
  5. 设置完成后,再次重启进入救援模式,方法同步骤1;
  6. 打开终端机,运行命令csrutil enable再次启用SIP;
  7. 重启到正常模式后,Bartender的对Spotlight的隐藏设置依然有效。

使用flock确保只有一个命令实例在运行

公司的机房设置了一个5分钟执行一次的数据同步脚本。一般每次同步只需要花费不到20秒即可完成,但网络出现问题时,就可能五分钟无法完成同步。脚本第二次启动可能干扰仍在运行的第一次脚本,需要有一个办法确保只有一个实例在运行。

Ubuntu系统提供了一个软件包叫run-one,可能实现这一功能,让我们来试试。首先安装软件包,以root权限运行:

# apt-get install run-one

安装好之后,运行run-one <要单实例运行的命令>,就可以确保只有一个实例运行了。比如:

# run-one tail -f /var/log/syslog

我们可以看到syslog的最后几行,并随着日志输出而滚动。此时如果打开另一个terminal,再次输入上述命令,会直接退出,并且exit code是1:

# run-one tail -f /var/log/syslog
# echo $?
1

除了run-one命令,run-one软件包中还提供了几个实用的命令:

  • run-one 只运行一个进程实例,如果实例已存在,直接退出
  • run-this-one 只运行一个进程实例,如果实例已存在,kill掉它并重新运行
  • run-one-constantlyrun-one一样,只运行一个进程实例,当进程退出时自动重新启动
  • keep-one-running run-one-constantly的别名
  • run-one-until-successrun-one-constantly相似,但只有当进程退出码不为0时才重新启动进程
  • run-one-until-failurerun-one-constantly相似,但只有当进程退出码为0时才重新启动进程

在CentOS系统中,并没有run-one软件包可供使用。不过我们可以利用flock锁定的机制自己实现只有一个进程运行。

可以写一个脚本:

#!/bin/bash

TODAY=`date +%Y%m%d`
(
  flock -xn 100 || exit 1
  scp root@myhost:/data/backups/$TODAY.log.gz /data/backups/myhost/
  gzip -d /data/backups/myhost/$TODAY.log.gz | xz -9 -e > /data/backups/myhost/$TODAY.log.xz && \
  rm /data/backups/myhost/$TODAY.log.gz
) 100>/tmp/backup_data.lock

上面的脚本中,flock命令会对/tmp/sync_data.lock文件加上写入锁(排它锁),分别在两个terminal中运行这个命令,会看到一个开始scp拷贝数据,另一个直接退出,退出状态码为1。

flock命令有三种写法:

  1. flock [-sxun][-w #] fd#
  2. flock [-sxon][-w #] file [-c] command...
  3. flock [-sxon][-w #] directory [-c] command...

我们前面用的是第一种,定义一个文件描述符,这种方法适合用于多行命令需要排它运行的场景。后两种flock的用法适合只有一条命令要运行的场景。flock-s选项表示要获取读取锁(共享锁);-x选项表示要获取写入锁(排它锁);-o选项表示在运行命令前关闭已取得锁定的文件,如果后面的命令可能产生不该取得锁定的子进程,这个选项会很有用;-n选项表示不要阻塞,如果无法取得锁,不要等待其它进程释放锁定,直接退出;-w 10表示等待10秒,如果10秒仍无法取得锁,就退出。

run-one是一个Bash脚本,通过查看run-one命令的源码得知,它也是利用flock实现的唯一化处理。如果不想自己编写带flock的程序,又想使用run-one提供的完整功能,可以去Github上下载run-one项目的代码。

SSH端口映射

SSH提供了两种端口映射方式,一种是本地端口映射,另一种是远程端口映射。

使用本地端口映射,SSH客户端会在本地监听一个端口,所有到该端口的连接全部转发到SSH服务器上指定的主机和端口号上。例如,我需要在我自己的电脑上访问VPS服务器上的数据库,但是服务器上的MySQL绑定在了127.0.0.1的IP地址上,可以用下面的命令把我电脑上的33306端口转发到服务器上的3306端口。

ssh xts.so -l root -L 33306:localhost:3306

运行这个命令后,我就可以直接用MySQL客户端连接自己电脑的33306端口访问服务器数据库了。

SSH的-L参数完整格式是-L [bind_address]:port:host:hostport,其中bind_address是本机(客户端)的绑定IP,可以省略,缺省值是127.0.0.1,如果需要允许其它电脑访问,可以监听0.0.0.0或者简单写个*port是本机开始监听的端口,这个端口的连接会转发到服务器上;host是相对于服务器而言的目标主机地址,域名、hostname、IP地址均可;hostport是目标主机的端口号。

3497093050.svg

如果需要在本地内网访问服务器机房内网的数据库,只需要指定binding_addresshost就可以了。

远程端口映射,SSH会在服务器上监听一个端口,所有到该端口的连接全部转发到SSH客户端指定的主机和端口号上。例如,我需要让本机的80端口可以在公网访问,却又不能独立使用公网IP,可以找一台VPS服务器作远程端口映射。

ssh xts.so -l root -R *:8080:localhost:80

运行这个命令后,用浏览器打开http://xts.so:8080/就相当于访问我本地电脑的80端口。

SSH的-R参数完整格式是-R [bind_address:]port:host:hostport,其中bind_address是远程(服务器)的绑定IP,可以省略,缺省值也是127.0.0.1;port是远程服务器上开始监听的端口;host是相对于本地电脑而言的目标主机地址;hostport是目标主机的端口号。

SSH远程映射也叫反向端口映射,因为常用于把内网主机的22端口暴露到公网。

ssh xts.so -l root -R *:2222:localhost:22 -N -f

这个命令可以把服务器的2222端口映射到本机的22端口,从而允许从Internet登录内网服务器。-N告诉ssh不要运行任何命令,此连接只用于端口映射。-f选项可以让ssh转入后台运行,这样ssh命令运行之后就能回到命令行,可以继续使用其它命令。

如何安全地保存用户的密码

最近数据库泄漏事件层出不穷,无数人的上网密码被人破解。本文来探讨一下如何安全地保存用户的密码。

为什么非要安全地保存密码?因为人类使用密码有三大偏好:

  1. 喜欢用简单好记的密码
  2. 喜欢到处用相同的密码
  3. 不喜欢经常地修改密码

为了你的客户不至于因为你的数据库泄漏事故和损失惨重,请保护好他们的密码!

最烂的方式:明文保存

许多早期制作的网站,还有众多的政府网站,都是这么保存密码的,包括著名的CSDN也是。有的时候这么保存密码是不得已的:我曾经接到过一个政府部门的项目,领导要求在他忘记密码的时候能让单位负责IT工作的小王帮助查一下密码是什么。不过还好一般并不难说服领导换另一种方式:如果您忘了密码,可以用手机重设密码。

明文保存密码的方法把密码安全完全交给了运维。任何安全漏洞,不论是操作系统漏洞,还是数据库漏洞,甚至应用程序中的漏洞,都会导致用户的密码大白于天下。

次烂的方式:MD5保存

相对明文密码好一点的方法是把用户的密码直接哈希保存。可惜大多数用这种方式保存密码的人并不是因为意识到明文保存密码有什么不妥,仅仅是因为学习编程的时候教材上是这么做的。利用单向哈希算法保存密码当然能比明文保存好一点点,但其最大的问题却在于会让开发者误以为用户的密码是非常安全的——即使泄漏了数据库,黑客也不可能知晓用户的密码是什么。

且不说MD5已经被证明是非常不安全的哈希算法,即使换成SHA-1或者复杂度更高的哈希算法,也不可能显著地提升用户密码的安全性,因为黑客攻击的方式往往并不是通过数学方法寻找哈希碰撞,而是直接在字典中查询。每个黑客手上都有上千万条记录的密码字典,包括常用的单词、拼音、19xx到20xx年的生日等等。他们只需要把MD5的结果输入,就能在字典库中找到对应的原文。一般一个MD5的密码库泄漏的时候,超过八成密码能在字典中反查得到。

比较好的方式:加盐哈希保存

如果定义一个长字符串,把它插入到用户密码中的某个地方,然后再哈希出结果,这样可以改变用户密码的哈希结果,使字典攻击失效。

比如用户的密码是abc123,直接MD5的结果是e99a18c428cb38d5f260853678922e03,大多数黑客的字典中都有这条记录。如果我们把用户的密码加上这个前缀ask3Kxsk777sA00bdsOo552,变成ask3Kxsk777sA00bdsOo552abc123,然后再进行MD5计算,得到的就是3ee795c4ceadf8b21a12f6e373cb1c56,一般黑客的字典里都不会有这条记录。这里用到的前缀就被称作“盐”

加盐哈希保存的结果是,黑客需要同时取得你的数据库和你的“盐”,并且加盐重新生成整个字典库才能破解你的用户密码。安全性比直接哈希保存要高多了。

更好的方式:随机加盐哈希保存

这是对于上一种方法的改进。在前面的方法中,盐是固定的,加盐的位置是固定的,以当今的计算机速度,黑客只需要多花点心思把你的盐搞到手,然后再花个一两天把密码库加盐跑一遍,还是能破解你大多数用户的密码。

如果在保存密码的时候盐随机生成,并插入到原始密码的随机位置,那么数据库里每条密码记录的盐和加盐位置都不同,黑客如果要破解密码,就需要为每一个密码生成一遍字典库,工作量要大得太多了。

最好的方法:没有密码

最安全的密码保存方法就是完全不保存用户密码。现在各大社交网站都支持账户接入非常发达,完全可以让用户用微博、微信、QQ、豆瓣、淘宝、人人、Google、Yahoo、Twitter、Facebook等等等等各种第三方账户来登录你的系统,再不济也可以让用户用随机短信密码来登录。没有保存密码,就不会丢失密码。

别人推荐的方式:慢哈希

慢哈希是一种特别的哈希算法,它比MD5、SHA1等常见的密码哈希算法要慢得多。它的安全原理是:在用户注册或者登录等正常行为时,哈希函数的运行时间由几毫秒变慢为几百毫秒,在用户感受上不会有太大的差别,而对于攻击者来说,因为需要大量计算哈希值试错,慢哈希函数就能有效延长破解密码所需的时间。